improved conversions

This commit is contained in:
meisnate12 2021-05-07 20:40:07 -04:00
parent 4cd14dbfc6
commit 24dffdbdfa
5 changed files with 234 additions and 519 deletions

View file

@ -1,4 +1,4 @@
import logging, requests import logging, re, requests
from lxml import html from lxml import html
from modules import util from modules import util
from modules.util import Failed from modules.util import Failed
@ -140,10 +140,10 @@ class ArmsAPI:
try: tvdb_id = self.config.TMDb.convert_imdb_to_tvdb(imdb_id) try: tvdb_id = self.config.TMDb.convert_imdb_to_tvdb(imdb_id)
except Failed: pass except Failed: pass
if not tmdb_id and not tvdb_id and self.config.Trakt: if not tmdb_id and not tvdb_id and self.config.Trakt:
try: tmdb_id = self.config.Trakt.convert_imdb_to_tmdb(imdb_id) try: tmdb_id = self.convert_imdb_to_tmdb(imdb_id)
except Failed: pass except Failed: pass
if not tmdb_id and not tvdb_id and self.config.Trakt: if not tmdb_id and not tvdb_id and self.config.Trakt:
try: tvdb_id = self.config.Trakt.convert_imdb_to_tvdb(imdb_id) try: tvdb_id = self.convert_imdb_to_tvdb(imdb_id)
except Failed: pass except Failed: pass
if tmdb_id and not from_cache: if tmdb_id and not from_cache:
try: self.config.TMDb.get_movie(tmdb_id) try: self.config.TMDb.get_movie(tmdb_id)
@ -159,3 +159,205 @@ class ArmsAPI:
if tvdb_id and update_tvdb is not False: if tvdb_id and update_tvdb is not False:
self.config.Cache.update_imdb("show", update_tvdb, imdb_id, tvdb_id) self.config.Cache.update_imdb("show", update_tvdb, imdb_id, tvdb_id)
return tmdb_id, tvdb_id return tmdb_id, tvdb_id
def convert_tmdb_to_imdb(self, tmdb_id, is_movie=True, fail=False):
try:
return self.config.TMDb.convert_from(tmdb_id, "imdb_id", is_movie)
except Failed:
if self.config.Trakt:
try:
return self.config.Trakt.convert(tmdb_id, "tmdb", "imdb", "movie" if is_movie else "show")
except Failed:
pass
if fail:
raise Failed(f"Arms Error: No IMDb ID Found for TMDb ID: {tmdb_id}")
return None
def convert_imdb_to_tmdb(self, imdb_id, is_movie=True, fail=False):
try:
return self.config.TMDb.convert_to(imdb_id, "imdb_id", is_movie)
except Failed:
if self.config.Trakt:
try:
return self.config.Trakt.convert(imdb_id, "imdb", "tmdb", "movie" if is_movie else "show")
except Failed:
pass
if fail:
raise Failed(f"Arms Error: No TMDb ID Found for IMDb ID: {imdb_id}")
return None
def convert_tmdb_to_tvdb(self, tmdb_id, fail=False):
try:
return self.config.TMDb.convert_from(tmdb_id, "tvdb_id", False)
except Failed:
if self.config.Trakt:
try:
return self.config.Trakt.convert(tmdb_id, "tmdb", "tvdb", "show")
except Failed:
pass
if fail:
raise Failed(f"Arms Error: No TVDb ID Found for TMDb ID: {tmdb_id}")
return None
def convert_tvdb_to_tmdb(self, tvdb_id, fail=False):
try:
return self.config.TMDb.convert_to(tvdb_id, "tvdb_id", False)
except Failed:
if self.config.Trakt:
try:
return self.config.Trakt.convert(tvdb_id, "tvdb", "tmdb", "show")
except Failed:
pass
if fail:
raise Failed(f"Arms Error: No TMDb ID Found for TVDb ID: {tvdb_id}")
return None
def convert_tvdb_to_imdb(self, tvdb_id, fail=False):
try:
return self.convert_tmdb_to_imdb(self.convert_tvdb_to_tmdb(tvdb_id), False)
except Failed:
if self.config.Trakt:
try:
return self.config.Trakt.convert(tvdb_id, "tvdb", "imdb", "show")
except Failed:
pass
if fail:
raise Failed(f"Arms Error: No IMDb ID Found for TVDb ID: {tvdb_id}")
return None
def convert_imdb_to_tvdb(self, imdb_id, fail=False):
try:
return self.convert_tmdb_to_tvdb(self.convert_imdb_to_tmdb(imdb_id, False))
except Failed:
if self.config.Trakt:
try:
return self.config.Trakt.convert(imdb_id, "imdb", "tvdb", "show")
except Failed:
pass
if fail:
raise Failed(f"Arms Error: No TVDb ID Found for IMDb ID: {imdb_id}")
return None
def get_id(self, item, library, length):
expired = None
tmdb_id = None
imdb_id = None
tvdb_id = None
anidb_id = None
mal_id = None
error_message = None
if self.config.Cache:
if library.is_movie: tmdb_id, expired = self.config.Cache.get_tmdb_id("movie", plex_guid=item.guid)
else: tvdb_id, expired = self.config.Cache.get_tvdb_id("show", plex_guid=item.guid)
if not tvdb_id and library.is_show:
tmdb_id, expired = self.config.Cache.get_tmdb_id("show", plex_guid=item.guid)
anidb_id, expired = self.config.Cache.get_anidb_id("show", plex_guid=item.guid)
if expired or (not tmdb_id and library.is_movie) or (not tvdb_id and not tmdb_id and library.is_show):
guid = requests.utils.urlparse(item.guid)
item_type = guid.scheme.split(".")[-1]
check_id = guid.netloc
if item_type == "plex":
tmdb_id = []
imdb_id = []
tvdb_id = []
if check_id == "movie":
try:
for guid_tag in library.get_guids(item):
url_parsed = requests.utils.urlparse(guid_tag.id)
if url_parsed.scheme == "tmdb": tmdb_id.append(int(url_parsed.netloc))
elif url_parsed.scheme == "imdb": imdb_id.append(url_parsed.netloc)
except requests.exceptions.ConnectionError:
util.print_stacktrace()
logger.error(f"{'Cache | ! |' if self.config.Cache else 'Mapping Error:'} {item.guid:<46} | No External GUIDs found for {item.title}")
return None, None
elif check_id == "show":
try:
for guid_tag in library.get_guids(item):
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:
util.print_stacktrace()
logger.error(f"{'Cache | ! |' if self.config.Cache else 'Mapping Error:'} {item.guid:<46} | No External GUIDs found for {item.title}")
return None, None
elif item_type == "imdb": imdb_id = check_id
elif item_type == "thetvdb": tvdb_id = int(check_id)
elif item_type == "themoviedb": tmdb_id = int(check_id)
elif item_type == "hama":
if check_id.startswith("tvdb"): tvdb_id = int(re.search("-(.*)", check_id).group(1))
elif check_id.startswith("anidb"): anidb_id = re.search("-(.*)", check_id).group(1)
else: error_message = f"Hama Agent ID: {check_id} not supported"
elif item_type == "myanimelist": mal_id = check_id
elif item_type == "local": error_message = "No match in Plex"
else: error_message = f"Agent {item_type} not supported"
if not error_message:
if mal_id and not anidb_id:
try: anidb_id = self.mal_to_anidb(mal_id)
except Failed: pass
if anidb_id and not tvdb_id:
try: tvdb_id = self.anidb_to_tvdb(anidb_id)
except Failed: pass
if anidb_id and not imdb_id:
try: imdb_id = self.anidb_to_imdb(anidb_id)
except Failed: pass
if not tmdb_id and imdb_id:
if isinstance(imdb_id, list):
tmdb_id = []
new_imdb_id = []
for imdb in imdb_id:
try:
tmdb_id.append(self.convert_imdb_to_tmdb(imdb_id, fail=True))
new_imdb_id.append(imdb)
except Failed:
continue
imdb_id = new_imdb_id
else:
tmdb_id = self.convert_imdb_to_tmdb(imdb_id)
if not tmdb_id and tvdb_id and library.is_show:
tmdb_id = self.convert_tvdb_to_tmdb(tvdb_id)
if not imdb_id and tmdb_id and library.is_movie:
imdb_id = self.convert_tmdb_to_imdb(tmdb_id)
if not imdb_id and tvdb_id and library.is_show:
imdb_id = self.convert_tvdb_to_imdb(tvdb_id)
if not tvdb_id and tmdb_id and library.is_show:
tvdb_id = self.convert_tmdb_to_tvdb(tmdb_id)
if not tvdb_id and imdb_id and library.is_show:
tvdb_id = self.convert_imdb_to_tvdb(imdb_id)
if (not tmdb_id and library.is_movie) or (not tvdb_id and not (anidb_id and tmdb_id) and library.is_show):
service_name = "TMDb ID" if library.is_movie else "TVDb ID"
if self.config.Trakt: api_name = "TMDb or Trakt"
else: api_name = "TMDb"
if tmdb_id and imdb_id: id_name = f"TMDb ID: {tmdb_id} or IMDb ID: {imdb_id}"
elif imdb_id and tvdb_id: id_name = f"IMDb ID: {imdb_id} or TVDb ID: {tvdb_id}"
elif tmdb_id: id_name = f"TMDb ID: {tmdb_id}"
elif imdb_id: id_name = f"IMDb ID: {imdb_id}"
elif tvdb_id: id_name = f"TVDb ID: {tvdb_id}"
else: id_name = None
if anidb_id and not tmdb_id and not tvdb_id: error_message = f"Unable to convert AniDB ID: {anidb_id} to TMDb ID or TVDb ID"
elif id_name: error_message = f"Unable to convert {id_name} to {service_name} using {api_name}"
else: error_message = f"No ID to convert to {service_name}"
if self.config.Cache and ((tmdb_id and library.is_movie) or ((tvdb_id or (anidb_id and tmdb_id)) and library.is_show)):
if not isinstance(tmdb_id, list): tmdb_id = [tmdb_id]
if not isinstance(imdb_id, list): imdb_id = [imdb_id]
if not isinstance(tvdb_id, list): tvdb_id = [tvdb_id]
try: tvdb_value = tvdb_id[0]
except IndexError: tvdb_value = None
for i in range(len(tmdb_id)):
try: imdb_value = imdb_id[i]
except IndexError: imdb_value = None
util.print_end(length, f"Cache | {'^' if expired is True else '+'} | {item.guid:<46} | {tmdb_id[i] if tmdb_id[i] else 'None':<6} | {imdb_value if imdb_value else 'None':<10} | {tvdb_value if tvdb_value else 'None':<6} | {anidb_id if anidb_id else 'None':<5} | {item.title}")
self.config.Cache.update_guid("movie" if library.is_movie else "show", item.guid, tmdb_id[i], imdb_value, tvdb_value, anidb_id, expired)
if tmdb_id and library.is_movie: return "movie", tmdb_id
elif tvdb_id and library.is_show: return "show", tvdb_id
elif anidb_id and tmdb_id: return "movie", tmdb_id
else:
util.print_end(length, f"{'Cache | ! |' if self.config.Cache else 'Mapping Error:'} {item.guid:<46} | {error_message} for {item.title}")
return None, None

