Last active
June 3, 2020 00:47
-
-
Save TheTimgor/81f54930bf9012a5ba7af4ca4728ab9c to your computer and use it in GitHub Desktop.
@moeshitbot annotated source code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ___ _ ______ ____ | |
# / | | / / __ \/ __ \ | |
# / /| | | /| / / / / / / / / | |
# / ___ | |/ |/ / /_/ / /_/ / | |
# /_/ |_|__/|__/\____/\____/ | |
# | |
# @moeshitbot, by timgor | timgor.moe | |
# annotated source code | |
# | |
# this is my shitty cute anime pics twitter bot. | |
# it makes requests to my timgor.moe api and yeets them up on to twitter. | |
# a lot of the heavy lifting is done by tweepy (www.tweepy.org), | |
# a twitter api wrapper for python. it makes doing this all an absolute breeze | |
# and is the gold standard for making twitter bots. | |
# | |
# also huge thanks to saucenao.com for letting me procedurally get the source (sauce) | |
# for all the images. i would never make this kind of bot without giving the original | |
# artists credit for their hard work, and saucenao provides me with that ability. | |
# for those unaquainted, saucenao is a reverse image search for artwork that | |
# is a goddamn blessing for figuring out who drew that amzing lewd you just downloaded. | |
# | |
print('sending a tweet') | |
import json | |
import tweepy | |
import requests | |
from io import BytesIO | |
import urllib | |
from random import choice | |
# load the saucenao api creds from a local json file | |
with open('saucenao_credentials.json') as f: | |
saucenao_credentials = json.load(f) | |
# request to saucenao api | |
# tries with up to 100 different images just in case it can't find the sauce for one | |
sauce = '' | |
try_num = 0 | |
num_tries = 100 | |
while not sauce: # try until we hit sauce | |
url = requests.get('https://timgor.moe/api/random') # get image url from timgor.moe api | |
# make the request to the saucenao api | |
# probably should've encoded the query parameters more readably | |
# basically means: | |
# json format | |
# one result | |
# >80% similarity | |
# all databases | |
sn_url = 'http://saucenao.com/search.php?output_type=2&numres=1&minsim=80!&db=999&api_key='+saucenao_credentials['api_key']+'&url='+urllib.parse.quote(url.content) | |
sn_response = requests.get(sn_url) | |
# it's json parsing time | |
sn_json = json.loads(sn_response.content) | |
result = sn_json['results'][0] | |
# set sauce if we got anything with high enough similarity | |
if float(result['header']['similarity']) > 80: | |
sauce = result['data']['ext_urls'][0] | |
try_num += 1 | |
# exit if retries exceeded | |
if num_tries < try_num: | |
print('retries exceeded') | |
exit(1) | |
# download the image and proceed if successfull | |
data = requests.get(url.content) | |
if data.status_code == 200: | |
# this code is designed to be as portable as possible, | |
# and runnable in places where you don't neccesarilly have | |
# write access. to have a file object usable with tweepy, | |
# i create a BytesIO object which acts a file, but is kept only in RAM | |
image = BytesIO(data.content) | |
# load twitter api and user creds from a local json file | |
with open('twitter_credentials.json') as f: | |
twitter_credentials = json.load(f) | |
# the witty messages are also kept externally | |
# it's nice to have these kinds of things in a seperate file so it's harder | |
# (not impossible) to break the whole program adding one | |
# this also maximizes code prettyness and reusability | |
with open('messages.json') as f: | |
messages = json.load(f) | |
# messages are all encoded as string.format() templates so i can easily insert the sauce url, like so: | |
# "programmatically selected from my anime pics folder. \nsauce: {0} (courtesy of saucenao.com)" | |
message = choice(messages).format(sauce) # choose random message | |
# tweepy wants a filename with an extension for guessing MIME content output_type | |
# i need to extract it from the headers of the response i got earlier | |
# this clusterfuck of a listcomp does that, i don't remember how | |
filename = [a for a in data.headers['Content-Disposition'].split(';') if 'filename=' in a][0].replace('filename=','').replace('"','') | |
# tweepy handles all the authorization for you | |
# manually dealing with oauth2 is like having razor blades that | |
# have been heated to 1000 C shoved up your dick hole. it's not fun i assure you | |
# i am very grateful for tweepy | |
auth = tweepy.OAuthHandler(twitter_credentials['consumer_key'], twitter_credentials['consumer_secret']) | |
auth.set_access_token(twitter_credentials['access_token'], twitter_credentials['access_token_secret']) | |
api = tweepy.API(auth) | |
try: | |
# sends the tweet with the BytesIO object and filename from earlier | |
api.update_with_media(filename,status=message,file=image) | |
except: | |
# that's right kids, except: pass in actual production code | |
# please never do this | |
# do actual error handling | |
# don't be like me | |
pass | |
print('tweet sent') # we did it, reddit! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment