My personal Discord chat bot, written in Python 3
acid-bot runs on Python 3.4+ (tested only on 3.5) and requires gTTS (Python TTS library), discord.py (Discord Bot API wrapper for Python), youtube-dl (to play songs in voice chat) and requests. It also requires my postfix calculator implementation, which comes included (postfix.py).
The bitmap generator requires nodejs installed, and sandbox installed via NPM.
The log_server.py Flask server requires flask to be installed. It is a separate program which gives users access to view the logs that the bot keeps.
On start-up, the Discord API token must be read from file secrettoken in the same directory.
\help This helpful message.
\rr [subreddit] Get a random image from [subreddit]
\calc [query] Postfix calculator
\whoami User stats
\whois [username] ^ Ditto
\ping Pong.
\define [word] Lookup the definition of [word]
\ud [word] Lookup the urban definition of [word]
\50/50 You feeling lucky?
\flip Flip a coin
\callvote [message] Calls a vote and counts the tally after 7 seconds.
\tell @[name] [msg] Send [msg] to @[name] next time the bot sees them.
\remind @[name] [msg] in [time] Send a reminder to @[name] after [time].
\imitate [username] (length) (tts) Imitate [username] (Markov Chains!).
\markovusers List users' markov ratings (higher number means better \imitate)
\markovsave Save markov data to disk
\reactionadd [name] [url] Add a new link to the [name] collection
\reactions Lists all the reaction collections
\\[name] Random link from [name] collection (TWO backslashes)
\voice Connect/disconnect from your voice channel
\play [URL or title] Plays the audio at [URL] or searches YouTube for [Title].
Supports playing from 1039 websites (http://bit.ly/2d9yknp)
If already playing, adds query to the queue.
\skip Skip current song.
\queue View the current queue.
\queuepop [n] Removes item [n] from the queue.
\stop Stop playback. Discards queue.
\tts Say something with the tts
\chlang Changes the tts language (from https://pastebin.com/QxdGXShe)
\scores List math scores
\problems Start a short 10 question basic facts test
\ans [ans1] [ans2] ... Answer the basic facts test
\logs Generates a link to the logs.
Debug (Admin) Commands:
\markovload \markovclear [username] \markovfeed [username] [url]
\rename [newname] \setgame [playing] \reactiondel [name] [num]
Everything is functional. Improvements are needed on the math-quiz commands and the markov bot imitation fails to produce correct output.
- The bot logs all messages, edits, and deletions into an sqlite3 database
logs.db. This is to counter censorship. - The bot saves all reactions to a
reactions.json. This file can be edited directly, but the bot must be restarted to take the changes. - Word-pair data for the markov bot is stored in
markov.pickle. This data is not saved unless the\markovsavecommand is run. - Math-quiz score data is storred in
mathscores.json. - The
[url]supplied to\markovfeedmust point to a resource withContent-Type: text/plain. - Permissions are defined per-command hardcoded into the bot. Change them to your liking. Use IDs given by
\whoamiand\whoiscommands. - You do not need to type the whole username for
\whoisto work. The first few letters will be sufficient.
There really needs to be some documentation on how to fully run this program. I'm going to assume you've installed all the required dependencies.
The program requires a file called secrettoken which contains the bot token generated by Discord. Put the token (NOT the client secret) in this file. It will be read when discordbot.py starts.
When you start discordbot.py a bunch of files will be loaded and settings will be set. First, it opens an sqlite3 database. This database must already exist. Creation of this table is trivial, just run this line of SQL:
CREATE TABLE logs (time real, channel text, id integer, name text, displayname text, messageid integer, deleted integer, edited integer, message text)
And save the file as logs.db. Put the file in the same directory as discordbot.py. The time field is the unix epoch of the event in UTC, id is the ID of the author, and messageid is the unique ID for that message.
Next, the Markov manager is started. It will load a Python pickle file, markov.pickle, containing the markov data (if it exists). To save markov data, you must run \markovsave command. This will save all past conversation data to the disk. The bot will not do this automatically.
Next, the VoiceWrapper is created. It has no settings. After that, MathRunner is created. This will load users' math game scores from mathscores.json (if it exists).
The reaction list is then loaded from reactions.json. The tells (see \tell) are loaded from tells.json. The reminders are loaded from reminders.json. The banned IDs are hardcoded. IDs in this list cannot execute commands. The settings for the logserver are loaded from logserver_config.json. This file MUST exist, even if you do not intend to use the logserver.
The log server
log_server.py contains a Python 3 Flask program which serves up the information contained in logs.db. It must run in the same directory as the logs.db file. To access the logs, a token must be generated by accessing /gentoken?password=password where the password is stored in logserver_config.json under token_generator_password. Only the server and the bot can know this password.
When a successful GET request is made to /gentoken the response body will be, in plaintext, a 12 character token, such as 43247b7fe87F. Then by accessing /logs/?t=43247b7fe87F a user will be granted access to view the logs. The token lasts 1 hour by default. This can be modified in logserver_config.json in the field token_lifetime.
The commands
\rrand\rrtopread JSON data from reddit.com.\calcruns on the RPN calculator implementation:postfix.py.\definemakes a GET request to dictionary.com and retrieves the first definition only. Seedictionarycom.py.\udmakes an API request to Urban Dictionary. Seedictionarycom.py.\50/50makes a request to reddit.com/r/fiftyfifty and reformats the title.\tellwill let you send messages to users. The messages will only be sent the next time they speak.\remindwill send messages after a fixed period, and regardless of whether or not the person is online.\voicewill join/leave the voice channel. It currently joins the first voice channel it finds.\ttswill send text to Google, and Google will return a wav file saved tovoice.wav. The bot will use ffmpeg to play the wav file on voice chat. The bot hangs while it downloads from Google, so really long tts texts will cause the bot to time out from Discord.\logswill generate a link and token for a user to access the logs that the bot keeps.\playtakes either a query or a URL. If it is a URL to a video or audio site, or is a video or audio stream, it will attempt to play, asyoutube-dlis capable of such things, being magic and all. All songs are downloaded into directorydownloaded/. This folder should probably exist before starting the bot. If a thing is currently playing, then the query (not the song) is added the the queue. When a new audio query starts downloading, the bot will start playing from it as soon as it can (instead of waiting for the download to finish).\volTakes a volume for a\playstream as a value from 0 to 100. Adjusts the volume on the fly.\plopTakes a javascript function of the formfunction(y,x) { ... }which must always return a 3 element array. It is safely run on the server in a nodejs sandbox, and the output is used by PIL to populate an image with pixels.
\plop function(y,x){ x -=128; y-=128; x*=4; y*=4; if( Math.abs( Math.tan(Math.hypot(x,y)*Math.PI/180) - y/x) < 2 ) return [255,255,255]; else return [0,0,0]; }
