1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
=== 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
|