View file

@ -206,7 +206,7 @@ class Config:
try: self.tmdb["apikey"] = check_for_attribute(self.data, "apikey", parent="tmdb", throw=True) try: self.tmdb["apikey"] = check_for_attribute(self.data, "apikey", parent="tmdb", throw=True)
except Failed as e: raise Failed(e) except Failed as e: raise Failed(e)
self.tmdb["language"] = check_for_attribute(self.data, "language", parent="tmdb", default="en") self.tmdb["language"] = check_for_attribute(self.data, "language", parent="tmdb", default="en")
self.TMDb = TMDbAPI(self.tmdb) self.TMDb = TMDbAPI(self, self.tmdb)
logger.info(f"TMDb Connection {'Failed' if self.TMDb is None else 'Successful'}") logger.info(f"TMDb Connection {'Failed' if self.TMDb is None else 'Successful'}")
else: else:
raise Failed("Config Error: tmdb attribute not found") raise Failed("Config Error: tmdb attribute not found")
@ -755,194 +755,21 @@ class Config:
for i, item in enumerate(items, 1): for i, item in enumerate(items, 1):
length = util.print_return(length, f"Processing: {i}/{len(items)} {item.title}") length = util.print_return(length, f"Processing: {i}/{len(items)} {item.title}")
try: try:
id_type, main_id = self.get_id(item, library, length) id_type, main_id = self.Arms.get_id(item, library, length)
except BadRequest: except BadRequest:
util.print_stacktrace() util.print_stacktrace()
util.print_end(length, f"{'Cache | ! |' if self.Cache else 'Mapping Error:'} | {item.guid} for {item.title} not found") util.print_end(length, f"{'Cache | ! |' if self.Cache else 'Mapping Error:'} | {item.guid} for {item.title} not found")
continue continue
if isinstance(main_id, list): if not isinstance(main_id, list):
if id_type == "movie": main_id = [main_id]
for m in main_id: if id_type == "movie":
if m in movie_map: for m in main_id:
movie_map[m].append(item.ratingKey) if m in movie_map: movie_map[m].append(item.ratingKey)
else: else: movie_map[m] = [item.ratingKey]
movie_map[m] = [item.ratingKey] elif id_type == "show":
elif id_type == "show": for m in main_id:
for m in main_id: if m in show_map: show_map[m].append(item.ratingKey)
if m in show_map: else: show_map[m] = [item.ratingKey]
show_map[m].append(item.ratingKey)
else:
show_map[m] = [item.ratingKey]
else:
if id_type == "movie":
if main_id in movie_map:
movie_map[main_id].append(item.ratingKey)
else:
movie_map[main_id] = [item.ratingKey]
elif id_type == "show":
if main_id in show_map:
show_map[main_id].append(item.ratingKey)
else:
show_map[main_id] = [item.ratingKey]
util.print_end(length, f"Processed {len(items)} {'Movies' if library.is_movie else 'Shows'}") util.print_end(length, f"Processed {len(items)} {'Movies' if library.is_movie else 'Shows'}")
return movie_map, show_map return movie_map, show_map
@retry(stop_max_attempt_number=6, wait_fixed=10000)
def get_guids(self, item):
return item.guids
def get_id(self, item, library, length):
expired = None
tmdb_id = None
imdb_id = None
tvdb_id = None
anidb_id = None
mal_id = None
error_message = None
if self.Cache:
if library.is_movie: tmdb_id, expired = self.Cache.get_tmdb_id("movie", plex_guid=item.guid)
else: tvdb_id, expired = self.Cache.get_tvdb_id("show", plex_guid=item.guid)
if not tvdb_id and library.is_show:
tmdb_id, expired = self.Cache.get_tmdb_id("show", plex_guid=item.guid)
anidb_id, expired = self.Cache.get_anidb_id("show", plex_guid=item.guid)
if expired or (not tmdb_id and library.is_movie) or (not tvdb_id and not tmdb_id and library.is_show):
guid = requests.utils.urlparse(item.guid)
item_type = guid.scheme.split(".")[-1]
check_id = guid.netloc
if item_type == "plex":
tmdb_id = []
imdb_id = []
tvdb_id = []
if check_id == "movie":
try:
for guid_tag in self.get_guids(item):
url_parsed = requests.utils.urlparse(guid_tag.id)
if url_parsed.scheme == "tmdb": tmdb_id.append(int(url_parsed.netloc))
elif url_parsed.scheme == "imdb": imdb_id.append(url_parsed.netloc)
except requests.exceptions.ConnectionError:
util.print_stacktrace()
logger.error(f"{'Cache | ! |' if self.Cache else 'Mapping Error:'} {item.guid:<46} | No External GUIDs found for {item.title}")
return None, None
elif check_id == "show":
try:
for guid_tag in self.get_guids(item):
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:
util.print_stacktrace()
logger.error(f"{'Cache | ! |' if self.Cache else 'Mapping Error:'} {item.guid:<46} | No External GUIDs found for {item.title}")
return None, None
elif item_type == "imdb": imdb_id = check_id
elif item_type == "thetvdb": tvdb_id = int(check_id)
elif item_type == "themoviedb": tmdb_id = int(check_id)
elif item_type == "hama":
if check_id.startswith("tvdb"): tvdb_id = int(re.search("-(.*)", check_id).group(1))
elif check_id.startswith("anidb"): anidb_id = re.search("-(.*)", check_id).group(1)
else: error_message = f"Hama Agent ID: {check_id} not supported"
elif item_type == "myanimelist": mal_id = check_id
elif item_type == "local": error_message = "No match in Plex"
else: error_message = f"Agent {item_type} not supported"
if not error_message:
if mal_id and not anidb_id:
try: anidb_id = self.Arms.mal_to_anidb(mal_id)
except Failed: pass
if anidb_id and not tvdb_id:
try: tvdb_id = self.Arms.anidb_to_tvdb(anidb_id)
except Failed: pass
if anidb_id and not imdb_id:
try: imdb_id = self.Arms.anidb_to_imdb(anidb_id)
except Failed: pass
if not tmdb_id and imdb_id:
if isinstance(imdb_id, list):
tmdb_id = []
new_imdb_id = []
for imdb in imdb_id:
try:
tmdb_id.append(self.TMDb.convert_imdb_to_tmdb(imdb))
new_imdb_id.append(imdb)
except Failed:
if self.Trakt:
try:
tmdb_id.append(self.Trakt.convert_imdb_to_tmdb(imdb))
new_imdb_id.append(imdb)
except Failed:
continue
else:
continue
imdb_id = new_imdb_id
else:
try: tmdb_id = self.TMDb.convert_imdb_to_tmdb(imdb_id)
except Failed: pass
if not tmdb_id and self.Trakt:
try: tmdb_id = self.Trakt.convert_imdb_to_tmdb(imdb_id)
except Failed: pass
if not tmdb_id and tvdb_id and library.is_show:
try: tmdb_id = self.TMDb.convert_tvdb_to_tmdb(tvdb_id)
except Failed: pass
if not tmdb_id and self.Trakt:
try: tmdb_id = self.Trakt.convert_tvdb_to_tmdb(tvdb_id)
except Failed: pass
if not imdb_id and tmdb_id and library.is_movie:
try: imdb_id = self.TMDb.convert_tmdb_to_imdb(tmdb_id)
except Failed: pass
if not imdb_id and self.Trakt:
try: imdb_id = self.Trakt.convert_tmdb_to_imdb(tmdb_id)
except Failed: pass
if not imdb_id and tvdb_id and library.is_show:
try: imdb_id = self.TMDb.convert_tvdb_to_imdb(tvdb_id)
except Failed: pass
if not imdb_id and self.Trakt:
try: imdb_id = self.Trakt.convert_tvdb_to_imdb(tvdb_id)
except Failed: pass
if not tvdb_id and library.is_show:
if tmdb_id:
try: tvdb_id = self.TMDb.convert_tmdb_to_tvdb(tmdb_id)
except Failed: pass
if not tvdb_id and self.Trakt:
try: tvdb_id = self.Trakt.convert_tmdb_to_tvdb(tmdb_id)
except Failed: pass
if not tvdb_id and imdb_id:
try: tvdb_id = self.TMDb.convert_imdb_to_tvdb(imdb_id)
except Failed: pass
if not tvdb_id and self.Trakt:
try: tvdb_id = self.Trakt.convert_imdb_to_tvdb(tmdb_id)
except Failed: pass
if (not tmdb_id and library.is_movie) or (not tvdb_id and not (anidb_id and tmdb_id) and library.is_show):
service_name = "TMDb ID" if library.is_movie else "TVDb ID"
if self.Trakt: api_name = "TMDb or Trakt"
else: api_name = "TMDb"
if tmdb_id and imdb_id: id_name = f"TMDb ID: {tmdb_id} or IMDb ID: {imdb_id}"
elif imdb_id and tvdb_id: id_name = f"IMDb ID: {imdb_id} or TVDb ID: {tvdb_id}"
elif tmdb_id: id_name = f"TMDb ID: {tmdb_id}"
elif imdb_id: id_name = f"IMDb ID: {imdb_id}"
elif tvdb_id: id_name = f"TVDb ID: {tvdb_id}"
else: id_name = None
if anidb_id and not tmdb_id and not tvdb_id: error_message = f"Unable to convert AniDB ID: {anidb_id} to TMDb ID or TVDb ID"
elif id_name: error_message = f"Unable to convert {id_name} to {service_name} using {api_name}"
else: error_message = f"No ID to convert to {service_name}"
if self.Cache and ((tmdb_id and library.is_movie) or ((tvdb_id or (anidb_id and tmdb_id)) and library.is_show)):
if not isinstance(tmdb_id, list): tmdb_id = [tmdb_id]
if not isinstance(imdb_id, list): imdb_id = [imdb_id]
if not isinstance(tvdb_id, list): tvdb_id = [tvdb_id]
try: tvdb_value = tvdb_id[0]
except IndexError: tvdb_value = None
for i in range(len(tmdb_id)):
try: imdb_value = imdb_id[i]
except IndexError: imdb_value = None
util.print_end(length, f"Cache | {'^' if expired is True else '+'} | {item.guid:<46} | {tmdb_id[i] if tmdb_id[i] else 'None':<6} | {imdb_value if imdb_value else 'None':<10} | {tvdb_value if tvdb_value else 'None':<6} | {anidb_id if anidb_id else 'None':<5} | {item.title}")
self.Cache.update_guid("movie" if library.is_movie else "show", item.guid, tmdb_id[i], imdb_value, tvdb_value, anidb_id, expired)
if tmdb_id and library.is_movie: return "movie", tmdb_id
elif tvdb_id and library.is_show: return "show", tvdb_id
elif anidb_id and tmdb_id: return "movie", tmdb_id
else:
util.print_end(length, f"{'Cache | ! |' if self.Cache else 'Mapping Error:'} {item.guid:<46} | {error_message} for {item.title}")
return None, None

