From 203f0e6cf565d2dd52804cdd0a6a1a6adfc12df9 Mon Sep 17 00:00:00 2001 From: meisnate12 Date: Fri, 5 Nov 2021 23:54:12 -0400 Subject: [PATCH] add operations --- config/config.yml.template | 10 +- modules/config.py | 80 +++++---- modules/library.py | 3 - modules/tvdb.py | 34 +++- modules/webhooks.py | 2 +- plex_meta_manager.py | 359 +++++++++++++++++++------------------ 6 files changed, 267 insertions(+), 221 deletions(-) diff --git a/config/config.yml.template b/config/config.yml.template index 89284dac..457eca31 100644 --- a/config/config.yml.template +++ b/config/config.yml.template @@ -3,19 +3,15 @@ libraries: # Library mappings must have a colon (:) placed after them Movies: metadata_path: - - file: config/Movies.yml # You have to create this file the other are online + - file: config/Movies.yml # You have to create this file the other is online - git: meisnate12/MovieCharts - - git: meisnate12/Studios - - git: meisnate12/IMDBGenres - - git: meisnate12/People TV Shows: metadata_path: - - file: config/TV Shows.yml # You have to create this file the other are online + - file: config/TV Shows.yml # You have to create this file the other is online - git: meisnate12/ShowCharts - - git: meisnate12/Networks Anime: metadata_path: - - file: config/Anime.yml # You have to create this file the other are online + - file: config/Anime.yml # You have to create this file the other is online - git: meisnate12/AnimeCharts settings: # Can be individually specified per library as well cache: true diff --git a/modules/config.py b/modules/config.py index 47531f36..368e3b0b 100644 --- a/modules/config.py +++ b/modules/config.py @@ -385,8 +385,6 @@ class Config: if params["asset_directory"] is None: logger.warning("Config Warning: Assets will not be used asset_directory attribute must be set under config or under this specific Library") - params["asset_folders"] = check_for_attribute(lib, "asset_folders", parent="settings", var_type="bool", default=self.general["asset_folders"], do_print=False, save=False) - assets_for_all = check_for_attribute(lib, "assets_for_all", parent="settings", var_type="bool", default=self.general["assets_for_all"], do_print=False, save=False) params["sync_mode"] = check_for_attribute(lib, "sync_mode", parent="settings", test_list=sync_modes, default=self.general["sync_mode"], do_print=False, save=False) params["show_unmanaged"] = check_for_attribute(lib, "show_unmanaged", parent="settings", var_type="bool", default=self.general["show_unmanaged"], do_print=False, save=False) params["show_filtered"] = check_for_attribute(lib, "show_filtered", parent="settings", var_type="bool", default=self.general["show_filtered"], do_print=False, save=False) @@ -400,42 +398,54 @@ class Config: params["collection_creation_webhooks"] = check_for_attribute(lib, "collection_creation_webhooks", parent="settings", var_type="list", default=self.general["collection_creation_webhooks"], do_print=False, save=False) params["collection_addition_webhooks"] = check_for_attribute(lib, "collection_addition_webhooks", parent="settings", var_type="list", default=self.general["collection_addition_webhooks"], do_print=False, save=False) params["collection_removing_webhooks"] = check_for_attribute(lib, "collection_removing_webhooks", parent="settings", var_type="list", default=self.general["collection_removing_webhooks"], do_print=False, save=False) + params["assets_for_all"] = check_for_attribute(lib, "assets_for_all", parent="settings", var_type="bool", default=self.general["assets_for_all"], do_print=False, save=False) + params["mass_genre_update"] = check_for_attribute(lib, "mass_genre_update", test_list=mass_update_options, default_is_none=True, save=False, do_print=False) + params["mass_audience_rating_update"] = check_for_attribute(lib, "mass_audience_rating_update", test_list=mass_update_options, default_is_none=True, save=False, do_print=False) + params["mass_critic_rating_update"] = check_for_attribute(lib, "mass_critic_rating_update", test_list=mass_update_options, default_is_none=True, save=False, do_print=False) + params["mass_trakt_rating_update"] = check_for_attribute(lib, "mass_trakt_rating_update", var_type="bool", default=False, save=False, do_print=False) + params["split_duplicates"] = check_for_attribute(lib, "split_duplicates", var_type="bool", default=False, save=False, do_print=False) + params["radarr_add_all"] = check_for_attribute(lib, "radarr_add_all", var_type="bool", default=False, save=False, do_print=False) + params["sonarr_add_all"] = check_for_attribute(lib, "sonarr_add_all", var_type="bool", default=False, save=False, do_print=False) - params["assets_for_all"] = check_for_attribute(lib, "assets_for_all", var_type="bool", default=assets_for_all, save=False, do_print=lib and "assets_for_all" in lib) - params["delete_unmanaged_collections"] = check_for_attribute(lib, "delete_unmanaged_collections", var_type="bool", default=False, save=False, do_print=lib and "delete_unmanaged_collections" in lib) - params["delete_collections_with_less"] = check_for_attribute(lib, "delete_collections_with_less", var_type="int", default_is_none=True, save=False, do_print=lib and "delete_collections_with_less" in lib) + if lib and "operations" in lib and lib["operations"]: + if isinstance(lib["operations"], dict): + if "assets_for_all" in lib["operations"]: + params["assets_for_all"] = check_for_attribute(lib["operations"], "assets_for_all", var_type="bool", default=False, save=False) + if "delete_unmanaged_collections" in lib["operations"]: + params["delete_unmanaged_collections"] = check_for_attribute(lib["operations"], "delete_unmanaged_collections", var_type="bool", default=False, save=False) + if "delete_collections_with_less" in lib["operations"]: + params["delete_collections_with_less"] = check_for_attribute(lib["operations"], "delete_collections_with_less", var_type="int", default_is_none=True, save=False) + if "mass_genre_update" in lib["operations"]: + params["mass_genre_update"] = check_for_attribute(lib["operations"], "mass_genre_update", test_list=mass_update_options, default_is_none=True, save=False) + if "mass_audience_rating_update" in lib["operations"]: + params["mass_audience_rating_update"] = check_for_attribute(lib["operations"], "mass_audience_rating_update", test_list=mass_update_options, default_is_none=True, save=False) + if "mass_critic_rating_update" in lib["operations"]: + params["mass_critic_rating_update"] = check_for_attribute(lib["operations"], "mass_critic_rating_update", test_list=mass_update_options, default_is_none=True, save=False) + if "mass_trakt_rating_update" in lib["operations"]: + params["mass_trakt_rating_update"] = check_for_attribute(lib["operations"], "mass_trakt_rating_update", var_type="bool", default=False, save=False) + if "split_duplicates" in lib["operations"]: + params["split_duplicates"] = check_for_attribute(lib["operations"], "split_duplicates", var_type="bool", default=False, save=False) + if "radarr_add_all" in lib["operations"]: + params["radarr_add_all"] = check_for_attribute(lib["operations"], "radarr_add_all", var_type="bool", default=False, save=False) + if "sonarr_add_all" in lib["operations"]: + params["sonarr_add_all"] = check_for_attribute(lib["operations"], "sonarr_add_all", var_type="bool", default=False, save=False) + else: + logger.error("Config Error: operations must be a dictionary") + + def error_check(attr, service): + params[attr] = None + err = f"Config Error: {attr} cannot be omdb without a successful {service} Connection" + self.errors.append(err) + logger.error(err) - params["mass_genre_update"] = check_for_attribute(lib, "mass_genre_update", test_list=mass_update_options, default_is_none=True, save=False, do_print=lib and "mass_genre_update" in lib) if self.OMDb is None and params["mass_genre_update"] == "omdb": - params["mass_genre_update"] = None - e = "Config Error: mass_genre_update cannot be omdb without a successful OMDb Connection" - self.errors.append(e) - logger.error(e) - - params["mass_audience_rating_update"] = check_for_attribute(lib, "mass_audience_rating_update", test_list=mass_update_options, default_is_none=True, save=False, do_print=lib and "mass_audience_rating_update" in lib) + error_check("mass_genre_update", "OMDb") if self.OMDb is None and params["mass_audience_rating_update"] == "omdb": - params["mass_audience_rating_update"] = None - e = "Config Error: mass_audience_rating_update cannot be omdb without a successful OMDb Connection" - self.errors.append(e) - logger.error(e) - - params["mass_critic_rating_update"] = check_for_attribute(lib, "mass_critic_rating_update", test_list=mass_update_options, default_is_none=True, save=False, do_print=lib and "mass_audience_rating_update" in lib) + error_check("mass_audience_rating_update", "OMDb") if self.OMDb is None and params["mass_critic_rating_update"] == "omdb": - params["mass_critic_rating_update"] = None - e = "Config Error: mass_critic_rating_update cannot be omdb without a successful OMDb Connection" - self.errors.append(e) - logger.error(e) - - params["mass_trakt_rating_update"] = check_for_attribute(lib, "mass_trakt_rating_update", var_type="bool", default=False, save=False, do_print=lib and "mass_trakt_rating_update" in lib) + error_check("mass_critic_rating_update", "OMDb") if self.Trakt is None and params["mass_trakt_rating_update"]: - params["mass_trakt_rating_update"] = None - e = "Config Error: mass_trakt_rating_update cannot run without a successful Trakt Connection" - self.errors.append(e) - logger.error(e) - - params["split_duplicates"] = check_for_attribute(lib, "split_duplicates", var_type="bool", default=False, save=False, do_print=lib and "split_duplicates" in lib) - params["radarr_add_all"] = check_for_attribute(lib, "radarr_add_all", var_type="bool", default=False, save=False, do_print=lib and "radarr_add_all" in lib) - params["sonarr_add_all"] = check_for_attribute(lib, "sonarr_add_all", var_type="bool", default=False, save=False, do_print=lib and "sonarr_add_all" in lib) + error_check("mass_trakt_rating_update", "Trakt") try: if lib and "metadata_path" in lib: @@ -448,9 +458,9 @@ class Config: def check_dict(attr, name): if attr in path: if path[attr] is None: - e = f"Config Error: metadata_path {attr} is blank" - self.errors.append(e) - logger.error(e) + err = f"Config Error: metadata_path {attr} is blank" + self.errors.append(err) + logger.error(err) else: params["metadata_path"].append((name, path[attr])) check_dict("url", "URL") diff --git a/modules/library.py b/modules/library.py index 5c47ce71..ff3b0ed5 100644 --- a/modules/library.py +++ b/modules/library.py @@ -67,9 +67,6 @@ class Library(ABC): self.empty_trash = params["plex"]["empty_trash"] # TODO: Here or just in Plex? self.optimize = params["plex"]["optimize"] # TODO: Here or just in Plex? - self.mass_update = self.mass_genre_update or self.mass_audience_rating_update or self.mass_critic_rating_update \ - or self.mass_trakt_rating_update or self.split_duplicates or self.radarr_add_all or self.sonarr_add_all - metadata = [] for file_type, metadata_file in self.metadata_path: if file_type == "Folder": diff --git a/modules/tvdb.py b/modules/tvdb.py index d9a05322..24f1f509 100644 --- a/modules/tvdb.py +++ b/modules/tvdb.py @@ -13,6 +13,28 @@ urls = { "movies": f"{base_url}/movies/", "alt_movies": f"{alt_url}/movies/", "series_id": f"{base_url}/dereferrer/series/", "movie_id": f"{base_url}/dereferrer/movie/" } +language_translation = { + "ab": "abk", "aa": "aar", "af": "afr", "ak": "aka", "sq": "sqi", "am": "amh", "ar": "ara", "an": "arg", "hy": "hye", + "as": "asm", "av": "ava", "ae": "ave", "ay": "aym", "az": "aze", "bm": "bam", "ba": "bak", "eu": "eus", "be": "bel", + "bn": "ben", "bi": "bis", "bs": "bos", "br": "bre", "bg": "bul", "my": "mya", "ca": "cat", "ch": "cha", "ce": "che", + "ny": "nya", "zh": "zho", "cv": "chv", "kw": "cor", "co": "cos", "cr": "cre", "hr": "hrv", "cs": "ces", "da": "dan", + "dv": "div", "nl": "nld", "dz": "dzo", "en": "eng", "eo": "epo", "et": "est", "ee": "ewe", "fo": "fao", "fj": "fij", + "fi": "fin", "fr": "fra", "ff": "ful", "gl": "glg", "ka": "kat", "de": "deu", "el": "ell", "gn": "grn", "gu": "guj", + "ht": "hat", "ha": "hau", "he": "heb", "hz": "her", "hi": "hin", "ho": "hmo", "hu": "hun", "ia": "ina", "id": "ind", + "ie": "ile", "ga": "gle", "ig": "ibo", "ik": "ipk", "io": "ido", "is": "isl", "it": "ita", "iu": "iku", "ja": "jpn", + "jv": "jav", "kl": "kal", "kn": "kan", "kr": "kau", "ks": "kas", "kk": "kaz", "km": "khm", "ki": "kik", "rw": "kin", + "ky": "kir", "kv": "kom", "kg": "kon", "ko": "kor", "ku": "kur", "kj": "kua", "la": "lat", "lb": "ltz", "lg": "lug", + "li": "lim", "ln": "lin", "lo": "lao", "lt": "lit", "lu": "lub", "lv": "lav", "gv": "glv", "mk": "mkd", "mg": "mlg", + "ms": "msa", "ml": "mal", "mt": "mlt", "mi": "mri", "mr": "mar", "mh": "mah", "mn": "mon", "na": "nau", "nv": "nav", + "nd": "nde", "ne": "nep", "ng": "ndo", "nb": "nob", "nn": "nno", "no": "nor", "ii": "iii", "nr": "nbl", "oc": "oci", + "oj": "oji", "cu": "chu", "om": "orm", "or": "ori", "os": "oss", "pa": "pan", "pi": "pli", "fa": "fas", "pl": "pol", + "ps": "pus", "pt": "por", "qu": "que", "rm": "roh", "rn": "run", "ro": "ron", "ru": "rus", "sa": "san", "sc": "srd", + "sd": "snd", "se": "sme", "sm": "smo", "sg": "sag", "sr": "srp", "gd": "gla", "sn": "sna", "si": "sin", "sk": "slk", + "sl": "slv", "so": "som", "st": "sot", "es": "spa", "su": "sun", "sw": "swa", "ss": "ssw", "sv": "swe", "ta": "tam", + "te": "tel", "tg": "tgk", "th": "tha", "ti": "tir", "bo": "bod", "tk": "tuk", "tl": "tgl", "tn": "tsn", "to": "ton", + "tr": "tur", "ts": "tso", "tt": "tat", "tw": "twi", "ty": "tah", "ug": "uig", "uk": "ukr", "ur": "urd", "uz": "uzb", + "ve": "ven", "vi": "vie", "vo": "vol", "wa": "wln", "cy": "cym", "wo": "wol", "fy": "fry", "xh": "xho", "yi": "yid", + "yo": "yor", "za": "zha", "zu": "zul"} class TVDbObj: def __init__(self, tvdb_url, language, is_movie, config): @@ -46,15 +68,21 @@ class TVDbObj: parse_results = [r.strip() for r in parse_results if len(r) > 0] return parse_results[0] if len(parse_results) > 0 else None - self.title = parse_page(f"//div[@class='change_translation_text' and @data-language='{self.language}']/@data-title") + def parse_title_summary(lang=None): + place = "//div[@class='change_translation_text' and " + place += f"@data-language='{lang}'" if lang else "not(@style='display:none')" + return parse_page(f"{place}/@data-title"), parse_page(f"{place}]/p/text()[normalize-space()]") + + self.title, self.summary = parse_title_summary(lang=self.language) + if not self.title and self.language in language_translation: + self.title, self.summary = parse_title_summary(lang=language_translation[self.language]) if not self.title: - self.title = parse_page("//div[@class='change_translation_text' and not(@style='display:none')]/@data-title") + self.title, self.summary = parse_title_summary() if not self.title: raise Failed(f"TVDb Error: Name not found from TVDb URL: {self.tvdb_url}") self.poster_path = parse_page("//div[@class='row hidden-xs hidden-sm']/div/img/@src") self.background_path = parse_page("(//h2[@class='mt-4' and text()='Backgrounds']/following::div/a/@href)[1]") - self.summary = parse_page("//div[@class='change_translation_text' and not(@style='display:none')]/p/text()[normalize-space()]") if self.is_movie: self.directors = parse_page("//strong[text()='Directors']/parent::li/span/a/text()[normalize-space()]") self.writers = parse_page("//strong[text()='Writers']/parent::li/span/a/text()[normalize-space()]") diff --git a/modules/webhooks.py b/modules/webhooks.py index 3a79f334..44e20c31 100644 --- a/modules/webhooks.py +++ b/modules/webhooks.py @@ -38,7 +38,7 @@ class Webhooks: def end_time_hooks(self, start_time, run_time, stats): if self.run_end_webhooks: self._request(self.run_end_webhooks, { - "start_time": start_time, + "start_time": start_time.strftime("%Y-%m-%dT%H:%M:%SZ"), "run_time": run_time, "collections_created": stats["created"], "collections_modified": stats["modified"], diff --git a/plex_meta_manager.py b/plex_meta_manager.py index b75c205f..9d580452 100644 --- a/plex_meta_manager.py +++ b/plex_meta_manager.py @@ -180,8 +180,6 @@ def update_libraries(config): util.separator(f"Mapping {library.name} Library", space=False, border=False) logger.info("") items = library.map_guids() - if not config.test_mode and not config.resume_from and not collection_only and library.mass_update: - mass_metadata(config, library, items=items) for metadata in library.metadata_files: logger.info("") util.separator(f"Running Metadata File\n{metadata.path}") @@ -212,42 +210,8 @@ def update_libraries(config): logger.info("") builder.sort_collection() - if not config.test_mode and not config.requested_collections and ((library.show_unmanaged and not library_only) or (library.assets_for_all and not collection_only)): - if library.delete_collections_with_less is not None: - logger.info("") - text = f" with less then {library.delete_collections_with_less} item{'s' if library.delete_collections_with_less > 1 else ''}" - util.separator(f"Deleting All Collections{text if library.delete_collections_with_less > 0 else ''}", space=False, border=False) - logger.info("") - unmanaged_collections = [] - for col in library.get_all_collections(): - if library.delete_collections_with_less is not None and (library.delete_collections_with_less == 0 or col.childCount < library.delete_collections_with_less): - library.query(col.delete) - logger.info(f"{col.title} Deleted") - if col.title not in library.collections: - unmanaged_collections.append(col) - - if library.show_unmanaged and not library_only: - logger.info("") - util.separator(f"Unmanaged Collections in {library.name} Library", space=False, border=False) - logger.info("") - for col in unmanaged_collections: - if library.delete_unmanaged_collections: - library.query(col.delete) - logger.info(f"{col.title} Deleted") - else: - logger.info(col.title) - logger.info("") - logger.info(f"{len(unmanaged_collections)} Unmanaged Collections") - - if library.assets_for_all and not collection_only: - logger.info("") - util.separator(f"All {library.type}s Assets Check for {library.name} Library", space=False, border=False) - logger.info("") - for col in unmanaged_collections: - poster, background = library.find_collection_assets(col, create=library.create_asset_folders) - library.upload_images(col, poster=poster, background=background) - for item in library.get_all(): - library.update_item_from_assets(item, create=library.create_asset_folders) + if not config.test_mode and not collection_only: + library_operations(config, library, items=items) logger.removeHandler(library_handler) except Exception as e: @@ -310,164 +274,215 @@ def update_libraries(config): if library.optimize: library.query(library.PlexServer.library.optimize) -def mass_metadata(config, library, items=None): +def library_operations(config, library, items=None): logger.info("") - util.separator(f"Mass Editing {library.type} Library: {library.name}") + util.separator(f"{library.name} Library Operations") logger.info("") - if items is None: - items = library.get_all() + if library.split_duplicates: items = library.search(**{"duplicate": True}) for item in items: item.split() logger.info(util.adjust_space(f"{item.title[:25]:<25} | Splitting")) - radarr_adds = [] - sonarr_adds = [] - trakt_ratings = config.Trakt.user_ratings(library.is_movie) if library.mass_trakt_rating_update else [] - for i, item in enumerate(items, 1): - try: - library.reload(item) - except Failed as e: - logger.error(e) - continue - util.print_return(f"Processing: {i}/{len(items)} {item.title}") - tmdb_id = None - tvdb_id = None - imdb_id = None - if config.Cache: - t_id, i_id, guid_media_type, _ = config.Cache.query_guid_map(item.guid) - if t_id: - if "movie" in guid_media_type: - tmdb_id = t_id[0] - else: - tvdb_id = t_id[0] - if i_id: - imdb_id = i_id[0] - if not tmdb_id and not tvdb_id: - tmdb_id = library.get_tmdb_from_map(item) - if not tmdb_id and not tvdb_id and library.is_show: - tvdb_id = library.get_tvdb_from_map(item) + if library.assets_for_all or library.mass_genre_update or library.mass_audience_rating_update or \ + library.mass_critic_rating_update or library.mass_trakt_rating_update or library.radarr_add_all or library.sonarr_add_all: + if items is None: + items = library.get_all() + radarr_adds = [] + sonarr_adds = [] + trakt_ratings = config.Trakt.user_ratings(library.is_movie) if library.mass_trakt_rating_update else [] - if library.mass_trakt_rating_update: + for i, item in enumerate(items, 1): try: - if library.is_movie and tmdb_id in trakt_ratings: - new_rating = trakt_ratings[tmdb_id] - elif library.is_show and tvdb_id in trakt_ratings: - new_rating = trakt_ratings[tvdb_id] - else: - raise Failed - if str(item.userRating) != str(new_rating): - library.edit_query(item, {"userRating.value": new_rating, "userRating.locked": 1}) - logger.info(util.adjust_space(f"{item.title[:25]:<25} | User Rating | {new_rating}")) - except Failed: - pass + library.reload(item) + except Failed as e: + logger.error(e) + continue + util.print_return(f"Processing: {i}/{len(items)} {item.title}") + tmdb_id = None + tvdb_id = None + imdb_id = None + if config.Cache: + t_id, i_id, guid_media_type, _ = config.Cache.query_guid_map(item.guid) + if t_id: + if "movie" in guid_media_type: + tmdb_id = t_id[0] + else: + tvdb_id = t_id[0] + if i_id: + imdb_id = i_id[0] + if not tmdb_id and not tvdb_id: + tmdb_id = library.get_tmdb_from_map(item) + if not tmdb_id and not tvdb_id and library.is_show: + tvdb_id = library.get_tvdb_from_map(item) - if library.Radarr and library.radarr_add_all and tmdb_id: - radarr_adds.append(tmdb_id) - if library.Sonarr and library.sonarr_add_all and tvdb_id: - sonarr_adds.append(tvdb_id) - - tmdb_item = None - if library.mass_genre_update == "tmdb" or library.mass_audience_rating_update == "tmdb" or library.mass_critic_rating_update == "tmdb": - if tvdb_id and not tmdb_id: - tmdb_id = config.Convert.tvdb_to_tmdb(tvdb_id) - if tmdb_id: + if library.mass_trakt_rating_update: try: - tmdb_item = config.TMDb.get_movie(tmdb_id) if library.is_movie else config.TMDb.get_show(tmdb_id) - except Failed as e: - logger.error(util.adjust_space(str(e))) - else: - logger.info(util.adjust_space(f"{item.title[:25]:<25} | No TMDb ID for Guid: {item.guid}")) + if library.is_movie and tmdb_id in trakt_ratings: + new_rating = trakt_ratings[tmdb_id] + elif library.is_show and tvdb_id in trakt_ratings: + new_rating = trakt_ratings[tvdb_id] + else: + raise Failed + if str(item.userRating) != str(new_rating): + library.edit_query(item, {"userRating.value": new_rating, "userRating.locked": 1}) + logger.info(util.adjust_space(f"{item.title[:25]:<25} | User Rating | {new_rating}")) + except Failed: + pass - omdb_item = None - if library.mass_genre_update in ["omdb", "imdb"] or library.mass_audience_rating_update in ["omdb", "imdb"] or library.mass_critic_rating_update in ["omdb", "imdb"]: - if config.OMDb.limit is False: - if tmdb_id and not imdb_id: - imdb_id = config.Convert.tmdb_to_imdb(tmdb_id) - elif tvdb_id and not imdb_id: - imdb_id = config.Convert.tvdb_to_imdb(tvdb_id) - if imdb_id: + if library.Radarr and library.radarr_add_all and tmdb_id: + radarr_adds.append(tmdb_id) + if library.Sonarr and library.sonarr_add_all and tvdb_id: + sonarr_adds.append(tvdb_id) + + tmdb_item = None + if library.mass_genre_update == "tmdb" or library.mass_audience_rating_update == "tmdb" or library.mass_critic_rating_update == "tmdb": + if tvdb_id and not tmdb_id: + tmdb_id = config.Convert.tvdb_to_tmdb(tvdb_id) + if tmdb_id: try: - omdb_item = config.OMDb.get_omdb(imdb_id) + tmdb_item = config.TMDb.get_movie(tmdb_id) if library.is_movie else config.TMDb.get_show(tmdb_id) except Failed as e: logger.error(util.adjust_space(str(e))) - except Exception: - logger.error(f"IMDb ID: {imdb_id}") - raise else: - logger.info(util.adjust_space(f"{item.title[:25]:<25} | No IMDb ID for Guid: {item.guid}")) + logger.info(util.adjust_space(f"{item.title[:25]:<25} | No TMDb ID for Guid: {item.guid}")) - tvdb_item = None - if library.mass_genre_update == "tvdb": - if tvdb_id: + omdb_item = None + if library.mass_genre_update in ["omdb", "imdb"] or library.mass_audience_rating_update in ["omdb", "imdb"] or library.mass_critic_rating_update in ["omdb", "imdb"]: + if config.OMDb.limit is False: + if tmdb_id and not imdb_id: + imdb_id = config.Convert.tmdb_to_imdb(tmdb_id) + elif tvdb_id and not imdb_id: + imdb_id = config.Convert.tvdb_to_imdb(tvdb_id) + if imdb_id: + try: + omdb_item = config.OMDb.get_omdb(imdb_id) + except Failed as e: + logger.error(util.adjust_space(str(e))) + except Exception: + logger.error(f"IMDb ID: {imdb_id}") + raise + else: + logger.info(util.adjust_space(f"{item.title[:25]:<25} | No IMDb ID for Guid: {item.guid}")) + + tvdb_item = None + if library.mass_genre_update == "tvdb": + if tvdb_id: + try: + tvdb_item = config.TVDb.get_item(tvdb_id, library.is_movie) + except Failed as e: + logger.error(util.adjust_space(str(e))) + else: + logger.info(util.adjust_space(f"{item.title[:25]:<25} | No TVDb ID for Guid: {item.guid}")) + + if not tmdb_item and not omdb_item and not tvdb_item: + continue + + if library.mass_genre_update: try: - tvdb_item = config.TVDb.get_item(tvdb_id, library.is_movie) - except Failed as e: - logger.error(util.adjust_space(str(e))) - else: - logger.info(util.adjust_space(f"{item.title[:25]:<25} | No TVDb ID for Guid: {item.guid}")) + if tmdb_item and library.mass_genre_update == "tmdb": + new_genres = [genre.name for genre in tmdb_item.genres] + elif omdb_item and library.mass_genre_update in ["omdb", "imdb"]: + new_genres = omdb_item.genres + elif tvdb_item and library.mass_genre_update == "tvdb": + new_genres = tvdb_item.genres + else: + raise Failed + library.edit_tags("genre", item, sync_tags=new_genres) + except Failed: + pass + if library.mass_audience_rating_update: + try: + if tmdb_item and library.mass_audience_rating_update == "tmdb": + new_rating = tmdb_item.vote_average + elif omdb_item and library.mass_audience_rating_update in ["omdb", "imdb"]: + new_rating = omdb_item.imdb_rating + else: + raise Failed + if new_rating is None: + logger.info(util.adjust_space(f"{item.title[:25]:<25} | No Rating Found")) + else: + if library.mass_audience_rating_update and str(item.audienceRating) != str(new_rating): + library.edit_query(item, {"audienceRating.value": new_rating, "audienceRating.locked": 1}) + logger.info(util.adjust_space(f"{item.title[:25]:<25} | Audience Rating | {new_rating}")) + except Failed: + pass + if library.mass_critic_rating_update: + try: + if tmdb_item and library.mass_critic_rating_update == "tmdb": + new_rating = tmdb_item.vote_average + elif omdb_item and library.mass_critic_rating_update in ["omdb", "imdb"]: + new_rating = omdb_item.imdb_rating + else: + raise Failed + if new_rating is None: + logger.info(util.adjust_space(f"{item.title[:25]:<25} | No Rating Found")) + else: + if library.mass_critic_rating_update and str(item.rating) != str(new_rating): + library.edit_query(item, {"rating.value": new_rating, "rating.locked": 1}) + logger.info(util.adjust_space(f"{item.title[:25]:<25} | Critic Rating | {new_rating}")) + except Failed: + pass - if not tmdb_item and not omdb_item and not tvdb_item: - continue + if library.assets_for_all: + library.update_item_from_assets(item, create=library.create_asset_folders) - if library.mass_genre_update: + if library.Radarr and library.radarr_add_all: try: - if tmdb_item and library.mass_genre_update == "tmdb": - new_genres = [genre.name for genre in tmdb_item.genres] - elif omdb_item and library.mass_genre_update in ["omdb", "imdb"]: - new_genres = omdb_item.genres - elif tvdb_item and library.mass_genre_update == "tvdb": - new_genres = tvdb_item.genres - else: - raise Failed - library.edit_tags("genre", item, sync_tags=new_genres) - except Failed: - pass - if library.mass_audience_rating_update: - try: - if tmdb_item and library.mass_audience_rating_update == "tmdb": - new_rating = tmdb_item.vote_average - elif omdb_item and library.mass_audience_rating_update in ["omdb", "imdb"]: - new_rating = omdb_item.imdb_rating - else: - raise Failed - if new_rating is None: - logger.info(util.adjust_space(f"{item.title[:25]:<25} | No Rating Found")) - else: - if library.mass_audience_rating_update and str(item.audienceRating) != str(new_rating): - library.edit_query(item, {"audienceRating.value": new_rating, "audienceRating.locked": 1}) - logger.info(util.adjust_space(f"{item.title[:25]:<25} | Audience Rating | {new_rating}")) - except Failed: - pass - if library.mass_critic_rating_update: - try: - if tmdb_item and library.mass_critic_rating_update == "tmdb": - new_rating = tmdb_item.vote_average - elif omdb_item and library.mass_critic_rating_update in ["omdb", "imdb"]: - new_rating = omdb_item.imdb_rating - else: - raise Failed - if new_rating is None: - logger.info(util.adjust_space(f"{item.title[:25]:<25} | No Rating Found")) - else: - if library.mass_critic_rating_update and str(item.rating) != str(new_rating): - library.edit_query(item, {"rating.value": new_rating, "rating.locked": 1}) - logger.info(util.adjust_space(f"{item.title[:25]:<25} | Critic Rating | {new_rating}")) - except Failed: - pass + library.Radarr.add_tmdb(radarr_adds) + except Failed as e: + logger.error(e) - if library.Radarr and library.radarr_add_all: - try: - library.Radarr.add_tmdb(radarr_adds) - except Failed as e: - logger.error(e) + if library.Sonarr and library.sonarr_add_all: + try: + library.Sonarr.add_tvdb(sonarr_adds) + except Failed as e: + logger.error(e) - if library.Sonarr and library.sonarr_add_all: - try: - library.Sonarr.add_tvdb(sonarr_adds) - except Failed as e: - logger.error(e) + if library.delete_collections_with_less is not None or library.delete_unmanaged_collections: + logger.info("") + suffix = "" + unmanaged = "" + if library.delete_collections_with_less is not None and library.delete_collections_with_less > 0: + suffix = f" with less then {library.delete_collections_with_less} item{'s' if library.delete_collections_with_less > 1 else ''}" + if library.delete_unmanaged_collections: + if library.delete_collections_with_less is None: + unmanaged = "Unmanaged Collections " + elif library.delete_collections_with_less > 0: + unmanaged = "Unmanaged Collections and " + util.separator(f"Deleting All {unmanaged}Collections{suffix}", space=False, border=False) + logger.info("") + unmanaged_collections = [] + for col in library.get_all_collections(): + if (library.delete_collections_with_less is not None + and (library.delete_collections_with_less == 0 or col.childCount < library.delete_collections_with_less)) \ + or (col.title not in library.collections and library.delete_unmanaged_collections): + library.query(col.delete) + logger.info(f"{col.title} Deleted") + elif col.title not in library.collections: + unmanaged_collections.append(col) + + if library.show_unmanaged and len(unmanaged_collections) > 0: + logger.info("") + util.separator(f"Unmanaged Collections in {library.name} Library", space=False, border=False) + logger.info("") + for col in unmanaged_collections: + logger.info(col.title) + logger.info("") + logger.info(f"{len(unmanaged_collections)} Unmanaged Collection{'s' if len(unmanaged_collections) > 1 else ''}") + elif library.show_unmanaged: + logger.info("") + util.separator(f"No Unmanaged Collections in {library.name} Library", space=False, border=False) + logger.info("") + + if library.assets_for_all and len(unmanaged_collections) > 0: + logger.info("") + util.separator(f"Unmanaged Collection Assets Check for {library.name} Library", space=False, border=False) + logger.info("") + for col in unmanaged_collections: + poster, background = library.find_collection_assets(col, create=library.create_asset_folders) + library.upload_images(col, poster=poster, background=background) def run_collection(config, library, metadata, requested_collections): global stats