async def buildMangaReplyWithAuthor(searchText, authorName, message, isExpanded, canEmbed, blockTracking=False): try: ani = await Anilist.getMangaWithAuthor(searchText, authorName) mal = None mu = None ap = None if ani: try: mal = await MAL.getMangaCloseToDescription( searchText, ani['description']) ap = await AniP.getMangaURL(ani['title_english'], authorName) except Exception as e: print(e) else: ap = await AniP.getMangaURL(searchText, authorName) mu = await MU.getMangaWithAuthor(searchText, authorName) if ani: try: titleToAdd = '' if mal is not None: titleToAdd = mal['title'] else: titleToAdd = ani['title_english'] if not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Manga', message.author.id, message.server.id) except: traceback.print_exc() pass if not canEmbed: return CommentBuilder.buildMangaComment( isExpanded, mal, ani, mu, ap) else: return CommentBuilder.buildMangaEmbed(isExpanded, mal, ani, mu, ap) except Exception as e: traceback.print_exc() return None
def buildVisualNovelReply(searchText, isExpanded, baseComment, blockTracking=False): """ Builds an VN reply from VNDB """ try: vndb = VNDB() try: query = ('SELECT dbLinks' ' FROM synonyms' ' WHERE type = "VN"' ' AND lower(name) = ?') sqlCur.execute(query, [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if synonym: if 'vndb' in synonym and synonym['vndb']: synonym = synonym['vndb'] if synonym: result = vndb.getVisualNovelDetailsById(synonym) else: result = None else: result = vndb.getVisualNovelDetails(searchText) vndb.close() if result: try: titleToAdd = result['title'] subreddit = str(baseComment.subreddit).lower ignored_subreddits = ('nihilate', 'roboragi') if subreddit not in ignored_subreddits and not blockTracking: DatabaseHandler.addRequest( name=titleToAdd, rType='VN', requester=baseComment.author.name, subreddit=baseComment.subreddit) except Exception: traceback.print_exc() pass return CommentBuilder.buildVisualNovelComment(isExpanded, result) else: print('No result found for ' + searchText) return None except Exception: traceback.print_exc() return None
def buildMangaReplyWithAuthor(searchText, authorName, message, isExpanded, blockTracking=False): try: ani = Anilist.getMangaWithAuthor(searchText, authorName) mal = None mu = None ap = None if ani: mal = MAL.getMangaCloseToDescription(searchText, ani['description']) ap = AniP.getMangaURL(ani['title_english'], authorName) else: ap = AniP.getMangaURL(searchText, authorName) mu = MU.getMangaWithAuthor(searchText, authorName) if ani: try: titleToAdd = '' if mal is not None: titleToAdd = mal['title'] else: titleToAdd = ani['title_english'] if not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Manga', message.author.id, message.server.id) except: traceback.print_exc() pass return CommentBuilder.buildMangaComment(isExpanded, mal, ani, mu, ap) except Exception as e: traceback.print_exc() return None
def buildMangaReplyWithAuthor(searchText, authorName, isExpanded, baseComment, blockTracking=False): try: ani = Anilist.getMangaWithAuthor(searchText, authorName) mal = None mu = None ap = None if ani: mal = MAL.getMangaCloseToDescription(searchText, ani['description']) ap = AniP.getMangaURL(ani['title_english'], authorName) else: ap = AniP.getMangaURL(searchText, authorName) mu = MU.getMangaWithAuthor(searchText, authorName) if ani: try: titleToAdd = '' if mal is not None: titleToAdd = mal['title'] else: titleToAdd = ani['title_english'] if (str(baseComment.subreddit).lower is not 'nihilate') and (str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Manga', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass return CommentBuilder.buildMangaComment(isExpanded, mal, ani, mu, ap) except Exception as e: traceback.print_exc() return None
def buildVisualNovelReply(searchText, isExpanded, baseComment, blockTracking=False): try: vndb = VNDB() try: sqlCur.execute( 'SELECT dbLinks FROM synonyms WHERE type = "VN" and lower(name) = ?', [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if synonym: vndbsyn = None if 'vndb' in synonym and synonym['vndb']: synonym = synonym['vndb'] result = vndb.getVisualNovelDetailsById( synonym) if synonym else None else: result = vndb.getVisualNovelDetails(searchText) vndb.close() if result: try: titleToAdd = result['title'] if (str(baseComment.subreddit).lower is not 'nihilate') and ( str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'VN', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass return CommentBuilder.buildVisualNovelComment(isExpanded, result) else: print('No result found for ' + searchText) return None except Exception as e: traceback.print_exc() return None
def buildMangaReply(searchText, isExpanded, baseComment): try: #Basic breakdown: #If Anilist finds something, use it to find the MAL version. #If hits either MAL or Ani, use it to find the MU version. #If it hits either, add it to the request-tracking DB. ani = Anilist.getMangaDetails(searchText) mal = None mu = None if not (ani is None): mal = MAL.getMangaDetails(ani['title_romaji']) else: mal = MAL.getMangaDetails(searchText) if not (mal is None): ani = Anilist.getMangaDetails(mal['title']) if (ani is not None) or (mal is not None): try: titleToAdd = '' if mal is not None: titleToAdd = mal['title'] mu = MU.getMangaURL(mal['title']) else: titleToAdd = ani['title_english'] mu = MU.getMangaURL(ani['title_romaji']) if (str(baseComment.subreddit).lower is not 'nihilate') and (str(baseComment.subreddit).lower is not 'roboragi'): DatabaseHandler.addRequest(titleToAdd, 'Manga', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass if ani is not None: if ani['adult'] is True: print("NSFW ENTRY") mal = None ani = None mu = None return CommentBuilder.buildMangaComment(isExpanded, mal, ani, mu) except Exception as e: traceback.print_exc() return None
def buildMangaReplyWithAuthor(searchText, authorName, isExpanded, baseComment, blockTracking=False): try: ani = Anilist.getMangaWithAuthor(searchText, authorName) mal = None mu = None ap = None if ani: mal = MAL.getMangaCloseToDescription(searchText, ani['description']) ap = AniP.getMangaURL(ani['title_english'], authorName) else: ap = AniP.getMangaURL(searchText, authorName) mu = MU.getMangaWithAuthor(searchText, authorName) if ani: try: titleToAdd = '' if mal is not None: titleToAdd = mal['title'] else: titleToAdd = ani['title_english'] if (str(baseComment.subreddit).lower is not 'nihilate') and ( str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Manga', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass return CommentBuilder.buildMangaComment(isExpanded, mal, ani, mu, ap) except Exception as e: traceback.print_exc() return None
def buildAnimeReply(searchText, isExpanded, baseComment, blockTracking=False): try: mal = { 'search_function': MAL.getAnimeDetails, 'synonym_function': MAL.getSynonyms, 'checked_synonyms': [], 'result': None } hb = { 'search_function': Hummingbird.getAnimeDetails, 'synonym_function': Hummingbird.getSynonyms, 'checked_synonyms': [], 'result': None } ani = { 'search_function': Anilist.getAnimeDetails, 'synonym_function': Anilist.getSynonyms, 'checked_synonyms': [], 'result': None } ap = {'search_function': AniP.getAnimeURL, 'result': None} adb = {'search_function': AniDB.getAnimeURL, 'result': None} try: sqlCur.execute( 'SELECT dbLinks FROM synonyms WHERE type = "Anime" and lower(name) = ?', [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if synonym: malsyn = None if 'mal' in synonym and synonym['mal']: malsyn = synonym['mal'] hbsyn = None if 'hb' in synonym and synonym['hb']: hbsyn = synonym['hb'] anisyn = None if 'ani' in synonym and synonym['ani']: anisyn = synonym['ani'] apsyn = None if 'ap' in synonym and synonym['ap']: apsyn = synonym['ap'] adbsyn = None if 'adb' in synonym and synonym['adb']: adbsyn = synonym['adb'] mal['result'] = MAL.getAnimeDetails( malsyn[0], malsyn[1]) if malsyn else None hb['result'] = Hummingbird.getAnimeDetailsById( hbsyn) if hbsyn else None ani['result'] = Anilist.getAnimeDetailsById( anisyn) if anisyn else None ap['result'] = AniP.getAnimeURLById(apsyn) if apsyn else None adb['result'] = AniDB.getAnimeURLById( adbsyn) if adbsyn else None else: data_sources = [ani, hb, mal] #aux_sources = [ap, adb] aux_sources = [ap] synonyms = set([searchText]) for x in range(len(data_sources)): for source in data_sources: if source['result']: break else: for synonym in synonyms: if synonym in source['checked_synonyms']: continue source['result'] = source['search_function']( synonym) source['checked_synonyms'].append(synonym) if source['result']: break if source['result']: synonyms.update([ synonym.lower() for synonym in source['synonym_function'](source['result']) ]) for source in aux_sources: for synonym in synonyms: source['result'] = source['search_function'](synonym) if source['result']: break if ani['result'] or hb['result'] or mal['result']: try: titleToAdd = '' if mal['result']: titleToAdd = mal['result']['title'] if hb['result']: titleToAdd = hb['result']['title'] if ani['result']: titleToAdd = ani['result']['title_romaji'] if (str(baseComment.subreddit).lower is not 'nihilate') and ( str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Anime', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass return CommentBuilder.buildAnimeComment(isExpanded, mal['result'], hb['result'], ani['result'], ap['result'], adb['result']) except Exception as e: traceback.print_exc() return None
async def process_message(message, is_edit=False): #Anime/Manga requests that are found go into separate arrays animeArray = [] mangaArray = [] lnArray = [] #Checks if bot has permissions to embed if message.channel.type != discord.ChannelType.private: canEmbed = message.channel.server.default_role.permissions.embed_links else: canEmbed = True if not canEmbed: botMember = Discord.getMemberFromID(Config.clientid, message.server) defaultroleperm = botMember.top_role.permissions canEmbed = defaultroleperm.embed_links isAdmin = message.author.top_role.permissions.administrator isServerMod = message.author.top_role.permissions.manage_server isOwner = message.author.id == ownerID if message.author.bot: return #ignores all "code" markup (i.e. anything between backticks) preCleanMessage = re.sub(r"\`(.*?)\`", "", message.clean_content) cleanMessage = re.sub(r'<:.+?:([0-9]{15,21})>', "", preCleanMessage) messageReply = '' if re.search('({!help.*?}|{{!help.*?}}|<!help.*?>|<<!help.*?>>)', cleanMessage, re.S) is not None: try: localEm = CommentBuilder.buildHelpEmbed() await Discord.client.send_message(message.channel, embed=localEm) return except: return if re.search( '({!command.*?}|{{!command.*?}}|<!command.*?>|<<!command.*?>>)', cleanMessage, re.S) is not None: if 'toggleexpanded' in cleanMessage.lower() and (isAdmin or isServerMod): try: allowedStatus = DatabaseHandler.toggleAllowExpanded( message.server.id) print("Toggled allowExpanded for server {}".format( message.server.id)) if allowedStatus.lower() == 'true': await Discord.client.send_message( message.channel, "Expanded requests are now allowed.") else: await Discord.client.send_message( message.channel, "Expanded requests are now disallowed.") return except Exception as e: print(e) return if 'addserver' in cleanMessage.lower() and (isOwner == True): try: DatabaseHandler.addServerToDatabase(message.server.id) await Discord.client.send_message(message.channel, "Server has been added.") return except Exception as e: print(e) return else: print("command failed, user probably has insufficient rights") return sender = re.search('[@]([A-Za-z0-9 _-]+?)(>|}|$)', cleanMessage, re.S) mentionArray = message.raw_mentions if re.search('({!stats.*?}|{{!stats.*?}}|<!stats.*?>|<<!stats.*?>>)', cleanMessage, re.S) is not None and sender is not None: for mention in mentionArray: if not canEmbed: messageReply = CommentBuilder.buildStatsComment( server=message.server, username=mention) else: localEm = CommentBuilder.buildStatsEmbed(server=message.server, username=mention) await Discord.client.send_message(message.channel, embed=localEm) return None if re.search('({!sstats}|{{!sstats}}|<!sstats>|<<!sstats>>)', cleanMessage, re.S) is not None: if not canEmbed: messageReply = CommentBuilder.buildStatsComment( server=message.server) else: localEm = CommentBuilder.buildStatsEmbed(server=message.server) await Discord.client.send_message(message.channel, embed=localEm) return None elif re.search('({!stats.*?}|{{!stats.*?}}|<!stats.*?>|<<!stats.*?>>)', cleanMessage, re.S) is not None: if not canEmbed: messageReply = CommentBuilder.buildStatsComment() else: localEm = CommentBuilder.buildStatsEmbed() await Discord.client.send_message(message.channel, embed=localEm) return None else: #The basic algorithm here is: #If it's an expanded request, build a reply using the data in the braces, clear the arrays, add the reply to the relevant array and ignore everything else. #If it's a normal request, build a reply using the data in the braces, add the reply to the relevant array. #Counts the number of expanded results vs total results. If it's not just a single expanded result, they all get turned into normal requests. numOfRequest = 0 numOfExpandedRequest = 0 forceNormal = False expandedAllowed = DatabaseHandler.checkServerConfig( 'allowexpanded', message.server.id) if expandedAllowed == False: forceNormal = True for match in re.finditer("\{{2}([^}]*)\}{2}|\<{2}([^>]*)\>{2}", cleanMessage, re.S): numOfRequest += 1 numOfExpandedRequest += 1 print("Request found: {}".format(match.group(0))) for match in re.finditer( "(?<=(?<!\{)\{)([^\{\}]*)(?=\}(?!\}))|(?<=(?<!\<)\<)([^\<\>]*)(?=\>(?!\>))", cleanMessage, re.S): numOfRequest += 1 print("Request found: {}".format(match.group(0))) if (numOfExpandedRequest >= 1) and (numOfRequest > 1): forceNormal = True #if numOfRequest != 0: #await Discord.client.send_typing(message.channel) #Expanded Anime for match in re.finditer("\{{2}([^}]*)\}{2}", cleanMessage, re.S): reply = '' if match.group(1) != '': if (forceNormal) or (str(message.channel).lower() in disableexpanded): reply = await DiscordoragiSearch.buildAnimeReply( match.group(1), message, False, canEmbed) else: reply = await DiscordoragiSearch.buildAnimeReply( match.group(1), message, True, canEmbed) if (reply is not None): animeArray.append(reply) else: print("Empty request, ignoring") #Normal Anime for match in re.finditer("(?<=(?<!\{)\{)([^\{\}]*)(?=\}(?!\}))", cleanMessage, re.S): if match.group(1) != '': reply = await DiscordoragiSearch.buildAnimeReply( match.group(1), message, False, canEmbed) if (reply is not None): animeArray.append(reply) else: print('Could not find anime') else: print("Empty request, ignoring") #Expanded Manga #NORMAL EXPANDED for match in re.finditer("\<{2}([^>]*)\>{2}(?!(:|\>))", cleanMessage, re.S): if match.group(1) != '': reply = '' if (forceNormal) or (str(message.channel).lower() in disableexpanded): reply = await DiscordoragiSearch.buildMangaReply( match.group(1), message, False, canEmbed) else: reply = await DiscordoragiSearch.buildMangaReply( match.group(1), message, True, canEmbed) if (reply is not None): mangaArray.append(reply) else: print("Empty request, ignoring") #AUTHOR SEARCH EXPANDED for match in re.finditer("\<{2}([^>]*)\>{2}:\(([^)]+)\)", cleanMessage, re.S): if match.group(1) != '': reply = '' if (forceNormal) or (str(message.server).lower() in disableexpanded): reply = await DiscordoragiSearch.buildMangaReplyWithAuthor( match.group(1), match.group(2), message, False, canEmbed) else: reply = await DiscordoragiSearch.buildMangaReplyWithAuthor( match.group(1), match.group(2), message, True, canEmbed) if (reply is not None): mangaArray.append(reply) else: print("Empty request, ignoring") #Normal Manga #NORMAL for match in re.finditer("(?<=(?<!\<)\<)([^\<\>]+)\>(?!(:|\>))", cleanMessage, re.S): if match.group(1) != '': reply = await DiscordoragiSearch.buildMangaReply( match.group(1), message, False, canEmbed) if (reply is not None): mangaArray.append(reply) else: print("Empty request, ignoring") #AUTHOR SEARCH for match in re.finditer("(?<=(?<!\<)\<)([^\<\>]*)\>:\(([^)]+)\)", cleanMessage, re.S): reply = await DiscordoragiSearch.buildMangaReplyWithAuthor( match.group(1), match.group(2), message, False, canEmbed) if (reply is not None): mangaArray.append(reply) #Expanded LN for match in re.finditer("\]{2}([^]]*)\[{2}", cleanMessage, re.S): if match.group(1) != '': reply = '' if (forceNormal) or (str(message.server).lower() in disableexpanded): reply = await DiscordoragiSearch.buildLightNovelReply( match.group(1), False, message, canEmbed) else: reply = await DiscordoragiSearch.buildLightNovelReply( match.group(1), True, message, canEmbed) if (reply is not None): lnArray.append(reply) else: print("Empty request, ignoring") #Normal LN for match in re.finditer("(?<=(?<!\])\])([^\]\[]*)(?=\[(?!\[))", cleanMessage, re.S): if match.group(1) != '': reply = await DiscordoragiSearch.buildLightNovelReply( match.group(1), False, message, canEmbed) if (reply is not None): lnArray.append(reply) else: print("Empty request, ignoring") #Here is where we create the final reply to be posted #The final message reply. We add stuff to this progressively. postedAnimeTitles = [] postedMangaTitles = [] postedLNTitles = [] messageReply = '' #Basically just to keep track of people posting the same title multiple times (e.g. {Nisekoi}{Nisekoi}{Nisekoi}) postedAnimeTitles = [] postedMangaTitles = [] postedLNTitles = [] #Adding all the anime to the final message. If there's manga too we split up all the paragraphs and indent them in Reddit markup by adding a '>', then recombine them for i, animeReply in enumerate(animeArray): if not (i is 0): messageReply += '\n\n' if not (animeReply['title'] in postedAnimeTitles): postedAnimeTitles.append(animeReply['title']) if not canEmbed: messageReply += animeReply['comment'] else: messageReply = 'n/a' if mangaArray: messageReply += '\n\n' #Adding all the manga to the final message for i, mangaReply in enumerate(mangaArray): if not (i is 0): messageReply += '\n\n' if not (mangaReply['title'] in postedMangaTitles): postedMangaTitles.append(mangaReply['title']) if not canEmbed: messageReply += mangaReply['comment'] else: messageReply = 'n/a' if lnArray: messageReply += '\n\n' #Adding all the manga to the final comment for i, lnReply in enumerate(lnArray): if not (i is 0): commentReply += '\n\n' if not (lnReply['title'] in postedLNTitles): postedLNTitles.append(lnReply['title']) if not canEmbed: messageReply += lnReply['comment'] else: messageReply = 'N/A' #If there are more than 10 requests, shorten them all if not (messageReply is '') and (len(animeArray) + len(mangaArray) >= 10): messageReply = re.sub(r"\^\((.*?)\)", "", messageReply, flags=re.M) #If there was actually something found, add the signature and post the message to Reddit. Then, add the message to the "already seen" database. if not (messageReply is ''): if is_edit: if not canEmbed: await Discord.client.send_message(message.channel, messageReply) else: for i, animeReply in enumerate(animeArray): await Discord.client.send_message( message.channel, embed=animeReply['embed']) for i, mangaReply in enumerate(mangaArray): await Discord.client.send_message( message.channel, embed=mangaReply['embed']) for i, lnReply in enumerate(lnArray): await Discord.client.send_message(message.channel, embed=lnReply['embed']) else: try: print("Message created.\n") if not canEmbed: await Discord.client.send_message(message.channel, messageReply) else: for i, animeReply in enumerate(animeArray): await Discord.client.send_message( message.channel, embed=animeReply['embed']) for i, mangaReply in enumerate(mangaArray): await Discord.client.send_message( message.channel, embed=mangaReply['embed']) for i, lnReply in enumerate(lnArray): await Discord.client.send_message( message.channel, embed=lnReply['embed']) except discord.errors.Forbidden: print('Request from banned channel: ' + str(message.channel) + '\n') except Exception as e: print(e) traceback.print_exc() except: traceback.print_exc() else: try: if is_edit: return None else: DatabaseHandler.addMessage(message.id, message.author.id, message.server.id, False) except: traceback.print_exc()
def buildAnimeReply(searchText, isExpanded, baseComment, blockTracking=False): try: kit = { 'search_function': Kitsu.search_anime, 'synonym_function': Kitsu.get_synonyms, 'title_function': Kitsu.get_titles, 'checked_synonyms': [], 'result': None } ani = { 'search_function': Anilist.getAnimeDetails, 'synonym_function': Anilist.getSynonyms, 'title_function': Anilist.getTitles, 'checked_synonyms': [], 'result': None } ap = {'search_function': AniP.getAnimeURL, 'result': None} try: sqlCur.execute( 'SELECT dbLinks FROM synonyms WHERE type = "Anime" and lower(name) = ?', [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if synonym: kitsyn = None if 'kit' in synonym and synonym['kit']: kitsyn = synonym['kit'] anisyn = None if 'ani' in synonym and synonym['ani']: anisyn = synonym['ani'] apsyn = None if 'ap' in synonym and synonym['ap']: apsyn = synonym['ap'] kit['result'] = Kitsu.get_anime(kitsyn) if kitsyn else None ani['result'] = Anilist.getAnimeDetailsById( anisyn) if anisyn else None ap['result'] = AniP.getAnimeURLById(apsyn) if apsyn else None else: data_sources = [ani, kit] aux_sources = [ap] synonyms = set([searchText]) titles = set() for x in range(len(data_sources)): for source in data_sources: if source['result']: break else: for synonym in (titles | synonyms): if synonym in source['checked_synonyms']: continue source['result'] = source['search_function']( synonym) source['checked_synonyms'].append(synonym) if source['result']: break if source['result']: synonyms.update([ synonym.lower() for synonym in source['synonym_function'](source['result']) ]) titles.update([ title.lower() for title in source['title_function'] (source['result']) ]) for source in aux_sources: for title in titles: source['result'] = source['search_function'](synonym) if source['result']: break if not source['result']: for synonym in synonyms: source['result'] = source['search_function'](synonym) if source['result']: break if ani['result'] or kit['result']: try: titleToAdd = '' if ani['result']: if 'title_romaji' in ani['result']: titleToAdd = ani['result']['title_romaji'] elif kit['result']: if 'title_romaji' in kit['result']: titleToAdd = kit['result']['title_romaji'] if (str(baseComment.subreddit).lower is not 'nihilate') and ( str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Anime', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass if ani['result'] or kit['result']: return CommentBuilder.buildAnimeComment(isExpanded, ani['result'], ap['result'], kit['result']) else: print('No result found for ' + searchText) return None except Exception as e: traceback.print_exc() return None
def buildMangaReply(searchText, isExpanded, baseComment, blockTracking=False): """ Builds a manga reply from multiple sources """ try: ani = { 'search_function': Anilist.getMangaDetails, 'title_function': Anilist.getTitles, 'synonym_function': Anilist.getSynonyms, 'checked_synonyms': [], 'result': None } kit = { 'search_function': Kitsu.search_manga, 'synonym_function': Kitsu.get_synonyms, 'title_function': Kitsu.get_titles, 'checked_synonyms': [], 'result': None } mu = {'search_function': MU.getMangaURL, 'result': None} ap = {'search_function': AniP.getMangaURL, 'result': None} try: query = ('SELECT dbLinks' ' FROM synonyms' ' WHERE type = "Manga"' ' AND lower(name) = ?') sqlCur.execute(query, [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if synonym: anisyn = None if 'ani' in synonym and synonym['ani']: anisyn = synonym['ani'] kitsyn = None if 'kit' in synonym and synonym['kit']: kitsyn = synonym['kit'] musyn = None if 'mu' in synonym and synonym['mu']: musyn = synonym['mu'] apsyn = None if 'ap' in synonym and synonym['ap']: apsyn = synonym['ap'] if anisyn: ani['result'] = Anilist.getMangaDetailsById(anisyn) else: ani['result'] = None kit['result'] = Kitsu.get_manga(kitsyn) if kitsyn else None mu['result'] = MU.getMangaURLById(musyn) if musyn else None ap['result'] = AniP.getMangaURLById(apsyn) if apsyn else None else: data_sources = [ani, kit] aux_sources = [mu, ap] synonyms = set([searchText]) titles = set() for x in range(len(data_sources)): for source in data_sources: if source['result']: break else: for title in titles: if title in source['checked_synonyms']: break if source['result']: break source['result'] = source['search_function'](title) source['checked_synonyms'].append(title) if source['result']: break for synonym in synonyms: if synonym in source['checked_synonyms']: break if source['result']: break search_function = source['search_function'] source['result'] = search_function(synonym) source['checked_synonyms'].append(synonym) if source['result']: break if source['result']: result = source['result'] synonym_function = source['synonym_function'] title_function = source['title_function'] synonyms.update( [s.lower() for s in synonym_function(result)]) titles.update( [t.lower() for t in title_function(result)]) for source in aux_sources: for title in titles: source['result'] = source['search_function'](synonym) if source['result']: break if not source['result']: for synonym in synonyms: source['result'] = source['search_function'](synonym) if source['result']: break if ani['result'] or kit['result']: try: titleToAdd = '' if ani['result']: try: titleToAdd = ani['result']['title_romaji'] except Exception: titleToAdd = ani['result']['title_english'] elif kit['result']: try: titleToAdd = kit['result']['title_romaji'] except Exception: titleToAdd = kit['result']['title_english'] subreddit = str(baseComment.subreddit).lower ignored_subreddits = ('nihilate', 'roboragi') if subreddit not in ignored_subreddits and not blockTracking: DatabaseHandler.addRequest( name=titleToAdd, rType='Manga', requester=baseComment.author.name, subreddit=baseComment.subreddit) except Exception: traceback.print_exc() pass if ani['result'] or kit['result']: return CommentBuilder.buildMangaComment(isExpanded=isExpanded, ani=ani['result'], mu=mu['result'], ap=ap['result'], kit=kit['result']) else: print('No result found for ' + searchText) return None except Exception: traceback.print_exc() return None
def process_comment(comment, is_edit=False): #Anime/Manga requests that are found go into separate arrays animeArray = [] mangaArray = [] lnArray = [] #ignores all "code" markup (i.e. anything between backticks) comment.body = re.sub(r"\`(?s)(.*?)\`", "", comment.body) #This checks for requests. First up we check all known tags for the !stats request if re.search('({!stats.*?}|{{!stats.*?}}|<!stats.*?>|<<!stats.*?>>)', comment.body, re.S) is not None: username = re.search('[uU]\/([A-Za-z0-9_-]+?)(>|}|$)', comment.body, re.S) subreddit = re.search('[rR]\/([A-Za-z0-9_]+?)(>|}|$)', comment.body, re.S) if username: commentReply = CommentBuilder.buildStatsComment(username=username.group(1)) elif subreddit: commentReply = CommentBuilder.buildStatsComment(subreddit=subreddit.group(1)) else: commentReply = CommentBuilder.buildStatsComment() else: #The basic algorithm here is: #If it's an expanded request, build a reply using the data in the braces, clear the arrays, add the reply to the relevant array and ignore everything else. #If it's a normal request, build a reply using the data in the braces, add the reply to the relevant array. #Counts the number of expanded results vs total results. If it's not just a single expanded result, they all get turned into normal requests. numOfRequest = 0 numOfExpandedRequest = 0 forceNormal = False for match in re.finditer("\{{2}([^}]*)\}{2}|\<{2}([^>]*)\>{2}", comment.body, re.S): numOfRequest += 1 numOfExpandedRequest += 1 for match in re.finditer("(?<=(?<!\{)\{)([^\{\}]*)(?=\}(?!\}))|(?<=(?<!\<)\<)([^\<\>]*)(?=\>(?!\>))", comment.body, re.S): numOfRequest += 1 if (numOfExpandedRequest >= 1) and (numOfRequest > 1): forceNormal = True #Expanded Anime for match in re.finditer("\{{2}([^}]*)\}{2}", comment.body, re.S): reply = '' if (forceNormal) or (str(comment.subreddit).lower() in disableexpanded): reply = Search.buildAnimeReply(match.group(1), False, comment) else: reply = Search.buildAnimeReply(match.group(1), True, comment) if (reply is not None): animeArray.append(reply) #Normal Anime for match in re.finditer("(?<=(?<!\{)\{)([^\{\}]*)(?=\}(?!\}))", comment.body, re.S): reply = Search.buildAnimeReply(match.group(1), False, comment) if (reply is not None): animeArray.append(reply) #Expanded Manga #NORMAL EXPANDED for match in re.finditer("\<{2}([^>]*)\>{2}(?!(:|\>))", comment.body, re.S): reply = '' if (forceNormal) or (str(comment.subreddit).lower() in disableexpanded): reply = Search.buildMangaReply(match.group(1), False, comment) else: reply = Search.buildMangaReply(match.group(1), True, comment) if (reply is not None): mangaArray.append(reply) #AUTHOR SEARCH EXPANDED for match in re.finditer("\<{2}([^>]*)\>{2}:\(([^)]+)\)", comment.body, re.S): reply = '' if (forceNormal) or (str(comment.subreddit).lower() in disableexpanded): reply = Search.buildMangaReplyWithAuthor(match.group(1), match.group(2), False, comment) else: reply = Search.buildMangaReplyWithAuthor(match.group(1), match.group(2), True, comment) if (reply is not None): mangaArray.append(reply) #Normal Manga #NORMAL for match in re.finditer("(?<=(?<!\<)\<)([^\<\>]+)\>(?!(:|\>))", comment.body, re.S): reply = Search.buildMangaReply(match.group(1), False, comment) if (reply is not None): mangaArray.append(reply) #AUTHOR SEARCH for match in re.finditer("(?<=(?<!\<)\<)([^\<\>]*)\>:\(([^)]+)\)", comment.body, re.S): reply = Search.buildMangaReplyWithAuthor(match.group(1), match.group(2), False, comment) if (reply is not None): mangaArray.append(reply) #Expanded LN for match in re.finditer("\]{2}([^]]*)\[{2}", comment.body, re.S): reply = '' if (forceNormal) or (str(comment.subreddit).lower() in disableexpanded): reply = Search.buildLightNovelReply(match.group(1), False, comment) else: reply = Search.buildLightNovelReply(match.group(1), True, comment) if (reply is not None): lnArray.append(reply) #Normal LN for match in re.finditer("(?<=(?<!\])\])([^\]\[]*)(?=\[(?!\[))", comment.body, re.S): reply = Search.buildLightNovelReply(match.group(1), False, comment) if (reply is not None): lnArray.append(reply) #Here is where we create the final reply to be posted #The final comment reply. We add stuff to this progressively. commentReply = '' #Basically just to keep track of people posting the same title multiple times (e.g. {Nisekoi}{Nisekoi}{Nisekoi}) postedAnimeTitles = [] postedMangaTitles = [] postedLNTitles = [] #Adding all the anime to the final comment. If there's manga too we split up all the paragraphs and indent them in Reddit markup by adding a '>', then recombine them for i, animeReply in enumerate(animeArray): if not (i is 0): commentReply += '\n\n' if not (animeReply['title'] in postedAnimeTitles): postedAnimeTitles.append(animeReply['title']) commentReply += animeReply['comment'] if mangaArray: commentReply += '\n\n' #Adding all the manga to the final comment for i, mangaReply in enumerate(mangaArray): if not (i is 0): commentReply += '\n\n' if not (mangaReply['title'] in postedMangaTitles): postedMangaTitles.append(mangaReply['title']) commentReply += mangaReply['comment'] if lnArray: commentReply += '\n\n' #Adding all the manga to the final comment for i, lnReply in enumerate(lnArray): if not (i is 0): commentReply += '\n\n' if not (lnReply['title'] in postedLNTitles): postedLNTitles.append(lnReply['title']) commentReply += lnReply['comment'] #If there are more than 10 requests, shorten them all if not (commentReply is '') and (len(animeArray) + len(mangaArray)+ len(lnArray) >= 10): commentReply = re.sub(r"\^\((.*?)\)", "", commentReply, flags=re.M) #If there was actually something found, add the signature and post the comment to Reddit. Then, add the comment to the "already seen" database. if commentReply is not '': '''if (comment.author.name == 'treborabc'): commentReply = '[No.](https://www.reddit.com/r/anime_irl/comments/4sba1n/anime_irl/d58xkha)''' commentReply += Config.getSignature(comment.permalink) commentReply += Reference.get_bling(comment.author.name) if is_edit: return commentReply else: try: comment.reply(commentReply) print("Comment made.\n") except praw.errors.Forbidden: print('Request from banned subreddit: ' + str(comment.subreddit) + '\n') except Exception: traceback.print_exc() try: DatabaseHandler.addComment(comment.id, comment.author.name, comment.subreddit, True) except: traceback.print_exc() else: try: if is_edit: return None else: DatabaseHandler.addComment(comment.id, comment.author.name, comment.subreddit, False) except: traceback.print_exc()
def buildAnimeReply(searchText, isExpanded, baseComment): try: #Basic breakdown: #If Anilist finds something, use it to find the HB version. #If we can't find it, try with HB and use it to try and "refind" Anilist #If we hit HB, we don't need to look for MAL, since we can get the MAL ID from within HB. If we don't hit HB, find MAL on its own. #If, at the end, we have something from Anilist, get the full set of Anilist data #If it hits anything, add it to the request-tracking DB. ani = Anilist.getAnimeDetails(searchText) hb = None mal = None if (ani is not None): hb = Hummingbird.getAnimeDetails(ani['title_romaji']) if (hb is None): for synonym in ani['synonyms']: hb = Hummingbird.getAnimeDetails(synonym) if hb is not None: break hb = Hummingbird.getAnimeDetails(ani['title_english']) else: hb = Hummingbird.getAnimeDetails(searchText) if (hb is not None): ani = Anilist.getAnimeDetails(hb['title']) if (hb is None): mal = MAL.getAnimeDetails(searchText) if (mal is not None): hb = Hummingbird.getAnimeDetails(mal['title']) if (hb is None): hb = Hummingbird.getAnimeDetails(mal['english']) if (ani is None): ani = Anilist.getAnimeDetails(mal['title']) if (ani is None): ani = Anilist.getAnimeDetails(mal['english']) try: if ani is not None: aniFull = Anilist.getFullAnimeDetails(ani['id']) if aniFull is not None: ani = aniFull except: pass if (ani is not None) or (hb is not None) or (mal is not None): try: titleToAdd = '' if ani is None: titleToAdd = hb['title'] elif hb is not None: titleToAdd = ani['title_romaji'] else: titleToAdd = mal['title'] if (str(baseComment.subreddit).lower is not 'nihilate') and (str(baseComment.subreddit).lower is not 'roboragi'): DatabaseHandler.addRequest(titleToAdd, 'Anime', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass if ani is not None: if ani['adult'] is True: print("NSFW ENTRY") mal = None hb = None ani = None return CommentBuilder.buildAnimeComment(isExpanded, mal, hb, ani) except Exception as e: traceback.print_exc() return None
def buildAnimeReply(searchText, isExpanded, baseComment, blockTracking=False): try: mal = None hb = None ani = None ap = None try: sqlCur.execute('SELECT dbLinks FROM synonyms WHERE type = "Anime" and lower(name) = ?', [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if (synonym['mal']): mal = MAL.getAnimeDetails(synonym['mal']) if (synonym['hb']): hb = Hummingbird.getAnimeDetails(synonym['hb']) if (synonym['ani']): ani = Anilist.getAnimeDetails(synonym['ani']) if (synonym['ap']): ap = AniP.getAnimeURL(synonym['ap']) else: #Basic breakdown: #If Anilist finds something, use it to find the HB version. #If we can't find it, try with HB and use it to try and "refind" Anilist #If we hit HB, we don't need to look for MAL, since we can get the MAL ID from within HB. If we don't hit HB, find MAL on its own. #If, at the end, we have something from Anilist, get the full set of Anilist data #If it hits anything, add it to the request-tracking DB. ani = Anilist.getAnimeDetails(searchText) if (ani is not None): hb = Hummingbird.getAnimeDetails(ani['title_romaji']) if (hb is None): for synonym in ani['synonyms']: hb = Hummingbird.getAnimeDetails(synonym) if hb is not None: break hb = Hummingbird.getAnimeDetails(ani['title_english']) else: hb = Hummingbird.getAnimeDetails(searchText) if (hb is not None): ani = Anilist.getAnimeDetails(hb['title']) #Doing MAL stuff if not mal: if hb: mal = MAL.getAnimeDetails(hb['title']) if not mal and hb['alternate_title']: if (hb['alternate_title']): mal = MAL.getAnimeDetails(hb['alternate_title']) if ani and not mal: mal = MAL.getAnimeDetails(ani['title_romaji']) if not mal: mal = MAL.getAnimeDetails(ani['title_english']) if not mal and ani['synonyms']: for synonym in ani['synonyms']: if mal: break mal = MAL.getAnimeDetails(synonym) if not mal: mal = MAL.getAnimeDetails(searchText) if mal and not hb: hb = Hummingbird.getAnimeDetails(mal['title']) if not hb: hb = Hummingbird.getAnimeDetails(mal['english']) if mal and not ani: ani = Anilist.getAnimeDetails(mal['title']) if not ani: ani = Anilist.getAnimeDetails(mal['english']) #----- Finally... -----# try: if ani is not None: aniFull = Anilist.getFullAnimeDetails(ani['id']) if aniFull is not None: ani = aniFull except: pass if (ani is not None) or (hb is not None) or (mal is not None): try: titleToAdd = '' if mal: titleToAdd = mal['title'] if hb: titleToAdd = hb['title'] if ani: titleToAdd = ani['title_romaji'] #Do Anime-Planet stuff if mal and not ap: if mal['title'] and not ap: ap = AniP.getAnimeURL(mal['title']) if mal['english'] and not ap: ap = AniP.getAnimeURL(mal['english']) if mal['synonyms'] and not ap: for synonym in mal['synonyms']: if ap: break ap = AniP.getAnimeURL(synonym) if hb and not ap: if hb['title'] and not ap: ap = AniP.getAnimeURL(hb['title']) if hb['alternate_title'] and not ap: ap = AniP.getAnimeURL(hb['alternate_title']) if ani and not ap: if ani['title_english'] and not ap: ap = AniP.getAnimeURL(ani['title_english']) if ani['title_romaji'] and not ap: ap = AniP.getAnimeURL(ani['title_romaji']) if ani['synonyms'] and not ap: for synonym in ani['synonyms']: if ap: break ap = AniP.getAnimeURL(synonym) if (str(baseComment.subreddit).lower is not 'nihilate') and (str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Anime', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass if ani is not None: if ani['adult'] is True: print("NSFW ENTRY") mal = None hb = None ani = None ap = None return CommentBuilder.buildAnimeComment(isExpanded, mal, hb, ani, ap) except Exception as e: traceback.print_exc() return None
async def process_message(message, is_edit=False): #Anime/Manga requests that are found go into separate arrays animeArray = [] mangaArray = [] lnArray = [] #ignores all "code" markup (i.e. anything between backticks) cleanMessage = re.sub(r"\`(?s)(.*?)\`", "", message.clean_content) sender = re.search('[@]([A-Za-z0-9_-]+?)(>|}|$)', cleanMessage, re.S) if re.search('({!stats.*?}|{{!stats.*?}}|<!stats.*?>|<<!stats.*?>>)', cleanMessage, re.S) is not None and sender is not None: messageReply = CommentBuilder.buildStatsComment(username=sender.group(1)) if re.search('({!sstats.*?}|{{!sstats.*?}}|<!sstats.*?>|<<!sstats.*?>>)', cleanMessage, re.S) is not None: server = re.search('([A-Za-z0-9_]+?)(>|}|$)', cleanMessage, re.S) messageReply = CommentBuilder.buildStatsComment(server=server.group(1)) elif re.search('({!stats.*?}|{{!stats.*?}}|<!stats.*?>|<<!stats.*?>>)', cleanMessage, re.S) is not None: messageReply = CommentBuilder.buildStatsComment() else: #The basic algorithm here is: #If it's an expanded request, build a reply using the data in the braces, clear the arrays, add the reply to the relevant array and ignore everything else. #If it's a normal request, build a reply using the data in the braces, add the reply to the relevant array. #Counts the number of expanded results vs total results. If it's not just a single expanded result, they all get turned into normal requests. numOfRequest = 0 numOfExpandedRequest = 0 forceNormal = False for match in re.finditer("\{{2}([^}]*)\}{2}|\<{2}([^>]*)\>{2}", cleanMessage, re.S): numOfRequest += 1 numOfExpandedRequest += 1 for match in re.finditer("(?<=(?<!\{)\{)([^\{\}]*)(?=\}(?!\}))|(?<=(?<!\<)\<)([^\<\>]*)(?=\>(?!\>))", cleanMessage, re.S): numOfRequest += 1 if (numOfExpandedRequest >= 1) and (numOfRequest > 1): forceNormal = True #Expanded Anime for match in re.finditer("\{{2}([^}]*)\}{2}", cleanMessage, re.S): reply = '' if (forceNormal) or (str(message.channel).lower() in disableexpanded): reply = DiscordoragiSearch.buildAnimeReply(match.group(1), message, False) else: reply = DiscordoragiSearch.buildAnimeReply(match.group(1), message, True) if (reply is not None): animeArray.append(reply) #Normal Anime for match in re.finditer("(?<=(?<!\{)\{)([^\{\}]*)(?=\}(?!\}))", cleanMessage, re.S): reply = DiscordoragiSearch.buildAnimeReply(match.group(1), message, False) if (reply is not None): animeArray.append(reply) #Expanded Manga #NORMAL EXPANDED for match in re.finditer("\<{2}([^>]*)\>{2}(?!(:|\>))", cleanMessage, re.S): reply = '' if (forceNormal) or (str(message.channel).lower() in disableexpanded): reply = DiscordoragiSearch.buildMangaReply(match.group(1), message, False) else: reply = DiscordoragiSearch.buildMangaReply(match.group(1), message, True) if (reply is not None): mangaArray.append(reply) #AUTHOR SEARCH EXPANDED for match in re.finditer("\<{2}([^>]*)\>{2}:\(([^)]+)\)", cleanMessage, re.S): reply = '' if (forceNormal) or (str(message.server).lower() in disableexpanded): reply = DiscordoragiSearch.buildMangaReplyWithAuthor(match.group(1), match.group(2), message, False) else: reply = DiscordoragiSearch.buildMangaReplyWithAuthor(match.group(1), match.group(2), message, True) if (reply is not None): mangaArray.append(reply) #Normal Manga #NORMAL for match in re.finditer("(?<=(?<!\<)\<)([^\<\>]+)\>(?!(:|\>))", cleanMessage, re.S): reply = DiscordoragiSearch.buildMangaReply(match.group(1), message, False) if (reply is not None): mangaArray.append(reply) #AUTHOR SEARCH for match in re.finditer("(?<=(?<!\<)\<)([^\<\>]*)\>:\(([^)]+)\)", cleanMessage, re.S): reply = DiscordoragiSearch.buildMangaReplyWithAuthor(match.group(1), match.group(2), message, False) if (reply is not None): mangaArray.append(reply) #Expanded LN for match in re.finditer("\]{2}([^]]*)\[{2}", cleanMessage, re.S): reply = '' if (forceNormal) or (str(message.server).lower() in disableexpanded): reply = DiscordoragiSearch.buildLightNovelReply(match.group(1), False, message) else: reply = DiscordoragiSearch.buildLightNovelReply(match.group(1), True, message) if (reply is not None): lnArray.append(reply) #Normal LN for match in re.finditer("(?<=(?<!\])\])([^\]\[]*)(?=\[(?!\[))", cleanMessage, re.S): reply = DiscordoragiSearch.buildLightNovelReply(match.group(1), False, message) if (reply is not None): lnArray.append(reply) #Here is where we create the final reply to be posted #The final message reply. We add stuff to this progressively. messageReply = '' #Basically just to keep track of people posting the same title multiple times (e.g. {Nisekoi}{Nisekoi}{Nisekoi}) postedAnimeTitles = [] postedMangaTitles = [] postedLNTitles = [] #Adding all the anime to the final message. If there's manga too we split up all the paragraphs and indent them in Reddit markup by adding a '>', then recombine them for i, animeReply in enumerate(animeArray): if not (i is 0): messageReply += '\n\n' if not (animeReply['title'] in postedAnimeTitles): postedAnimeTitles.append(animeReply['title']) messageReply += animeReply['comment'] if mangaArray: messageReply += '\n\n' #Adding all the manga to the final message for i, mangaReply in enumerate(mangaArray): if not (i is 0): messageReply += '\n\n' if not (mangaReply['title'] in postedMangaTitles): postedMangaTitles.append(mangaReply['title']) messageReply += mangaReply['comment'] if lnArray: messageReply += '\n\n' #Adding all the manga to the final comment for i, lnReply in enumerate(lnArray): if not (i is 0): commentReply += '\n\n' if not (lnReply['title'] in postedLNTitles): postedLNTitles.append(lnReply['title']) messageReply += lnReply['comment'] #If there are more than 10 requests, shorten them all if not (messageReply is '') and (len(animeArray) + len(mangaArray) >= 10): messageReply = re.sub(r"\^\((.*?)\)", "", messageReply, flags=re.M) #If there was actually something found, add the signature and post the message to Reddit. Then, add the message to the "already seen" database. if not (messageReply is ''): messageReply += Config.getSignature() if is_edit: await Discord.client.send_message(message.channel, messageReply) else: try: print("Message created.\n") await Discord.client.send_message(message.channel, messageReply) except discord.errors.Forbidden: print('Request from banned channel: ' + str(message.channel) + '\n') except Exception: traceback.print_exc() try: DatabaseHandler.addMessage(message.id, message.author.id, message.server.id, True) except: traceback.print_exc() else: try: if is_edit: return None else: DatabaseHandler.addMessage(message.id, message.author.id, message.server.id, False) except: traceback.print_exc()
def buildAnimeReply(searchText, isExpanded, baseComment, blockTracking=False): try: mal = {'search_function': MAL.getAnimeDetails, 'synonym_function': MAL.getSynonyms, 'checked_synonyms': [], 'result': None} hb = {'search_function': Hummingbird.getAnimeDetails, 'synonym_function': Hummingbird.getSynonyms, 'checked_synonyms': [], 'result': None} ani = {'search_function': Anilist.getAnimeDetails, 'synonym_function': Anilist.getSynonyms, 'checked_synonyms': [], 'result': None} ap = {'search_function': AniP.getAnimeURL, 'result': None} adb = {'search_function': AniDB.getAnimeURL, 'result': None} try: sqlCur.execute('SELECT dbLinks FROM synonyms WHERE type = "Anime" and lower(name) = ?', [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if synonym: malsyn = None if 'mal' in synonym and synonym['mal']: malsyn = synonym['mal'] hbsyn = None if 'hb' in synonym and synonym['hb']: hbsyn = synonym['hb'] anisyn = None if 'ani' in synonym and synonym['ani']: anisyn = synonym['ani'] apsyn = None if 'ap' in synonym and synonym['ap']: apsyn = synonym['ap'] adbsyn = None if 'adb' in synonym and synonym['adb']: adbsyn = synonym['adb'] mal['result'] = MAL.getAnimeDetails(malsyn[0],malsyn[1]) if malsyn else None hb['result'] = Hummingbird.getAnimeDetailsById(hbsyn) if hbsyn else None ani['result'] = Anilist.getAnimeDetailsById(anisyn) if anisyn else None ap['result'] = AniP.getAnimeURLById(apsyn) if apsyn else None adb['result'] = AniDB.getAnimeURLById(adbsyn) if adbsyn else None else: data_sources = [ani, hb, mal] aux_sources = [ap, adb] synonyms = set([searchText]) for x in range(len(data_sources)): for source in data_sources: if source['result']: break else: for synonym in synonyms: if synonym in source['checked_synonyms']: continue source['result'] = source['search_function'](synonym) source['checked_synonyms'].append(synonym) if source['result']: break if source['result']: synonyms.update([synonym.lower() for synonym in source['synonym_function'](source['result'])]) for source in aux_sources: for synonym in synonyms: source['result'] = source['search_function'](synonym) if source['result']: break if ani['result'] or hb['result'] or mal['result']: try: titleToAdd = '' if mal['result']: titleToAdd = mal['result']['title'] if hb['result']: titleToAdd = hb['result']['title'] if ani['result']: titleToAdd = ani['result']['title_romaji'] if (str(baseComment.subreddit).lower is not 'nihilate') and (str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Anime', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass return CommentBuilder.buildAnimeComment(isExpanded, mal['result'], hb['result'], ani['result'], ap['result'], adb['result']) except Exception as e: traceback.print_exc() return None
def start(): print('Starting comment stream:') #This opens a constant stream of comments. It will loop until there's a major error (usually this means the Reddit access token needs refreshing) comment_stream = praw.helpers.comment_stream(reddit, subredditlist, limit=250, verbosity=0) for comment in comment_stream: #Is the comment valid (i.e. it's not made by Roboragi and I haven't seen it already). If no, try to add it to the "already seen pile" and skip to the next comment. If yes, keep going. if not (Search.isValidComment(comment, reddit)): try: if not (DatabaseHandler.commentExists(comment.id)): DatabaseHandler.addComment(comment.id, comment.author.name, comment.subreddit, False) except: pass continue #Anime/Manga requests that are found go into separate arrays animeArray = [] mangaArray = [] #The "hasExpandedRequest" variable puts a stop on any other requests (since you can only have one expanded request in a comment) hasExpandedRequest = False #ignores all "code" markup (i.e. anything between backticks) comment.body = re.sub(r"\`(?s)(.*?)\`", "", comment.body) #This checks for requests. First up we check all known tags for the !stats request # Assumes tag begins and ends with a whitespace OR at the string beginning/end if re.search('(^|\s)({!stats}|{{!stats}}|<!stats>|<<!stats>>)($|\s|.)', comment.body, re.S) is not None: commentReply = CommentBuilder.buildStatsComment(comment.subreddit) else: #The basic algorithm here is: #If it's an expanded request, build a reply using the data in the braces, clear the arrays, add the reply to the relevant array and ignore everything else. #If it's a normal request, build a reply using the data in the braces, add the reply to the relevant array. #Expanded Anime for match in re.finditer("\{{2}([^}]*)\}{2}", comment.body, re.S): if (str(comment.subreddit).lower() not in disableexpanded): if hasExpandedRequest: break reply = Search.buildAnimeReply(match.group(1), True, comment) if not (reply is None): hasExpandedRequest = True animeArray = [reply] mangaArray = [] else: if hasExpandedRequest: break reply = Search.buildAnimeReply(match.group(1), False, comment) if (reply is not None) and (len(animeArray) + len(mangaArray) < 10): animeArray.append(reply) #Normal Anime for match in re.finditer("(?<=(?<!\{)\{)([^\{\}]*)(?=\}(?!\}))", comment.body, re.S): if hasExpandedRequest: break reply = Search.buildAnimeReply(match.group(1), False, comment) if (reply is not None) and (len(animeArray) + len(mangaArray) < 10): animeArray.append(reply) #Expanded Manga for match in re.finditer("\<{2}([^>]*)\>{2}", comment.body, re.S): if (str(comment.subreddit).lower() not in disableexpanded): if hasExpandedRequest: break; reply = Search.buildMangaReply(match.group(1), True, comment) if not (reply is None): hasExpandedRequest = True animeArray = [] mangaArray = [reply] else: if hasExpandedRequest: break reply = Search.buildMangaReply(match.group(1), False, comment) if (reply is not None) and (len(animeArray) + len(mangaArray) < 10): mangaArray.append(reply) #Normal Manga for match in re.finditer("(?<=(?<!\<)\<)([^\<\>]*)(?=\>(?!\>))", comment.body, re.S): if hasExpandedRequest: break reply = Search.buildMangaReply(match.group(1), False, comment) if (reply is not None) and (len(animeArray) + len(mangaArray) < 10): mangaArray.append(reply) #Here is where we create the final reply to be posted #The final comment reply. We add stuff to this progressively. commentReply = '' #If we have anime AND manga in one reply we format stuff a little differently multipleTypes = False #Basically just to keep track of people posting the same title multiple times (e.g. {Nisekoi}{Nisekoi}{Nisekoi}) postedAnimeTitles = [] postedMangaTitles = [] if (len(animeArray) > 0) and (len(mangaArray) > 0): multipleTypes = True commentReply += '**Anime**\n\n' #Adding all the anime to the final comment. If there's manga too we split up all the paragraphs and indent them in Reddit markup by adding a '>', then recombine them for i, animeReply in enumerate(animeArray): if not (i is 0): commentReply += '\n\n' if multipleTypes: splitSections = re.split('\s{2,}',animeReply['comment']) newSections = [] for section in splitSections: newSections.append('>' + section) animeReply['comment'] = '\n\n'.join(newSections) if not (animeReply['title'] in postedAnimeTitles): postedAnimeTitles.append(animeReply['title']) commentReply += animeReply['comment'] if multipleTypes: commentReply += '\n\n**Manga**\n\n' #Adding all the manga to the final comment for i, mangaReply in enumerate(mangaArray): if not (i is 0): commentReply += '\n\n' if multipleTypes: splitSections = re.split('\s{2,}',mangaReply['comment']) newSections = [] for section in splitSections: newSections.append('>' + section) mangaReply['comment'] = '\n\n'.join(newSections) if not (mangaReply['title'] in postedMangaTitles): postedMangaTitles.append(mangaReply['title']) commentReply += mangaReply['comment'] #If there was actually something found, add the signature and post the comment to Reddit. Then, add the comment to the "already seen" database. if not (commentReply is ''): commentReply += '\n\n---\n\n [^How ^to ^use](http://www.reddit.com/r/Roboragi/wiki/index#wiki_how_do_i_use_it.3F) ^| ^[FAQ](http://www.reddit.com/r/Roboragi/wiki/index) ^| ^[Subreddit](http://www.reddit.com/r/Roboragi/) ^| ^[Issue/mistake?](http://www.reddit.com/r/Roboragi/submit?selftext=true&title=[ISSUE]&text=' + comment.permalink + ') ^| ^[Source](https://github.com/Nihilate/Roboragi)' try: comment.reply(commentReply) print("Comment made.\n") try: DatabaseHandler.addComment(comment.id, comment.author.name, comment.subreddit, True) except: traceback.print_exc() except: traceback.print_exc() else: try: DatabaseHandler.addComment(comment.id, comment.author.name, comment.subreddit, False) except: traceback.print_exc()
async def process_message(message, is_edit=False): #Anime/Manga requests that are found go into separate arrays animeArray = [] mangaArray = [] lnArray = [] #ignores all "code" markup (i.e. anything between backticks) cleanMessage = re.sub(r"\`(?s)(.*?)\`", "", message.clean_content) sender = re.search('[@]([A-Za-z0-9_-]+?)(>|}|$)', cleanMessage, re.S) if re.search('({!stats.*?}|{{!stats.*?}}|<!stats.*?>|<<!stats.*?>>)', cleanMessage, re.S) is not None and sender is not None: messageReply = CommentBuilder.buildStatsComment( username=sender.group(1)) if re.search('({!sstats.*?}|{{!sstats.*?}}|<!sstats.*?>|<<!sstats.*?>>)', cleanMessage, re.S) is not None: server = re.search('([A-Za-z0-9_]+?)(>|}|$)', cleanMessage, re.S) messageReply = CommentBuilder.buildStatsComment(server=server.group(1)) elif re.search('({!stats.*?}|{{!stats.*?}}|<!stats.*?>|<<!stats.*?>>)', cleanMessage, re.S) is not None: messageReply = CommentBuilder.buildStatsComment() else: #The basic algorithm here is: #If it's an expanded request, build a reply using the data in the braces, clear the arrays, add the reply to the relevant array and ignore everything else. #If it's a normal request, build a reply using the data in the braces, add the reply to the relevant array. #Counts the number of expanded results vs total results. If it's not just a single expanded result, they all get turned into normal requests. numOfRequest = 0 numOfExpandedRequest = 0 forceNormal = False for match in re.finditer("\{{2}([^}]*)\}{2}|\<{2}([^>]*)\>{2}", cleanMessage, re.S): numOfRequest += 1 numOfExpandedRequest += 1 for match in re.finditer( "(?<=(?<!\{)\{)([^\{\}]*)(?=\}(?!\}))|(?<=(?<!\<)\<)([^\<\>]*)(?=\>(?!\>))", cleanMessage, re.S): numOfRequest += 1 if (numOfExpandedRequest >= 1) and (numOfRequest > 1): forceNormal = True #Expanded Anime for match in re.finditer("\{{2}([^}]*)\}{2}", cleanMessage, re.S): reply = '' if (forceNormal) or (str(message.channel).lower() in disableexpanded): reply = DiscordoragiSearch.buildAnimeReply( match.group(1), message, False) else: reply = DiscordoragiSearch.buildAnimeReply( match.group(1), message, True) if (reply is not None): animeArray.append(reply) #Normal Anime for match in re.finditer("(?<=(?<!\{)\{)([^\{\}]*)(?=\}(?!\}))", cleanMessage, re.S): reply = DiscordoragiSearch.buildAnimeReply(match.group(1), message, False) if (reply is not None): animeArray.append(reply) #Expanded Manga #NORMAL EXPANDED for match in re.finditer("\<{2}([^>]*)\>{2}(?!(:|\>))", cleanMessage, re.S): reply = '' if (forceNormal) or (str(message.channel).lower() in disableexpanded): reply = DiscordoragiSearch.buildMangaReply( match.group(1), message, False) else: reply = DiscordoragiSearch.buildMangaReply( match.group(1), message, True) if (reply is not None): mangaArray.append(reply) #AUTHOR SEARCH EXPANDED for match in re.finditer("\<{2}([^>]*)\>{2}:\(([^)]+)\)", cleanMessage, re.S): reply = '' if (forceNormal) or (str(message.server).lower() in disableexpanded): reply = DiscordoragiSearch.buildMangaReplyWithAuthor( match.group(1), match.group(2), message, False) else: reply = DiscordoragiSearch.buildMangaReplyWithAuthor( match.group(1), match.group(2), message, True) if (reply is not None): mangaArray.append(reply) #Normal Manga #NORMAL for match in re.finditer("(?<=(?<!\<)\<)([^\<\>]+)\>(?!(:|\>))", cleanMessage, re.S): reply = DiscordoragiSearch.buildMangaReply(match.group(1), message, False) if (reply is not None): mangaArray.append(reply) #AUTHOR SEARCH for match in re.finditer("(?<=(?<!\<)\<)([^\<\>]*)\>:\(([^)]+)\)", cleanMessage, re.S): reply = DiscordoragiSearch.buildMangaReplyWithAuthor( match.group(1), match.group(2), message, False) if (reply is not None): mangaArray.append(reply) #Expanded LN for match in re.finditer("\]{2}([^]]*)\[{2}", cleanMessage, re.S): reply = '' if (forceNormal) or (str(message.server).lower() in disableexpanded): reply = DiscordoragiSearch.buildLightNovelReply( match.group(1), False, message) else: reply = DiscordoragiSearch.buildLightNovelReply( match.group(1), True, message) if (reply is not None): lnArray.append(reply) #Normal LN for match in re.finditer("(?<=(?<!\])\])([^\]\[]*)(?=\[(?!\[))", cleanMessage, re.S): reply = DiscordoragiSearch.buildLightNovelReply( match.group(1), False, message) if (reply is not None): lnArray.append(reply) #Here is where we create the final reply to be posted #The final message reply. We add stuff to this progressively. messageReply = '' #Basically just to keep track of people posting the same title multiple times (e.g. {Nisekoi}{Nisekoi}{Nisekoi}) postedAnimeTitles = [] postedMangaTitles = [] postedLNTitles = [] #Adding all the anime to the final message. If there's manga too we split up all the paragraphs and indent them in Reddit markup by adding a '>', then recombine them for i, animeReply in enumerate(animeArray): if not (i is 0): messageReply += '\n\n' if not (animeReply['title'] in postedAnimeTitles): postedAnimeTitles.append(animeReply['title']) messageReply += animeReply['comment'] if mangaArray: messageReply += '\n\n' #Adding all the manga to the final message for i, mangaReply in enumerate(mangaArray): if not (i is 0): messageReply += '\n\n' if not (mangaReply['title'] in postedMangaTitles): postedMangaTitles.append(mangaReply['title']) messageReply += mangaReply['comment'] if lnArray: messageReply += '\n\n' #Adding all the manga to the final comment for i, lnReply in enumerate(lnArray): if not (i is 0): commentReply += '\n\n' if not (lnReply['title'] in postedLNTitles): postedLNTitles.append(lnReply['title']) messageReply += lnReply['comment'] #If there are more than 10 requests, shorten them all if not (messageReply is '') and (len(animeArray) + len(mangaArray) >= 10): messageReply = re.sub(r"\^\((.*?)\)", "", messageReply, flags=re.M) #If there was actually something found, add the signature and post the message to Reddit. Then, add the message to the "already seen" database. if not (messageReply is ''): messageReply += Config.getSignature() if is_edit: await Discord.client.send_message(message.channel, messageReply) else: try: print("Message created.\n") await Discord.client.send_message(message.channel, messageReply) except discord.errors.Forbidden: print('Request from banned channel: ' + str(message.channel) + '\n') except Exception: traceback.print_exc() try: DatabaseHandler.addMessage(message.id, message.author.id, message.server.id, True) except: traceback.print_exc() else: try: if is_edit: return None else: DatabaseHandler.addMessage(message.id, message.author.id, message.server.id, False) except: traceback.print_exc()
def process_comment(comment, is_edit=False): """ process dat comment """ # Anime/Manga requests that are found go into separate arrays animeArray = [] mangaArray = [] lnArray = [] vnArray = [] # ignores all "code" markup (i.e. anything between backticks) comment.body = re.sub(r"\`[{<\[]+(.*?)[}>\]]+\`", "", comment.body) num_so_far = 0 numOfRequest = 0 numOfExpandedRequest = 0 # Ignore any blacklisted users if (comment.author.name.lower() in user_blacklist): print('User in blacklist: ' + comment.author.name) commentReply = '' # This checks for requests. First up we check all known tags for the !stats request elif re.search('({!stats.*?}|{{!stats.*?}}|<!stats.*?>|<<!stats.*?>>)', comment.body, re.S) is not None: username = USERNAME_PATTERN.search(comment.body) subreddit = SUBREDDIT_PATTERN.search(comment.body) if username: commentReply = CommentBuilder.buildStatsComment( username=username.group(1) ) elif subreddit: commentReply = CommentBuilder.buildStatsComment( subreddit=subreddit.group(1) ) else: commentReply = CommentBuilder.buildStatsComment() else: # The basic algorithm here is: # If it's an expanded request, build a reply using the data in the # braces, clear the arrays, add the reply to the relevant array and # ignore everything else. If it's a normal request, build a reply using # the data in the braces, add the reply to the relevant array. # Counts the number of expanded results vs total results. If it's not # just a single expanded result, they all get turned into normal # requests. forceNormal = False for match in find_requests('all', comment.body, expanded=True): numOfRequest += 1 numOfExpandedRequest += 1 for match in find_requests('all', comment.body): numOfRequest += 1 if (numOfExpandedRequest >= 1) and (numOfRequest > 1): forceNormal = True # Determine whether we'll build an expanded reply just once. subredditName = str(comment.subreddit).lower() isExpanded = False if (forceNormal or (subredditName in disableexpanded)) else True # The final comment reply. We add stuff to this progressively. commentReply = '' # Expanded Anime for match in find_requests('anime', comment.body, expanded=True): if num_so_far < 30: reply = Search.buildAnimeReply(match, isExpanded, comment) if (reply is not None): num_so_far = num_so_far + 1 animeArray.append(reply) # Normal Anime for match in find_requests('anime', comment.body): if num_so_far < 30: reply = Search.buildAnimeReply(match, False, comment) if (reply is not None): num_so_far = num_so_far + 1 animeArray.append(reply) # Expanded Manga # NORMAL EXPANDED for match in find_requests('manga', comment.body, expanded=True): if num_so_far < 30: reply = Search.buildMangaReply(match, isExpanded, comment) if (reply is not None): num_so_far = num_so_far + 1 mangaArray.append(reply) # Normal Manga # NORMAL for match in find_requests('manga', comment.body): if num_so_far < 30: reply = Search.buildMangaReply(match, False, comment) if (reply is not None): num_so_far = num_so_far + 1 mangaArray.append(reply) # Expanded LN for match in find_requests('light_novel', comment.body, expanded=True): if num_so_far < 30: reply = Search.buildLightNovelReply(match, isExpanded, comment) if (reply is not None): num_so_far = num_so_far + 1 lnArray.append(reply) # Normal LN for match in find_requests('light_novel', comment.body): if num_so_far < 30: reply = Search.buildLightNovelReply(match, False, comment) if (reply is not None): num_so_far = num_so_far + 1 lnArray.append(reply) # Expanded VN for match in find_requests('visual_novel', comment.body, expanded=True): if num_so_far < 30: reply = Search.buildVisualNovelReply(match, isExpanded, comment) if (reply is not None): num_so_far = num_so_far + 1 vnArray.append(reply) # Normal VN for match in find_requests('visual_novel', comment.body): if num_so_far < 30: reply = Search.buildVisualNovelReply(match, False, comment) if (reply is not None): num_so_far = num_so_far + 1 vnArray.append(reply) # Here is where we create the final reply to be posted # Basically just to keep track of people posting the same title # multiple times (e.g. {Nisekoi}{Nisekoi}{Nisekoi}) postedAnimeTitles = [] postedMangaTitles = [] postedLNTitles = [] postedVNTitles = [] # Adding all the anime to the final comment. If there's manga too we # split up all the paragraphs and indent them in Reddit markup by # adding a '>', then recombine them for i, animeReply in enumerate(animeArray): if not (i is 0): commentReply += '\n\n' if not (animeReply['title'] in postedAnimeTitles): postedAnimeTitles.append(animeReply['title']) commentReply += animeReply['comment'] if mangaArray: commentReply += '\n\n' # Adding all the manga to the final comment for i, mangaReply in enumerate(mangaArray): if not (i is 0): commentReply += '\n\n' if not (mangaReply['title'] in postedMangaTitles): postedMangaTitles.append(mangaReply['title']) commentReply += mangaReply['comment'] if lnArray: commentReply += '\n\n' # Adding all the light novels to the final comment for i, lnReply in enumerate(lnArray): if not (i is 0): commentReply += '\n\n' if not (lnReply['title'] in postedLNTitles): postedLNTitles.append(lnReply['title']) commentReply += lnReply['comment'] if vnArray: commentReply += '\n\n' # Adding all the visual novels to the final comment for i, vnReply in enumerate(vnArray): if not (i is 0): commentReply += '\n\n' if not (vnReply['title'] in postedVNTitles): postedVNTitles.append(vnReply['title']) commentReply += vnReply['comment'] # If there are more than 10 requests, shorten them all lenRequests = sum(map(len, (animeArray, mangaArray, lnArray, vnArray))) if not (commentReply is '') and (lenRequests >= 10): commentReply = re.sub(r"\^\((.*?)\)", "", commentReply, flags=re.M) # If there was actually something found, add the signature and post the # comment to Reddit. Then, add the comment to the "already seen" database. if commentReply is not '': if num_so_far >= 30: commentReply += ("\n\nI'm limited to 30 requests at once and have " "had to cut off some, sorry for the " "inconvenience!\n\n") commentReply += Config.getSignature(comment.permalink) commentReply += Reference.get_bling(comment.author.name) total_expected = int(numOfRequest) total_found = sum(map(len, (animeArray, mangaArray, lnArray, vnArray))) if total_found != total_expected: commentReply += ' | ({0}/{1})'.format(total_found, total_expected) if is_edit: return commentReply else: try: comment.reply(commentReply) print("Comment made.\n") except praw.errors.Forbidden: print('Request from banned ' 'subreddit: {0}\n'.format(comment.subreddit)) except Exception as e: logger.debug(traceback.print_exc()) logger.warn(e) comment_author = comment.author.name if comment.author else '!UNKNOWN!' try: DatabaseHandler.addComment( comment.id, comment_author, comment.subreddit, True ) except Exception as e: logger.debug(traceback.print_exc()) logger.warn(e) else: try: if is_edit: return None else: comment_author = comment.author.name if comment.author else '!UNKNOWN!' DatabaseHandler.addComment( comment.id, comment_author, comment.subreddit, False ) except Exception as e: logger.debug(traceback.print_exc()) logger.warn(e)
def buildLightNovelReply(searchText, isExpanded, baseComment, blockTracking=False): try: mal = { 'search_function': MAL.getLightNovelDetails, 'synonym_function': MAL.getSynonyms, 'checked_synonyms': [], 'result': None } ani = { 'search_function': Anilist.getLightNovelDetails, 'synonym_function': Anilist.getSynonyms, 'checked_synonyms': [], 'result': None } nu = {'search_function': NU.getLightNovelURL, 'result': None} lndb = {'search_function': LNDB.getLightNovelURL, 'result': None} try: sqlCur.execute( 'SELECT dbLinks FROM synonyms WHERE type = "LN" and lower(name) = ?', [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if synonym: malsyn = None if 'mal' in synonym and synonym['mal']: malsyn = synonym['mal'] anisyn = None if 'ani' in synonym and synonym['ani']: anisyn = synonym['ani'] nusyn = None if 'nu' in synonym and synonym['nu']: nusyn = synonym['nu'] lndbsyn = None if 'lndb' in synonym and synonym['lndb']: lndbsyn = synonym['lndb'] mal['result'] = MAL.getLightNovelDetails( malsyn[0], malsyn[1]) if malsyn else None ani['result'] = Anilist.getMangaDetailsById( anisyn) if anisyn else None nu['result'] = NU.getLightNovelById(nusyn) if nusyn else None lndb['result'] = LNDB.getLightNovelById( lndbsyn) if lndbsyn else None else: data_sources = [ani, mal] aux_sources = [nu, lndb] synonyms = set([searchText]) for x in range(len(data_sources)): for source in data_sources: if source['result']: break else: for synonym in synonyms: if synonym in source['checked_synonyms']: continue source['result'] = source['search_function']( synonym) source['checked_synonyms'].append(synonym) if source['result']: break if source['result']: synonyms.update([ synonym.lower() for synonym in source['synonym_function'](source['result']) ]) for source in aux_sources: for synonym in synonyms: source['result'] = source['search_function'](synonym) if source['result']: break if ani['result'] or mal['result']: try: titleToAdd = '' if mal['result']: titleToAdd = mal['result']['title'] if ani['result']: try: titleToAdd = ani['result']['title_romaji'] except: titleToAdd = ani['result']['title_english'] if (str(baseComment.subreddit).lower is not 'nihilate') and ( str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'LN', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass return CommentBuilder.buildLightNovelComment(isExpanded, mal['result'], ani['result'], nu['result'], lndb['result']) except Exception as e: traceback.print_exc() return None
async def buildAnimeReply(searchText, message, isExpanded, canEmbed, blockTracking=False): try: mal = { 'search_function': MAL.getAnimeDetails, 'synonym_function': MAL.getSynonyms, 'checked_synonyms': [], 'result': None } ani = { 'search_function': Anilist.getAnimeDetails, 'synonym_function': Anilist.getSynonyms, 'checked_synonyms': [], 'result': None } ap = {'search_function': AniP.getAnimeURL, 'result': None} adb = {'search_function': AniDB.getAnimeURL, 'result': None} try: sqlCur.execute( 'SELECT dbLinks FROM synonyms WHERE type = "Anime" and lower(name) = ?', [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if synonym: malsyn = None if 'mal' in synonym and synonym['mal']: malsyn = synonym['mal'] anisyn = None if 'ani' in synonym and synonym['ani']: anisyn = synonym['ani'] apsyn = None if 'ap' in synonym and synonym['ap']: apsyn = synonym['ap'] adbsyn = None if 'adb' in synonym and synonym['adb']: adbsyn = synonym['adb'] mal['result'] = await MAL.getAnimeDetails( malsyn[0], malsyn[1]) if malsyn else None ani['result'] = await Anilist.getAnimeDetailsById( anisyn) if anisyn else None ap['result'] = AniP.getAnimeURLById(apsyn) if apsyn else None adb['result'] = AniDB.getAnimeURLById( adbsyn) if adbsyn else None print(ani['result']) else: data_sources = [ani, mal] aux_sources = [ap, adb] #aux_sources = [ap] synonyms = set([searchText]) for x in range(len(data_sources)): for source in data_sources: if source['result']: break else: for synonym in synonyms: if synonym in source['checked_synonyms']: continue source['result'] = await source['search_function']( synonym) source['checked_synonyms'].append(synonym) if source['result']: break if source['result']: synonyms.update([ synonym.lower() for synonym in source['synonym_function'](source['result']) ]) for source in aux_sources: for synonym in synonyms: source['result'] = await source['search_function'](synonym) if source['result']: break if ani['result'] or mal['result']: try: titleToAdd = '' if mal['result']: if 'title' in mal['result']: titleToAdd = mal['result']['title'] '''if hb['result']: if 'title' in hb['result']: titleToAdd = hb['result']['title']''' if ani['result']: if 'title_romaji' in ani['result']: titleToAdd = ani['result']['title_romaji'] if not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Anime', message.author.id, message.server.id) except: traceback.print_exc() pass if mal['result']: print('trying to add an anime to cache') try: DatabaseHandler.addMalEntry('malanime', mal['result']) except: traceback.print_exc() pass if ani: try: DatabaseHandler.addAniEntry('anilistanime', ani['result']) except: traceback.print_exc() pass if not canEmbed: return CommentBuilder.buildAnimeComment(isExpanded, mal['result'], ani['result'], ap['result'], adb['result']) else: return CommentBuilder.buildAnimeEmbed(isExpanded, mal['result'], ani['result'], ap['result'], adb['result']) except Exception as e: traceback.print_exc() return None
def buildMangaReply(searchText, isExpanded, baseComment, blockTracking=False): try: ani = None mal = None mu = None ap = None try: sqlCur.execute( 'SELECT dbLinks FROM synonyms WHERE type = "Manga" and lower(name) = ?', [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if (synonym['mal']): mal = MAL.getMangaDetails(synonym['mal'][0], synonym['mal'][1]) if (synonym['ani']): ani = Anilist.getMangaDetailsById(synonym['ani']) if (synonym['mu']): mu = MU.getMangaURLById(synonym['mu']) if (synonym['ap']): ap = AniP.getMangaURLById(synonym['ap']) else: #Basic breakdown: #If Anilist finds something, use it to find the MAL version. #If hits either MAL or Ani, use it to find the MU version. #If it hits either, add it to the request-tracking DB. ani = Anilist.getMangaDetails(searchText) if ani: try: mal = MAL.getMangaDetails(ani['title_romaji']) except: pass if not mal: try: mal = MAL.getMangaDetails(ani['title_english']) except: pass if not mal: mal = MAL.getMangaDetails(searchText) else: mal = MAL.getMangaDetails(searchText) if mal: ani = Anilist.getMangaDetails(mal['title']) #----- Finally... -----# if ani or mal: try: titleToAdd = '' if mal: titleToAdd = mal['title'] else: try: titleToAdd = ani['title_english'] except: titleToAdd = ani['title_romaji'] if not alternateLinks: #MU stuff if mal: mu = MU.getMangaURL(mal['title']) else: mu = MU.getMangaURL(ani['title_romaji']) #Do the anime-planet stuff if mal and not ap: if mal['title'] and not ap: ap = AniP.getMangaURL(mal['title']) if mal['english'] and not ap: ap = AniP.getMangaURL(mal['english']) if mal['synonyms'] and not ap: for synonym in mal['synonyms']: if ap: break ap = AniP.getMangaURL(synonym) if ani and not ap: if ani['title_english'] and not ap: ap = AniP.getMangaURL(ani['title_english']) if ani['title_romaji'] and not ap: ap = AniP.getMangaURL(ani['title_romaji']) if ani['synonyms'] and not ap: for synonym in ani['synonyms']: if ap: break ap = AniP.getMangaURL(synonym) if (str(baseComment.subreddit).lower is not 'nihilate') and ( str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Manga', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass return CommentBuilder.buildMangaComment(isExpanded, mal, ani, mu, ap) except Exception as e: traceback.print_exc() return None
def buildLightNovelReply(searchText, isExpanded, baseComment, blockTracking=False): """ Builds an LN reply from multiple sources """ try: ani = { 'search_function': Anilist.getLightNovelDetails, 'synonym_function': Anilist.getSynonyms, 'title_function': Anilist.getTitles, 'checked_synonyms': [], 'result': None } kit = { 'search_function': Kitsu.search_light_novel, 'synonym_function': Kitsu.get_synonyms, 'title_function': Kitsu.get_titles, 'checked_synonyms': [], 'result': None } nu = {'search_function': NU.getLightNovelURL, 'result': None} lndb = {'search_function': LNDB.getLightNovelURL, 'result': None} try: query = ('SELECT dbLinks' ' FROM synonyms' ' WHERE type = "LN"' ' AND lower(name) = ?') sqlCur.execute(query, [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if synonym: anisyn = None if 'ani' in synonym and synonym['ani']: anisyn = synonym['ani'] kitsyn = None if 'kit' in synonym and synonym['kit']: kitsyn = synonym['kit'] nusyn = None if 'nu' in synonym and synonym['nu']: nusyn = synonym['nu'] lndbsyn = None if 'lndb' in synonym and synonym['lndb']: lndbsyn = synonym['lndb'] if anisyn: ani['result'] = Anilist.getMangaDetailsById(anisyn) else: ani['result'] = None if kitsyn: kit['result'] = Kitsu.get_light_novel(kitsyn) else: kit['result'] = None nu['result'] = NU.getLightNovelById(nusyn) if nusyn else None if lndbsyn: lndb['result'] = LNDB.getLightNovelById(lndbsyn) else: lndb['result'] = None else: data_sources = [ani, kit] aux_sources = [nu, lndb] synonyms = set([searchText]) titles = set() for x in range(len(data_sources)): for source in data_sources: if source['result']: break else: for synonym in (titles | synonyms): if synonym in source['checked_synonyms']: continue search_function = source['search_function'] source['result'] = search_function(synonym) source['checked_synonyms'].append(synonym) if source['result']: break if source['result']: result = source['result'] synonym_function = source['synonym_function'] title_function = source['title_function'] synonyms.update( [s.lower() for s in synonym_function(result)]) titles.update( [t.lower() for t in title_function(result)]) for source in aux_sources: for title in titles: source['result'] = source['search_function'](synonym) if source['result']: break if not source['result']: for synonym in synonyms: source['result'] = source['search_function'](synonym) if source['result']: break if ani['result'] or kit['result']: try: titleToAdd = '' if ani['result']: try: titleToAdd = ani['result']['title_romaji'] except Exception: titleToAdd = ani['result']['title_english'] elif kit['result']: try: titleToAdd = kit['result']['title_romaji'] except Exception: titleToAdd = kit['result']['title_english'] subreddit = str(baseComment.subreddit).lower ignored_subreddits = ('nihilate', 'roboragi') if subreddit not in ignored_subreddits and not blockTracking: DatabaseHandler.addRequest( name=titleToAdd, rType='LN', requester=baseComment.author.name, subreddit=baseComment.subreddit) except Exception: traceback.print_exc() pass if ani['result'] or kit['result']: return CommentBuilder.buildLightNovelComment(isExpanded=isExpanded, ani=ani['result'], nu=nu['result'], lndb=lndb['result'], kit=kit['result']) else: print('No result found for ' + searchText) return None except Exception: traceback.print_exc() return None
def buildMangaReply(searchText, isExpanded, baseComment, blockTracking=False): try: ani = None mal = None mu = None ap = None try: sqlCur.execute('SELECT dbLinks FROM synonyms WHERE type = "Manga" and lower(name) = ?', [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if (synonym['mal']): mal = MAL.getMangaDetails(synonym['mal']) if (synonym['ani']): ani = Anilist.getMangaDetails(synonym['ani']) if (synonym['mu']): mu = MU.getMangaURL(synonym['mu']) if (synonym['ap']): ap = AniP.getMangaURL(synonym['ap']) else: #Basic breakdown: #If Anilist finds something, use it to find the MAL version. #If hits either MAL or Ani, use it to find the MU version. #If it hits either, add it to the request-tracking DB. ani = Anilist.getMangaDetails(searchText) if not (ani is None): mal = MAL.getMangaDetails(ani['title_romaji']) else: mal = MAL.getMangaDetails(searchText) if not (mal is None): ani = Anilist.getMangaDetails(mal['title']) #----- Finally... -----# if ani or mal: try: titleToAdd = '' if mal: titleToAdd = mal['title'] else: titleToAdd = ani['title_english'] if not alternateLinks: #MU stuff if mal: mu = MU.getMangaURL(mal['title']) else: mu = MU.getMangaURL(ani['title_romaji']) #Do the anime-planet stuff if mal and not ap: if mal['title'] and not ap: ap = AniP.getMangaURL(mal['title']) if mal['english'] and not ap: ap = AniP.getMangaURL(mal['english']) if mal['synonyms'] and not ap: for synonym in mal['synonyms']: if ap: break ap = AniP.getMangaURL(synonym) if ani and not ap: if ani['title_english'] and not ap: ap = AniP.getMangaURL(ani['title_english']) if ani['title_romaji'] and not ap: ap = AniP.getMangaURL(ani['title_romaji']) if ani['synonyms'] and not ap: for synonym in ani['synonyms']: if ap: break ap = AniP.getMangaURL(synonym) if (str(baseComment.subreddit).lower is not 'nihilate') and (str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Manga', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass if ani is not None: if ani['adult'] is True: mal = None ani = None mu = None ap = None return CommentBuilder.buildMangaComment(isExpanded, mal, ani, mu, ap) except Exception as e: traceback.print_exc() return None
def buildLightNovelReply(searchText, isExpanded, baseComment, blockTracking=False): try: mal = {'search_function': MAL.getLightNovelDetails, 'synonym_function': MAL.getSynonyms, 'checked_synonyms': [], 'result': None} ani = {'search_function': Anilist.getLightNovelDetails, 'synonym_function': Anilist.getSynonyms, 'checked_synonyms': [], 'result': None} nu = {'search_function': NU.getLightNovelURL, 'result': None} lndb = {'search_function': LNDB.getLightNovelURL, 'result': None} try: sqlCur.execute('SELECT dbLinks FROM synonyms WHERE type = "LN" and lower(name) = ?', [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if synonym: malsyn = None if 'mal' in synonym and synonym['mal']: malsyn = synonym['mal'] anisyn = None if 'ani' in synonym and synonym['ani']: anisyn = synonym['ani'] nusyn = None if 'nu' in synonym and synonym['nu']: nusyn = synonym['nu'] lndbsyn = None if 'lndb' in synonym and synonym['lndb']: lndbsyn = synonym['lndb'] mal['result'] = MAL.getLightNovelDetails(malsyn[0],malsyn[1]) if malsyn else None ani['result'] = Anilist.getMangaDetailsById(anisyn) if anisyn else None nu['result'] = NU.getLightNovelById(nusyn) if nusyn else None lndb['result'] = LNDB.getLightNovelById(lndbsyn) if lndbsyn else None else: data_sources = [ani, mal] aux_sources = [nu, lndb] synonyms = set([searchText]) for x in range(len(data_sources)): for source in data_sources: if source['result']: break else: for synonym in synonyms: if synonym in source['checked_synonyms']: continue source['result'] = source['search_function'](synonym) source['checked_synonyms'].append(synonym) if source['result']: break if source['result']: synonyms.update([synonym.lower() for synonym in source['synonym_function'](source['result'])]) for source in aux_sources: for synonym in synonyms: source['result'] = source['search_function'](synonym) if source['result']: break if ani['result'] or mal['result']: try: titleToAdd = '' if mal['result']: titleToAdd = mal['result']['title'] if ani['result']: try: titleToAdd = ani['result']['title_romaji'] except: titleToAdd = ani['result']['title_english'] if (str(baseComment.subreddit).lower is not 'nihilate') and (str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'LN', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass return CommentBuilder.buildLightNovelComment(isExpanded, mal['result'], ani['result'], nu['result'], lndb['result']) except Exception as e: traceback.print_exc() return None
def buildMangaReply(searchText, isExpanded, baseComment, blockTracking=False): try: ani = { 'search_function': Anilist.getMangaDetails, 'synonym_function': Anilist.getSynonyms, 'checked_synonyms': [], 'result': None } mal = { 'search_function': MAL.getMangaDetails, 'synonym_function': MAL.getSynonyms, 'checked_synonyms': [], 'result': None } kit = { 'search_function': Kitsu.search_manga, 'synonym_function': Kitsu.get_synonyms, 'checked_synonyms': [], 'result': None } mu = {'search_function': MU.getMangaURL, 'result': None} ap = {'search_function': AniP.getMangaURL, 'result': None} try: sqlCur.execute( 'SELECT dbLinks FROM synonyms WHERE type = "Manga" and lower(name) = ?', [searchText.lower()]) except sqlite3.Error as e: print(e) alternateLinks = sqlCur.fetchone() if (alternateLinks): synonym = json.loads(alternateLinks[0]) if synonym: malsyn = None if 'mal' in synonym and synonym['mal']: malsyn = synonym['mal'] anisyn = None if 'ani' in synonym and synonym['ani']: anisyn = synonym['ani'] kitsyn = None if 'kit' in synonym and synonym['kit']: kitsyn = synonym['kit'] musyn = None if 'mu' in synonym and synonym['mu']: musyn = synonym['mu'] apsyn = None if 'ap' in synonym and synonym['ap']: apsyn = synonym['ap'] mal['result'] = MAL.getMangaDetails( malsyn[0], malsyn[1]) if malsyn else None ani['result'] = Anilist.getMangaDetailsById( anisyn) if anisyn else None kit['result'] = Kitsu.get_manga(kitsyn) if kitsyn else None mu['result'] = MU.getMangaURLById(musyn) if musyn else None ap['result'] = AniP.getMangaURLById(apsyn) if apsyn else None else: data_sources = [ani, kit, mal] aux_sources = [mu, ap] synonyms = set([searchText]) for x in range(len(data_sources)): for source in data_sources: if source['result']: break else: for synonym in synonyms: if synonym in source['checked_synonyms']: continue source['result'] = source['search_function']( synonym) source['checked_synonyms'].append(synonym) if source['result']: break if source['result']: synonyms.update([ synonym.lower() for synonym in source['synonym_function'](source['result']) ]) for source in aux_sources: for synonym in synonyms: source['result'] = source['search_function'](synonym) if source['result']: break if ani['result'] or mal['result'] or kit['result']: try: titleToAdd = '' if ani['result']: try: titleToAdd = ani['result']['title_romaji'] except: titleToAdd = ani['result']['title_english'] elif mal['result']: titleToAdd = mal['result']['title'] elif kit['result']: try: titleToAdd = kit['result']['title_romaji'] except: titleToAdd = kit['result']['title_english'] if (str(baseComment.subreddit).lower is not 'nihilate') and ( str(baseComment.subreddit).lower is not 'roboragi') and not blockTracking: DatabaseHandler.addRequest(titleToAdd, 'Manga', baseComment.author.name, baseComment.subreddit) except: traceback.print_exc() pass return CommentBuilder.buildMangaComment(isExpanded, mal['result'], ani['result'], mu['result'], ap['result'], kit['result']) except Exception as e: traceback.print_exc() return None
def process_comment(comment, is_edit=False): #Anime/Manga requests that are found go into separate arrays animeArray = [] mangaArray = [] lnArray = [] #ignores all "code" markup (i.e. anything between backticks) comment.body = re.sub(r"\`(?s)(.*?)\`", "", comment.body) #This checks for requests. First up we check all known tags for the !stats request if re.search('({!stats.*?}|{{!stats.*?}}|<!stats.*?>|<<!stats.*?>>)', comment.body, re.S) is not None: username = re.search('[uU]\/([A-Za-z0-9_-]+?)(>|}|$)', comment.body, re.S) subreddit = re.search('[rR]\/([A-Za-z0-9_]+?)(>|}|$)', comment.body, re.S) if username: commentReply = CommentBuilder.buildStatsComment( username=username.group(1)) elif subreddit: commentReply = CommentBuilder.buildStatsComment( subreddit=subreddit.group(1)) else: commentReply = CommentBuilder.buildStatsComment() else: #The basic algorithm here is: #If it's an expanded request, build a reply using the data in the braces, clear the arrays, add the reply to the relevant array and ignore everything else. #If it's a normal request, build a reply using the data in the braces, add the reply to the relevant array. #Counts the number of expanded results vs total results. If it's not just a single expanded result, they all get turned into normal requests. numOfRequest = 0 numOfExpandedRequest = 0 forceNormal = False for match in re.finditer("\{{2}([^}]*)\}{2}|\<{2}([^>]*)\>{2}", comment.body, re.S): numOfRequest += 1 numOfExpandedRequest += 1 for match in re.finditer( "(?<=(?<!\{)\{)([^\{\}]*)(?=\}(?!\}))|(?<=(?<!\<)\<)([^\<\>]*)(?=\>(?!\>))", comment.body, re.S): numOfRequest += 1 if (numOfExpandedRequest >= 1) and (numOfRequest > 1): forceNormal = True #Expanded Anime for match in re.finditer("\{{2}([^}]*)\}{2}", comment.body, re.S): reply = '' if (forceNormal) or (str(comment.subreddit).lower() in disableexpanded): reply = Search.buildAnimeReply(match.group(1), False, comment) else: reply = Search.buildAnimeReply(match.group(1), True, comment) if (reply is not None): animeArray.append(reply) #Normal Anime for match in re.finditer("(?<=(?<!\{)\{)([^\{\}]*)(?=\}(?!\}))", comment.body, re.S): reply = Search.buildAnimeReply(match.group(1), False, comment) if (reply is not None): animeArray.append(reply) #Expanded Manga #NORMAL EXPANDED for match in re.finditer("\<{2}([^>]*)\>{2}(?!(:|\>))", comment.body, re.S): reply = '' if (forceNormal) or (str(comment.subreddit).lower() in disableexpanded): reply = Search.buildMangaReply(match.group(1), False, comment) else: reply = Search.buildMangaReply(match.group(1), True, comment) if (reply is not None): mangaArray.append(reply) #AUTHOR SEARCH EXPANDED for match in re.finditer("\<{2}([^>]*)\>{2}:\(([^)]+)\)", comment.body, re.S): reply = '' if (forceNormal) or (str(comment.subreddit).lower() in disableexpanded): reply = Search.buildMangaReplyWithAuthor( match.group(1), match.group(2), False, comment) else: reply = Search.buildMangaReplyWithAuthor( match.group(1), match.group(2), True, comment) if (reply is not None): mangaArray.append(reply) #Normal Manga #NORMAL for match in re.finditer("(?<=(?<!\<)\<)([^\<\>]+)\>(?!(:|\>))", comment.body, re.S): reply = Search.buildMangaReply(match.group(1), False, comment) if (reply is not None): mangaArray.append(reply) #AUTHOR SEARCH for match in re.finditer("(?<=(?<!\<)\<)([^\<\>]*)\>:\(([^)]+)\)", comment.body, re.S): reply = Search.buildMangaReplyWithAuthor(match.group(1), match.group(2), False, comment) if (reply is not None): mangaArray.append(reply) #Expanded LN for match in re.finditer("\]{2}([^]]*)\[{2}", comment.body, re.S): reply = '' if (forceNormal) or (str(comment.subreddit).lower() in disableexpanded): reply = Search.buildLightNovelReply(match.group(1), False, comment) else: reply = Search.buildLightNovelReply(match.group(1), True, comment) if (reply is not None): lnArray.append(reply) #Normal LN for match in re.finditer("(?<=(?<!\])\])([^\]\[]*)(?=\[(?!\[))", comment.body, re.S): reply = Search.buildLightNovelReply(match.group(1), False, comment) if (reply is not None): lnArray.append(reply) #Here is where we create the final reply to be posted #The final comment reply. We add stuff to this progressively. commentReply = '' #Basically just to keep track of people posting the same title multiple times (e.g. {Nisekoi}{Nisekoi}{Nisekoi}) postedAnimeTitles = [] postedMangaTitles = [] postedLNTitles = [] #Adding all the anime to the final comment. If there's manga too we split up all the paragraphs and indent them in Reddit markup by adding a '>', then recombine them for i, animeReply in enumerate(animeArray): if not (i is 0): commentReply += '\n\n' if not (animeReply['title'] in postedAnimeTitles): postedAnimeTitles.append(animeReply['title']) commentReply += animeReply['comment'] if mangaArray: commentReply += '\n\n' #Adding all the manga to the final comment for i, mangaReply in enumerate(mangaArray): if not (i is 0): commentReply += '\n\n' if not (mangaReply['title'] in postedMangaTitles): postedMangaTitles.append(mangaReply['title']) commentReply += mangaReply['comment'] if lnArray: commentReply += '\n\n' #Adding all the manga to the final comment for i, lnReply in enumerate(lnArray): if not (i is 0): commentReply += '\n\n' if not (lnReply['title'] in postedLNTitles): postedLNTitles.append(lnReply['title']) commentReply += lnReply['comment'] #If there are more than 10 requests, shorten them all if not (commentReply is '') and ( len(animeArray) + len(mangaArray) + len(lnArray) >= 10): commentReply = re.sub(r"\^\((.*?)\)", "", commentReply, flags=re.M) #If there was actually something found, add the signature and post the comment to Reddit. Then, add the comment to the "already seen" database. if commentReply is not '': '''if (comment.author.name == 'treborabc'): commentReply = '[No.](https://www.reddit.com/r/anime_irl/comments/4sba1n/anime_irl/d58xkha)''' commentReply += Config.getSignature(comment.permalink) commentReply += Reference.get_bling(comment.author.name) if is_edit: return commentReply else: try: comment.reply(commentReply) print("Comment made.\n") except praw.errors.Forbidden: print('Request from banned subreddit: ' + str(comment.subreddit) + '\n') except Exception: traceback.print_exc() try: DatabaseHandler.addComment(comment.id, comment.author.name, comment.subreddit, True) except: traceback.print_exc() else: try: if is_edit: return None else: DatabaseHandler.addComment(comment.id, comment.author.name, comment.subreddit, False) except: traceback.print_exc()