=== bracket bot === this is a system for running a bracket in discord via polls. the python files in this repository are released under the unlicense (see unlicense.txt). === usage === == requirements == this project uses python with the requests library. assuming you have the pip and venv modules for python, you can set up an environment like so: python3 -m venv env env/bin/pip3 install -r requirements.txt == create database == next, we need to make a csv file with a list of entries in our bracket. each line of the csv file corresponds to one entry. if a line has one column, the text in that column is the name of the entry. if a line has two columns, the text in the first column is the name of the entry, and the text in the second column is an associated emoji. this can be a unicode emoji (at time of writing, discord supports up to unicode 15.0), or it can be the id of a server emoji that your bot will have access to. now, use the make-db.py script to create the database. there are two positional arguments, first the path where the database will be created, and second the path to the csv file to read. there is one optional argument, "-s". if this argument is present, the entries are shuffled, and otherwise the order from the csv file is preserved. for example, if the csv file we made is in entries.csv, we want to put the database in database.db, and we want to shuffle the entries, we can run: python3 make-db.py database.db entries.csv -s we do not need to use our venv environment when we run this. == posting a poll == to post a poll, use the post-poll.py script. this has three positional arguments. first, the path to the database. second, the id of the channel to post in. third, the number of hours to keep the poll open for. the script also expects an environment variable named TOKEN with the bot token. with the setup above, if we want a bot with token ABC123DEF456 to post a 24-hour poll in a channel whose id is 1234567890, we can run: TOKEN=ABC123DEF456 env/bin/python3 post-poll.py database.db 1234567890 24 the script finds two entries that have not been eliminated and are not currently in any (unprocessed) polls. entries are picked first preferring entries that have never been in a poll in the order from the database creation step, and then entries that have been in polls in the order that the most recent polls they were each in in occurred. for two entries that have the same most recent poll (i.e. ones where the most recent poll was a tie), the order from the database creation step is used. if there are not two qualified entries, the script just prints a message and quits. == processing polls == to process the posted polls, use the process-polls.py script. this script has one positional argument, the path to the database. it also expects the environment variable TOKEN as above. with the setup above, to have the same bot process all of its polls, we can run: TOKEN=ABC123DEF456 env/bin/python3 process-polls.py database.db the script waits until every posted poll has both expired and finalized. == cron script == it is recommended to call a script like this from a crontab once per day: start_time=$(date +%s) cd bracket-bot export TOKEN=ABC123DEF456 env/bin/python3 process-polls.py database.db now_time=$(date +%s) hours=$(echo \($start_time + 86400 - $now_time\) / 3600 | bc) env/bin/python3 post-poll.py database.db 1234567890 $hours this script posts one poll that lasts as long as it can while expiring within 24 hours of this script starting. to post more than one poll per day, you can put the last three lines in a loop that runs some number of times. change the bot token, the channel, and the paths as needed. === database schema === == table entries == name TEXT UNIQUE NOT NULL - json string representing the name of the entry emoji TEXT - either null, a unicode emoji, or a discord emoji id status INT NOT NULL - 0 = safe, 1 = in poll, 2 = eliminated last_poll_number INT NOT NULL - poll_number for the last (or current) poll it was in, or 0 if none sort_number INT UNIQUE NOT NULL - a number used to sort the entries (the values don't matter, just the order) == table polls == poll_number INT UNIQUE NOT NULL - what number poll it is (starts at 1) entry_1 TEXT NOT NULL - entries.name for first entry entry_2 TEXT NOT NULL - entries.name for second entry posted INT NOT NULL - unix timestamp of when poll was posted expires INT NOT NULL - unix timestamp of when poll expires / expired channel_id TEXT NOT NULL - discord channel with poll message_id TEXT NOT NULL - discord message with poll voters_1 TEXT - comma-separated user ids who voted for first entry, or null if active voters_2 TEXT - comma-separated user ids who voted for second entry, or null if active == table users == id TEXT UNIQUE NOT NULL - discord id global_display TEXT NOT NULL - global display name, or username if there is none avatar_hash TEXT - the user's avatar hash on discord's cdn, or null if they haven't set one retrieved INT NOT NULL - unix timestamp of when this was last updated