├── cron.sh ├── requirements.txt ├── .gitignore ├── .env.example ├── README.md ├── favourite-question-bluesky-bot.py └── db.sql /cron.sh: -------------------------------------------------------------------------------- 1 | python favourite-question-bluesky-bot.py -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | atproto==0.0.55 2 | psycopg2-binary==2.9.10 3 | python-dotenv==1.0.1 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | env 2 | images 3 | cron.log 4 | _TODO.txt 5 | .env 6 | .env.local 7 | .env.production 8 | .vscode -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Bluesky credentials 2 | BLUESKY_HANDLE='' 3 | BLUESKY_PASSWORD='' 4 | 5 | # PostgreSQL credentials 6 | DB_NAME='' 7 | DB_USER='' 8 | DB_PASSWORD='' 9 | DB_HOST='localhost' 10 | DB_PORT='5432' 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Favourite Question - Bluesky bot 2 | 3 | [![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) 4 | 5 | What is your favourite question? 6 | 7 | A Bluesky bot that posts a new question daily. 8 | 9 | A recreation of an old Twitter bot from the good old days... 10 | 11 | 12 | ## Requirements 13 | 14 | - Python 3 15 | - PostgreSQL 16 | - A Bluesky account 17 | 18 | 19 | ## Set up 20 | 21 | ### Bluesky 22 | 23 | Set up a new Bluesky account, make a note of the handle and password. 24 | 25 | Even better, create a new application password just for this app. 26 | 27 | 28 | ### Database 29 | 30 | #### DB access 31 | 32 | If necessary, create a new database and user within PostgreSQL: 33 | 34 | ```sql 35 | CREATE DATABASE favouritequestiondb; 36 | \c favouritequestiondb; 37 | CREATE USER favouritequestionuser WITH PASSWORD 'favouritequestionpw'; 38 | GRANT ALL PRIVILEGES ON DATABASE favouritequestiondb TO favouritequestionuser; 39 | GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public to favouritequestionuser; 40 | GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to favouritequestionuser; 41 | ``` 42 | 43 | #### DB population 44 | 45 | Run the SQL commands in `db.sql` to create and populate the database with questions. 46 | 47 | 48 | ### Script 49 | 50 | Clone this repo somewhere... 51 | 52 | Set up a new virtual env: 53 | 54 | ```sh 55 | python -m venv env 56 | source env/bin/activate 57 | ``` 58 | 59 | Install dependencies: 60 | 61 | ```sh 62 | pip install -r requirements.txt 63 | ``` 64 | 65 | Copy the `.env.example` file to `.env` and populate the relevant details: 66 | 67 | ```sh 68 | cp .env.example .env 69 | ``` 70 | 71 | You may need to make the cron script executable: 72 | 73 | ```sh 74 | chmod +x cron.sh 75 | ``` 76 | 77 | Set up a cron to run this daily: 78 | 79 | ```sh 80 | crontab -e 81 | ``` 82 | 83 | Edit cron to run script daily, e.g. at 8:42am: 84 | 85 | ```sh 86 | 42 8 * * * /path/to/cron.sh >> /path/to/cron.log 2>&1 87 | ``` 88 | 89 | 90 | --- 91 | 92 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 93 | Version 2, December 2004 94 | 95 | Copyright (C) 2004 Sam Hocevar 96 | 97 | Everyone is permitted to copy and distribute verbatim or modified 98 | copies of this license document, and changing it is allowed as long 99 | as the name is changed. 100 | 101 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 102 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 103 | 104 | 0. You just DO WHAT THE FUCK YOU WANT TO. 105 | -------------------------------------------------------------------------------- /favourite-question-bluesky-bot.py: -------------------------------------------------------------------------------- 1 | import os 2 | import psycopg2 3 | from atproto import Client 4 | from dotenv import load_dotenv 5 | 6 | load_dotenv() 7 | 8 | 9 | class FavouriteQuestion: 10 | def __init__(self): 11 | self.db_config = { 12 | "dbname": os.getenv("DB_NAME"), 13 | "user": os.getenv("DB_USER"), 14 | "password": os.getenv("DB_PASSWORD"), 15 | "host": os.getenv("DB_HOST"), 16 | "port": os.getenv("DB_PORT", "5432"), 17 | } 18 | self.connection = None 19 | 20 | def connect(self): 21 | """Connect to the database""" 22 | try: 23 | self.connection = psycopg2.connect(**self.db_config) 24 | except psycopg2.Error as e: 25 | print(f"Database connection error: {e}") 26 | 27 | def close_connection(self): 28 | """Close database connection""" 29 | if self.connection: 30 | self.connection.close() 31 | 32 | def get_random_question(self): 33 | """Fetch a random question that hasn't been posted""" 34 | try: 35 | with self.connection.cursor() as cursor: 36 | cursor.execute(""" 37 | SELECT id, question 38 | FROM questions 39 | WHERE date_posted IS NULL 40 | ORDER BY RANDOM() 41 | LIMIT 1; 42 | """) 43 | result = cursor.fetchone() # (id, question) tuple or None 44 | return result 45 | except psycopg2.Error as e: 46 | print(f"Error fetching random question: {e}") 47 | return None 48 | 49 | def mark_question_as_posted(self, question_id): 50 | """Update the question as posted on the current date""" 51 | try: 52 | with self.connection.cursor() as cursor: 53 | cursor.execute( 54 | """ 55 | UPDATE questions 56 | SET date_posted = CURRENT_DATE 57 | WHERE id = %s; 58 | """, 59 | (question_id,), 60 | ) 61 | self.connection.commit() 62 | except psycopg2.Error as e: 63 | print(f"Error updating question: {e}") 64 | 65 | def post_to_bluesky(self, question_text): 66 | try: 67 | client = Client() 68 | client.login(os.getenv("BLUESKY_HANDLE"), os.getenv("BLUESKY_PASSWORD")) 69 | client.send_post(question_text, langs=["en-GB"]) 70 | except Exception as e: 71 | print(f"Error posting question: {e}") 72 | 73 | def post_question(self): 74 | """Select a random question, post it, and mark it as posted""" 75 | question = self.get_random_question() 76 | if question: 77 | question_id, question_text = question 78 | 79 | self.post_to_bluesky(question_text) 80 | 81 | self.mark_question_as_posted(question_id) 82 | else: 83 | print("No unposted questions found") 84 | 85 | 86 | def main(): 87 | question = FavouriteQuestion() 88 | question.connect() 89 | question.post_question() 90 | question.close_connection() 91 | 92 | 93 | if __name__ == "__main__": 94 | main() 95 | -------------------------------------------------------------------------------- /db.sql: -------------------------------------------------------------------------------- 1 | -- table 2 | CREATE TABLE questions ( 3 | id SERIAL PRIMARY KEY, 4 | question TEXT NOT NULL CHECK (length(question) <= 200), 5 | date_added TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, 6 | date_posted DATE 7 | ); 8 | 9 | -- questions 10 | INSERT INTO questions (question) VALUES 11 | ('What''s your favourite 80s film?'), 12 | ('What''s your favourite accent?'), 13 | ('What''s your favourite adjective?'), 14 | ('What''s your favourite age?'), 15 | ('What''s your favourite album from the 90s?'), 16 | ('What''s your favourite animal?'), 17 | ('What''s your favourite argument?'), 18 | ('What''s your favourite Arnie film?'), 19 | ('What''s your favourite bacon?'), 20 | ('What''s your favourite band?'), 21 | ('What''s your favourite battle?'), 22 | ('What''s your favourite bean?'), 23 | ('What''s your favourite bed?'), 24 | ('What''s your favourite beer?'), 25 | ('What''s your favourite belief?'), 26 | ('What''s your favourite bird?'), 27 | ('What''s your favourite biscuit?'), 28 | ('What''s your favourite blind?'), 29 | ('What''s your favourite body part?'), 30 | ('What''s your favourite bonus?'), 31 | ('What''s your favourite bottle?'), 32 | ('What''s your favourite box?'), 33 | ('What''s your favourite brand?'), 34 | ('What''s your favourite break?'), 35 | ('What''s your favourite breed of cow?'), 36 | ('What''s your favourite breed of dog?'), 37 | ('What''s your favourite budget supermarket?'), 38 | ('What''s your favourite bug?'), 39 | ('What''s your favourite cake?'), 40 | ('What''s your favourite cartoon?'), 41 | ('What''s your favourite cat?'), 42 | ('What''s your favourite catchphrase?'), 43 | ('What''s your favourite celebrity?'), 44 | ('What''s your favourite cephalopod?'), 45 | ('What''s your favourite cereal?'), 46 | ('What''s your favourite chain?'), 47 | ('What''s your favourite chair?'), 48 | ('What''s your favourite character?'), 49 | ('What''s your favourite charger?'), 50 | ('What''s your favourite charity?'), 51 | ('What''s your favourite cheek?'), 52 | ('What''s your favourite cheese joke?'), 53 | ('What''s your favourite cheese?'), 54 | ('What''s your favourite chord?'), 55 | ('What''s your favourite city?'), 56 | ('What''s your favourite cliche?'), 57 | ('What''s your favourite clock?'), 58 | ('What''s your favourite cloud?'), 59 | ('What''s your favourite club?'), 60 | ('What''s your favourite collective noun?'), 61 | ('What''s your favourite colour?'), 62 | ('What''s your favourite comic?'), 63 | ('What''s your favourite condiment?'), 64 | ('What''s your favourite controversial subject?'), 65 | ('What''s your favourite core?'), 66 | ('What''s your favourite country that begins with the letter B?'), 67 | ('What''s your favourite county?'), 68 | ('What''s your favourite cover?'), 69 | ('What''s your favourite cowboy name?'), 70 | ('What''s your favourite crisp?'), 71 | ('What''s your favourite curry?'), 72 | ('What''s your favourite danger?'), 73 | ('What''s your favourite day?'), 74 | ('What''s your favourite defence?'), 75 | ('What''s your favourite degree?'), 76 | ('What''s your favourite dinosaur?'), 77 | ('What''s your favourite disease?'), 78 | ('What''s your favourite door?'), 79 | ('What''s your favourite dragon?'), 80 | ('What''s your favourite drink?'), 81 | ('What''s your favourite drop?'), 82 | ('What''s your favourite duck joke?'), 83 | ('What''s your favourite Eddie Murphy film?'), 84 | ('What''s your favourite egg?'), 85 | ('What''s your favourite emoticon?'), 86 | ('What''s your favourite end-of-the-world scenario?'), 87 | ('What''s your favourite error?'), 88 | ('What''s your favourite excuse?'), 89 | ('What''s your favourite extinct species?'), 90 | ('What''s your favourite face?'), 91 | ('What''s your favourite feeling?'), 92 | ('What''s your favourite film?'), 93 | ('What''s your favourite finishing move?'), 94 | ('What''s your favourite fish?'), 95 | ('What''s your favourite five-syllable word?'), 96 | ('What''s your favourite flap?'), 97 | ('What''s your favourite flavour Fruit Pastel?'), 98 | ('What''s your favourite football team?'), 99 | ('What''s your favourite forest?'), 100 | ('What''s your favourite French word?'), 101 | ('What''s your favourite fruit?'), 102 | ('What''s your favourite furry animal?'), 103 | ('What''s your favourite gap?'), 104 | ('What''s your favourite German word?'), 105 | ('What''s your favourite ghost?'), 106 | ('What''s your favourite glue?'), 107 | ('What''s your favourite Guinness world record?'), 108 | ('What''s your favourite handle?'), 109 | ('What''s your favourite hat?'), 110 | ('What''s your favourite head wear?'), 111 | ('What''s your favourite high?'), 112 | ('What''s your favourite highlighter pen?'), 113 | ('What''s your favourite holiday destination?'), 114 | ('What''s your favourite horse?'), 115 | ('What''s your favourite inanimate object?'), 116 | ('What''s your favourite Indian dish?'), 117 | ('What''s your favourite item of clothing?'), 118 | ('What''s your favourite item of formal clothing?'), 119 | ('What''s your favourite job?'), 120 | ('What''s your favourite key?'), 121 | ('What''s your favourite keyboard shortcut?'), 122 | ('What''s your favourite kind of light?'), 123 | ('What''s your favourite kind of sauce?'), 124 | ('What''s your favourite knot?'), 125 | ('What''s your favourite language?'), 126 | ('What''s your favourite letter?'), 127 | ('What''s your favourite lie?'), 128 | ('What''s your favourite line?'), 129 | ('What''s your favourite link?'), 130 | ('What''s your favourite lyric?'), 131 | ('What''s your favourite made up fact?'), 132 | ('What''s your favourite measure?'), 133 | ('What''s your favourite meme?'), 134 | ('What''s your favourite method of transport?'), 135 | ('What''s your favourite Michael J Fox film?'), 136 | ('What''s your favourite mistake?'), 137 | ('What''s your favourite moon?'), 138 | ('What''s your favourite museum?'), 139 | ('What''s your favourite mustache?'), 140 | ('What''s your favourite naughty word?'), 141 | ('What''s your favourite neckline?'), 142 | ('What''s your favourite need?'), 143 | ('What''s your favourite news?'), 144 | ('What''s your favourite number?'), 145 | ('What''s your favourite nut?'), 146 | ('What''s your favourite one-syllable word?'), 147 | ('What''s your favourite onomatopoeic word?'), 148 | ('What''s your favourite organ?'), 149 | ('What''s your favourite paint?'), 150 | ('What''s your favourite painting?'), 151 | ('What''s your favourite pan?'), 152 | ('What''s your favourite paper?'), 153 | ('What''s your favourite part of a pig?'), 154 | ('What''s your favourite party?'), 155 | ('What''s your favourite paste?'), 156 | ('What''s your favourite pattern?'), 157 | ('What''s your favourite pen?'), 158 | ('What''s your favourite piece of electrical equipment?'), 159 | ('What''s your favourite pill?'), 160 | ('What''s your favourite planet?'), 161 | ('What''s your favourite plant?'), 162 | ('What''s your favourite pole?'), 163 | ('What''s your favourite Police Academy film?'), 164 | ('What''s your favourite portmanteau?'), 165 | ('What''s your favourite pound?'), 166 | ('What''s your favourite power?'), 167 | ('What''s your favourite prescription drug?'), 168 | ('What''s your favourite pub?'), 169 | ('What''s your favourite punctuation mark?'), 170 | ('What''s your favourite radio station?'), 171 | ('What''s your favourite rain?'), 172 | ('What''s your favourite reptile?'), 173 | ('What''s your favourite rhetorical question?'), 174 | ('What''s your favourite Rick Moranis film?'), 175 | ('What''s your favourite rim?'), 176 | ('What''s your favourite rise?'), 177 | ('What''s your favourite road?'), 178 | ('What''s your favourite roof covering?'), 179 | ('What''s your favourite rope?'), 180 | ('What''s your favourite rule?'), 181 | ('What''s your favourite sausage?'), 182 | ('What''s your favourite school?'), 183 | ('What''s your favourite screen?'), 184 | ('What''s your favourite secret?'), 185 | ('What''s your favourite semi-aquatic egg-laying mammal?'), 186 | ('What''s your favourite service?'), 187 | ('What''s your favourite shellfish?'), 188 | ('What''s your favourite shop?'), 189 | ('What''s your favourite shower?'), 190 | ('What''s your favourite side?'), 191 | ('What''s your favourite size of envelope?'), 192 | ('What''s your favourite size?'), 193 | ('What''s your favourite song?'), 194 | ('What''s your favourite sound?'), 195 | ('What''s your favourite soup?'), 196 | ('What''s your favourite source of existential angst?'), 197 | ('What''s your favourite space?'), 198 | ('What''s your favourite speling mistaek?'), 199 | ('What''s your favourite spin?'), 200 | ('What''s your favourite spirit?'), 201 | ('What''s your favourite spoonerism?'), 202 | ('What''s your favourite star?'), 203 | ('What''s your favourite station?'), 204 | ('What''s your favourite stew?'), 205 | ('What''s your favourite story?'), 206 | ('What''s your favourite superlative?'), 207 | ('What''s your favourite team?'), 208 | ('What''s your favourite thing to do just before you go to sleep?'), 209 | ('What''s your favourite tool?'), 210 | ('What''s your favourite Tube stop?'), 211 | ('What''s your favourite type of heavy metal?'), 212 | ('What''s your favourite unit of measurement?'), 213 | ('What''s your favourite university?'), 214 | ('What''s your favourite vegetable?'), 215 | ('What''s your favourite war?'), 216 | ('What''s your favourite way to cause pain?'), 217 | ('What''s your favourite weed?'), 218 | ('What''s your favourite wind?'), 219 | ('What''s your favourite window?'), 220 | ('What''s your favourite wire?'), 221 | ('What''s your favourite word for someone who''s behaving a bit unpredictably?'), 222 | ('What''s your favourite word?'), 223 | ('What''s your favourite worm?'), 224 | ('When''s your favourite time?'), 225 | ('Who''s your favourite Akabusi?'), 226 | ('Who''s your favourite alien?'), 227 | ('Who''s your favourite animal?'), 228 | ('Who''s your favourite archer?'), 229 | ('Who''s your favourite artist?'), 230 | ('Who''s your favourite bearded gentleman?'), 231 | ('Who''s your favourite blind person?'), 232 | ('Who''s your favourite Booth?'), 233 | ('Who''s your favourite Boris?'), 234 | ('Who''s your favourite British Prime Minister from the 19th Century?'), 235 | ('Who''s your favourite captain?'), 236 | ('Who''s your favourite celebrity?'), 237 | ('Who''s your favourite character from Neighbours?'), 238 | ('Who''s your favourite Charles?'), 239 | ('Who''s your favourite Chris?'), 240 | ('Who''s your favourite Collins?'), 241 | ('Who''s your favourite comedian?'), 242 | ('Who''s your favourite Daniel?'), 243 | ('Who''s your favourite Darren?'), 244 | ('Who''s your favourite deity?'), 245 | ('Who''s your favourite designer?'), 246 | ('Who''s your favourite developer?'), 247 | ('Who''s your favourite dictator?'), 248 | ('Who''s your favourite Disney character?'), 249 | ('Who''s your favourite DJ?'), 250 | ('Who''s your favourite doctor?'), 251 | ('Who''s your favourite duck?'), 252 | ('Who''s your favourite Ed?'), 253 | ('Who''s your favourite ex?'), 254 | ('Who''s your favourite explorer?'), 255 | ('Who''s your favourite fatty?'), 256 | ('Who''s your favourite fish?'), 257 | ('Who''s your favourite foot?'), 258 | ('Who''s your favourite game show host?'), 259 | ('Who''s your favourite geek?'), 260 | ('Who''s your favourite German?'), 261 | ('Who''s your favourite giant?'), 262 | ('Who''s your favourite ginger?'), 263 | ('Who''s your favourite hacker?'), 264 | ('Who''s your favourite hero?'), 265 | ('Who''s your favourite hipster?'), 266 | ('Who''s your favourite idiot?'), 267 | ('Who''s your favourite inanimate object?'), 268 | ('Who''s your favourite Jackson?'), 269 | ('Who''s your favourite James?'), 270 | ('Who''s your favourite king?'), 271 | ('Who''s your favourite lady?'), 272 | ('Who''s your favourite lord?'), 273 | ('Who''s your favourite maiden?'), 274 | ('Who''s your favourite man?'), 275 | ('Who''s your favourite manager?'), 276 | ('Who''s your favourite mass murderer?'), 277 | ('Who''s your favourite Mike?'), 278 | ('Who''s your favourite mum?'), 279 | ('Who''s your favourite Nelson?'), 280 | ('Who''s your favourite news presenter?'), 281 | ('Who''s your favourite person from Essex?'), 282 | ('Who''s your favourite person from the 80s?'), 283 | ('Who''s your favourite person with sideburns?'), 284 | ('Who''s your favourite Pete?'), 285 | ('Who''s your favourite prince?'), 286 | ('Who''s your favourite queen?'), 287 | ('Who''s your favourite scientist?'), 288 | ('Who''s your favourite Smith?'), 289 | ('Who''s your favourite sports personality?'), 290 | ('Who''s your favourite star wars character?'), 291 | ('Who''s your favourite Trevor?'), 292 | ('Who''s your favourite valentine?'), 293 | ('Who''s your favourite Viking?'), 294 | ('Who''s your favourite weblebrity?'), 295 | ('Who''s your favourite wrestler?'), 296 | ('Who''s your favourite Wu-Tang member?'); 297 | --------------------------------------------------------------------------------