Plex-Meta-Manager/modules/convert.py

353 lines
16 KiB
Python
Raw Normal View History

2021-05-08 00:40:07 +00:00
import logging, re, requests
2021-04-22 23:51:03 +00:00
from modules import util
from modules.util import Failed
2021-05-19 17:12:34 +00:00
from plexapi.exceptions import BadRequest
2021-04-22 23:51:03 +00:00
logger = logging.getLogger("Plex Meta Manager")
anime_lists_url = "https://raw.githubusercontent.com/Fribb/anime-lists/master/anime-list-full.json"
2021-07-14 14:47:20 +00:00
2021-05-08 04:05:10 +00:00
class Convert:
2021-04-22 23:51:03 +00:00
def __init__(self, config):
self.config = config
2021-12-12 07:38:59 +00:00
self._loaded = False
self._anidb_ids = {}
self._mal_to_anidb = {}
self._anilist_to_anidb = {}
self._anidb_to_imdb = {}
self._anidb_to_tvdb = {}
@property
def anidb_ids(self):
self._load_anime_conversion()
return self._anidb_ids
@property
def mal_to_anidb(self):
self._load_anime_conversion()
return self._mal_to_anidb
@property
def anilist_to_anidb(self):
self._load_anime_conversion()
return self._anilist_to_anidb
@property
def anidb_to_imdb(self):
self._load_anime_conversion()
return self._anidb_to_imdb
@property
def anidb_to_tvdb(self):
self._load_anime_conversion()
return self._anidb_to_tvdb
def _load_anime_conversion(self):
if not self._loaded:
for anime_id in self.config.get_json(anime_lists_url):
if "anidb_id" in anime_id:
self._anidb_ids[anime_id["anidb_id"]] = anime_id
if "mal_id" in anime_id:
self._mal_to_anidb[int(anime_id["mal_id"])] = int(anime_id["anidb_id"])
if "anilist_id" in anime_id:
self._anilist_to_anidb[int(anime_id["anilist_id"])] = int(anime_id["anidb_id"])
if "imdb_id" in anime_id and str(anime_id["imdb_id"]).startswith("tt"):
self._anidb_to_imdb[int(anime_id["anidb_id"])] = util.get_list(anime_id["imdb_id"])
if "thetvdb_id" in anime_id:
self._anidb_to_tvdb[int(anime_id["anidb_id"])] = int(anime_id["thetvdb_id"])
self._loaded = True
2021-04-22 23:51:03 +00:00
def anidb_to_ids(self, anidb_ids, library):
2021-08-07 06:01:21 +00:00
ids = []
anidb_list = anidb_ids if isinstance(anidb_ids, list) else [anidb_ids]
2021-05-08 04:05:10 +00:00
for anidb_id in anidb_list:
if anidb_id in library.anidb_map:
ids.append((library.anidb_map[anidb_id], "ratingKey"))
elif anidb_id in self.anidb_to_imdb:
added = False
for imdb in self.anidb_to_imdb[anidb_id]:
tmdb, tmdb_type = self.imdb_to_tmdb(imdb)
if tmdb and tmdb_type == "movie":
ids.append((tmdb, "tmdb"))
added = True
if added is False and anidb_id in self.anidb_to_tvdb:
ids.append((self.anidb_to_tvdb[anidb_id], "tvdb"))
elif anidb_id in self.anidb_to_tvdb:
ids.append((self.anidb_to_tvdb[anidb_id], "tvdb"))
elif anidb_id in self.anidb_ids:
2022-01-25 07:45:31 +00:00
logger.warning(f"Convert Error: No TVDb ID or IMDb ID found for AniDB ID: {anidb_id}")
else:
2022-01-25 07:45:31 +00:00
logger.warning(f"Convert Error: AniDB ID: {anidb_id} not found")
2021-08-07 06:01:21 +00:00
return ids
2021-05-08 04:05:10 +00:00
def anilist_to_ids(self, anilist_ids, library):
2021-05-08 04:05:10 +00:00
anidb_ids = []
for anilist_id in anilist_ids:
if anilist_id in self.anilist_to_anidb:
anidb_ids.append(self.anilist_to_anidb[anilist_id])
2021-05-08 04:05:10 +00:00
else:
2022-01-25 07:45:31 +00:00
logger.warning(f"Convert Error: AniDB ID not found for AniList ID: {anilist_id}")
return self.anidb_to_ids(anidb_ids, library)
2021-05-08 04:05:10 +00:00
def myanimelist_to_ids(self, mal_ids, library):
ids = []
for mal_id in mal_ids:
2021-09-14 15:10:24 +00:00
if int(mal_id) in library.mal_map:
ids.append((library.mal_map[int(mal_id)], "ratingKey"))
elif int(mal_id) in self.mal_to_anidb:
ids.extend(self.anidb_to_ids(self.mal_to_anidb[int(mal_id)], library))
2021-05-08 04:05:10 +00:00
else:
2022-01-25 07:45:31 +00:00
logger.warning(f"Convert Error: AniDB ID not found for MyAnimeList ID: {mal_id}")
return ids
2021-05-08 00:40:07 +00:00
2021-05-08 04:05:10 +00:00
def tmdb_to_imdb(self, tmdb_id, is_movie=True, fail=False):
2021-05-09 05:38:41 +00:00
media_type = "movie" if is_movie else "show"
expired = False
if self.config.Cache and is_movie:
2021-08-07 06:01:21 +00:00
cache_id, expired = self.config.Cache.query_imdb_to_tmdb_map(tmdb_id, imdb=False, media_type=media_type)
2021-05-09 05:38:41 +00:00
if cache_id and not expired:
return cache_id
2021-05-08 00:40:07 +00:00
try:
2021-05-09 05:38:41 +00:00
imdb_id = self.config.TMDb.convert_from(tmdb_id, "imdb_id", is_movie)
2021-08-07 06:01:21 +00:00
if imdb_id:
if self.config.Cache:
self.config.Cache.update_imdb_to_tmdb_map(media_type, expired, imdb_id, tmdb_id)
return imdb_id
2021-05-08 00:40:07 +00:00
except Failed:
2021-08-04 19:17:56 +00:00
pass
2021-08-07 06:01:21 +00:00
if fail:
2021-05-08 04:05:10 +00:00
raise Failed(f"Convert Error: No IMDb ID Found for TMDb ID: {tmdb_id}")
2021-08-04 19:17:56 +00:00
else:
return None
2021-05-08 00:40:07 +00:00
2021-08-07 06:01:21 +00:00
def imdb_to_tmdb(self, imdb_id, fail=False):
2021-05-08 23:49:55 +00:00
expired = False
2021-08-07 06:01:21 +00:00
if self.config.Cache:
cache_id, cache_type, expired = self.config.Cache.query_imdb_to_tmdb_map(imdb_id, imdb=True, return_type=True)
2021-05-08 23:49:55 +00:00
if cache_id and not expired:
2021-08-07 06:01:21 +00:00
return cache_id, cache_type
2021-05-08 00:40:07 +00:00
try:
2021-08-07 06:01:21 +00:00
tmdb_id, tmdb_type = self.config.TMDb.convert_imdb_to(imdb_id)
if tmdb_id:
if self.config.Cache:
self.config.Cache.update_imdb_to_tmdb_map(tmdb_type, expired, imdb_id, tmdb_id)
return tmdb_id, tmdb_type
2021-05-08 00:40:07 +00:00
except Failed:
2021-08-04 19:17:56 +00:00
pass
2021-08-07 06:01:21 +00:00
if fail:
2021-05-08 04:05:10 +00:00
raise Failed(f"Convert Error: No TMDb ID Found for IMDb ID: {imdb_id}")
2021-08-04 19:17:56 +00:00
else:
2021-08-07 06:01:21 +00:00
return None, None
2021-05-08 00:40:07 +00:00
2021-05-08 04:05:10 +00:00
def tmdb_to_tvdb(self, tmdb_id, fail=False):
2021-05-09 05:38:41 +00:00
expired = False
if self.config.Cache:
cache_id, expired = self.config.Cache.query_tmdb_to_tvdb_map(tmdb_id, tmdb=True)
if cache_id and not expired:
return cache_id
2021-05-08 00:40:07 +00:00
try:
2021-08-04 19:17:56 +00:00
tvdb_id = self.config.TMDb.convert_from(tmdb_id, "tvdb_id", False)
2021-08-07 06:01:21 +00:00
if tvdb_id:
if self.config.Cache:
self.config.Cache.update_tmdb_to_tvdb_map(expired, tmdb_id, tvdb_id)
return tvdb_id
2021-05-08 00:40:07 +00:00
except Failed:
2021-08-04 19:17:56 +00:00
pass
2021-08-07 06:01:21 +00:00
if fail:
2021-05-08 04:05:10 +00:00
raise Failed(f"Convert Error: No TVDb ID Found for TMDb ID: {tmdb_id}")
2021-08-04 19:17:56 +00:00
else:
return None
2021-05-08 00:40:07 +00:00
2021-05-08 04:05:10 +00:00
def tvdb_to_tmdb(self, tvdb_id, fail=False):
2021-05-09 05:38:41 +00:00
expired = False
if self.config.Cache:
cache_id, expired = self.config.Cache.query_tmdb_to_tvdb_map(tvdb_id, tmdb=False)
if cache_id and not expired:
return cache_id
2021-05-08 00:40:07 +00:00
try:
2021-08-07 06:01:21 +00:00
tmdb_id = self.config.TMDb.convert_tvdb_to(tvdb_id)
if tmdb_id:
if self.config.Cache:
self.config.Cache.update_tmdb_to_tvdb_map(expired, tmdb_id, tvdb_id)
return tmdb_id
2021-05-08 00:40:07 +00:00
except Failed:
2021-08-04 19:17:56 +00:00
pass
2021-08-07 06:01:21 +00:00
if fail:
2021-05-08 04:05:10 +00:00
raise Failed(f"Convert Error: No TMDb ID Found for TVDb ID: {tvdb_id}")
2021-08-04 19:17:56 +00:00
else:
return None
2021-05-08 00:40:07 +00:00
2021-05-08 04:05:10 +00:00
def tvdb_to_imdb(self, tvdb_id, fail=False):
2021-05-09 05:38:41 +00:00
expired = False
if self.config.Cache:
cache_id, expired = self.config.Cache.query_imdb_to_tvdb_map(tvdb_id, imdb=False)
if cache_id and not expired:
return cache_id
2021-05-08 00:40:07 +00:00
try:
2021-05-21 14:30:23 +00:00
imdb_id = self.tmdb_to_imdb(self.tvdb_to_tmdb(tvdb_id, fail=True), is_movie=False, fail=True)
2021-08-07 06:01:21 +00:00
if imdb_id:
if self.config.Cache:
self.config.Cache.update_imdb_to_tvdb_map(expired, imdb_id, tvdb_id)
return imdb_id
2021-05-08 00:40:07 +00:00
except Failed:
2021-08-04 19:17:56 +00:00
pass
2021-08-07 06:01:21 +00:00
if fail:
2021-05-08 04:05:10 +00:00
raise Failed(f"Convert Error: No IMDb ID Found for TVDb ID: {tvdb_id}")
2021-08-04 19:17:56 +00:00
else:
return None
2021-05-08 00:40:07 +00:00
2021-05-08 04:05:10 +00:00
def imdb_to_tvdb(self, imdb_id, fail=False):
2021-05-08 23:49:55 +00:00
expired = False
if self.config.Cache:
2021-05-09 05:38:41 +00:00
cache_id, expired = self.config.Cache.query_imdb_to_tvdb_map(imdb_id, imdb=True)
2021-05-08 23:49:55 +00:00
if cache_id and not expired:
return cache_id
2021-05-08 00:40:07 +00:00
try:
2021-08-07 06:01:21 +00:00
tmdb_id, tmdb_type = self.imdb_to_tmdb(imdb_id, fail=True)
if tmdb_type == "show":
tvdb_id = self.tmdb_to_tvdb(tmdb_id, fail=True)
if tvdb_id:
if self.config.Cache:
self.config.Cache.update_imdb_to_tvdb_map(expired, imdb_id, tvdb_id)
return tvdb_id
2021-05-08 00:40:07 +00:00
except Failed:
2021-08-04 19:17:56 +00:00
pass
2021-08-07 06:01:21 +00:00
if fail:
2021-05-08 04:05:10 +00:00
raise Failed(f"Convert Error: No TVDb ID Found for IMDb ID: {imdb_id}")
2021-08-04 19:17:56 +00:00
else:
return None
2021-05-08 00:40:07 +00:00
2021-05-26 13:25:32 +00:00
def get_id(self, item, library):
2021-05-08 00:40:07 +00:00
expired = None
2021-08-04 14:20:52 +00:00
tmdb_id = []
tvdb_id = []
imdb_id = []
anidb_id = None
2021-09-14 21:50:39 +00:00
guid = requests.utils.urlparse(item.guid)
item_type = guid.scheme.split(".")[-1]
check_id = guid.netloc
2021-05-08 00:40:07 +00:00
if self.config.Cache:
2021-08-07 06:01:21 +00:00
cache_id, imdb_check, media_type, expired = self.config.Cache.query_guid_map(item.guid)
2021-11-28 08:18:12 +00:00
if (cache_id or imdb_check) and not expired:
2021-05-08 23:49:55 +00:00
media_id_type = "movie" if "movie" in media_type else "show"
2021-09-14 21:50:39 +00:00
if item_type == "hama" and check_id.startswith("anidb"):
anidb_id = int(re.search("-(.*)", check_id).group(1))
library.anidb_map[anidb_id] = item.ratingKey
elif item_type == "myanimelist":
library.mal_map[int(check_id)] = item.ratingKey
2021-08-07 06:01:21 +00:00
return media_id_type, cache_id, imdb_check
2021-05-08 23:49:55 +00:00
try:
2021-05-08 00:40:07 +00:00
if item_type == "plex":
2021-05-08 23:49:55 +00:00
try:
2021-10-05 04:30:04 +00:00
for guid_tag in item.guids:
2021-05-08 23:49:55 +00:00
url_parsed = requests.utils.urlparse(guid_tag.id)
if url_parsed.scheme == "tvdb": tvdb_id.append(int(url_parsed.netloc))
elif url_parsed.scheme == "imdb": imdb_id.append(url_parsed.netloc)
elif url_parsed.scheme == "tmdb": tmdb_id.append(int(url_parsed.netloc))
except requests.exceptions.ConnectionError:
2021-05-24 22:16:19 +00:00
library.query(item.refresh)
2021-05-08 23:49:55 +00:00
util.print_stacktrace()
raise Failed("No External GUIDs found")
2021-05-18 21:56:57 +00:00
if not tvdb_id and not imdb_id and not tmdb_id:
2021-08-04 14:20:52 +00:00
library.query(item.refresh)
2021-05-18 21:56:57 +00:00
raise Failed("Refresh Metadata")
2021-08-04 14:20:52 +00:00
elif item_type == "imdb": imdb_id.append(check_id)
elif item_type == "thetvdb": tvdb_id.append(int(check_id))
elif item_type == "themoviedb": tmdb_id.append(int(check_id))
2021-12-11 04:15:08 +00:00
elif item_type in ["xbmcnfo", "xbmcnfotv"]:
if len(check_id) > 10:
raise Failed(f"XMBC NFO Local ID: {check_id}")
try:
if item_type == "xbmcnfo":
tmdb_id.append(int(check_id))
else:
tvdb_id.append(int(check_id))
except ValueError:
imdb_id.append(check_id)
2021-05-08 00:40:07 +00:00
elif item_type == "hama":
if check_id.startswith("tvdb"):
tvdb_id.append(int(re.search("-(.*)", check_id).group(1)))
elif check_id.startswith("anidb"):
2021-12-02 06:39:46 +00:00
anidb_str = str(re.search("-(.*)", check_id).group(1))
anidb_id = int(anidb_str[1:] if anidb_str[0] == "a" else anidb_str)
library.anidb_map[anidb_id] = item.ratingKey
else:
raise Failed(f"Hama Agent ID: {check_id} not supported")
2021-05-08 23:49:55 +00:00
elif item_type == "myanimelist":
library.mal_map[int(check_id)] = item.ratingKey
2021-09-14 12:57:40 +00:00
if int(check_id) in self.mal_to_anidb:
anidb_id = self.mal_to_anidb[int(check_id)]
else:
raise Failed(f"Convert Error: AniDB ID not found for MyAnimeList ID: {check_id}")
2021-05-08 23:49:55 +00:00
elif item_type == "local": raise Failed("No match in Plex")
else: raise Failed(f"Agent {item_type} not supported")
2021-05-08 00:40:07 +00:00
2021-05-08 23:49:55 +00:00
if anidb_id:
if anidb_id in self.anidb_to_imdb:
added = False
for imdb in self.anidb_to_imdb[anidb_id]:
tmdb, tmdb_type = self.imdb_to_tmdb(imdb)
if tmdb and tmdb_type == "movie":
imdb_id.append(imdb)
tmdb_id.append(tmdb)
added = True
if added is False and anidb_id in self.anidb_to_tvdb:
tvdb_id.append(self.anidb_to_tvdb[anidb_id])
elif anidb_id in self.anidb_to_tvdb:
tvdb_id.append(self.anidb_to_tvdb[anidb_id])
else:
raise Failed(f"AniDB: {anidb_id} not found")
2021-08-04 14:20:52 +00:00
else:
if not tmdb_id and imdb_id:
2021-05-08 23:49:55 +00:00
for imdb in imdb_id:
2021-08-07 06:01:21 +00:00
tmdb, tmdb_type = self.imdb_to_tmdb(imdb)
if tmdb and ((tmdb_type == "movie" and library.is_movie) or (tmdb_type == "show" and library.is_show)):
2021-08-04 14:20:52 +00:00
tmdb_id.append(tmdb)
2021-08-07 06:01:21 +00:00
if not imdb_id and tmdb_id and library.is_movie:
for tmdb in tmdb_id:
imdb = self.tmdb_to_imdb(tmdb)
if imdb:
imdb_id.append(imdb)
2021-08-04 14:20:52 +00:00
if not tvdb_id and tmdb_id and library.is_show:
2021-05-12 02:34:14 +00:00
for tmdb in tmdb_id:
2021-08-04 14:20:52 +00:00
tvdb = self.tmdb_to_tvdb(tmdb)
if tvdb:
tvdb_id.append(tvdb)
if not tvdb_id:
2021-08-13 14:33:56 +00:00
raise Failed(f"Unable to convert TMDb ID: {', '.join([str(t) for t in tmdb_id])} to TVDb ID")
2021-05-08 00:40:07 +00:00
2021-08-07 06:01:21 +00:00
if not imdb_id and tvdb_id:
for tvdb in tvdb_id:
imdb = self.tvdb_to_imdb(tvdb)
if imdb:
imdb_id.append(imdb)
2021-05-12 14:38:11 +00:00
2021-08-07 06:01:21 +00:00
def update_cache(cache_ids, id_type, imdb_in, guid_type):
2021-05-08 23:49:55 +00:00
if self.config.Cache:
2021-08-13 14:33:56 +00:00
cache_ids = ",".join([str(c) for c in cache_ids])
imdb_in = ",".join([str(i) for i in imdb_in]) if imdb_in else None
2021-08-07 06:01:21 +00:00
ids = f"{item.guid:<46} | {id_type} ID: {cache_ids:<7} | IMDb ID: {str(imdb_in):<10}"
logger.info(util.adjust_space(f" Cache | {'^' if expired else '+'} | {ids} | {item.title}"))
self.config.Cache.update_guid_map(item.guid, cache_ids, imdb_in, expired, guid_type)
2021-05-08 00:40:07 +00:00
2021-11-26 08:24:36 +00:00
if (tmdb_id or imdb_id) and library.is_movie:
2021-08-07 06:01:21 +00:00
update_cache(tmdb_id, "TMDb", imdb_id, "movie")
return "movie", tmdb_id, imdb_id
2021-11-26 08:24:36 +00:00
elif (tvdb_id or imdb_id) and library.is_show:
2021-08-07 06:01:21 +00:00
update_cache(tvdb_id, "TVDb", imdb_id, "show")
return "show", tvdb_id, imdb_id
2021-11-26 08:24:36 +00:00
elif anidb_id and (tmdb_id or imdb_id) and library.is_show:
2021-08-07 06:01:21 +00:00
update_cache(tmdb_id, "TMDb", imdb_id, "show_movie")
return "movie", tmdb_id, imdb_id
2021-05-08 23:49:55 +00:00
else:
2021-08-05 14:59:45 +00:00
logger.debug(f"TMDb: {tmdb_id}, IMDb: {imdb_id}, TVDb: {tvdb_id}")
2021-05-08 23:49:55 +00:00
raise Failed(f"No ID to convert")
except Failed as e:
2021-12-01 15:17:19 +00:00
logger.info(util.adjust_space(f'Mapping Error | {item.guid:<46} | {e} for "{item.title}"'))
2021-05-19 17:12:34 +00:00
except BadRequest:
util.print_stacktrace()
2021-12-01 15:17:19 +00:00
logger.info(util.adjust_space(f'Mapping Error | {item.guid:<46} | Bad Request for "{item.title}"'))
2021-08-07 06:01:21 +00:00
return None, None, None