def danbooru(danbooru_id): '''returns danbooru post using id''' if danbooru_id != 0: print('checking details on danbooru.donmai.us') try: client = Danbooru('danbooru') post = client.post_show(danbooru_id) logger.dump(post, 'last_danbooru_response.txt') #debug return post except Exception as e: print(e) return ''
class BotClass(): schema_config_path = "schema/config.json" schema_db_path = "schema/db.json" schema_image_path = "schema/image.json" db = {"images": []} def __init__(self, config): logger.debug("loading config...") with open(self.schema_config_path) as data: self.schema_config = json.load(data) logger.debug("validating config...") validate(config, self.schema_config) logger.debug("config is valid!") # apply dictionary as properties of self.settings self.settings = json.loads( json.dumps(config), object_hook=lambda d: namedtuple('X', d.keys())(*d.values())) logger.debug(self.settings) self.load_images() self.login() def login(self): logger.info("login into mastodon bot...") self.mastodon_api = Mastodon(client_id=self.settings.client_id, client_secret=self.settings.client_secret, access_token=self.settings.access_token, api_base_url=self.settings.domain) try: logger.info("login into twitter account...") auth = tweepy.OAuthHandler( self.settings.accounts.twitter.consumer_key, self.settings.accounts.twitter.consumer_secret) auth.set_access_token( self.settings.accounts.twitter.access_token, self.settings.accounts.twitter.access_token_secret) self.tweet_api = tweepy.API(auth) except AttributeError: logger.debug("twitter credentials not definied") self.tweet_api = False try: logger.info("login into danbooru account...") self.danbooru_api = Danbooru( 'danbooru', username=self.settings.accounts.danbooru.username, api_key=self.settings.accounts.danbooru.token) except AttributeError: logger.debug("danbooru credentials not definied") self.danbooru_api = False try: logger.info("login into pixiv account...") self.pixiv_api = AppPixivAPI() self.pixiv_api.login(self.settings.accounts.pixiv.username, self.settings.accounts.pixiv.password) except AttributeError: logger.debug("pixiv credentials not definied") # self.pixiv_api = AppPixivAPI() self.pixiv_api = False def post_toot(self): logger.info("creating new toot...") self.load_images() image = {} while not image: logger.debug("choosing random image...") image = random.choice(self.db['images']) logger.debug(image) source = image['source'] paths = image['image_paths'] try: source = image['posted'] posted = True # to reduce boosting repeat process in 70% of cases # if the image has already been posted if random.randint(0, 100) < 70: image = {} except KeyError: posted = False # check if already posted or a mastodon link to boost original toot if paths[0] == "mastodon.png" or posted or re_mastodon.search(source): search = self.mastodon_api.search(source, resolve=True) logger.debug(search) status_id = search['statuses'][0]['id'] logger.debug("toot id: " + str(status_id)) logger.debug("boosting toot...") toot = self.mastodon_api.status_reblog(status_id) else: name = image['author']['name'] handle = image['author']['handle'] status = "Created by: {}({})\nSource: {}".format( name, handle, source) try: additional = image['additional'] for link in additional: status += "\n" + link except KeyError: pass try: description = image['description'] status += "\n\n" + description[:400] except KeyError: pass try: nsfw = image['nsfw'] except KeyError: nsfw = False media_ids = [] for path in paths: logger.debug("'{}' uploading...".format(path)) media = self.mastodon_api.media_post(media_file=path) media_ids.append(media['id']) logger.debug(media) logger.debug("posting toot...") try: cw = image['cw'] toot = self.mastodon_api.status_post(status, media_ids=media_ids, sensitive=nsfw, visibility='public', spoiler_text=cw) except KeyError: toot = self.mastodon_api.status_post(status, media_ids=media_ids, sensitive=nsfw, visibility='public') logger.debug(toot) image['posted'] = toot['url'] logger.info(toot['url']) with open(self.settings.db_path, 'w') as output: json.dump(self.db, output) # save to database logger.debug("toot url saved to db") # logger.debug(self.db) def scheduled_toots(self): logger.debug("posting toots every: {}min".format( self.settings.offset_min)) schedule.every(self.settings.offset_min).minutes.do(self.post_toot) while True: try: schedule.run_pending() except Exception as e: logger.warning(repr(e)) logger.warning(error_info(e)) time.sleep(1) def load_images(self): logger.debug("loading images from: " + self.settings.db_path) with open(self.schema_db_path) as data: self.schema_db = json.load(data) if os.path.isfile(self.settings.db_path): with open(self.settings.db_path) as data: self.db = json.load(data) # change relative paths to a absolute paths schema_path = 'file:///{0}/'.format( os.path.dirname(os.path.abspath(self.schema_db_path)).replace( "\\", '/')) resolver = RefResolver(schema_path, self.schema_db) logger.debug("validating db...") validate(self.db, self.schema_db, resolver=resolver) logger.debug("db is valid!") # logger.debug("validating db...") # validate(self.db, self.schema_db) # logger.debug("db is valid!") def add_images(self): with open(self.schema_image_path) as data: self.schema_image = json.load(data) while True: logger.debug("adding Image to db") # logger.debug(self.db) source = input("enter image source (leave empty to abort):\n") if source: self.load_images() # check if image was already added if self.image_exists(source): print("already added!") continue # jump into next loop # if url is part of these automatically retrieve image and # additional info if re_mastodon.search(source): image = { "source": source, "image_paths": ["mastodon.png"], "author": { "handle": "", "name": "" }, "description": "", "nsfw": False } elif re_twitter.search(source) and self.tweet_api: image = self.twitter_info(source) elif re_danbooru.search(source): image = self.danbooru_info(source) elif re_pixiv.search(source) and self.pixiv_api: # currently pixiv downloading only works while logged in to # pixiv image = self.pixiv_info(source) else: # enter info manually image = self.manual_info(source) if self.image_exists(image["source"]): print("already added!") continue # jump into next loop logger.debug("validating entered info...") validate(image, self.schema_image) logger.debug("info is valid") self.db["images"].append(image) with open(self.settings.db_path, 'w') as output: json.dump(self.db, output) # save to database logger.info("{} images in db".format(len(self.db["images"]))) else: break def manual_info(self, url): paths = [] source = url.strip() additional = [] link = "" while len(paths) < 4: path = input("enter a relative image path or url:\n") if path: # instead of posting images mastodon links can be # boosted if path == "mastodon": # to be still validatable paths.append(path + ".png") break elif not os.path.isfile(path): path = download_image(path) paths.append(path) elif paths: break nsfw = input( "Is this image not safe for work: false/true (empty = false)\n") if nsfw.lower() == "true" or nsfw.lower() == "y" or nsfw.lower( ) == "yes": nsfw = True else: nsfw = False handle = input( "enter author handle, eg [email protected] (optional):\n") name = input("enter author name (optional):\n") while True: link = input("Additional links? (optional):\n") additional.append(link) if not link.strip(): break description = input("enter description (optional)\n") cw = input("enter content warnings (optional)\n") image = { "source": source, "image_paths": paths, "author": { "handle": handle.strip(), "name": name.strip() }, "description": description.strip(), "nsfw": nsfw, "cw": cw.strip() } return image def twitter_info(self, url): nsfw = False paths = [] handle = "" name = "" description = "" source = url id = source.split('/')[-1] tweet = self.tweet_api.get_status(id) logger.debug(tweet.extended_entities['media']) for media in tweet.extended_entities['media']: if media['type'] == 'photo': file_url = media['media_url_https'] path = download_image(file_url) paths.append(path) else: file_url = media['video_info']['variants'][0]['url'] path = download_image(file_url) paths.append(path) handle = "@{}@twitter.com".format(tweet.user.screen_name) name = tweet.user.name # last word is always the shortened link to the media if len(tweet.text.rsplit(' ', 1)): description = tweet.text.rsplit(' ', 1)[0] if tweet.possibly_sensitive: nsfw = True image = { "source": source, "image_paths": paths, "author": { "handle": handle.strip(), "name": name.strip() }, "description": description.strip(), "nsfw": nsfw } return image def danbooru_info(self, url): nsfw = False paths = [] handle = "" name = "" description = "" source = url.strip().split("?")[0] if self.danbooru_api: id = source.split("/")[-1] post = self.danbooru_api.post_show(id) else: url = source.split("?")[0] + ".json" resp = requests.get(url) post = json.loads(resp.text) logger.debug(post) try: file_url = 'http://danbooru.donmai.us' + \ post['file_url'] except NameError: file_url = post['source'] path = download_image(file_url) paths.append(path) # get name and handle if possible from pixiv, check if api # shows pawoo handle name = post['tag_string_artist'] if post['source']: if re_link.search(parse.unquote(post['source'])): source = parse.unquote(post['source']) if re_tweet.search(source): username = re_tweet.search(source).group(1) handle = get_handle(username) if post['pixiv_id']: source = "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=" + \ str(post['pixiv_id']) pixiv = self.pixiv_info(source) source = pixiv["source"] if pixiv["author"]["handle"]: handle = pixiv["author"]["handle"] if pixiv["author"]["name"]: name = pixiv["author"]["name"] if post['tag_string_copyright']: description = '#' + \ post['tag_string_copyright'].replace(' ', ' #').replace( "#original", ' ').replace("_(series)", ' ').replace("-", "_") if post['rating'] is not "s": nsfw = True image = { "source": source, "image_paths": paths, "author": { "handle": handle.strip(), "name": name.strip() }, "description": description.strip(), "nsfw": nsfw } return image def pixiv_info(self, url): nsfw = False paths = [] handle = "" name = "" description = "" source = url.strip() # currently pixiv downloading only works while logged in to # pixiv id = source.split('id=')[1] illust = self.pixiv_api.illust_detail(id, req_auth=True) logger.debug(illust) post = illust.illust file_url = post.image_urls['large'].replace("/c/600x1200_90", '') path = "images/pixiv/" + id + ".jpg" paths.append(path) if not os.path.isdir("images/pixiv"): os.makedirs("images/pixiv") self.pixiv_api.download(file_url, path="images/pixiv/", name=id + ".jpg") name = post.user['name'] handle = str(post.user['id']) user = self.pixiv_api.user_detail(int(handle), req_auth=True) if user.profile['twitter_account']: username = user.profile['twitter_account'] handle = get_handle(username) if user.profile['pawoo_url']: # resolve redirected url r = requests.get(user.profile['pawoo_url']) username = r.url.split("@")[1] handle = get_handle(username, domain="pawoo.net") try: description = post.title if post.tags: description += "\n\n" for tag in post.tags: tag = tag['name'].replace("/", "_").replace("-", "_") description += '#' + tag + ' ' description = description[:-1] except AttributeError: pass image = { "source": source, "image_paths": paths, "author": { "handle": handle.strip(), "name": name.strip() }, "description": description.strip(), "nsfw": nsfw } return image def image_exists(self, source): for image in self.db["images"]: if source == image["source"]: return True return False