#365 added collection_level

pull/368/head
meisnate12 3 years ago
parent ddc81cde11
commit ec0b1ba329

@ -4,7 +4,7 @@ from modules import anidb, anilist, icheckmovies, imdb, letterboxd, mal, plex, r
from modules.util import Failed, ImageData from modules.util import Failed, ImageData
from PIL import Image from PIL import Image
from plexapi.exceptions import BadRequest, NotFound from plexapi.exceptions import BadRequest, NotFound
from plexapi.video import Movie, Show from plexapi.video import Movie, Show, Season, Episode
from urllib.parse import quote from urllib.parse import quote
logger = logging.getLogger("Plex Meta Manager") logger = logging.getLogger("Plex Meta Manager")
@ -64,7 +64,7 @@ filter_translation = {
modifier_alias = {".greater": ".gt", ".less": ".lt"} modifier_alias = {".greater": ".gt", ".less": ".lt"}
all_builders = anidb.builders + anilist.builders + icheckmovies.builders + imdb.builders + letterboxd.builders + \ all_builders = anidb.builders + anilist.builders + icheckmovies.builders + imdb.builders + letterboxd.builders + \
mal.builders + plex.builders + stevenlu.builders + tautulli.builders + tmdb.builders + trakt.builders + tvdb.builders mal.builders + plex.builders + stevenlu.builders + tautulli.builders + tmdb.builders + trakt.builders + tvdb.builders
show_only_builders = ["tmdb_network", "tmdb_show", "tmdb_show_details", "tvdb_show", "tvdb_show_details"] show_only_builders = ["tmdb_network", "tmdb_show", "tmdb_show_details", "tvdb_show", "tvdb_show_details", "collection_level"]
movie_only_builders = [ movie_only_builders = [
"letterboxd_list", "letterboxd_list_details", "icheckmovies_list", "icheckmovies_list_details", "stevenlu_popular", "letterboxd_list", "letterboxd_list_details", "icheckmovies_list", "icheckmovies_list_details", "stevenlu_popular",
"tmdb_collection", "tmdb_collection_details", "tmdb_movie", "tmdb_movie_details", "tmdb_now_playing", "tmdb_collection", "tmdb_collection_details", "tmdb_movie", "tmdb_movie_details", "tmdb_now_playing",
@ -78,13 +78,19 @@ poster_details = ["url_poster", "tmdb_poster", "tmdb_profile", "tvdb_poster", "f
background_details = ["url_background", "tmdb_background", "tvdb_background", "file_background"] background_details = ["url_background", "tmdb_background", "tvdb_background", "file_background"]
boolean_details = ["visible_library", "visible_home", "visible_shared", "show_filtered", "show_missing", "save_missing", "item_assets", "missing_only_released"] boolean_details = ["visible_library", "visible_home", "visible_shared", "show_filtered", "show_missing", "save_missing", "item_assets", "missing_only_released"]
string_details = ["sort_title", "content_rating", "name_mapping"] string_details = ["sort_title", "content_rating", "name_mapping"]
ignored_details = ["smart_filter", "smart_label", "smart_url", "run_again", "schedule", "sync_mode", "template", "test", "tmdb_person", "build_collection", "collection_order", "validate_builders"] ignored_details = [
details = ["collection_mode", "collection_order", "label"] + boolean_details + string_details "smart_filter", "smart_label", "smart_url", "run_again", "schedule", "sync_mode", "template", "test",
"tmdb_person", "build_collection", "collection_order", "collection_level", "validate_builders"
]
details = ["collection_mode", "collection_order", "collection_level", "label"] + boolean_details + string_details
collectionless_details = ["collection_order", "plex_collectionless", "label", "label_sync_mode", "test"] + \ collectionless_details = ["collection_order", "plex_collectionless", "label", "label_sync_mode", "test"] + \
poster_details + background_details + summary_details + string_details poster_details + background_details + summary_details + string_details
item_details = ["item_label", "item_radarr_tag", "item_sonarr_tag", "item_overlay"] + list(plex.item_advance_keys.keys()) item_details = ["item_label", "item_radarr_tag", "item_sonarr_tag", "item_overlay"] + list(plex.item_advance_keys.keys())
radarr_details = ["radarr_add", "radarr_add_existing", "radarr_folder", "radarr_monitor", "radarr_search", "radarr_availability", "radarr_quality", "radarr_tag"] radarr_details = ["radarr_add", "radarr_add_existing", "radarr_folder", "radarr_monitor", "radarr_search", "radarr_availability", "radarr_quality", "radarr_tag"]
sonarr_details = ["sonarr_add", "sonarr_add_existing", "sonarr_folder", "sonarr_monitor", "sonarr_language", "sonarr_series", "sonarr_quality", "sonarr_season", "sonarr_search", "sonarr_cutoff_search", "sonarr_tag"] sonarr_details = [
"sonarr_add", "sonarr_add_existing", "sonarr_folder", "sonarr_monitor", "sonarr_language", "sonarr_series",
"sonarr_quality", "sonarr_season", "sonarr_search", "sonarr_cutoff_search", "sonarr_tag"
]
all_filters = [ all_filters = [
"actor", "actor.not", "actor", "actor.not",
"audio_language", "audio_language.not", "audio_language", "audio_language.not",
@ -130,7 +136,7 @@ movie_only_filters = [
"writer", "writer.not" "writer", "writer.not"
] ]
show_only_filters = ["first_episode_aired", "last_episode_aired", "network"] show_only_filters = ["first_episode_aired", "last_episode_aired", "network"]
smart_invalid = ["collection_order"] smart_invalid = ["collection_order", "collection_level"]
smart_url_invalid = ["filters", "run_again", "sync_mode", "show_filtered", "show_missing", "save_missing", "smart_label"] + radarr_details + sonarr_details smart_url_invalid = ["filters", "run_again", "sync_mode", "show_filtered", "show_missing", "save_missing", "smart_label"] + radarr_details + sonarr_details
custom_sort_builders = [ custom_sort_builders = [
"tmdb_list", "tmdb_popular", "tmdb_now_playing", "tmdb_top_rated", "tmdb_list", "tmdb_popular", "tmdb_now_playing", "tmdb_top_rated",
@ -142,6 +148,10 @@ custom_sort_builders = [
"mal_all", "mal_airing", "mal_upcoming", "mal_tv", "mal_movie", "mal_ova", "mal_special", "mal_all", "mal_airing", "mal_upcoming", "mal_tv", "mal_movie", "mal_ova", "mal_special",
"mal_popular", "mal_favorite", "mal_suggested", "mal_userlist", "mal_season", "mal_genre", "mal_studio" "mal_popular", "mal_favorite", "mal_suggested", "mal_userlist", "mal_season", "mal_genre", "mal_studio"
] ]
parts_collection_valid = [
"plex_search", "trakt_list", "trakt_list_details", "collection_mode", "label", "visible_library",
"visible_home", "visible_shared", "show_missing", "save_missing", "missing_only_released"
] + summary_details + poster_details + background_details + string_details
class CollectionBuilder: class CollectionBuilder:
def __init__(self, config, library, metadata, name, no_missing, data): def __init__(self, config, library, metadata, name, no_missing, data):
@ -165,6 +175,7 @@ class CollectionBuilder:
self.sonarr_details = {} self.sonarr_details = {}
self.missing_movies = [] self.missing_movies = []
self.missing_shows = [] self.missing_shows = []
self.missing_parts = []
self.builders = [] self.builders = []
self.filters = [] self.filters = []
self.tmdb_filters = [] self.tmdb_filters = []
@ -411,6 +422,21 @@ class CollectionBuilder:
else: else:
raise Failed(f"Collection Error: {self.data[methods['collection_order']]} collection_order invalid\n\trelease (Order Collection by release dates)\n\talpha (Order Collection Alphabetically)\n\tcustom (Custom Order Collection)") raise Failed(f"Collection Error: {self.data[methods['collection_order']]} collection_order invalid\n\trelease (Order Collection by release dates)\n\talpha (Order Collection Alphabetically)\n\tcustom (Custom Order Collection)")
self.collection_level = "movie" if self.library.is_movie else "show"
if "collection_level" in methods:
logger.debug("")
logger.debug("Validating Method: collection_level")
if self.data[methods["collection_level"]] is None:
raise Failed(f"Collection Warning: collection_level attribute is blank")
else:
logger.debug(f"Value: {self.data[methods['collection_level']]}")
if self.data[methods["collection_level"]].lower() in plex.collection_level_options:
self.collection_level = self.data[methods["collection_level"]].lower()
else:
raise Failed(f"Collection Error: {self.data[methods['collection_level']]} collection_level invalid\n\tseason (Collection at the Season Level)\n\tepisode (Collection at the Episode Level)")
self.parts_collection = self.collection_level in ["season", "episode"]
self.media_type = self.collection_level.capitalize()
if "tmdb_person" in methods: if "tmdb_person" in methods:
logger.debug("") logger.debug("")
logger.debug("Validating Method: tmdb_person") logger.debug("Validating Method: tmdb_person")
@ -479,6 +505,8 @@ class CollectionBuilder:
cant_interact("smart_url", "collectionless") cant_interact("smart_url", "collectionless")
cant_interact("smart_url", "run_again") cant_interact("smart_url", "run_again")
cant_interact("smart_label_collection", "smart_url", fail=True) cant_interact("smart_label_collection", "smart_url", fail=True)
cant_interact("smart_label_collection", "parts_collection", fail=True)
cant_interact("smart_url", "parts_collection", fail=True)
self.smart = self.smart_url or self.smart_label_collection self.smart = self.smart_url or self.smart_label_collection
@ -501,6 +529,7 @@ class CollectionBuilder:
elif self.library.is_show and method_name in movie_only_builders: raise Failed(f"Collection Error: {method_final} attribute only works for movie libraries") elif self.library.is_show and method_name in movie_only_builders: raise Failed(f"Collection Error: {method_final} attribute only works for movie libraries")
elif self.library.is_show and method_name in plex.movie_only_searches: raise Failed(f"Collection Error: {method_final} plex search only works for movie libraries") elif self.library.is_show and method_name in plex.movie_only_searches: raise Failed(f"Collection Error: {method_final} plex search only works for movie libraries")
elif self.library.is_movie and method_name in plex.show_only_searches: raise Failed(f"Collection Error: {method_final} plex search only works for show libraries") elif self.library.is_movie and method_name in plex.show_only_searches: raise Failed(f"Collection Error: {method_final} plex search only works for show libraries")
elif self.parts_collection and method_name not in parts_collection_valid: raise Failed(f"Collection Error: {method_final} attribute does not work with Collection Level: {self.details['collection_level'].capitalize()}")
elif self.smart and method_name in smart_invalid: raise Failed(f"Collection Error: {method_final} attribute only works with normal collections") elif self.smart and method_name in smart_invalid: raise Failed(f"Collection Error: {method_final} attribute only works with normal collections")
elif self.collectionless and method_name not in collectionless_details: raise Failed(f"Collection Error: {method_final} attribute does not work for Collectionless collection") elif self.collectionless and method_name not in collectionless_details: raise Failed(f"Collection Error: {method_final} attribute does not work for Collectionless collection")
elif self.smart_url and method_name in all_builders + smart_url_invalid: raise Failed(f"Collection Error: {method_final} builder not allowed when using smart_filter") elif self.smart_url and method_name in all_builders + smart_url_invalid: raise Failed(f"Collection Error: {method_final} builder not allowed when using smart_filter")
@ -869,7 +898,8 @@ class CollectionBuilder:
for dict_data, dict_methods in util.parse(method_name, method_data, datatype="dictlist"): for dict_data, dict_methods in util.parse(method_name, method_data, datatype="dictlist"):
new_dictionary = {} new_dictionary = {}
if method_name == "plex_search": if method_name == "plex_search":
new_dictionary = self.build_filter("plex_search", dict_data) type_override = f"{self.collection_level}s" if self.collection_level in plex.collection_level_options else None
new_dictionary = self.build_filter("plex_search", dict_data, type_override=type_override)
elif method_name == "plex_collectionless": elif method_name == "plex_collectionless":
prefix_list = util.parse("exclude_prefix", dict_data, datatype="list", methods=dict_methods) prefix_list = util.parse("exclude_prefix", dict_data, datatype="list", methods=dict_methods)
exact_list = util.parse("exclude", dict_data, datatype="list", methods=dict_methods) exact_list = util.parse("exclude", dict_data, datatype="list", methods=dict_methods)
@ -1070,12 +1100,12 @@ class CollectionBuilder:
for i, input_data in enumerate(ids, 1): for i, input_data in enumerate(ids, 1):
input_id, id_type = input_data input_id, id_type = input_data
util.print_return(f"Parsing ID {i}/{total_ids}") util.print_return(f"Parsing ID {i}/{total_ids}")
if id_type == "tmdb": if id_type == "tmdb" and not self.parts_collection:
if input_id in self.library.movie_map: if input_id in self.library.movie_map:
rating_keys.append(self.library.movie_map[input_id][0]) rating_keys.append(self.library.movie_map[input_id][0])
elif input_id not in self.missing_movies: elif input_id not in self.missing_movies:
self.missing_movies.append(input_id) self.missing_movies.append(input_id)
elif id_type in ["tvdb", "tmdb_show"]: elif id_type in ["tvdb", "tmdb_show"] and not self.parts_collection:
if id_type == "tmdb_show": if id_type == "tmdb_show":
try: try:
input_id = self.config.Convert.tmdb_to_tvdb(input_id, fail=True) input_id = self.config.Convert.tmdb_to_tvdb(input_id, fail=True)
@ -1086,7 +1116,7 @@ class CollectionBuilder:
rating_keys.append(self.library.show_map[input_id][0]) rating_keys.append(self.library.show_map[input_id][0])
elif input_id not in self.missing_shows: elif input_id not in self.missing_shows:
self.missing_shows.append(input_id) self.missing_shows.append(input_id)
elif id_type == "imdb": elif id_type == "imdb" and not self.parts_collection:
if input_id in self.library.imdb_map: if input_id in self.library.imdb_map:
rating_keys.append(self.library.imdb_map[input_id][0]) rating_keys.append(self.library.imdb_map[input_id][0])
else: else:
@ -1103,6 +1133,28 @@ class CollectionBuilder:
except Failed as e: except Failed as e:
logger.error(e) logger.error(e)
continue continue
elif id_type == "tvdb_season" and self.collection_level == "season":
show_id, season_num = input_id.split("_")
if int(show_id) in self.library.show_map:
show_item = self.library.fetchItem(self.library.show_map[int(show_id)][0])
try:
episode_item = show_item.season(season=int(season_num))
rating_keys.append(episode_item.ratingKey)
except NotFound:
self.missing_parts.append(f"{show_item.title} Season: {season_num} Missing")
elif int(show_id) not in self.missing_shows:
self.missing_shows.append(int(show_id))
elif id_type == "tvdb_episode" and self.collection_level == "episode":
show_id, season_num, episode_num = input_id.split("_")
if int(show_id) in self.library.show_map:
show_item = self.library.fetchItem(self.library.show_map[int(show_id)][0])
try:
episode_item = show_item.episode(season=int(season_num), episode=int(episode_num))
rating_keys.append(episode_item.ratingKey)
except NotFound:
self.missing_parts.append(f"{show_item.title} Season: {season_num} Episode: {episode_num} Missing")
elif int(show_id) not in self.missing_shows:
self.missing_shows.append(int(show_id))
util.print_end() util.print_end()
if len(rating_keys) > 0: if len(rating_keys) > 0:
@ -1125,7 +1177,7 @@ class CollectionBuilder:
except Failed as e: except Failed as e:
logger.error(e) logger.error(e)
continue continue
current_title = f"{current.title} ({current.year})" if current.year else current.title current_title = self.item_title(current)
if self.check_filters(current, f"{(' ' * (max_length - len(str(i))))}{i}/{total}"): if self.check_filters(current, f"{(' ' * (max_length - len(str(i))))}{i}/{total}"):
self.rating_keys.append(key) self.rating_keys.append(key)
else: else:
@ -1133,7 +1185,7 @@ class CollectionBuilder:
if self.details["show_filtered"] is True: if self.details["show_filtered"] is True:
logger.info(f"{name} Collection | X | {current_title}") logger.info(f"{name} Collection | X | {current_title}")
def build_filter(self, method, plex_filter, smart=False): def build_filter(self, method, plex_filter, smart=False, type_override=None):
if smart: if smart:
logger.info("") logger.info("")
logger.info(f"Validating Method: {method}") logger.info(f"Validating Method: {method}")
@ -1149,7 +1201,9 @@ class CollectionBuilder:
if "any" in filter_alias and "all" in filter_alias: if "any" in filter_alias and "all" in filter_alias:
raise Failed(f"Collection Error: Cannot have more then one base") raise Failed(f"Collection Error: Cannot have more then one base")
if smart and "type" in filter_alias and self.library.is_show: if type_override:
sort_type = type_override
elif smart and "type" in filter_alias and self.library.is_show:
if plex_filter[filter_alias["type"]] not in ["shows", "seasons", "episodes"]: if plex_filter[filter_alias["type"]] not in ["shows", "seasons", "episodes"]:
raise Failed(f"Collection Error: type: {plex_filter[filter_alias['type']]} is invalid, must be either shows, season, or episodes") raise Failed(f"Collection Error: type: {plex_filter[filter_alias['type']]} is invalid, must be either shows, season, or episodes")
sort_type = plex_filter[filter_alias["type"]] sort_type = plex_filter[filter_alias["type"]]
@ -1388,8 +1442,8 @@ class CollectionBuilder:
def fetch_item(self, item): def fetch_item(self, item):
try: try:
current = self.library.fetchItem(item.ratingKey if isinstance(item, (Movie, Show)) else int(item)) current = self.library.fetchItem(item.ratingKey if isinstance(item, (Movie, Show, Season, Episode)) else int(item))
if not isinstance(current, (Movie, Show)): if not isinstance(current, (Movie, Show, Season, Episode)):
raise NotFound raise NotFound
return current return current
except (BadRequest, NotFound): except (BadRequest, NotFound):
@ -1404,19 +1458,17 @@ class CollectionBuilder:
except Failed as e: except Failed as e:
logger.error(e) logger.error(e)
continue continue
current_title = f"{current.title} ({current.year})" if current.year else current.title
current_operation = "=" if current in collection_items else "+" current_operation = "=" if current in collection_items else "+"
logger.info(util.adjust_space(f"{name} Collection | {current_operation} | {current_title}")) logger.info(util.adjust_space(f"{name} Collection | {current_operation} | {self.item_title(current)}"))
if current in collection_items: if current in collection_items:
self.plex_map[current.ratingKey] = None self.plex_map[current.ratingKey] = None
elif self.smart_label_collection: elif self.smart_label_collection:
self.library.query_data(current.addLabel, name) self.library.query_data(current.addLabel, name)
else: else:
self.library.query_data(current.addCollection, name) self.library.query_data(current.addCollection, name)
media_type = f"{'Movie' if self.library.is_movie else 'Show'}{'s' if total > 1 else ''}"
util.print_end() util.print_end()
logger.info("") logger.info("")
logger.info(f"{total} {media_type} Processed") logger.info(f"{total} {self.collection_level.capitalize()}{'s' if total > 1 else ''} Processed")
def check_tmdb_filter(self, item_id, is_movie, item=None, check_released=False): def check_tmdb_filter(self, item_id, is_movie, item=None, check_released=False):
if self.tmdb_filters or check_released: if self.tmdb_filters or check_released:
@ -1610,6 +1662,26 @@ class CollectionBuilder:
logger.error(e) logger.error(e)
if self.run_again: if self.run_again:
self.run_again_shows.extend(missing_tvdb_ids) self.run_again_shows.extend(missing_tvdb_ids)
if len(self.missing_parts) > 0 and self.library.is_show and self.details["save_missing"] is True:
for missing in self.missing_parts:
logger.info(f"{self.name} Collection | X | {missing}")
def item_title(self, item):
if self.collection_level == "season":
if f"Season {item.index}" == item.title:
return f"{item.parentTitle} {item.title}"
else:
return f"{item.parentTitle} Season {item.index}: {item.title}"
elif self.collection_level == "episode":
text = f"{item.grandparentTitle} S{util.add_zero(item.parentIndex)}E{util.add_zero(item.index)}"
if f"Season {item.parentIndex}" == item.parentTitle:
return f"{text}: {item.title}"
else:
return f"{text}: {item.parentTitle}: {item.title}"
elif self.collection_level == "movie" and item.year:
return f"{item.title} ({item.year})"
else:
return item.title
def sync_collection(self): def sync_collection(self):
count_removed = 0 count_removed = 0
@ -1620,7 +1692,7 @@ class CollectionBuilder:
util.separator(f"Removed from {self.name} Collection", space=False, border=False) util.separator(f"Removed from {self.name} Collection", space=False, border=False)
logger.info("") logger.info("")
self.library.reload(item) self.library.reload(item)
logger.info(f"{self.name} Collection | - | {item.title}") logger.info(f"{self.name} Collection | - | {self.item_title(item)}")
if self.smart_label_collection: if self.smart_label_collection:
self.library.query_data(item.removeLabel, self.name) self.library.query_data(item.removeLabel, self.name)
else: else:
@ -1628,7 +1700,7 @@ class CollectionBuilder:
count_removed += 1 count_removed += 1
if count_removed > 0: if count_removed > 0:
logger.info("") logger.info("")
logger.info(f"{count_removed} {'Movie' if self.library.is_movie else 'Show'}{'s' if count_removed == 1 else ''} Removed") logger.info(f"{count_removed} {self.collection_level.capitalize()}{'s' if count_removed == 1 else ''} Removed")
def update_item_details(self): def update_item_details(self):
add_tags = self.item_details["item_label"] if "item_label" in self.item_details else None add_tags = self.item_details["item_label"] if "item_label" in self.item_details else None
@ -1697,7 +1769,7 @@ class CollectionBuilder:
key, options = plex.item_advance_keys[method_name] key, options = plex.item_advance_keys[method_name]
if getattr(item, key) != options[method_data]: if getattr(item, key) != options[method_data]:
advance_edits[key] = options[method_data] advance_edits[key] = options[method_data]
self.library.edit_item(item, item.title, "Movie" if self.library.is_movie else "Show", advance_edits, advanced=True) self.library.edit_item(item, item.title, self.collection_level.capitalize(), advance_edits, advanced=True)
if len(tmdb_ids) > 0: if len(tmdb_ids) > 0:
if "item_radarr_tag" in self.item_details: if "item_radarr_tag" in self.item_details:
@ -1890,7 +1962,8 @@ class CollectionBuilder:
logger.debug(keys) logger.debug(keys)
logger.debug(self.rating_keys) logger.debug(self.rating_keys)
for key in self.rating_keys: for key in self.rating_keys:
logger.info(f"Moving {keys[key].title} {'after {}'.format(keys[previous].title) if previous else 'to the beginning'}") text = f"after {self.item_title(keys[previous])}" if previous else "to the beginning"
logger.info(f"Moving {self.item_title(keys[key])} {text}")
self.library.move_item(self.obj, key, after=previous) self.library.move_item(self.obj, key, after=previous)
previous = key previous = key
@ -1912,13 +1985,12 @@ class CollectionBuilder:
except (BadRequest, NotFound): except (BadRequest, NotFound):
logger.error(f"Plex Error: Item {rating_key} not found") logger.error(f"Plex Error: Item {rating_key} not found")
continue continue
current_title = f"{current.title} ({current.year})" if current.year else current.title
if current in collection_items: if current in collection_items:
logger.info(f"{name} Collection | = | {current_title}") logger.info(f"{name} Collection | = | {self.item_title(current)}")
else: else:
self.library.query_data(current.addLabel if self.smart_label_collection else current.addCollection, name) self.library.query_data(current.addLabel if self.smart_label_collection else current.addCollection, name)
logger.info(f"{name} Collection | + | {current_title}") logger.info(f"{name} Collection | + | {self.item_title(current)}")
logger.info(f"{len(rating_keys)} {'Movie' if self.library.is_movie else 'Show'}{'s' if len(rating_keys) > 1 else ''} Processed") logger.info(f"{len(rating_keys)} {self.collection_level.capitalize()}{'s' if len(rating_keys) > 1 else ''} Processed")
if len(self.run_again_movies) > 0: if len(self.run_again_movies) > 0:
logger.info("") logger.info("")

@ -61,6 +61,7 @@ collection_mode_options = {
"show_items": "showItems", "showitems": "showItems" "show_items": "showItems", "showitems": "showItems"
} }
collection_order_options = ["release", "alpha", "custom"] collection_order_options = ["release", "alpha", "custom"]
collection_level_options = ["episode", "season"]
collection_mode_keys = {-1: "default", 0: "hide", 1: "hideItems", 2: "showItems"} collection_mode_keys = {-1: "default", 0: "hide", 1: "hideItems", 2: "showItems"}
collection_order_keys = {0: "release", 1: "alpha", 2: "custom"} collection_order_keys = {0: "release", 1: "alpha", 2: "custom"}
item_advance_keys = { item_advance_keys = {
@ -395,10 +396,6 @@ class Plex:
@retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_plex) @retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_plex)
def _upload_image(self, item, image): def _upload_image(self, item, image):
logger.debug(item)
logger.debug(image.is_poster)
logger.debug(image.is_url)
logger.debug(image.location)
if image.is_poster and image.is_url: if image.is_poster and image.is_url:
item.uploadPoster(url=image.location) item.uploadPoster(url=image.location)
elif image.is_poster: elif image.is_poster:
@ -411,8 +408,6 @@ class Plex:
@retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_plex) @retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_plex)
def upload_file_poster(self, item, image): def upload_file_poster(self, item, image):
logger.debug(item)
logger.debug(image)
item.uploadPoster(filepath=image) item.uploadPoster(filepath=image)
self.reload(item) self.reload(item)

@ -16,6 +16,7 @@ sorts = [
"rank", "added", "title", "released", "runtime", "popularity", "rank", "added", "title", "released", "runtime", "popularity",
"percentage", "votes", "random", "my_rating", "watched", "collected" "percentage", "votes", "random", "my_rating", "watched", "collected"
] ]
id_translation = {"movie": "tmdb", "show": "tvdb", "season": "TVDb Season", "episode": "TVDb Episode"}
class Trakt: class Trakt:
def __init__(self, config, params): def __init__(self, config, params):
@ -142,26 +143,31 @@ class Trakt:
except Failed: except Failed:
raise Failed(f"Trakt Error: List {data} not found") raise Failed(f"Trakt Error: List {data} not found")
def _parse(self, items, top=True, item_type=None): def _parse(self, items, typeless=False, item_type=None):
ids = [] ids = []
for item in items: for item in items:
if top: if typeless:
if item_type: data = item
current_type = None
elif item_type:
data = item[item_type] data = item[item_type]
elif item["type"] in ["movie", "show"]: current_type = item_type
data = item[item["type"]] elif "type" in item and item["type"] in id_translation:
data = item["movie" if item["type"] == "movie" else "show"]
current_type = item["type"]
else: else:
continue continue
id_type = "tmdb" if item["type"] == "movie" else "tvdb"
if data["ids"][id_type]:
final_id = data["ids"][id_type]
if current_type == "episode":
final_id = f"{final_id}_{item[current_type]['season']}"
if current_type in ["episode", "season"]:
final_id = f"{final_id}_{item[current_type]['number']}"
final_type = f"{id_type}_{current_type}" if current_type in ["episode", "season"] else id_type
ids.append((final_id, final_type))
else: else:
data = item logger.error(f"Trakt Error: No {id_type.upper().replace('B', 'b')} ID found for {data['title']} ({data['year']})")
if item_type:
id_type = "TMDb" if item_type == "movie" else "TVDb"
else:
id_type = "TMDb" if item["type"] == "movie" else "TVDb"
if data["ids"][id_type.lower()]:
ids.append((data["ids"][id_type.lower()], id_type.lower()))
else:
logger.error(f"Trakt Error: No {id_type} ID found for {data['title']} ({data['year']})")
return ids return ids
def _user_list(self, data): def _user_list(self, data):
@ -184,7 +190,7 @@ class Trakt:
def _pagenation(self, pagenation, amount, is_movie): def _pagenation(self, pagenation, amount, is_movie):
items = self._request(f"/{'movies' if is_movie else 'shows'}/{pagenation}?limit={amount}") items = self._request(f"/{'movies' if is_movie else 'shows'}/{pagenation}?limit={amount}")
return self._parse(items, top=pagenation != "popular", item_type="movie" if is_movie else "show") return self._parse(items, typeless=pagenation == "popular", item_type="movie" if is_movie else "show")
def validate_trakt(self, trakt_lists, is_movie, trakt_type="list"): def validate_trakt(self, trakt_lists, is_movie, trakt_type="list"):
values = util.get_list(trakt_lists, split=False) values = util.get_list(trakt_lists, split=False)

@ -66,6 +66,9 @@ def tab_new_lines(data):
def make_ordinal(n): def make_ordinal(n):
return f"{n}{'th' if 11 <= (n % 100) <= 13 else ['th', 'st', 'nd', 'rd', 'th'][min(n % 10, 4)]}" return f"{n}{'th' if 11 <= (n % 100) <= 13 else ['th', 'st', 'nd', 'rd', 'th'][min(n % 10, 4)]}"
def add_zero(number):
return str(number) if len(str(number)) > 1 else f"0{number}"
def add_dict_list(keys, value, dict_map): def add_dict_list(keys, value, dict_map):
for key in keys: for key in keys:
if key in dict_map: if key in dict_map:

Loading…
Cancel
Save