---
title: Creating Hilarity on April Fools Using Discord, Python and Google Translate
description: And leading people on a little bit too...
publishedDate: 2024-04-01
tags:
    - projects
---
Happy April Fools!

At the moment, I'm on the committee of my uni's computer science society, which also means I've got permissions on the big society Discord server - ***and I can add bots to it.*** >:)

Since we had no proper April Fools plan, I decided now was a good time to revive my April Fools gag from 2020 - [Fubot](https://github.com/codemicro/fubot).

Fubot was an atrocious contraption that repeated every single message sent in a given channel back to the author. I deployed it in a decently large server I was an admin of at the time and, as you can imagine, it caused immense frustration and much amusement (for me).

This time, in order to make it less frustrating and more amusing, I decided to add a little spin on it. Instead of repeating *every* message, it repeats only some. And instead of simply repeating the message, it translates it into Polish and sends you that - so if you think about it, Fubot provides a useful service!

This is all quite easy to implement, thanks to [Pycord](https://pycord.dev), though there are some fun little implementation details.

First, deciding when we actually want to repeat a message would be boring if it had static odds. Oh no - instead, we do it based on how far through the day we are. At the beginning of the day, we can start off with a 1 in 25 chance of repeating a message - and since in the morning, the server is usually a bit quieter, it'll probably be quite unlikely to see the bot doing anything. Over the course of the day, we have the probability of activation rise until it eventually becomes 1 in 1 at midnight - for the ultimate chaos.

A somewhat cursed way of implementing that is this:

```python
def get_max_prob() -> int:
    end = int((datetime.date.today() + datetime.timedelta(days=1)).strftime("%s"))
    remaining = end - int((datetime.datetime.utcnow()).strftime("%s"))
    return (int(24*(remaining/86400))) + 1

@bot.event
async def on_message(msg):
    # ...
    if random.randint(1, get_max_prob()) != 1:
        return
    # ....
```
The other fun detail is how we actually do translation.

The Google Translate API, for example, requires registration and payment to use, and I really couldn't be bothered to deal with that at 2am in the morning when I was setting this up. Luckily for me, there are ways to get around the restrictions quite easily provided you're only doing a small amount of translation for no important reason - that way being `https://translate.googleapis.com/translate_a/single`, which is an ungated API endpoint that I *believe* is intended for use by Google Chrome's built-in translate feature.

We can abuse it like this:

```python
def translate_string(en_txt: str) -> str:
    # source: https://web.archive.org/web/20220101090143/https://danpetrov.xyz/programming/2021/12/30/telegram-google-translate.html
    uri = (
        "https://translate.googleapis.com/translate_a/single?client=gtx&sl="
        + "en"  # this is the source language
        + "&tl="
        + "pl"  # this is the target language
        + "&dt=t&ie=UTF-8&oe=UTF-8&otf=1&ssel=0&tsel=0&kc=7&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&q="
    )
    uri += urllib.parse.quote_plus(en_txt)  # this is normal url encoding
    res = requests.get(uri)
    j = res.json()
    return j[0][0][0]  # lol
```

Throw these all together into [a single Python file](https://github.com/codemicro/fubot/blob/dfa11056914f23bb68ea1ba10db7be2da7a1131c/main.py), set up a Discord bot user and grab a token and you've got a recipe for slight chaos. All you have to do is sit back and wait. It's also containerised for my (and potentially your) deployment convenience.

One unexpected side effect of piping stuff through Google Translate is that it gets modified slightly - you know when you type something garbled into Google Translate and it does its best to sort it out for you and fix it? That happens in the above endpoint too, which led to some broken corrections and further amusement.

I was quite pleased with how the bot functioned throughout the day - I thoroughly enjoyed seeing people's theories about what the trigger criteria was (no, it was not sentient), and likewise I enjoyed seeing people's reactions to my stupid creation. As a closing note, here are some of my favourite exchanges:

![who added this bot??; What bot; Jakiego robota; Yeah no idea what you're on about](2.png)

![does it reply to me now?; No; NIE](3.png)

![That seems unfair; Tell me about it; Opowiedz mio tym; Fuck you.](4.png)

![did i miss something with regards as to why the polish bot is wreaking havoc; czy przeoczylem cos w odniesieniu do tego, dlaczego polski bot sieje spustoszenie?; dont patronise me; nie patronuj mi](5.png)

![<odwrocony obiekt pod adresem 0x7f8726165670>](6.png)
The context to this one is that there was a small chance that messages would be reversed as well as translated as an ode to [Reverse Polish Notation](https://en.wikipedia.org/wiki/Reverse_Polish_notation) but I didn't realise that this was broken.

![Eyyyy; yyyy](7.png)

![also someone remove this bot](1.png)

![I'm already so attached to this bot](8.png)