├── bot ├── __init__.py ├── settings.sample.py ├── tweet.py ├── generator.py └── blacklist.py ├── requirements.txt ├── ready.sh ├── start.sh ├── .gitignore ├── setup.py ├── cron_line.py ├── tests └── tests.py ├── LICENSE └── README.md /bot/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | TwitterAPI==2.4.2 2 | -------------------------------------------------------------------------------- /ready.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source venv/bin/activate 4 | python3 setup.py install 5 | python3 tests/tests.py 6 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | virtualenv -p python3 venv 4 | source venv/bin/activate 5 | pip install -r requirements.txt 6 | cp bot/settings.sample.py bot/settings.py 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.pyc 3 | .DS_Store 4 | .Python 5 | pip-selfcheck.json 6 | *.sass-cache 7 | buid/ 8 | 9 | build/ 10 | dist/ 11 | *.egg-info 12 | 13 | venv/ 14 | settings.py 15 | queue.json 16 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | ''' setup script ''' 2 | from setuptools import setup 3 | 4 | setup( 5 | name='Twitter Bot', 6 | version='0.0.1', 7 | 8 | author='', 9 | author_email='', 10 | 11 | packages=['bot'], 12 | 13 | license='MIT', 14 | install_requires=['TwitterAPI==2.4.2'], 15 | ) 16 | -------------------------------------------------------------------------------- /cron_line.py: -------------------------------------------------------------------------------- 1 | ''' print out a cron entry for the bot ''' 2 | from bot import settings 3 | 4 | # populate queue 5 | if settings.USE_QUEUE: 6 | print('5 */%s * * * %s/venv/bin/python3 %s/bot/generator.py' % \ 7 | (settings.FREQUENCY, settings.FILEPATH, settings.FILEPATH)) 8 | 9 | # actual tweeting 10 | print('0 */%s * * * %s/venv/bin/python3 %s/bot/tweet.py' % \ 11 | (settings.FREQUENCY, settings.FILEPATH, settings.FILEPATH)) 12 | -------------------------------------------------------------------------------- /tests/tests.py: -------------------------------------------------------------------------------- 1 | ''' test language creation ''' 2 | from bot import generator 3 | import unittest 4 | 5 | class Tests(unittest.TestCase): 6 | ''' my tests are as comprehensive as a ... ''' 7 | 8 | def test_tweet_structure(self): 9 | ''' check if a valid data object is created ''' 10 | data = generator.get_tweet() 11 | 12 | self.assertIn('status', data) 13 | 14 | 15 | if __name__ == '__main__': 16 | unittest.main() 17 | -------------------------------------------------------------------------------- /bot/settings.sample.py: -------------------------------------------------------------------------------- 1 | ''' settings ''' 2 | 3 | TWITTER_API_KEY = '' 4 | TWITTER_API_SECRET = '' 5 | TWITTER_ACCESS_TOKEN = '' 6 | TWITTER_ACCESS_SECRET = '' 7 | 8 | # the location of your twitter bot's repo, ie: 9 | # /Users/mouse/bestbot 10 | FILEPATH = '' 11 | 12 | # Number of hours between tweets 13 | FREQUENCY = 3 14 | 15 | # Set this to True if you want to create a backlog of tweets as json 16 | # to post later. QUEUE_COUNT represents the number of items it will 17 | # attempt to add to the backlog 18 | USE_QUEUE = False 19 | QUEUE_COUNT = 10 20 | -------------------------------------------------------------------------------- /bot/tweet.py: -------------------------------------------------------------------------------- 1 | ''' post a tweet from the queued file ''' 2 | from bot import settings, generator 3 | import json 4 | from TwitterAPI import TwitterAPI 5 | 6 | try: 7 | API = TwitterAPI(settings.TWITTER_API_KEY, 8 | settings.TWITTER_API_SECRET, 9 | settings.TWITTER_ACCESS_TOKEN, 10 | settings.TWITTER_ACCESS_SECRET) 11 | except: 12 | API = None 13 | 14 | if settings.USE_QUEUE: 15 | queue = json.load(open('%s/queue.json' % settings.FILEPATH)) 16 | 17 | data = queue[0] 18 | 19 | json.dump(queue[1:], open('%s/queue.json' % settings.FILEPATH, 'w')) 20 | else: 21 | data = generator.get_tweet() 22 | 23 | if data: 24 | if API: 25 | r = API.request('statuses/update', data) 26 | 27 | if r.status_code != 200: 28 | print(r.response) 29 | else: 30 | print('----- API unavailable -----') 31 | print(data) 32 | -------------------------------------------------------------------------------- /bot/generator.py: -------------------------------------------------------------------------------- 1 | ''' Create the bot's content ''' 2 | from bot import settings 3 | from bot.blacklist import check_blacklist 4 | 5 | import json 6 | 7 | def get_tweet(): 8 | ''' create tweet content ''' 9 | 10 | # TODO: Your neat stuff here! 11 | text = 'test tweet' 12 | 13 | # make sure it isn't posting something gross 14 | if check_blacklist(text): 15 | return False 16 | 17 | data = {'status': text} 18 | return data 19 | 20 | 21 | def fill_queue(): 22 | ''' populate a json file with things to post the future ''' 23 | try: 24 | queue = json.load(open('%s/queue.json' % settings.FILEPATH)) 25 | except OSError: 26 | queue = [] 27 | 28 | for _ in range(0, settings.QUEUE_COUNT): 29 | tweet = get_tweet() 30 | if tweet: 31 | queue.append(tweet) 32 | 33 | json.dump(queue, open('%s/queue.json' % settings.FILEPATH, 'w')) 34 | 35 | 36 | if __name__ == '__main__': 37 | if settings.USE_QUEUE: 38 | fill_queue() 39 | else: 40 | print(get_tweet()) 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Mouse Reeve 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Twitter Bot Template 2 | 3 | Boilerplate for creating simple, non-interactive twitter bots that post periodically. My comparisons bot, [@botaphor](https://github.com/mouse-reeve/metaphinder), is an example of how I use this template in practice. 4 | 5 | This is intended for coders familiar with Python and bash. 6 | 7 | ## Instructions 8 | 9 | To make a bot, copy this repo and run `start.sh` to create 10 | a virtualenv and settings file. 11 | 12 | When you're done (or at a stop-and-test point) with your bot, 13 | run `ready.sh` to set up the python package and run tests. 14 | 15 | To start tweeting on a schedule, run `python cron_lines.py` to generate 16 | the lines you'll need to add to cron. 17 | 18 | 19 | ## Structure 20 | 21 | The code that generates tweet content lives in the `get_tweet` method in `bot/generator.py`. Until you add your own functionality, it will tweet out "test tweet". 22 | 23 | You will need to fill out the `bot/settings.py` that is generated when you run `start.sh`. Make sure you set an absolute path in `FILEPATH`, and fill in the API keys section with the keys you get from twitter. 24 | 25 | If you set `USE_QUEUE` to `True` in `bot/settings.py`, a `queue.json` file will be created when the bot runs and populated with tweet data objects, which can be tweeted out later. This allows you to check what your bot will do before it goes live, and make sure that there is enough content waiting if your `get_tweet` script doesn't always produce results. The script will attempt to write 10 tweets to the queue every time it is run; you can customize this number by changing `QUEUE_COUNT`. 26 | 27 | By default, potential tweets will be checked against a non-comprehensive list of potentially offensive words in `bot/blacklist.py`, and if the check fails, no tweet will be created or posted. 28 | -------------------------------------------------------------------------------- /bot/blacklist.py: -------------------------------------------------------------------------------- 1 | ''' try to avoid being a bad bot ''' 2 | import re 3 | 4 | def check_blacklist(sentence): 5 | ''' check a sentence for blacklisted content ''' 6 | sentence = sentence.lower() 7 | sentence = re.sub(r'[\.,;\'"\(\)\?!]', '', sentence) 8 | for word in blacklist: 9 | if word in sentence: 10 | return True 11 | return False 12 | 13 | # --------------------------------------- 14 | # Abandon all hope, ye who read past here 15 | # --------------------------------------- 16 | 17 | blacklist = [ 18 | "2g1c", 19 | "2 girls 1 cup", 20 | "abortion", 21 | "acrotomophilia", 22 | "alabama hot pocket", 23 | "alaskan pipeline", 24 | "anal", 25 | "anilingus", 26 | "anus", 27 | "arsehole", 28 | "ass", 29 | "asshole", 30 | "assmunch", 31 | "babeland", 32 | "baby batter", 33 | "baby juice", 34 | "ball gag", 35 | "ball gravy", 36 | "ball kicking", 37 | "ball licking", 38 | "ball sack", 39 | "ball sucking", 40 | "bangbros", 41 | "bareback", 42 | "barely legal", 43 | "barenaked", 44 | "bastard", 45 | "bastardo", 46 | "bastinado", 47 | "bbw", 48 | "bdsm", 49 | "beaner", 50 | "beaners", 51 | "beaver cleaver", 52 | "beaver lips", 53 | "bestiality", 54 | "big black", 55 | "big breasts", 56 | "big knockers", 57 | "big tits", 58 | "bimbos", 59 | "birdlock", 60 | "bitch", 61 | "bitches", 62 | "bitchy", 63 | "black cock", 64 | "blonde action", 65 | "blonde on blonde action", 66 | "blowjob", 67 | "blow job", 68 | "blow your load", 69 | "blue waffle", 70 | "blumpkin", 71 | "bollocks", 72 | "bondage", 73 | "boner", 74 | "boob", 75 | "boobs", 76 | "booty call", 77 | "brown showers", 78 | "brunette action", 79 | "bukkake", 80 | "bulldyke", 81 | "bullet vibe", 82 | "bung hole", 83 | "bunghole", 84 | "busty", 85 | "butt", 86 | "buttcheeks", 87 | "butthole", 88 | "camel toe", 89 | "camgirl", 90 | "camslut", 91 | "camwhore", 92 | "carpet muncher", 93 | "carpetmuncher", 94 | "chocolate rosebuds", 95 | "circlejerk", 96 | "cleveland steamer", 97 | "clit", 98 | "clitoris", 99 | "clover clamps", 100 | "clusterfuck", 101 | "cock", 102 | "cocks", 103 | "coprolagnia", 104 | "coprophilia", 105 | "cornhole", 106 | "coon", 107 | "coons", 108 | "creampie", 109 | "cum", 110 | "cumming", 111 | "cunnilingus", 112 | "cunt", 113 | "darkie", 114 | "date rape", 115 | "daterape", 116 | "deep throat", 117 | "deepthroat", 118 | "dendrophilia", 119 | "dick", 120 | "dildo", 121 | "dingleberry", 122 | "dingleberries", 123 | "dirty pillows", 124 | "dirty sanchez", 125 | "doggie style", 126 | "doggiestyle", 127 | "doggy style", 128 | "doggystyle", 129 | "dog style", 130 | "dolcett", 131 | "domination", 132 | "dominatrix", 133 | "dommes", 134 | "donkey punch", 135 | "double dong", 136 | "double penetration", 137 | "dp action", 138 | "dry hump", 139 | "dvda", 140 | "eat my ass", 141 | "ecchi", 142 | "ejaculation", 143 | "erotic", 144 | "erotism", 145 | "escort", 146 | "eunuch", 147 | "faggot", 148 | "fecal", 149 | "felch", 150 | "fellatio", 151 | "feltch", 152 | "female squirting", 153 | "femdom", 154 | "figging", 155 | "fingerbang", 156 | "fingering", 157 | "fisting", 158 | "foot fetish", 159 | "footjob", 160 | "frotting", 161 | "fuck", 162 | "fuck buttons", 163 | "fuckin", 164 | "fucking", 165 | "fucktards", 166 | "fudge packer", 167 | "fudgepacker", 168 | "futanari", 169 | "gang bang", 170 | "gay sex", 171 | "genitals", 172 | "giant cock", 173 | "girl on", 174 | "girl on top", 175 | "girls gone wild", 176 | "goatcx", 177 | "goatse", 178 | "gokkun", 179 | "golden shower", 180 | "goodpoop", 181 | "goo girl", 182 | "goregasm", 183 | "grope", 184 | "group sex", 185 | "g-spot", 186 | "guro", 187 | "hand job", 188 | "handjob", 189 | "hard core", 190 | "hardcore", 191 | "hentai", 192 | "homoerotic", 193 | "honkey", 194 | "hooker", 195 | "hot carl", 196 | "hot chick", 197 | "how to kill", 198 | "how to murder", 199 | "huge fat", 200 | "humping", 201 | "incest", 202 | "intercourse", 203 | "jack off", 204 | "jail bait", 205 | "jailbait", 206 | "jelly donut", 207 | "jerk off", 208 | "jigaboo", 209 | "jiggaboo", 210 | "jiggerboo", 211 | "jizz", 212 | "juggs", 213 | "kike", 214 | "kinbaku", 215 | "kinkster", 216 | "kinky", 217 | "knobbing", 218 | "leather restraint", 219 | "leather straight jacket", 220 | "lemon party", 221 | "lolita", 222 | "lovemaking", 223 | "make me come", 224 | "male squirting", 225 | "masturbate", 226 | "menage a trois", 227 | "milf", 228 | "missionary position", 229 | "motherfucker", 230 | "mound of venus", 231 | "mr hands", 232 | "muff diver", 233 | "muffdiving", 234 | "nambla", 235 | "nawashi", 236 | "negro", 237 | "neonazi", 238 | "nigga", 239 | "nigger", 240 | "nig nog", 241 | "nimphomania", 242 | "nipple", 243 | "nipples", 244 | "nsfw images", 245 | "nude", 246 | "nudity", 247 | "nympho", 248 | "nymphomania", 249 | "octopussy", 250 | "omorashi", 251 | "one cup two girls", 252 | "one guy one jar", 253 | "orgasm", 254 | "orgy", 255 | "paedophile", 256 | "paki", 257 | "panties", 258 | "panty", 259 | "pedobear", 260 | "pedophile", 261 | "pegging", 262 | "phone sex", 263 | "pissing", 264 | "piss pig", 265 | "pisspig", 266 | "playboy", 267 | "pleasure chest", 268 | "pole smoker", 269 | "ponyplay", 270 | "poof", 271 | "poon", 272 | "poontang", 273 | "punany", 274 | "poop chute", 275 | "poopchute", 276 | "porn", 277 | "porno", 278 | "pornography", 279 | "prince albert piercing", 280 | "pthc", 281 | "pubes", 282 | "pussy", 283 | "queaf", 284 | "queef", 285 | "quim", 286 | "raghead", 287 | "raging boner", 288 | "rape", 289 | "raping", 290 | "rapist", 291 | "rectum", 292 | "reverse cowgirl", 293 | "rimjob", 294 | "rimming", 295 | "rosy palm", 296 | "rosy palm and her 5 sisters", 297 | "rusty trombone", 298 | "sadism", 299 | "santorum", 300 | "scat", 301 | "schlong", 302 | "scissoring", 303 | "semen", 304 | "sexo", 305 | "shaved beaver", 306 | "shaved pussy", 307 | "shemale", 308 | "shibari", 309 | "shitblimp", 310 | "shit", 311 | "shota", 312 | "shrimping", 313 | "skeet", 314 | "slanteye", 315 | "slut", 316 | "s&m", 317 | "smut", 318 | "snatch", 319 | "snowballing", 320 | "sodomize", 321 | "sodomy", 322 | "spic", 323 | "splooge", 324 | "splooge moose", 325 | "spooge", 326 | "spread legs", 327 | "spunk", 328 | "strap on", 329 | "strapon", 330 | "strappado", 331 | "strip club", 332 | "style doggy", 333 | "suck", 334 | "sucks", 335 | "suicide girls", 336 | "sultry women", 337 | "swastika", 338 | "swinger", 339 | "tainted love", 340 | "taste my", 341 | "tea bagging", 342 | "threesome", 343 | "throating", 344 | "tied up", 345 | "tight white", 346 | "tits", 347 | "titties", 348 | "titty", 349 | "tongue in a", 350 | "topless", 351 | "tosser", 352 | "towelhead", 353 | "tranny", 354 | "tribadism", 355 | "tub girl", 356 | "tubgirl", 357 | "tushy", 358 | "twat", 359 | "twink", 360 | "twinkie", 361 | "two girls one cup", 362 | "undressing", 363 | "upskirt", 364 | "urethra play", 365 | "urophilia", 366 | "venus mound", 367 | "vibrator", 368 | "violet wand", 369 | "vorarephilia", 370 | "vulva", 371 | "wank", 372 | "wetback", 373 | "wet dream", 374 | "white power", 375 | "wrapping men", 376 | "wrinkled starfish", 377 | "xx", 378 | "xxx", 379 | "yaoi", 380 | "yellow showers", 381 | "yiffy", 382 | "zoophilia", 383 | "cuck", 384 | "retard", 385 | "retart", 386 | 'molest', 387 | 'kkk', 388 | ] 389 | --------------------------------------------------------------------------------