View file

@ -1,4 +1,4 @@
import glob, logging, os, re, requests import glob, logging, os, requests
from datetime import datetime, timedelta from datetime import datetime, timedelta
from modules import util from modules import util
from modules.meta import Metadata from modules.meta import Metadata
@ -113,7 +113,7 @@ searches = [
"duration.gt", "duration.gte", "duration.lt", "duration.lte", "duration.gt", "duration.gte", "duration.lt", "duration.lte",
"user_rating.gt", "user_rating.gte", "user_rating.lt", "user_rating.lte", "user_rating.gt", "user_rating.gte", "user_rating.lt", "user_rating.lte",
"critic_rating.gt", "critic_rating.gte", "critic_rating.lt", "critic_rating.lte", "critic_rating.gt", "critic_rating.gte", "critic_rating.lt", "critic_rating.lte",
"audience_rating.gt", "audience_rating.gte", "audience_rating.lt", "audience_rating.lte"\ "audience_rating.gt", "audience_rating.gte", "audience_rating.lt", "audience_rating.lte",
"year", "year.not", "year.gt", "year.gte", "year.lt", "year.lte" "year", "year.not", "year.gt", "year.gte", "year.lt", "year.lte"
] ]
movie_only_searches = [ movie_only_searches = [
@ -398,6 +398,10 @@ class PlexAPI:
def collection_order_query(self, collection, data): def collection_order_query(self, collection, data):
collection.sortUpdate(sort=data) collection.sortUpdate(sort=data)
@retry(stop_max_attempt_number=6, wait_fixed=10000)
def get_guids(self, item):
return item.guids
@retry(stop_max_attempt_number=6, wait_fixed=10000) @retry(stop_max_attempt_number=6, wait_fixed=10000)
def edit_query(self, item, edits, advanced=False): def edit_query(self, item, edits, advanced=False):
if advanced: if advanced:
@ -790,311 +794,6 @@ class PlexAPI:
util.print_stacktrace() util.print_stacktrace()
logger.error(f"{item_type}: {name}{' Advanced' if advanced else ''} Details Update Failed") logger.error(f"{item_type}: {name}{' Advanced' if advanced else ''} Details Update Failed")
def update_metadata(self, TMDb, test):
logger.info("")
util.separator(f"{self.name} Library Metadata")
logger.info("")
if not self.metadata:
raise Failed("No metadata to edit")
for mapping_name, meta in self.metadata.items():
methods = {mm.lower(): mm for mm in meta}
if test and ("test" not in methods or meta[methods["test"]] is not True):
continue
updated = False
edits = {}
advance_edits = {}
def add_edit(name, current, group, alias, key=None, value=None, var_type="str"):
if value or name in alias:
if value or group[alias[name]]:
if key is None: key = name
if value is None: value = group[alias[name]]
try:
if var_type == "date":
final_value = util.check_date(value, name, return_string=True, plex_date=True)
elif var_type == "float":
final_value = util.check_number(value, name, number_type="float", minimum=0, maximum=10)
else:
final_value = value
if str(current) != str(final_value):
edits[f"{key}.value"] = final_value
edits[f"{key}.locked"] = 1
logger.info(f"Detail: {name} updated to {final_value}")
except Failed as ee:
logger.error(ee)
else:
logger.error(f"Metadata Error: {name} attribute is blank")
def add_advanced_edit(attr, obj, group, alias, show_library=False, new_agent=False):
key, options = advance_keys[attr]
if attr in alias:
if new_agent and self.agent not in new_plex_agents:
logger.error(f"Metadata Error: {attr} attribute only works for with the New Plex Movie Agent and New Plex TV Agent")
elif show_library and not self.is_show:
logger.error(f"Metadata Error: {attr} attribute only works for show libraries")
elif group[alias[attr]]:
method_data = str(group[alias[attr]]).lower()
if method_data not in options:
logger.error(f"Metadata Error: {group[alias[attr]]} {attr} attribute invalid")
elif getattr(obj, key) != options[method_data]:
advance_edits[key] = options[method_data]
logger.info(f"Detail: {attr} updated to {method_data}")
else:
logger.error(f"Metadata Error: {attr} attribute is blank")
def edit_tags(attr, obj, group, alias, key=None, extra=None, movie_library=False):
if key is None:
key = f"{attr}s"
if attr in alias and f"{attr}.sync" in alias:
logger.error(f"Metadata Error: Cannot use {attr} and {attr}.sync together")
elif attr in alias or f"{attr}.sync" in alias:
attr_key = attr if attr in alias else f"{attr}.sync"
if movie_library and not self.is_movie:
logger.error(f"Metadata Error: {attr_key} attribute only works for movie libraries")
elif group[alias[attr_key]] or extra:
item_tags = [item_tag.tag for item_tag in getattr(obj, key)]
input_tags = []
if group[alias[attr_key]]:
input_tags.extend(util.get_list(group[alias[attr_key]]))
if extra:
input_tags.extend(extra)
if f"{attr}.sync" in alias:
remove_method = getattr(obj, f"remove{attr.capitalize()}")
for tag in (t for t in item_tags if t not in input_tags):
updated = True
remove_method(tag)
logger.info(f"Detail: {attr.capitalize()} {tag} removed")
add_method = getattr(obj, f"add{attr.capitalize()}")
for tag in (t for t in input_tags if t not in item_tags):
updated = True
add_method(tag)
logger.info(f"Detail: {attr.capitalize()} {tag} added")
else:
logger.error(f"Metadata Error: {attr} attribute is blank")
def set_image(attr, obj, group, alias, poster=True, url=True):
if group[alias[attr]]:
message = f"{'poster' if poster else 'background'} to [{'URL' if url else 'File'}] {group[alias[attr]]}"
self.upload_image(obj, group[alias[attr]], poster=poster, url=url)
logger.info(f"Detail: {attr} updated {message}")
else:
logger.error(f"Metadata Error: {attr} attribute is blank")
def set_images(obj, group, alias):
if "url_poster" in alias:
set_image("url_poster", obj, group, alias)
elif "file_poster" in alias:
set_image("file_poster", obj, group, alias, url=False)
if "url_background" in alias:
set_image("url_background", obj, group, alias, poster=False)
elif "file_background" in alias:
set_image("file_background", obj, group, alias, poster=False, url=False)
logger.info("")
util.separator()
logger.info("")
year = None
if "year" in methods:
year = util.check_number(meta[methods["year"]], "year", minimum=1800, maximum=datetime.now().year + 1)
title = mapping_name
if "title" in methods:
if meta[methods["title"]] is None: logger.error("Metadata Error: title attribute is blank")
else: title = meta[methods["title"]]
item = self.search_item(title, year=year)
if item is None:
item = self.search_item(f"{title} (SUB)", year=year)
if item is None and "alt_title" in methods:
if meta[methods["alt_title"]] is None:
logger.error("Metadata Error: alt_title attribute is blank")
else:
alt_title = meta["alt_title"]
item = self.search_item(alt_title, year=year)
if item is None:
logger.error(f"Plex Error: Item {mapping_name} not found")
logger.error(f"Skipping {mapping_name}")
continue
item_type = "Movie" if self.is_movie else "Show"
logger.info(f"Updating {item_type}: {title}...")
tmdb_item = None
tmdb_is_movie = None
if ("tmdb_show" in methods or "tmdb_id" in methods) and "tmdb_movie" in methods:
logger.error("Metadata Error: Cannot use tmdb_movie and tmdb_show when editing the same metadata item")
if "tmdb_show" in methods or "tmdb_id" in methods or "tmdb_movie" in methods:
try:
if "tmdb_show" in methods or "tmdb_id" in methods:
data = meta[methods["tmdb_show" if "tmdb_show" in methods else "tmdb_id"]]
if data is None:
logger.error("Metadata Error: tmdb_show attribute is blank")
else:
tmdb_is_movie = False
tmdb_item = TMDb.get_show(util.regex_first_int(data, "Show"))
elif "tmdb_movie" in methods:
if meta[methods["tmdb_movie"]] is None:
logger.error("Metadata Error: tmdb_movie attribute is blank")
else:
tmdb_is_movie = True
tmdb_item = TMDb.get_movie(util.regex_first_int(meta[methods["tmdb_movie"]], "Movie"))
except Failed as e:
logger.error(e)
originally_available = None
original_title = None
rating = None
studio = None
tagline = None
summary = None
genres = []
if tmdb_item:
originally_available = tmdb_item.release_date if tmdb_is_movie else tmdb_item.first_air_date
if tmdb_item and tmdb_is_movie is True and tmdb_item.original_title != tmdb_item.title:
original_title = tmdb_item.original_title
elif tmdb_item and tmdb_is_movie is False and tmdb_item.original_name != tmdb_item.name:
original_title = tmdb_item.original_name
rating = tmdb_item.vote_average
if tmdb_is_movie is True and tmdb_item.production_companies:
studio = tmdb_item.production_companies[0].name
elif tmdb_is_movie is False and tmdb_item.networks:
studio = tmdb_item.networks[0].name
tagline = tmdb_item.tagline if len(tmdb_item.tagline) > 0 else None
summary = tmdb_item.overview
genres = [genre.name for genre in tmdb_item.genres]
edits = {}
add_edit("title", item.title, meta, methods, value=title)
add_edit("sort_title", item.titleSort, meta, methods, key="titleSort")
add_edit("originally_available", str(item.originallyAvailableAt)[:-9], meta, methods, key="originallyAvailableAt", value=originally_available, var_type="date")
add_edit("critic_rating", item.rating, meta, methods, value=rating, key="rating", var_type="float")
add_edit("audience_rating", item.audienceRating, meta, methods, key="audienceRating", var_type="float")
add_edit("content_rating", item.contentRating, meta, methods, key="contentRating")
add_edit("original_title", item.originalTitle, meta, methods, key="originalTitle", value=original_title)
add_edit("studio", item.studio, meta, methods, value=studio)
add_edit("tagline", item.tagline, meta, methods, value=tagline)
add_edit("summary", item.summary, meta, methods, value=summary)
self.edit_item(item, mapping_name, item_type, edits)
advance_edits = {}
add_advanced_edit("episode_sorting", item, meta, methods, show_library=True)
add_advanced_edit("keep_episodes", item, meta, methods, show_library=True)
add_advanced_edit("delete_episodes", item, meta, methods, show_library=True)
add_advanced_edit("season_display", item, meta, methods, show_library=True)
add_advanced_edit("episode_ordering", item, meta, methods, show_library=True)
add_advanced_edit("metadata_language", item, meta, methods, new_agent=True)
add_advanced_edit("use_original_title", item, meta, methods, new_agent=True)
self.edit_item(item, mapping_name, item_type, advance_edits, advanced=True)
edit_tags("genre", item, meta, methods, extra=genres)
edit_tags("label", item, meta, methods)
edit_tags("collection", item, meta, methods)
edit_tags("country", item, meta, methods, key="countries", movie_library=True)
edit_tags("director", item, meta, methods, movie_library=True)
edit_tags("producer", item, meta, methods, movie_library=True)
edit_tags("writer", item, meta, methods, movie_library=True)
logger.info(f"{item_type}: {mapping_name} Details Update {'Complete' if updated else 'Not Needed'}")
set_images(item, meta, methods)
if "seasons" in methods and self.is_show:
if meta[methods["seasons"]]:
for season_id in meta[methods["seasons"]]:
updated = False
logger.info("")
logger.info(f"Updating season {season_id} of {mapping_name}...")
if isinstance(season_id, int):
season = None
for s in item.seasons():
if s.index == season_id:
season = s
break
if season is None:
logger.error(f"Metadata Error: Season: {season_id} not found")
else:
season_dict = meta[methods["seasons"]][season_id]
season_methods = {sm.lower(): sm for sm in season_dict}
if "title" in season_methods and season_dict[season_methods["title"]]:
title = season_dict[season_methods["title"]]
else:
title = season.title
if "sub" in season_methods:
if season_dict[season_methods["sub"]] is None:
logger.error("Metadata Error: sub attribute is blank")
elif season_dict[season_methods["sub"]] is True and "(SUB)" not in title:
title = f"{title} (SUB)"
elif season_dict[season_methods["sub"]] is False and title.endswith(" (SUB)"):
title = title[:-6]
else:
logger.error("Metadata Error: sub attribute must be True or False")
edits = {}
add_edit("title", season.title, season_dict, season_methods, value=title)
add_edit("summary", season.summary, season_dict, season_methods)
self.edit_item(season, season_id, "Season", edits)
set_images(season, season_dict, season_methods)
else:
logger.error(f"Metadata Error: Season: {season_id} invalid, it must be an integer")
logger.info(f"Season {season_id} of {mapping_name} Details Update {'Complete' if updated else 'Not Needed'}")
else:
logger.error("Metadata Error: seasons attribute is blank")
elif "seasons" in methods:
logger.error("Metadata Error: seasons attribute only works for show libraries")
if "episodes" in methods and self.is_show:
if meta[methods["episodes"]]:
for episode_str in meta[methods["episodes"]]:
updated = False
logger.info("")
match = re.search("[Ss]\\d+[Ee]\\d+", episode_str)
if match:
output = match.group(0)[1:].split("E" if "E" in match.group(0) else "e")
season_id = int(output[0])
episode_id = int(output[1])
logger.info(f"Updating episode S{season_id}E{episode_id} of {mapping_name}...")
try: episode = item.episode(season=season_id, episode=episode_id)
except NotFound: logger.error(f"Metadata Error: episode {episode_id} of season {season_id} not found")
else:
episode_dict = meta[methods["episodes"]][episode_str]
episode_methods = {em.lower(): em for em in episode_dict}
if "title" in episode_methods and episode_dict[episode_methods["title"]]:
title = episode_dict[episode_methods["title"]]
else:
title = episode.title
if "sub" in episode_dict:
if episode_dict[episode_methods["sub"]] is None:
logger.error("Metadata Error: sub attribute is blank")
elif episode_dict[episode_methods["sub"]] is True and "(SUB)" not in title:
title = f"{title} (SUB)"
elif episode_dict[episode_methods["sub"]] is False and title.endswith(" (SUB)"):
title = title[:-6]
else:
logger.error("Metadata Error: sub attribute must be True or False")
edits = {}
add_edit("title", episode.title, episode_dict, episode_methods, value=title)
add_edit("sort_title", episode.titleSort, episode_dict, episode_methods, key="titleSort")
add_edit("rating", episode.rating, episode_dict, episode_methods)
add_edit("originally_available", str(episode.originallyAvailableAt)[:-9], episode_dict, episode_methods, key="originallyAvailableAt")
add_edit("summary", episode.summary, episode_dict, episode_methods)
self.edit_item(episode, f"{season_id} Episode: {episode_id}", "Season", edits)
edit_tags("director", episode, episode_dict, episode_methods)
edit_tags("writer", episode, episode_dict, episode_methods)
set_images(episode, episode_dict, episode_methods)
logger.info(f"Episode S{episode_id}E{season_id} of {mapping_name} Details Update {'Complete' if updated else 'Not Needed'}")
else:
logger.error(f"Metadata Error: episode {episode_str} invalid must have S##E## format")
else:
logger.error("Metadata Error: episodes attribute is blank")
elif "episodes" in methods:
logger.error("Metadata Error: episodes attribute only works for show libraries")
def update_item_from_assets(self, item, dirs=None): def update_item_from_assets(self, item, dirs=None):
if dirs is None: if dirs is None:
dirs = self.asset_directory dirs = self.asset_directory

View file

@ -109,7 +109,8 @@ discover_tv_sort = [
] ]
class TMDbAPI: class TMDbAPI:
def __init__(self, params): def __init__(self, config, params):
self.config = config
self.TMDb = tmdbv3api.TMDb() self.TMDb = tmdbv3api.TMDb()
self.TMDb.api_key = params["apikey"] self.TMDb.api_key = params["apikey"]
self.TMDb.language = params["language"] self.TMDb.language = params["language"]
@ -131,7 +132,7 @@ class TMDbAPI:
self.image_url = "https://image.tmdb.org/t/p/original" self.image_url = "https://image.tmdb.org/t/p/original"
@retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_failed) @retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_failed)
def _from_tmdb(self, tmdb_id, convert_to, is_movie): def convert_from(self, tmdb_id, convert_to, is_movie):
try: try:
id_to_return = self.Movie.external_ids(tmdb_id)[convert_to] if is_movie else self.TV.external_ids(tmdb_id)[convert_to] id_to_return = self.Movie.external_ids(tmdb_id)[convert_to] if is_movie else self.TV.external_ids(tmdb_id)[convert_to]
if not id_to_return or (convert_to == "tvdb_id" and id_to_return == 0): if not id_to_return or (convert_to == "tvdb_id" and id_to_return == 0):
@ -141,19 +142,12 @@ class TMDbAPI:
raise Failed(f"TMDb Error: {'Movie' if is_movie else 'Show'} TMDb ID: {tmdb_id} not found") raise Failed(f"TMDb Error: {'Movie' if is_movie else 'Show'} TMDb ID: {tmdb_id} not found")
@retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_failed) @retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_failed)
def _to_tmdb(self, external_id, external_source, is_movie): def convert_to(self, external_id, external_source, is_movie):
search_results = self.Movie.external(external_id=external_id, external_source=external_source) search_results = self.Movie.external(external_id=external_id, external_source=external_source)
search = search_results["movie_results" if is_movie else "tv_results"] search = search_results["movie_results" if is_movie else "tv_results"]
if len(search) == 1: return int(search[0]["id"]) if len(search) == 1: return int(search[0]["id"])
else: raise Failed(f"TMDb Error: No TMDb ID found for {external_source.upper().replace('B_', 'b ')} {external_id}") else: raise Failed(f"TMDb Error: No TMDb ID found for {external_source.upper().replace('B_', 'b ')} {external_id}")
def convert_tmdb_to_imdb(self, tmdb_id, is_movie=True): return self._from_tmdb(tmdb_id, "imdb_id", is_movie)
def convert_imdb_to_tmdb(self, imdb_id, is_movie=True): return self._to_tmdb(imdb_id, "imdb_id", is_movie)
def convert_tmdb_to_tvdb(self, tmdb_id): return self._from_tmdb(tmdb_id, "tvdb_id", False)
def convert_tvdb_to_tmdb(self, tvdb_id): return self._to_tmdb(tvdb_id, "tvdb_id", False)
def convert_tvdb_to_imdb(self, tvdb_id): return self.convert_tmdb_to_imdb(self.convert_tvdb_to_tmdb(tvdb_id), False)
def convert_imdb_to_tvdb(self, imdb_id): return self.convert_tmdb_to_tvdb(self.convert_imdb_to_tmdb(imdb_id, False))
def get_movie_show_or_collection(self, tmdb_id, is_movie): def get_movie_show_or_collection(self, tmdb_id, is_movie):
if is_movie: if is_movie:
try: return self.get_collection(tmdb_id) try: return self.get_collection(tmdb_id)
@ -217,7 +211,7 @@ class TMDbAPI:
movie_ids.append(credit.id) movie_ids.append(credit.id)
elif credit.media_type == "tv": elif credit.media_type == "tv":
try: try:
show_ids.append(self.convert_tmdb_to_tvdb(credit.id)) show_ids.append(self.config.Arms.convert_tmdb_to_tvdb(credit.id))
except Failed as e: except Failed as e:
logger.warning(e) logger.warning(e)
for credit in actor_credits.crew: for credit in actor_credits.crew:
@ -229,7 +223,7 @@ class TMDbAPI:
movie_ids.append(credit.id) movie_ids.append(credit.id)
elif credit.media_type == "tv": elif credit.media_type == "tv":
try: try:
show_ids.append(self.convert_tmdb_to_tvdb(credit.id)) show_ids.append(self.config.Arms.convert_tmdb_to_tvdb(credit.id))
except Failed as e: except Failed as e:
logger.warning(e) logger.warning(e)
return movie_ids, show_ids return movie_ids, show_ids
@ -246,7 +240,7 @@ class TMDbAPI:
else: raise Failed(f"TMDb Error: {method} method not supported") else: raise Failed(f"TMDb Error: {method} method not supported")
for tmdb_item in tmdb_items: for tmdb_item in tmdb_items:
try: try:
ids.append(tmdb_item.id if is_movie else self.convert_tmdb_to_tvdb(tmdb_item.id)) ids.append(tmdb_item.id if is_movie else self.config.Arms.convert_tmdb_to_tvdb(tmdb_item.id))
count += 1 count += 1
except Failed: except Failed:
pass pass
@ -269,7 +263,7 @@ class TMDbAPI:
tmdb_items = self.Discover.discover_movies(attrs) if is_movie else self.Discover.discover_tv_shows(attrs) tmdb_items = self.Discover.discover_movies(attrs) if is_movie else self.Discover.discover_tv_shows(attrs)
for tmdb_item in tmdb_items: for tmdb_item in tmdb_items:
try: try:
ids.append(tmdb_item.id if is_movie else self.convert_tmdb_to_tvdb(tmdb_item.id)) ids.append(tmdb_item.id if is_movie else self.config.Arms.convert_tmdb_to_tvdb(tmdb_item.id))
count += 1 count += 1
except Failed as e: except Failed as e:
logger.error(e) logger.error(e)
@ -345,7 +339,7 @@ class TMDbAPI:
if tmdb_item.media_type == "movie": if tmdb_item.media_type == "movie":
movie_ids.append(tmdb_item.id) movie_ids.append(tmdb_item.id)
elif tmdb_item.media_type == "tv": elif tmdb_item.media_type == "tv":
try: show_ids.append(self.convert_tmdb_to_tvdb(tmdb_item.id)) try: show_ids.append(self.config.Arms.convert_tmdb_to_tvdb(tmdb_item.id))
except Failed: pass except Failed: pass
elif method == "tmdb_movie": elif method == "tmdb_movie":
tmdb_name = str(self.get_movie(tmdb_id).title) tmdb_name = str(self.get_movie(tmdb_id).title)
@ -357,7 +351,7 @@ class TMDbAPI:
movie_ids.append(tmdb_item["id"]) movie_ids.append(tmdb_item["id"])
elif method == "tmdb_show": elif method == "tmdb_show":
tmdb_name = str(self.get_show(tmdb_id).name) tmdb_name = str(self.get_show(tmdb_id).name)
show_ids.append(self.convert_tmdb_to_tvdb(tmdb_id)) show_ids.append(self.config.Arms.convert_tmdb_to_tvdb(tmdb_id))
else: else:
tmdb_name = str(self.get_person(tmdb_id).name) tmdb_name = str(self.get_person(tmdb_id).name)
if method == "tmdb_actor": movie_ids, show_ids = self._credits(tmdb_id, actor=True) if method == "tmdb_actor": movie_ids, show_ids = self._credits(tmdb_id, actor=True)

