diff --git a/modules/builder.py b/modules/builder.py
index 38ccfd2f..75d4d153 100644
--- a/modules/builder.py
+++ b/modules/builder.py
@@ -111,8 +111,8 @@ sonarr_details = [
"sonarr_quality", "sonarr_season", "sonarr_search", "sonarr_cutoff_search", "sonarr_tag"
]
album_details = ["non_item_remove_label", "item_label", "item_album_sorting"]
-discover_types = {0: "returning", 1: "planned", 2: "production", 3: "ended", 4: "cancelled", 5: "pilot"}
-discover_status = {0: "documentary", 1: "news", 2: "miniseries", 3: "reality", 4: "scripted", 5: "talk_show", 6: "video"}
+discover_types = {0: "documentary", 1: "news", 2: "miniseries", 3: "reality", 4: "scripted", 5: "talk_show", 6: "video"}
+discover_status = {0: "returning", 1: "planned", 2: "production", 3: "ended", 4: "cancelled", 5: "pilot"}
filters_by_type = {
"movie_show_season_episode_artist_album_track": ["title", "summary", "collection", "has_collection", "added", "last_played", "user_rating", "plays"],
"movie_show_season_episode_album_track": ["year"],
@@ -1589,9 +1589,9 @@ class CollectionBuilder:
return data.lower()
raise Failed(f"{self.Type} Error: history attribute invalid: {data} must be a number between 1-30, day, or month")
elif attribute == "tmdb_type":
- return util.parse(self.Type, final, data, datatype="commalist", options=[v for k, v in discover_types.items()]).lower()
+ return util.parse(self.Type, final, data, datatype="commalist", options=[v for k, v in discover_types.items()])
elif attribute == "tmdb_status":
- return util.parse(self.Type, final, data, datatype="commalist", options=[v for k, v in discover_status.items()]).lower()
+ return util.parse(self.Type, final, data, datatype="commalist", options=[v for k, v in discover_status.items()])
elif attribute in plex.tag_attributes and modifier in ["", ".not"]:
if attribute in plex.tmdb_attributes:
final_values = []
diff --git a/modules/meta.py b/modules/meta.py
index 3f1a9b91..30d14fb5 100644
--- a/modules/meta.py
+++ b/modules/meta.py
@@ -10,10 +10,10 @@ logger = logging.getLogger("Plex Meta Manager")
github_base = "https://raw.githubusercontent.com/meisnate12/Plex-Meta-Manager-Configs/master/"
all_auto = ["genre"]
-
+ms_auto = ["trakt_user_lists", "trakt_people_list"]
auto = {
- "Movie": ["tmdb_collection", "country"] + all_auto,
- "Show": ["network"] + all_auto,
+ "Movie": ["tmdb_collection", "country"] + all_auto + ms_auto,
+ "Show": ["network"] + all_auto + ms_auto,
"Artist": ["mood", "style", "country"] + all_auto,
"Video": ["country"] + all_auto
}
@@ -239,20 +239,23 @@ class MetadataFile(DataFile):
self.templates = get_dict("templates", data)
self.collections = get_dict("collections", data, library.collections)
col_names = library.collections + [c for c in self.collections]
- for auto_name, auto_data in get_dict("auto_collections", data).items():
+ for map_name, dynamic in get_dict("dynamic_collections", data).items():
try:
- auto_methods = {dm.lower(): dm for dm in auto_data}
- if "auto_list" not in auto_methods:
- raise Failed(f"Config Error: {auto_name}'s auto_list attribute not found")
- elif not auto_data[auto_methods["auto_list"]]:
- raise Failed(f"Config Error: {auto_name}'s auto_list attribute is blank")
- elif auto_data[auto_methods["auto_list"]].lower() not in auto[library.type]:
- raise Failed(f"Config Error: auto_list attribute {auto_data[auto_methods['auto_list']].lower()} invalid Options: {auto[library.type]}")
- elif auto_data[auto_methods["auto_list"]].lower() == "network" and library.agent not in plex.new_plex_agents:
- raise Failed(f"Config Error: network auto_list only works with the New Plex TV Agent")
+ methods = {dm.lower(): dm for dm in dynamic}
+ if "type" not in methods:
+ raise Failed(f"Config Error: {map_name}'s type attribute not found")
+ elif not dynamic[methods["type"]]:
+ raise Failed(f"Config Error: {map_name}'s type attribute is blank")
+ elif dynamic[methods["type"]].lower() not in auto[library.type]:
+ raise Failed(f"Config Error: type attribute {dynamic[methods['type']].lower()} invalid Options: {auto[library.type]}")
+ elif dynamic[methods["type"]].lower() == "network" and library.agent not in plex.new_plex_agents:
+ raise Failed(f"Config Error: network type only works with the New Plex TV Agent")
+ elif dynamic[methods["type"]].lower().startswith("trakt") and not self.config.Trakt:
+ raise Failed(f"Config Error: trakt must be configured to use {dynamic[methods['type']]}")
else:
- auto_type = auto_data[auto_methods["auto_list"]].lower()
- exclude = util.parse("Config", "exclude", auto_data, methods=auto_methods, datatype="list") if "exclude" in auto_methods else []
+ auto_type = dynamic[methods["type"]].lower()
+ exclude = util.parse("Config", "exclude", dynamic, methods=methods, datatype="list") if "exclude" in methods else []
+ default_title_format = "<
>"
if auto_type in ["genre", "mood", "style", "country", "network"]:
auto_list = {i.title: i.title for i in library.get_tags(auto_type) if i.title not in exclude}
if library.is_music:
@@ -272,29 +275,47 @@ class MetadataFile(DataFile):
auto_list[tmdb_item.collection.id] = tmdb_item.collection.name
util.print_end()
default_template = {"tmdb_collection_details": "<>"}
- default_title_format = "<>"
else:
- raise Failed(f"Config Error: {auto_name}'s auto_list attribute {auto_data[auto_methods['auto_list']]} invalid")
+ if "data" not in methods:
+ raise Failed(f"Config Error: {map_name}'s data attribute not found")
+ elif not dynamic[methods["data"]]:
+ raise Failed(f"Config Error: {map_name}'s data attribute is blank")
+ else:
+ options = dynamic[methods["data"]]
+ if not isinstance(options, list):
+ options = [options]
+ if auto_type == "trakt_people_list":
+ auto_list = []
+ for option in options:
+ auto_list.extend(self.config.Trakt.get_people(option))
+ default_template = {"tmdb_person": "<>", "plex_search": {"all": {"actor": "tmdb"}}}
+ elif auto_type == "trakt_user_lists":
+ auto_list = []
+ for option in options:
+ auto_list.extend(self.config.Trakt.get_user_lists(option))
+ default_template = {"trakt_list_details": "<>"}
+ else:
+ raise Failed(f"Config Error: {map_name}'s type attribute {dynamic[methods['type']]} invalid")
title_format = default_title_format
- if "title_format" in auto_methods:
- title_format = util.parse("Config", "title_format", auto_data, methods=auto_methods, default=default_title_format)
+ if "title_format" in methods:
+ title_format = util.parse("Config", "title_format", dynamic, methods=methods, default=default_title_format)
if "<>" not in title_format:
logger.error(f"Config Error: <> not in title_format: {title_format} using default: {default_title_format}")
title_format = default_title_format
if "<>" in title_format:
title_format = title_format.replace("<>", library.type)
- dictionary_variables = util.parse("Config", "dictionary_variables", auto_data, methods=auto_methods, datatype="dictdict") if "dictionary_variables" in auto_methods else {}
- template_name = util.parse("Config", "template", auto_data, methods=auto_methods)
+ dictionary_variables = util.parse("Config", "dictionary_variables", dynamic, methods=methods, datatype="dictdict") if "dictionary_variables" in methods else {}
+ template_name = util.parse("Config", "template", dynamic, methods=methods)
if template_name:
if template_name not in self.templates:
raise Failed(f"Config Error: template: {template_name} not found")
if f"<<{auto_type}>>" not in str(self.templates[template_name]):
raise Failed(f"Config Error: template: {template_name} is required to have the template variable <<{auto_type}>>")
else:
- self.templates[auto_name] = default_template
- template_name = auto_name
- remove_prefix = util.parse("Config", "remove_prefix", auto_data, methods=auto_methods, datatype="commalist") if "remove_prefix" in auto_methods else []
- remove_suffix = util.parse("Config", "remove_suffix", auto_data, methods=auto_methods, datatype="commalist") if "remove_suffix" in auto_methods else []
+ self.templates[map_name] = default_template
+ template_name = map_name
+ remove_prefix = util.parse("Config", "remove_prefix", dynamic, methods=methods, datatype="commalist") if "remove_prefix" in methods else []
+ remove_suffix = util.parse("Config", "remove_suffix", dynamic, methods=methods, datatype="commalist") if "remove_suffix" in methods else []
for key, value in auto_list.items():
template_call = {"name": template_name, auto_type: key}
for k, v in dictionary_variables.items():
diff --git a/modules/trakt.py b/modules/trakt.py
index c3e0cf0c..31a1c59c 100644
--- a/modules/trakt.py
+++ b/modules/trakt.py
@@ -18,7 +18,7 @@ sorts = [
"rank", "added", "title", "released", "runtime", "popularity",
"percentage", "votes", "random", "my_rating", "watched", "collected"
]
-id_translation = {"movie": "tmdb", "show": "tvdb", "season": "TVDb Season", "episode": "TVDb Episode"}
+id_translation = {"movie": "movie", "show": "show", "season": "show", "episode": "show", "person": "person"}
class Trakt:
def __init__(self, config, params):
@@ -159,23 +159,34 @@ class Trakt:
data = item[item_type]
current_type = item_type
elif "type" in item and item["type"] in id_translation:
- data = item["movie" if item["type"] == "movie" else "show"]
+ data = item[id_translation[item["type"]]]
current_type = item["type"]
else:
continue
- id_type = "tmdb" if current_type == "movie" else "tvdb"
+ id_type = "tmdb" if current_type in ["movie", "person"] else "tvdb"
if id_type in data["ids"] and 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
+ if current_type == "person":
+ final_id = (final_id, data["name"])
+ final_type = f"{id_type}_{current_type}" if current_type in ["episode", "season", "person"] else id_type
ids.append((final_id, final_type))
else:
logger.error(f"Trakt Error: No {id_type.upper().replace('B', 'b')} ID found for {data['title']} ({data['year']})")
return ids
+ def get_user_lists(self, data):
+ try:
+ items = self._request(f"/users/{data}/lists")
+ except Failed:
+ raise Failed(f"Trakt Error: User {data} not found")
+ if len(items) == 0:
+ raise Failed(f"Trakt Error: User {data} has no lists")
+ return {f"{base_url}/users/{data}/lists/{i['ids']['slug']}": i["name"] for i in items}
+
def _user_list(self, data):
try:
items = self._request(f"{requests.utils.urlparse(data).path}/items")
@@ -198,6 +209,9 @@ class Trakt:
items = self._request(f"/{'movies' if is_movie else 'shows'}/{pagenation}?limit={amount}")
return self._parse(items, typeless=pagenation == "popular", item_type="movie" if is_movie else "show")
+ def get_people(self, data):
+ return {i[0][0]: i[0][1] for i in self._user_list(data) if i[1] == "tmdb_person"}
+
def validate_trakt(self, trakt_lists, is_movie, trakt_type="list"):
values = util.get_list(trakt_lists, split=False)
trakt_values = []