From f1918c02f44c1171b08bfd3c3a26a9567d1c1fea Mon Sep 17 00:00:00 2001 From: meisnate12 Date: Mon, 2 May 2022 15:05:52 -0400 Subject: [PATCH] [57] #784 add radarr_taglist, sonarr_taglist, radarr_all, and sonarr_all --- VERSION | 2 +- docs/metadata/builders/radarr.md | 40 ++++++++++++++++++++++++++++++++ docs/metadata/builders/sonarr.md | 40 ++++++++++++++++++++++++++++++++ modules/builder.py | 26 +++++++++++++++------ modules/meta.py | 3 ++- modules/radarr.py | 19 +++++++++++++++ modules/sonarr.py | 19 +++++++++++++++ modules/tautulli.py | 12 +++++----- plex_meta_manager.py | 2 +- 9 files changed, 147 insertions(+), 16 deletions(-) create mode 100644 docs/metadata/builders/radarr.md create mode 100644 docs/metadata/builders/sonarr.md diff --git a/VERSION b/VERSION index 5d46a82c..4db59420 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.16.5-develop56 +1.16.5-develop57 diff --git a/docs/metadata/builders/radarr.md b/docs/metadata/builders/radarr.md new file mode 100644 index 00000000..7b203c81 --- /dev/null +++ b/docs/metadata/builders/radarr.md @@ -0,0 +1,40 @@ +# Radarr Builders + +You can find items in your Plex using the features of [Radarr](https://radarr.video/). + +[Configuring Radarr](../../config/radarr) in the config is required for any of these builders. + +| Attribute | Description | Works with Movies | Works with Shows | Works with Playlists and Custom Sort | +|:------------------------------------|:---------------------------------------------|:-----------------:|:----------------:|:------------------------------------:| +| [`radarr_all`](#radarr-all) | Gets all Movies in Radarr. | ✅ | ❌ | ❌ | +| [`radarr_taglist`](#radarr-taglist) | Gets Movies from Radarr based on their tags. | ✅ | ❌ | ❌ | + +## Radarr All + +Gets all Movies in Radarr. + +```yaml +collections: + ALL Radarr Movies: + radarr_all: true +``` + +## Radarr Taglist + +Gets Movies from Radarr based on their tags. + +Set the attribute to the tag you want to search for. Multiple values are supported as either a list or a comma-separated string. + +```yaml +collections: + Radarr Movies Without Tags: + radarr_taglist: action, drama +``` + +If no tag is specified then it gets every Movie without a tag. + +```yaml +collections: + Radarr Movies Without Tags: + radarr_taglist: +``` \ No newline at end of file diff --git a/docs/metadata/builders/sonarr.md b/docs/metadata/builders/sonarr.md new file mode 100644 index 00000000..4ba18693 --- /dev/null +++ b/docs/metadata/builders/sonarr.md @@ -0,0 +1,40 @@ +# Sonarr Builders + +You can find items in your Plex using the features of [Sonarr](https://sonarr.tv/). + +[Configuring Sonarr](../../config/sonarr) in the config is required for any of these builders. + +| Attribute | Description | Works with Movies | Works with Shows | Works with Playlists and Custom Sort | +|:------------------------------------|:---------------------------------------------|:-----------------:|:----------------:|:------------------------------------:| +| [`sonarr_all`](#sonarr-all) | Gets all Series in Sonarr. | ❌ | ✅ | ❌ | +| [`sonarr_taglist`](#sonarr-taglist) | Gets Series from Sonarr based on their tags. | ❌ | ✅ | ❌ | + +## Sonarr All + +Gets all Series in Sonarr. + +```yaml +collections: + ALL Sonarr Series: + sonarr_all: true +``` + +## Sonarr Taglist + +Gets Series from Sonarr based on their tags. + +Set the attribute to the tag you want to search for. Multiple values are supported as either a list or a comma-separated string. + +```yaml +collections: + Sonarr Series Without Tags: + sonarr_taglist: action, drama +``` + +If no tag is specified then it gets every Movie without a tag. + +```yaml +collections: + Sonarr Series Without Tags: + sonarr_taglist: +``` \ No newline at end of file diff --git a/modules/builder.py b/modules/builder.py index a9b72a79..fb8f2490 100644 --- a/modules/builder.py +++ b/modules/builder.py @@ -13,15 +13,15 @@ advance_new_agent = ["item_metadata_language", "item_use_original_title"] advance_show = ["item_episode_sorting", "item_keep_episodes", "item_delete_episodes", "item_season_display", "item_episode_sorting"] all_builders = anidb.builders + anilist.builders + flixpatrol.builders + icheckmovies.builders + imdb.builders + \ letterboxd.builders + mal.builders + plex.builders + reciperr.builders + tautulli.builders + \ - tmdb.builders + trakt.builders + tvdb.builders + mdblist.builders + tmdb.builders + trakt.builders + tvdb.builders + mdblist.builders + radarr.builders + sonarr.builders show_only_builders = [ "tmdb_network", "tmdb_show", "tmdb_show_details", "tvdb_show", "tvdb_show_details", "tmdb_airing_today", - "tmdb_on_the_air", "collection_level", "item_tmdb_season_titles" + "tmdb_on_the_air", "collection_level", "item_tmdb_season_titles", "sonarr_all", "sonarr_taglist" ] movie_only_builders = [ "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", - "tvdb_movie", "tvdb_movie_details", "tmdb_upcoming", "trakt_boxoffice", "reciperr_list" + "tvdb_movie", "tvdb_movie_details", "tmdb_upcoming", "trakt_boxoffice", "reciperr_list", "radarr_all", "radarr_taglist" ] music_only_builders = ["item_album_sorting"] summary_details = [ @@ -50,7 +50,7 @@ collectionless_details = ["collection_order", "plex_collectionless", "label", "l item_false_details = ["item_lock_background", "item_lock_poster", "item_lock_title"] item_bool_details = ["item_tmdb_season_titles", "revert_overlay", "item_refresh"] + item_false_details item_details = ["non_item_remove_label", "item_label", "item_radarr_tag", "item_sonarr_tag", "item_overlay", "item_refresh_delay"] + item_bool_details + list(plex.item_advance_keys.keys()) -none_details = ["label.sync", "item_label.sync"] +none_details = ["label.sync", "item_label.sync", "radarr_taglist", "sonarr_taglist"] radarr_details = [ "radarr_add_missing", "radarr_add_existing", "radarr_upgrade_existing", "radarr_folder", "radarr_monitor", "radarr_search", "radarr_availability", "radarr_quality", "radarr_tag", "item_radarr_tag" @@ -718,9 +718,9 @@ class CollectionBuilder: self._details(method_name, method_data, method_final, methods) elif method_name in item_details: self._item_details(method_name, method_data, method_mod, method_final, methods) - elif method_name in radarr_details: + elif method_name in radarr_details or method_name in radarr.builders: self._radarr(method_name, method_data) - elif method_name in sonarr_details: + elif method_name in sonarr_details or method_name in sonarr.builders: self._sonarr(method_name, method_data) elif method_name in anidb.builders: self._anidb(method_name, method_data) @@ -1018,6 +1018,10 @@ class CollectionBuilder: self.radarr_details["quality"] = method_data elif method_name == "radarr_tag": self.radarr_details["tag"] = util.get_list(method_data, lower=True) + elif method_name == "radarr_taglist": + self.builders.append((method_name, util.get_list(method_data, lower=True))) + elif method_name == "radarr_all": + self.builders.append((method_name, True)) def _sonarr(self, method_name, method_data): if method_name in ["sonarr_add_missing", "sonarr_add_existing", "sonarr_upgrade_existing", "sonarr_season", "sonarr_search", "sonarr_cutoff_search"]: @@ -1036,6 +1040,10 @@ class CollectionBuilder: raise Failed(f"{self.Type} Error: {method_name} attribute must be either standard, daily, or anime") elif method_name == "sonarr_tag": self.sonarr_details["tag"] = util.get_list(method_data, lower=True) + elif method_name == "sonarr_taglist": + self.builders.append((method_name, util.get_list(method_data, lower=True))) + elif method_name == "sonarr_all": + self.builders.append((method_name, True)) def _anidb(self, method_name, method_data): if method_name == "anidb_popular": @@ -1452,7 +1460,7 @@ class CollectionBuilder: if "plex" in method: ids = self.library.get_rating_keys(method, value) elif "tautulli" in method: - ids = self.library.Tautulli.get_rating_keys(self.library, value, self.playlist) + ids = self.library.Tautulli.get_rating_keys(value, self.playlist) elif "anidb" in method: anidb_ids = self.config.AniDB.get_anidb_ids(method, value) ids = self.config.Convert.anidb_to_ids(anidb_ids, self.library) @@ -1480,6 +1488,10 @@ class CollectionBuilder: ids = self.config.TMDb.get_tmdb_ids(method, value, self.library.is_movie, self.tmdb_region) elif "trakt" in method: ids = self.config.Trakt.get_trakt_ids(method, value, self.library.is_movie) + elif "radarr" in method: + ids = self.library.Radarr.get_tmdb_ids(method, value) + elif "sonarr" in method: + ids = self.library.Sonarr.get_tvdb_ids(method, value) else: ids = [] logger.error(f"{self.Type} Error: {method} method not supported") diff --git a/modules/meta.py b/modules/meta.py index 36db1bd8..070120a4 100644 --- a/modules/meta.py +++ b/modules/meta.py @@ -138,7 +138,8 @@ class DataFile: variables["playlist_name"] = str(name) if self.data_type == "Overlay" and "overlay_name" not in variables: variables["overlay_name"] = str(name) - variables["library_type"] = self.library.type.lower() + + variables["library_type"] = self.library.type.lower() if self.library else "items" template_name = variables["name"] template, temp_vars = self.templates[template_name] diff --git a/modules/radarr.py b/modules/radarr.py index d98099e8..8e1dcd16 100644 --- a/modules/radarr.py +++ b/modules/radarr.py @@ -5,6 +5,7 @@ from arrapi.exceptions import ArrException logger = util.logger +builders = ["radarr_all", "radarr_taglist"] availability_translation = {"announced": "announced", "cinemas": "inCinemas", "released": "released", "db": "preDB"} apply_tags_translation = {"": "add", "sync": "replace", "remove": "remove"} availability_descriptions = {"announced": "For Announced", "cinemas": "For In Cinemas", "released": "For Released", "db": "For PreDB"} @@ -217,3 +218,21 @@ class Radarr: remove_items.append(movie) if remove_items: self.api.delete_multiple_movies(remove_items) + + def get_tmdb_ids(self, method, data): + ids = [] + for movie in self.api.all_movies(): + append = False + if method == "radarr_all": + append = True + elif method == "radarr_taglist": + if data: + for tag in movie.tags: + if tag.label.lower() in data: + append = True + break + elif not movie.tags: + append = True + if append: + ids.append((movie.tmdbId, "tmdb")) + return ids diff --git a/modules/sonarr.py b/modules/sonarr.py index 60e4567f..9ad4e3b5 100644 --- a/modules/sonarr.py +++ b/modules/sonarr.py @@ -5,6 +5,7 @@ from arrapi.exceptions import ArrException logger = util.logger +builders = ["sonarr_all", "sonarr_taglist"] series_types = ["standard", "daily", "anime"] monitor_translation = { "all": "all", "future": "future", "missing": "missing", "existing": "existing", @@ -243,3 +244,21 @@ class Sonarr: remove_items.append(series) if remove_items: self.api.delete_multiple_series(remove_items) + + def get_tvdb_ids(self, method, data): + ids = [] + for series in self.api.all_series(): + append = False + if method == "sonarr_all": + append = True + elif method == "sonarr_taglist": + if data: + for tag in series.tags: + if tag.label.lower() in data: + append = True + break + elif not series.tags: + append = True + if append: + ids.append((series.tvdbId, "tvdb")) + return ids diff --git a/modules/tautulli.py b/modules/tautulli.py index a9c52911..37c9a2ed 100644 --- a/modules/tautulli.py +++ b/modules/tautulli.py @@ -23,11 +23,11 @@ class Tautulli: if response["response"]["result"] != "success": raise Failed(f"Tautulli Error: {response['response']['message']}") - def get_rating_keys(self, library, params, all_items): + def get_rating_keys(self, params, all_items): query_size = int(params["list_size"]) + int(params["list_buffer"]) - logger.info(f"Processing Tautulli Most {params['list_type'].capitalize()}: {params['list_size']} {'Movies' if library.is_movie else 'Shows'}") + logger.info(f"Processing Tautulli Most {params['list_type'].capitalize()}: {params['list_size']} {'Movies' if self.library.is_movie else 'Shows'}") response = self._request(f"{self.url}/api/v2?apikey={self.apikey}&cmd=get_home_stats&time_range={params['list_days']}&stats_count={query_size}") - stat_id = f"{'popular' if params['list_type'] == 'popular' else 'top'}_{'movies' if library.is_movie else 'tv'}" + stat_id = f"{'popular' if params['list_type'] == 'popular' else 'top'}_{'movies' if self.library.is_movie else 'tv'}" stat_type = "users_watched" if params['list_type'] == 'popular' else "total_plays" items = None @@ -38,19 +38,19 @@ class Tautulli: if items is None: raise Failed("Tautulli Error: No Items found in the response") - section_id = library.Plex.key + section_id = self.library.Plex.key rating_keys = [] for item in items: if (all_items or item["section_id"] == section_id) and len(rating_keys) < int(params['list_size']): if int(item[stat_type]) < params['list_minimum']: continue try: - plex_item = library.fetchItem(int(item["rating_key"])) + plex_item = self.library.fetchItem(int(item["rating_key"])) if not isinstance(plex_item, (Movie, Show)): raise BadRequest rating_keys.append((item["rating_key"], "ratingKey")) except (BadRequest, NotFound): - new_item = library.exact_search(item["title"], year=item["year"]) + new_item = self.library.exact_search(item["title"], year=item["year"]) if new_item: rating_keys.append((new_item[0].ratingKey, "ratingKey")) else: diff --git a/plex_meta_manager.py b/plex_meta_manager.py index 9bb1f8b1..f7e7da7d 100644 --- a/plex_meta_manager.py +++ b/plex_meta_manager.py @@ -664,7 +664,7 @@ def run_playlists(config): elif "tautulli" in method: ids = [] for pl_library in builder.libraries: - ids.extend(pl_library.Tautulli.get_rating_keys(pl_library, value, True)) + ids.extend(pl_library.Tautulli.get_rating_keys(value, True)) else: ids = builder.gather_ids(method, value)