View file

@ -90,15 +90,8 @@ class TraktAPI:
return True return True
return False return False
def convert_tmdb_to_imdb(self, tmdb_id, is_movie=True): return self._convert(tmdb_id, "tmdb", "imdb", "movie" if is_movie else "show")
def convert_imdb_to_tmdb(self, imdb_id, is_movie=True): return self._convert(imdb_id, "imdb", "tmdb", "movie" if is_movie else "show")
def convert_tmdb_to_tvdb(self, tmdb_id): return self._convert(tmdb_id, "tmdb", "tvdb", "show")
def convert_tvdb_to_tmdb(self, tvdb_id): return self._convert(tvdb_id, "tvdb", "tmdb", "show")
def convert_tvdb_to_imdb(self, tvdb_id): return self._convert(tvdb_id, "tvdb", "imdb", "show")
def convert_imdb_to_tvdb(self, imdb_id): return self._convert(imdb_id, "imdb", "tvdb", "show")
@retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_failed) @retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_failed)
def _convert(self, external_id, from_source, to_source, media_type): def convert(self, external_id, from_source, to_source, media_type):
lookup = Trakt["search"].lookup(external_id, from_source, media_type) lookup = Trakt["search"].lookup(external_id, from_source, media_type)
if lookup: if lookup:
lookup = lookup[0] if isinstance(lookup, list) else lookup lookup = lookup[0] if isinstance(lookup, list) else lookup