def Update(metadata, media, lang, force, movie): from common import Log #Import here for startup logging to go to the plex pms log Log.Open(media=media, movie=movie, search=False) source = metadata.id.split('-', 1)[0] error_log = { 'AniDB summaries missing' :[], 'AniDB posters missing' :[], 'anime-list AniDBid missing':[], 'anime-list studio logos' :[], 'TVDB posters missing' :[], 'TVDB season posters missing':[], 'anime-list TVDBid missing' :[], 'Plex themes missing' :[], 'Missing Episodes' :[], 'Missing Specials' :[], 'Missing Episode Summaries' :[], 'Missing Special Summaries':[]} Log.Info('=== Update() ==='.ljust(157, '=')) Log.Info("id: {}, title: {}, lang: {}, force: {}, movie: {}".format(metadata.id, metadata.title, lang, force, movie)) Log.Info("start: {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f"))) dict_AnimeLists, AniDBid, TVDBid, TMDbid, IMDbid, mappingList = AnimeLists.GetMetadata(media, movie, error_log, metadata.id) dict_TheTVDB, IMDbid = TheTVDBv2.GetMetadata(media, movie, error_log, lang, source, AniDBid, TVDBid, IMDbid, mappingList, Dict(AniDB, 'movie')) dict_tvdb4 = common.GetMetadata(media, movie, source, TVDBid, mappingList) dict_AniDB, ANNid, MALid = AniDB.GetMetadata(media, movie, error_log, source, AniDBid, TVDBid, AnimeLists.AniDBMovieSets, mappingList) dict_TheMovieDb, TSDbid, TMDbid, IMDbid = TheMovieDb.GetMetadata(media, movie, TVDBid, TMDbid, IMDbid) dict_FanartTV = FanartTV.GetMetadata( movie, TVDBid, TMDbid, IMDbid) dict_Plex = Plex.GetMetadata(metadata, error_log, TVDBid, Dict(dict_TheTVDB, 'title')) dict_TVTunes = TVTunes.GetMetadata(metadata, Dict(dict_TheTVDB, 'title'), Dict(mappingList, AniDBid, 'name')) #Sources[m:eval('dict_'+m)] dict_OMDb = OMDb.GetMetadata(movie, IMDbid) #TVDBid=='hentai' dict_MyAnimeList = MyAnimeList.GetMetadata(movie, MALid ) dict_Local = Local.GetMetadata(media, movie) if common.AdjustMapping(source, mappingList, dict_AniDB, dict_TheTVDB): dict_AniDB, ANNid, MALid = AniDB.GetMetadata(media, movie, error_log, source, AniDBid, TVDBid, AnimeLists.AniDBMovieSets, mappingList) Log.Info('=== Update() ==='.ljust(157, '=')) Log.Info("AniDBid: '{}', TVDBid: '{}', TMDbid: '{}', IMDbid: '{}', ANNid:'{}', MALid: '{}'".format(AniDBid, TVDBid, TMDbid, IMDbid, ANNid, MALid)) common.write_logs(media, movie, error_log, source, AniDBid, TVDBid) common.UpdateMeta(metadata, media, movie, {'AnimeLists': dict_AnimeLists, 'AniDB': dict_AniDB, 'TheTVDB': dict_TheTVDB, 'TheMovieDb': dict_TheMovieDb, 'FanartTV': dict_FanartTV, 'tvdb4': dict_tvdb4, 'Plex': dict_Plex, 'TVTunes': dict_TVTunes, 'OMDb': dict_OMDb, 'MyAnimeList': dict_MyAnimeList, 'Local': dict_Local}, mappingList) Log.Info('=== Update() ==='.ljust(157, '=')) Log.Info("end: {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f"))) Log.Close()
def Search(results, media, lang, manual, movie): from common import Log #Import here for startup logging to go to the plex pms log orig_title = media.title if movie else media.show Log.Open(media=media, movie=movie, search=True) Log.Info('=== Search() ==='.ljust(157, '=')) Log.Info("title: '%s', name: '%s', filename: '%s', manual: '%s', year: '%s'" % (orig_title, media.name, media.filename, str(manual), media.year)) #if media.filename is not None: filename = String.Unquote(media.filename) #auto match only Log.Info("start: {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f"))) Log.Info("".ljust(157, '=')) if not orig_title: return #clear-cache directive if orig_title == "clear-cache": HTTP.ClearCache() results.Append(MetadataSearchResult(id='clear-cache', name='Plex web cache cleared', year=media.year, lang=lang, score=0)) return ### Check if a guid is specified "Show name [anidb-id]" ### Log.Info('--- force id ---'.ljust(157, '-')) match = re.search(r"(?P<show>.*?) ?\[(?P<source>(anidb(|[2-9])|tvdb(|[2-9])|tmdb|tsdb|imdb))-(tt)?(?P<guid>[^\[\]]*)\]", orig_title, re.IGNORECASE) if ' [' in orig_title else None if match is not None: guid=match.group('source') + '-' + match.group('guid') if guid.startswith('anidb') and not movie and max(map(int, media.seasons.keys()))>1: Log.Info('[!] multiple seasons = tvdb numbering, BAKA!') results.Append(MetadataSearchResult(id=guid, name=match.group('show')+" ["+guid+']', year=media.year, lang=lang, score=100)) Log.Info("Forced ID - source: {}, id: {}, title: '{}'".format(match.group('source'), match.group('guid'), match.group('show'))) else: #if media.year is not None: orig_title = orig_title + " (" + str(media.year) + ")" ### Year - if present (manual search or from scanner but not mine), include in title ### Log.Info('--- source searches ---'.ljust(157, '-')) maxi, n = 0, 0 if movie or max(map(int, media.seasons.keys()))<=1: maxi, n = AniDB.Search(results, media, lang, manual, movie) if maxi<50 and movie: maxi = TheMovieDb.Search(results, media, lang, manual, movie) if maxi<80 and not movie or n>1: maxi = max(TheTVDBv2.Search(results, media, lang, manual, movie), maxi) Log.Info("".ljust(157, '=')) Log.Info("end: {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f"))) Log.Close()
def Update(metadata, media, lang, force, movie): log = common.PlexLog(media=media, movie=movie, search=False) source = metadata.id.split('-', 1)[0] error_log = { 'AniDB summaries missing' :[], 'AniDB posters missing' :[], 'anime-list AniDBid missing':[], 'anime-list studio logos' :[], 'TVDB posters missing' :[], 'TVDB season posters missing':[], 'anime-list TVDBid missing' :[], 'Plex themes missing' :[], 'Missing Episodes' :[], 'Missing Specials' :[], 'Missing Episode Summaries' :[], 'Missing Special Summaries':[]} Log.Info('=== Update ==='.ljust(157, '=')) Log.Info("id: {}, title: {}, lang: {}, force: {}, movie: {}".format(metadata.id, metadata.title, lang, force, movie)) dict_AnimeLists, AniDBid, TVDBid, TMDbid, IMDbid, mappingList = AnimeLists.GetMetadata(media, movie, error_log, metadata.id, AniDBMovieSets) #, AniDBTVDBMap dict_AniDB, ANNid, MALid = AniDB.GetMetadata(media, movie, error_log, source, AniDBid, TVDBid, AniDBMovieSets, mappingList) dict_TheTVDB, IMDbid = TheTVDBv2.GetMetadata(media, movie, error_log, lang, source, AniDBid, TVDBid, IMDbid, mappingList, Dict(AniDB, 'movie')) dict_TheMovieDb, TSDbid, TMDbid, IMDbid = TheMovieDb.GetMetadata(media, movie, TVDBid, TMDbid, IMDbid) dict_FanartTV = FanartTV.GetMetadata( movie, TVDBid, TMDbid, IMDbid) dict_tvdb4 = common.GetMetadata(media, movie, source, TVDBid) dict_Plex = Plex.GetMetadata(metadata, error_log, TVDBid, Dict(dict_TheTVDB, 'title')) dict_TVTunes = TVTunes.GetMetadata(metadata, Dict(dict_TheTVDB, 'title'), Dict(mappingList, AniDBid, 'name')) #Sources[m:eval('dict_'+m)] dict_OMDb = OMDb.GetMetadata(movie, IMDbid) if Prefs['OMDbApiKey'] not in ('None', '', 'N/A') else {} #TVDBid=='hentai' dict_MyAnimeList = MyAnimeList.GetMetadata(movie, MALid ) if MALid else {} # dict_Local = Local.GetMetadata(media, movie) Log.Info("".ljust(157, '-')) Log.Info("Update() - AniDBid: '{}', TVDBid: '{}', TMDbid: '{}', IMDbid: '{}', ANNid:'{}', MALid: '{}'".format(AniDBid, TVDBid, TMDbid, IMDbid, ANNid, MALid)) common.write_logs(media, movie, error_log, source, id, AniDBid, TVDBid) common.UpdateMeta(metadata, media, movie, {'AnimeLists': dict_AnimeLists, 'TheTVDB': dict_TheTVDB, 'AniDB': dict_AniDB, 'Plex': dict_Plex, 'MyAnimeList': dict_MyAnimeList, 'TheMovieDb': dict_TheMovieDb, 'TVTunes': dict_TVTunes, 'tvdb4': dict_tvdb4, 'OMDb': dict_OMDb, 'FanartTV': dict_FanartTV}, mappingList) log.stop()
def Search(results, media, lang, manual, movie): orig_title = media.title if movie else media.show log = common.PlexLog(media=media, movie=movie, search=True) Log.Info('=== Search ============================================================================================================') Log.Info("Title: '%s', name: '%s', filename: '%s', manual: '%s', year: '%s'" % (orig_title, media.name, media.filename, str(manual), media.year)) #if media.filename is not None: filename = String.Unquote(media.filename) #auto match only Log.Info("".ljust(157, '=')) if not orig_title: return #clear-cache directive if orig_title == "clear-cache": HTTP.ClearCache() results.Append(MetadataSearchResult(id='clear-cache', name='Plex web cache cleared', year=media.year, lang=lang, score=0)) return ### Check if a guid is specified "Show name [anidb-id]" ### match = re.search(u"(?P<show>.*?) ?\[(?P<source>([a-zA-Z0-9]*))-(tt)?(?P<guid>[0-9]{1,7})\]", orig_title, re.IGNORECASE) if ' [' in orig_title else False if match: guid=match.group('source') + '-' + match.group('guid') if guid.startswith('anidb') and max(map(int, media.seasons.keys()))>1: Log.Info('[!] multiple seasons = tvdb numbering, BAKA!') results.Append(MetadataSearchResult(id=guid, name=match.group('show')+" ["+guid+']', year=media.year, lang=lang, score=100)) Log.Info("Forced ID - source: {}, id: {}, title: '{}'".format(match.group('source'), match.group('guid'), match.group('show'))) else: #if media.year is not None: orig_title = orig_title + " (" + str(media.year) + ")" ### Year - if present (manual search or from scanner but not mine), include in title ### maxi, n = 0, 0 if movie or max(map(int, media.seasons.keys()))<=1: maxi, n = AniDB.Search(results, media, lang, manual, movie) if maxi<50 and movie: maxi = TheMovieDb.Search(results, media, lang, manual, movie) if maxi<80 and not movie or n>1: maxi = max(TheTVDBv2.Search(results, media, lang, manual, movie), maxi) Log.Info("".ljust(157, '=')) log.stop()
def Start(): Log.Info("".ljust(157, '=')) Log.Info("HTTP Anidb Metadata Agent by ZeroQI (Forked from Atomicstrawberry's v0.4, AnimeLists XMLs by SdudLee) - CPU: {}, OS: {}".format(Platform.CPU, Platform.OS)) #HTTP.CacheTime = CACHE_1DAY # in sec: CACHE_1MINUTE, CACHE_1HOUR, CACHE_1DAY, CACHE_1WEEK, CACHE_1MONTH HTTP.CacheTime = CACHE_1MINUTE*30 ValidatePrefs() # Load core files AnimeLists.GetAniDBTVDBMap() AnimeLists.GetAniDBMovieSets() AniDB.GetAniDBTitlesDB()
def buildAnimeReply(searchText, isExpanded, baseComment, blockTracking=False): try: mal = { 'search_function': MAL.getAnimeDetails, 'synonym_function': MAL.getSynonyms, 'checked_synonyms': [], 'result': None } kit = { 'search_function': Kitsu.search_anime, 'synonym_function': Kitsu.get_synonyms, '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'] 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'] adbsyn = None if 'adb' in synonym and synonym['adb']: adbsyn = synonym['adb'] mal['result'] = MAL.getAnimeDetails( malsyn[0], malsyn[1]) if malsyn else None 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 adb['result'] = AniDB.getAnimeURLById( adbsyn) if adbsyn else None else: data_sources = [ani, kit, 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 mal['result'] or kit['result']: try: titleToAdd = '' if ani['result']: if 'title_romaji' in ani['result']: titleToAdd = ani['result']['title_romaji'] elif mal['result']: if 'title' in mal['result']: titleToAdd = mal['result']['title'] 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 return CommentBuilder.buildAnimeComment(isExpanded, mal['result'], ani['result'], ap['result'], adb['result'], kit['result']) except Exception as e: traceback.print_exc() return None
def GetMetadata(media, movie, error_log, id): Log.Info("=== AnimeLists.GetMetadata() ===".ljust(157, '=')) mappingList, AnimeLists_dict = {}, {} found = False source, id = id.split('-', 1) if '-' in id else ("", id) AniDB_id = id if source.startswith('anidb') else "" TVDB_id = id if source.startswith('tvdb') else "" TMDB_id = id if source.startswith('tmdb') else "" IMDB_id = id if source.startswith('imdb') else "" AniDBid = "" TVDBid = "" TMDBid = "" IMDBid = "" tvdb_numbering = True if not movie and ( TVDB_id or AniDB_id and max(map(int, media.seasons.keys())) > 1) else False tvdbcounts = {} ### Search for match ### Log.Info("tvdb_numbering: {}".format(tvdb_numbering)) AniDB_id2, TVDB_id2 = "", "" AniDBTVDBMapCustom = GetAniDBTVDBMapCustom(media, movie) if AniDBTVDBMapCustom: AniDBTVDBMapFull = MergeMaps(AniDBTVDBMap, AniDBTVDBMapCustom) else: AniDBTVDBMapFull = AniDBTVDBMap def anime_core(anime): defaulttvdbseason = anime.get('defaulttvdbseason') if anime.get( 'defaulttvdbseason' ) and anime.get('defaulttvdbseason') != 'a' else '1' episodeoffset = anime.get('episodeoffset') if anime.get( 'episodeoffset') else '0' s1_mapping_count = len( anime.xpath( "mapping-list/mapping[@anidbseason='1'][@tvdbseason='0' or @tvdbseason='1']" )) s1e1_mapping = True if anime.xpath( "mapping-list/mapping[@anidbseason='1'][@tvdbseason='1'][contains(text(), '-1;')]" ) else False is_primary_series = True if defaulttvdbseason == '1' and episodeoffset == '0' and ( s1_mapping_count == 0 or s1e1_mapping) else False return defaulttvdbseason, episodeoffset, s1_mapping_count, is_primary_series Log.Info("--- AniDBTVDBMap ---".ljust(157, '-')) forcedID = { 'anidbid': AniDB_id, 'tvdbid': TVDB_id, 'tmdbid': TMDB_id, 'imdbid': IMDB_id } for anime in AniDBTVDBMapFull.iter('anime') if AniDBTVDBMapFull else []: # gather any manually specified source ids foundID, wantedID = {}, {} for check in forcedID.keys(): foundID[check] = anime.get(check, "") wantedID[check] = True if foundID[check] == forcedID[ check] and forcedID[check] != '' else False # if this row matches our specified source-id if True in wantedID.values(): # save the found values for later use in other GetMetadata that dont depend on AniDB etc. IMDBid, TMDBid, TVDBid, AniDBid = foundID['imdbid'], foundID[ 'tmdbid'], foundID['tvdbid'], foundID['anidbid'] # use the old check to decide whether to proceed if TVDBid == '' and AniDBid == '': continue # nothing found, skip else: continue found = True # record the number of entries using the same tvdb id SaveDict(Dict(tvdbcounts, TVDBid, default=0) + 1, tvdbcounts, TVDBid) defaulttvdbseason, episodeoffset, s1_mapping_count, is_primary_series = anime_core( anime) if not tvdb_numbering and not TVDB_id: TVDB_id2 = TVDBid if tvdb_numbering and AniDBid and TVDBid.isdigit( ) and is_primary_series and not AniDB_id: AniDB_id2 = AniDBid Log.Info( "[+] AniDBid: {:>5}, TVDBid: {:>6}, defaulttvdbseason: {:>4}, offset: {:>3}, TMDBid: {:>7}, IMDBid: {:>10}, name: {}" .format( AniDBid, TVDBid, ("({})".format(anime.get('defaulttvdbseason')) if anime.get('defaulttvdbseason') != defaulttvdbseason else '') + defaulttvdbseason, episodeoffset, TMDBid, IMDBid, GetXml(anime, 'name'))) ### AniDB/TMDB/IMDB numbered series ### if AniDB_id or TMDB_id or IMDB_id: AniDB_id2 = AniDBid # Needs to be set if TMDB/IMDB TVDB_id2 = TVDBid SaveDict(TMDBid, mappingList, 'tmdbid') SaveDict(IMDBid, mappingList, 'imdbid') SaveDict(defaulttvdbseason, mappingList, 'defaulttvdbseason') SaveDict(True if anime.get('defaulttvdbseason') == 'a' else False, mappingList, 'defaulttvdbseason_a') SaveDict(episodeoffset, mappingList, 'episodeoffset') SaveDict(GetXml(anime, 'name'), mappingList, 'name') SaveDict(GetXml(anime, "supplemental-info/studio"), AnimeLists_dict, 'studio') SaveDict(GetXml(anime, "supplemental-info/director"), AnimeLists_dict, 'director') SaveDict(GetXml(anime, "supplemental-info/credits"), AnimeLists_dict, 'writer') for genre in anime.xpath('supplemental-info/genre'): SaveDict([genre.text], AnimeLists_dict, 'genres') for art in anime.xpath('supplemental-info/fanart/thumb'): SaveDict( { art.text: ('/'.join( art.text.split('/')[3:]), 1, art.get('preview')) }, AnimeLists_dict, 'art') ### TheTVDB/multi-season numbered series and the Primary/Starting(s1e1) AniDB id ### if (TVDB_id or not movie and max(map(int, media.seasons.keys())) > 1 and AniDB_id == '') and TVDBid.isdigit() and is_primary_series: AniDB_id2 = AniDBid SaveDict(TMDBid, mappingList, 'tmdbid') SaveDict(IMDBid, mappingList, 'imdbid') SaveDict(defaulttvdbseason, mappingList, 'defaulttvdbseason') SaveDict(True if anime.get('defaulttvdbseason') == 'a' else False, mappingList, 'defaulttvdbseason_a') ### if TVDBid.isdigit(): SaveDict(episodeoffset, mappingList, 'TVDB', 's-1' if defaulttvdbseason == '0' and s1_mapping_count >= 1 else 's' + defaulttvdbseason, AniDBid) #mappingList['TVDB'][s1][anidbid]=episodeoffset SaveDict( { 'min': defaulttvdbseason, 'max': defaulttvdbseason }, mappingList, 'season_map', AniDBid) # Set the min/max season to the 'defaulttvdbseason' if source == "tvdb6" and int(episodeoffset) > 0: SaveDict( { 'min': '0', 'max': '0' }, mappingList, 'season_map', AniDBid ) # Force series as special if not starting the TVDB season for season in anime.iter( 'mapping' ): ### mapping list: <mapping-list> <mapping anidbseason="0" tvdbseason="0">;1-12;2-14;3-16;4-18;</mapping> </mapping-list> anidbseason, tvdbseason, offset, start, end = season.get( 'anidbseason'), season.get( 'tvdbseason'), season.get('offset') or '0', season.get( 'start'), season.get('end') Log.Info( " - season: [{:>2}], [{:>2}], range: [{:>3}-{:>3}], offset: {:>3}, text: {}" .format(anidbseason, tvdbseason, start or '000', end or '000', offset, (season.text or '').strip(';'))) for ep in range(int(start), int(end) + 1) if start else []: #Log.Info("[?] start: {}, end: {}, ep: {}".format(start, end, ep)) if not Dict(mappingList, 'TVDB', 's' + tvdbseason + 'e' + str(ep + int(offset))): SaveDict( (anidbseason, str(ep), AniDBid), mappingList, 'TVDB', 's' + tvdbseason + 'e' + str(ep + int(offset)) ) #mappingList['TVDB'][s1e1]=(AniDB_season, AniDB_episode, AniDBid) for start-end mappings #else: Log.Info("already present") for ep in filter( None, season.text.split(';')) if season.text else []: if not '-' in ep: Log.Info( '[!] MAPPING ERROR, season.text: "{}", ep mapping missing hyphen: "{}"' .format(season.text, ep)) elif not Dict(mappingList, 'TVDB', 's' + tvdbseason + 'e' + ep.split('-')[1]): SaveDict( (anidbseason, ep.split('-')[0], AniDBid), mappingList, 'TVDB', 's' + tvdbseason + 'e' + ep.split('-')[1] ) #mappingList['TVDB'][s1e1]=(AniDB_season, AniDB_episode, AniDBid) for manual mapping like '1-12' #elif '-' not in (mappingList, 'TVDB', 's'+tvdbseason+'e'+ep.split('-')[1]): # SaveDict((anidbseason, Dict(mappingList, 'TVDB', 's'+tvdbseason+'e'+ep.split('-')[1])[1]+'-'+ep.split('-')[0], AniDBid), mappingList, 'TVDB', 's'+tvdbseason+'e'+ep.split('-')[1]) # Log.Info("already present so converting to range but range not supported") if int(Dict(mappingList, 'season_map', AniDBid, 'max')) < int( season.get("tvdbseason")): SaveDict( season.get("tvdbseason"), mappingList, 'season_map', AniDBid, 'max' ) # Update the max season to the largest 'tvdbseason' season seen in 'mapping-list' ### if TVDBid == "hentai": SaveDict("X", AnimeLists_dict, 'content_rating') elif TVDBid in ("", "unknown", None): link = SCHUDLEE_FEEDBACK.format( title="aid:%s '%s' TVDBid:" % (AniDB_id, "title"), body=String.StripTags( XML.StringFromElement(anime, encoding='utf8'))) error_log['anime-list TVDBid missing'].append( 'AniDBid: "{}" | Title: "{}" | Has no matching TVDBid "{}" in mapping file | <a href="{}" target="_blank">Submit bug report</a>' .format(AniDB_id, "title", TVDBid, link)) Log.Info( '"anime-list TVDBid missing.htm" log added as tvdb serie id missing in mapping file: "{}"' .format(TVDBid)) # guid need 1 entry only, not an TheTVDB numbered serie with anidb guid if (AniDB_id or TMDB_id or IMDB_id) and (movie or max(map(int, media.seasons.keys())) <= 1): break else: # Loop has gone through all entries. This only happens when the exact entry is not found or a TVDB entry that needs to loop through all. if not found: Log.Info("ERROR: Could not find %s: %s" % (source, id)) if AniDB_id != "": error_log['anime-list AniDBid missing'].append( "AniDBid: " + common.WEB_LINK % (common.ANIDB_SERIE_URL + AniDB_id, AniDB_id)) # Reset the variables used for matching so it does not just keep the value of the last entry in the loop IMDBid, TMDBid, TVDBid, AniDBid = '', '', '', '' AniDB_winner = AniDB_id or AniDB_id2 TVDB_winner = TVDB_id or TVDB_id2 Log.Info(' ----- ------') Log.Info(' {:>5} {:>6}'.format( AniDB_winner, TVDB_winner)) SaveDict(Dict(tvdbcounts, TVDB_winner), mappingList, 'tvdbcount') if source == "tvdb": for s in media.seasons: for e in media.seasons[s].episodes: if int(e) > 100: SaveDict(True, mappingList, 'possible_anidb3') break else: SaveDict(False, mappingList, 'possible_anidb3') else: SaveDict(False, mappingList, 'possible_anidb3') for values in Dict(mappingList, 'TVDB', default={}).values(): if isinstance(values, tuple) and values[0] == '1' and values[1] == '1': SaveDict(True, mappingList, 's1e1_mapped') break else: SaveDict(False, mappingList, 's1e1_mapped') ### Update collection/studio TVDB_collection, title, studio = [], '', '' for anime in AniDBTVDBMapFull.iter( 'anime') if AniDBTVDBMapFull and TVDB_winner.isdigit() else []: if anime.get('tvdbid', "") == TVDB_winner: TVDB_collection.append(anime.get("anidbid", "")) if anime_core(anime)[3]: #[3]==is_primary_series title = AniDB.GetAniDBTitle( AniDB.AniDBTitlesDB.xpath( '/animetitles/anime[@aid="{}"]/title'.format( anime.get("anidbid", ""))))[ 0] #returns [title, main, language_rank] studio = GetXml(anime, "supplemental-info/studio") if len( TVDB_collection ) > 1 and title: # Require that there be at least 2 anidb mappings for a collection Log.Info( "[ ] collection: TVDBid '%s' is part of collection: '%s', related_anime_list: %s" % (TVDB_winner, SaveDict([title + ' Collection'], AnimeLists_dict, 'collections'), TVDB_collection)) else: Log.Info("[ ] collection: TVDBid '%s' is not part of any collection" % TVDB_winner) Log.Info("[ ] studio: {}".format( SaveDict(studio, AnimeLists_dict, 'studio'))) Log.Info("--- return ---".ljust(157, '-')) Log.Info( "AniDB_id: '{}', AniDB_id2: '{}', AniDBid: '{}', TVDB_id: '{}', TVDB_id2: '{}', TVDBid: '{}'" .format(AniDB_id, AniDB_id2, AniDBid, TVDB_id, TVDB_id2, TVDBid)) Log.Info("mappingList: {}".format(DictString(mappingList, 1))) Log.Info("AnimeLists_dict: {}".format(DictString(AnimeLists_dict, 1))) return AnimeLists_dict, AniDB_winner, TVDB_winner if TVDB_winner.isdigit( ) else "", Dict(mappingList, 'tmdbid'), Dict(mappingList, 'imdbid'), mappingList
def GetMetadata(media, movie, error_log, id): Log.Info("=== AnimeLists.GetMetadata() ===".ljust(157, '=')) MAPPING_FEEDBACK = 'http://github.com/ScudLee/anime-lists/issues/new?title=%s&body=%s' # ScudLee mapping file git feedback url mappingList, AnimeLists_dict = {}, {} #mappingList['poster_id_array'] = {} found = False source, id = id.split('-', 1) if '-' in id else ("", id) AniDB_id = id if source.startswith('anidb') else "" TVDB_id = id if source.startswith('tvdb') else "" TMDB_id = id if source.startswith('tmdb') else "" AniDBid = "" TVDBid = "" TMDBid = "" IMDBid = "" tvdb_numbering = True if not movie and ( TVDB_id or AniDB_id and max(map(int, media.seasons.keys())) > 1) else False tvdbcounts = {} ### Search for match ### Log.Info("tvdb_numbering: {}".format(tvdb_numbering)) AniDB_id2, TVDB_id2 = "", "" Log.Info("--- AniDBTVDBMap ---".ljust(157, '-')) forcedID = { 'anidbid': AniDB_id, 'tvdbid': TVDB_id, 'tmdbid': TMDB_id, "imdbid": "" } for anime in AniDBTVDBMap.iter('anime') if AniDBTVDBMap else []: # gather any manually specified source ids foundID, wantedID = {}, {} for check in forcedID.keys(): foundID[check] = anime.get(check, "") wantedID[check] = True if foundID[check] == forcedID[ check] and forcedID[check] != '' else False # if this row matches our specified source-id if True in wantedID.values(): # save the found values for later use in other GetMetadata that dont depend on AniDB etc. IMDBid, TMDBid, TVDBid, AniDBid = foundID['imdbid'], foundID[ 'tmdbid'], foundID['tvdbid'], foundID['anidbid'] # use the old check to decide whether to proceed if TVDBid == '' and AniDBid == '': continue # nothing found, skip else: continue # record the number of entries using the same tvdb id SaveDict(Dict(tvdbcounts, TVDBid, default=0) + 1, tvdbcounts, TVDBid) found = True if not tvdb_numbering and not TVDB_id: TVDB_id = TVDBid if tvdb_numbering and AniDBid and TVDBid.isdigit( ) and anime.get('defaulttvdbseason') in [ 'a', '1' ] and anime.get('episodeoffset') in ['', '0'] and len( anime.xpath( "mapping-list/mapping[@anidbseason='1'][@tvdbseason='0']") ) == 0 and not AniDB_id: AniDB_id2 = AniDBid Log.Info( "[+] AniDBid: {:>5}, TVDBid: {:>6}, defaulttvdbseason: {:>2}, offset: {:>3}, name: {}" .format(AniDBid, TVDBid, anime.get('defaulttvdbseason'), anime.get('episodeoffset') or '0', GetXml(anime, 'name'))) ### Anidb numbered serie ### if AniDB_id: # or defaulttvdbseason=='1': SaveDict(anime.get('tmdbid', ""), mappingList, 'tmdbid') SaveDict(anime.get('imdbid', ""), mappingList, 'imdbid') SaveDict(anime.get('defaulttvdbseason'), mappingList, 'defaulttvdbseason') SaveDict( anime.get('episodeoffset') or '0', mappingList, 'episodeoffset') SaveDict(GetXml(anime, 'name'), mappingList, 'name') SaveDict(GetXml(anime, 'studio'), AnimeLists_dict, 'studio') SaveDict(GetXml(anime, "supplemental-info/director"), AnimeLists_dict, 'director') SaveDict(GetXml(anime, "supplemental-info/credits"), AnimeLists_dict, 'writer') for genre in anime.xpath('supplemental-info/genre'): SaveDict([genre.text], AnimeLists_dict, 'genres') for art in anime.xpath('supplemental-info/fanart/thumb'): SaveDict( { art.text: ('/'.join( art.text.split('/')[3:]), 1, art.get('preview')) }, AnimeLists_dict, 'art') ### TheTVDB numbered series ### if TVDB_id or not movie and max(map(int, media.seasons.keys( ))) > 1 and AniDB_id == '': #In case AniDB guid but multiple seasons if TVDBid.isdigit(): if anime.get('defaulttvdbseason'): if anime.get('defaulttvdbseason') in [ 'a', '1' ] and anime.get('episodeoffset') in ['', '0'] and len( anime.xpath( "mapping-list/mapping[@anidbseason='1'][@tvdbseason='0']" )) == 0: SaveDict(anime.get('defaulttvdbseason'), mappingList, 'defaulttvdbseason') AniDB_id2 = AniDBid SaveDict( anime.get('episodeoffset') or '0', mappingList, 'TVDB', 's-1' if anime.get('defaulttvdbseason') == '0' and len( anime.xpath( "mapping-list/mapping[@anidbseason='1'][@tvdbseason='0']" )) >= 1 else 's' + anime.get('defaulttvdbseason'), AniDBid ) #mappingList['TVDB'][s1][anidbid]=episodeoffset SaveDict( { 'min': anime.get('defaulttvdbseason'), 'max': anime.get('defaulttvdbseason') }, mappingList, 'season_map', AniDBid ) # Set the min/max season to the 'defaulttvdbseason' if source == "tvdb6" and anime.get( 'episodeoffset').isdigit() and int( anime.get('episodeoffset')) > 0: SaveDict( { 'min': '0', 'max': '0' }, mappingList, 'season_map', AniDBid ) # Force series as special if not starting the TVDB season for season in anime.iter( 'mapping' ): ### mapping list: <mapping-list> <mapping anidbseason="0" tvdbseason="0">;1-12;2-14;3-16;4-18;</mapping> </mapping-list> anidbseason, tvdbseason, offset, start, end = season.get( 'anidbseason'), season.get('tvdbseason'), season.get( 'offset') or '0', season.get('start'), season.get( 'end') Log.Info( " - season: [{:>2}], [{:>2}], range: [{:>3}-{:>3}], offset: {:>3}, text: {}" .format(anidbseason, tvdbseason, start or '000', end or '000', offset, (season.text or '').strip(';'))) for ep in range(int(start), int(end) + 1) if start else []: #Log.Info("[?] start: {}, end: {}, ep: {}".format(start, end, ep)) if not Dict( mappingList, 'TVDB', 's' + tvdbseason + 'e' + str(ep + int(offset))): SaveDict( (anidbseason, str(ep), AniDBid), mappingList, 'TVDB', 's' + tvdbseason + 'e' + str(ep + int(offset)) ) #mappingList['TVDB'][s1e1]=(AniDB_season, AniDB_episode, AniDBid) for start-end mappings #else: Log.Info("already present") for ep in filter( None, season.text.split(';')) if season.text else []: if not '-' in ep: Log.Info( '[!] MAPPING ERROR, season.text: "{}", ep mapping missing hyphen: "{}"' .format(season.text, ep)) elif not Dict( mappingList, 'TVDB', 's' + tvdbseason + 'e' + ep.split('-')[1]): SaveDict( (anidbseason, ep.split('-')[0], AniDBid), mappingList, 'TVDB', 's' + tvdbseason + 'e' + ep.split('-')[1] ) #mappingList['TVDB'][s1e1]=(AniDB_season, AniDB_episode, AniDBid) for manual mapping like '1-12' #elif '-' not in (mappingList, 'TVDB', 's'+tvdbseason+'e'+ep.split('-')[1]): # SaveDict((anidbseason, Dict(mappingList, 'TVDB', 's'+tvdbseason+'e'+ep.split('-')[1])[1]+'-'+ep.split('-')[0], AniDBid), mappingList, 'TVDB', 's'+tvdbseason+'e'+ep.split('-')[1]) # Log.Info("already present so converting to range but range not supported") if Dict(mappingList, 'season_map', AniDBid, 'max').isdigit() and int( Dict(mappingList, 'season_map', AniDBid, 'max')) < int(season.get("tvdbseason")): SaveDict( season.get("tvdbseason"), mappingList, 'season_map', AniDBid, 'max' ) # Update the max season to the largest 'tvdbseason' season seen in 'mapping-list' elif TVDBid == "hentai": SaveDict("X", AnimeLists_dict, 'content_rating') elif TVDBid in ("", "unknown", None): link = MAPPING_FEEDBACK % ("aid:%s '%s' TVDBid:" % (AniDB_id, "title"), String.StripTags( XML.StringFromElement( anime, encoding='utf8'))) error_log['anime-list TVDBid missing'].append( 'AniDBid: "{}" | Title: "{}" | Has no matching TVDBid "{}" in mapping file | <a href="{}" target="_blank">Submit bug report</a>' .format(AniDB_id, "title", TVDBid, link)) Log.Info( '"anime-list TVDBid missing.htm" log added as tvdb serie id missing in mapping file: "{}"' .format(TVDBid)) #AniDB guid need 1 AniDB xml only, not an TheTVDB numbered serie with anidb guid (not anidb2 since seen as TheTVDB) if AniDB_id and (movie or max(map(int, media.seasons.keys())) <= 1): break else: # case [tmdb-123]: # <anime anidbid="456" tvdbid="" defaulttvdbseason="" episodeoffset="" tmdbid="123" imdbid=""> # fails the above tvdbid + anidb check, but useful info was still obtained (anidbid=456) # <anime tmdbid="123"> # fails the above tvdbid + anidbid check, so this used to return a blank tmdbid to be later used in # TheMovieDB.GetMetadata(), and '' as AniDBid to be used in AniDB.GetMetadata() # so, not resetting the AniDBid/TVDBid, and saving found info if ((TMDB_id or TMDBid) or IMDBid): SaveDict(TMDB_id or TMDBid or '', mappingList, 'tmdbid') SaveDict(IMDBid or '', mappingList, 'imdbid') Log.Info( "Saved possible tmdb/imdb values for later '%s'/'%s' for later, since not in AnimeList." % (Dict(mappingList, 'tmdbid'), Dict(mappingList, 'imdbid'))) elif not found: Log.Info("ERROR: Could not find %s: %s" % (source, id)) # this error only makes sense if it's AniDB_id, right? otherwise AniDB_id is always == "" # since it cant be not found and also have been set if AniDB_id != "": error_log['anime-list AniDBid missing'].append( "AniDBid: " + common.WEB_LINK % (common.ANIDB_SERIE_URL + AniDB_id, AniDB_id)) # keeping this reset since im not clear on it's purpose. AniDBid, TVDBid = '', '' Log.Info(' ----- ------') Log.Info(' {:>5} {:>6}'.format( AniDB_id or AniDB_id2 or AniDBid, TVDB_id or TVDBid)) SaveDict(Dict(tvdbcounts, TVDB_id or TVDBid), mappingList, 'tvdbcount') ### Update collection TVDB_collection, title = [], '' for anime in AniDBTVDBMap.iter( 'anime') if AniDBTVDBMap and TVDB_id.isdigit() else []: if anime.get('tvdbid', "") == TVDB_id: TVDB_collection.append(anime.get("anidbid", "")) if anime.get('defaulttvdbseason') in [ 'a', '1' ] and anime.get('episodeoffset') in ['', '0'] and len( anime.xpath( "mapping-list/mapping[@anidbseason='1'][@tvdbseason='0']" )) == 0: title = AniDB.GetAniDBTitle( AniDB.AniDBTitlesDB.xpath( '/animetitles/anime[@aid="{}"]/title'.format( anime.get("anidbid", ""))))[ 0] #returns [title, main, language_rank] if len(TVDB_collection) > 1 and title: SaveDict([title + ' Collection'], AnimeLists_dict, 'collections') Log.Info("[ ] collection: TVDBid '%s' is part of collection: '%s'" % (TVDB_id, title)) else: Log.Info("[ ] collection: TVDBid '%s' is not part of any collection" % (TVDB_id)) Log.Info("--- return ---".ljust(157, '-')) Log.Info( "AniDB_id: '{}', AniDB_id2: '{}', AniDBid: '{}', TVDB_id: '{}', TVDBid: '{}'" .format(AniDB_id, AniDB_id2, AniDBid, TVDB_id, TVDBid)) Log.Info("mappingList: {}".format(DictString(mappingList, 1))) Log.Info("AnimeLists_dict: {}".format(DictString(AnimeLists_dict, 1))) return AnimeLists_dict, AniDB_id or AniDB_id2 or AniDBid, ( TVDB_id or TVDBid) if (TVDB_id or TVDBid).isdigit() else "", Dict( mappingList, 'tmdbid'), Dict(mappingList, 'imdbid'), mappingList
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 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