[76] fix mal and trailing tag spaces

pull/865/head
meisnate12 3 years ago
parent b9a0f87c40
commit 0354b76200

@ -1 +1 @@
1.16.5-develop75 1.16.5-develop76

@ -2,30 +2,32 @@
All the following attributes serve various functions as how the collection/playlist functions inside of Plex Meta Manager. All the following attributes serve various functions as how the collection/playlist functions inside of Plex Meta Manager.
| Attribute | Description & Values | | Attribute | Description & Values |
|:------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |:-----------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name` | **Description:** Used to specify the name off the collection/playlist in Plex as different then the mapping name.<br>**Values:** Any String | | `name` | **Description:** Used to specify the name off the collection/playlist in Plex as different then the mapping name.<br>**Values:** Any String |
| `limit` | **Description:** Used to specify the max number of items for the collection/playlist<br>**Values:** Number greater then 0 | | `limit` | **Description:** Used to specify the max number of items for the collection/playlist<br>**Values:** Number greater then 0 |
| `template` | **Description:** Used to specify a template and template variables to use for this collection/playlist. See the [Templates Page](../templates) for more information.<br>**Values:** Dictionary | | `template` | **Description:** Used to specify a template and template variables to use for this collection/playlist. See the [Templates Page](../templates) for more information.<br>**Values:** Dictionary |
| `run_again` | **Description:** Used to try and add all the missing items to the collection/playlist again after the daily run.<br>**Default:** `false`<br>**Values:** `true` or `false` | | `run_again` | **Description:** Used to try and add all the missing items to the collection/playlist again after the daily run.<br>**Default:** `false`<br>**Values:** `true` or `false` |
| `sync_mode` | **Description:** Used to change how builders sync with this collection/playlist.<br>**Default:** `sync_mode` [settings value](../../config/settings) in the Configuration File<br>**Values:**<table class="clearTable"><tr><td>`append`</td><td>Only Add Items to the Collection</td></tr><tr><td>`sync`</td><td>Add & Remove Items from the Collection</td></tr></table> | | `sync_mode` | **Description:** Used to change how builders sync with this collection/playlist.<br>**Default:** `sync_mode` [settings value](../../config/settings) in the Configuration File<br>**Values:**<table class="clearTable"><tr><td>`append`</td><td>Only Add Items to the Collection</td></tr><tr><td>`sync`</td><td>Add & Remove Items from the Collection</td></tr></table> |
| `minimum_items` | **Description:** Minimum items that must be found to add to a collection/playlist.<br>**Default:** `minimum_items` [settings value](../../config/settings) in the Configuration File<br>**Values:** number greater then 0 | | `minimum_items` | **Description:** Minimum items that must be found to add to a collection/playlist.<br>**Default:** `minimum_items` [settings value](../../config/settings) in the Configuration File<br>**Values:** number greater then 0 |
| `delete_below_minimum` | **Description:** Deletes the collection/playlist if below the minimum.<br>**Default:** `delete_below_minimum` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` | | `delete_below_minimum` | **Description:** Deletes the collection/playlist if below the minimum.<br>**Default:** `delete_below_minimum` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` |
| `delete_not_scheduled` | **Description:** Deletes the collection/playlist if its skipped because its not scheduled.<br>**Default:** `delete_not_scheduled` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` | | `delete_not_scheduled` | **Description:** Deletes the collection/playlist if its skipped because its not scheduled.<br>**Default:** `delete_not_scheduled` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` |
| `tmdb_region` | **Description:** Sets the region for `tmdb_popular`, `tmdb_now_playing`, `tmdb_top_rated`, and `tmdb_upcoming` | | `tmdb_region` | **Description:** Sets the region for `tmdb_popular`, `tmdb_now_playing`, `tmdb_top_rated`, and `tmdb_upcoming` |
| `validate_builders` | **Description:** When set to false the collection/playlist will not fail if one builder fails.<br>**Default:** `true`<br>**Values:** `true` or `false` | | `validate_builders` | **Description:** When set to false the collection/playlist will not fail if one builder fails.<br>**Default:** `true`<br>**Values:** `true` or `false` |
| `cache_builders` | **Description:** Caches the items found by the builders for a number of days. This is useful if you run the same configuration on multiple libraries/servers in one run just set the value to `1`.<br>**Default:** `0` <br>**Values:** number 0 or greater | | `cache_builders` | **Description:** Caches the items found by the builders for a number of days. This is useful if you run the same configuration on multiple libraries/servers in one run just set the value to `1`.<br>**Default:** `0` <br>**Values:** number 0 or greater |
| `blank_collection` | **Description:** When set to true the collection will be created with no builders and no items added.<br>**Default:** `false`<br>**Values:** `true` or `false` | | `blank_collection` | **Description:** When set to true the collection will be created with no builders and no items added.<br>**Default:** `false`<br>**Values:** `true` or `false` |
| `build_collection` | **Description:** When set to false the collection won't be created but items can still be added to Radarr/Sonarr. Does not work for playlists.<br>**Default:** `true`<br>**Values:** `true` or `false` | | `build_collection` | **Description:** When set to false the collection won't be created but items can still be added to Radarr/Sonarr. Does not work for playlists.<br>**Default:** `true`<br>**Values:** `true` or `false` |
| `server_preroll` | **Description:** Used to set the `Movie pre-roll video` Text box in Plex under Settings -> Extras.<br>You can run this with a [schedule](schedule) to change the pre-rolls automatically.<br>**Values:** Any String | | `server_preroll` | **Description:** Used to set the `Movie pre-roll video` Text box in Plex under Settings -> Extras.<br>You can run this with a [schedule](schedule) to change the pre-rolls automatically.<br>**Values:** Any String |
| `missing_only_released` | **Description:** Collection/Playlist Level `missing_only_released` toggle.<br>**Default:** `missing_only_released` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` | | `missing_only_released` | **Description:** Collection/Playlist Level `missing_only_released` toggle.<br>**Default:** `missing_only_released` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` |
| `only_filter_missing` | **Description:** Collection/Playlist Level `only_filter_missing` toggle.<br>**Default:** `only_filter_missing` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` | | `only_filter_missing` | **Description:** Collection/Playlist Level `only_filter_missing` toggle.<br>**Default:** `only_filter_missing` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` |
| `show_filtered` | **Description:** Collection/Playlist level `show_filtered` toggle.<br>**Default:** `show_filtered` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` | | `show_filtered` | **Description:** Collection/Playlist level `show_filtered` toggle.<br>**Default:** `show_filtered` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` |
| `show_missing` | **Description:** Collection/Playlist level `show_missing` toggle.<br>**Default:** `show_missing` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` | | `show_missing` | **Description:** Collection/Playlist level `show_missing` toggle.<br>**Default:** `show_missing` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` |
| `save_missing` | **Description:** Collection/Playlist level `save_missing` toggle.<br>**Default:** `save_missing` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` | | `save_missing` | **Description:** Collection/Playlist level `save_missing` toggle.<br>**Default:** `save_missing` [settings value](../../config/settings) in the Configuration File<br>**Values:** `true` or `false` |
| `ignore_ids` | **Description:** Collection/Playlist level `ignore_ids` which is combined with the library and global `ignore_ids`.<br>**Default:** `ignore_ids` [settings value](../../config/settings) in the Configuration File<br>**Values:** List or comma-separated String of TMDb/TVDb IDs | | `ignore_ids` | **Description:** Collection/Playlist level `ignore_ids` which is combined with the library and global `ignore_ids`.<br>**Default:** `ignore_ids` [settings value](../../config/settings) in the Configuration File<br>**Values:** List or comma-separated String of TMDb/TVDb IDs |
| `ignore_imdb_ids` | **Description:** Collection/Playlist level `ignore_imdb_ids` which is combined with the library and global `ignore_imdb_ids`.<br>**Default:** `ignore_imdb_ids` [settings value](../../config/settings) in the Configuration File<br>**Values:** List or comma-separated String of IMDb IDs | | `ignore_imdb_ids` | **Description:** Collection/Playlist level `ignore_imdb_ids` which is combined with the library and global `ignore_imdb_ids`.<br>**Default:** `ignore_imdb_ids` [settings value](../../config/settings) in the Configuration File<br>**Values:** List or comma-separated String of IMDb IDs |
| `name_mapping` | **Description:** Used to specify the folder name in the [Image Assets Directory](../../home/guides/assets) i.e. if your collection/playlist name contains characters that are not allowed in file paths (i.e. for windows `<`, `>`, `:`, `"`, `/`, `\`, `?`, `*` cannot be in the file path), but you want them in your name you can this to specify the name in the file system.<br>**Values:** Any String | | `name_mapping` | **Description:** Used to specify the folder name in the [Image Assets Directory](../../home/guides/assets) i.e. if your collection/playlist name contains characters that are not allowed in file paths (i.e. for windows `<`, `>`, `:`, `"`, `/`, `\`, `?`, `*` cannot be in the file path), but you want them in your name you can this to specify the name in the file system.<br>**Values:** Any String |
| `test` | **Description:** When running in Test Mode (`--run-tests` [option](../../home/environmental)) only collections/playlists with `test: true` will be run.<br>**Default:** `false`<br>**Values:** `true` or `false` | | `test` | **Description:** When running in Test Mode (`--run-tests` [option](../../home/environmental)) only collections/playlists with `test: true` will be run.<br>**Default:** `false`<br>**Values:** `true` or `false` |
| `changes_webhooks` | **Description:** Used to specify a collection/playlist changes webhook for just this collection/playlist.<br>**Values:** List of webhooks | | `changes_webhooks` | **Description:** Used to specify a collection/playlist changes webhook for just this collection/playlist.<br>**Values:** List of webhooks |
| `sync_to_trakt_list` | **Description:** Used to specify a trakt list you want the collection/playlist synced to.<br>**Values:** Trakt List Slug you want to sync to |
| `sync_missing_to_trakt_list` | **Description:** Used to also sync missing items to the Trakt List specified by `sync_to_trakt_list`.<br>**Values:** `ture` or `false` |

@ -419,6 +419,7 @@ class CollectionBuilder:
self.url_theme = None self.url_theme = None
self.file_theme = None self.file_theme = None
self.sync_to_trakt_list = None self.sync_to_trakt_list = None
self.sync_missing_to_trakt_list = False
self.collection_poster = None self.collection_poster = None
self.collection_background = None self.collection_background = None
self.exists = False self.exists = False
@ -753,7 +754,7 @@ class CollectionBuilder:
self._tautulli(method_name, method_data) self._tautulli(method_name, method_data)
elif method_name in tmdb.builders: elif method_name in tmdb.builders:
self._tmdb(method_name, method_data) self._tmdb(method_name, method_data)
elif method_name in trakt.builders or method_name == "sync_to_trakt_list": elif method_name in trakt.builders or method_name in ["sync_to_trakt_list", "sync_missing_to_trakt_list"]:
self._trakt(method_name, method_data) self._trakt(method_name, method_data)
elif method_name in tvdb.builders: elif method_name in tvdb.builders:
self._tvdb(method_name, method_data) self._tvdb(method_name, method_data)
@ -1465,6 +1466,8 @@ class CollectionBuilder:
if method_data not in self.config.Trakt.slugs: if method_data not in self.config.Trakt.slugs:
raise Failed(f"{self.Type} Error: {method_data} invalid. Options {', '.join(self.config.Trakt.slugs)}") raise Failed(f"{self.Type} Error: {method_data} invalid. Options {', '.join(self.config.Trakt.slugs)}")
self.sync_to_trakt_list = method_data self.sync_to_trakt_list = method_data
elif method_name == "sync_missing_to_trakt_list":
self.sync_missing_to_trakt_list = util.parse(self.Type, method_name, method_data, datatype="bool", default=False)
elif method_name in trakt.builders: elif method_name in trakt.builders:
if method_name in ["trakt_chart", "trakt_userlist"]: if method_name in ["trakt_chart", "trakt_userlist"]:
trakt_dicts = method_data trakt_dicts = method_data
@ -1982,7 +1985,7 @@ class CollectionBuilder:
else: else:
final_values.append(value) final_values.append(value)
else: else:
final_values = util.get_list(data) final_values = util.get_list(data, trim=False)
search_choices, names = self.library.get_search_choices(attribute, title=not plex_search) search_choices, names = self.library.get_search_choices(attribute, title=not plex_search)
valid_list = [] valid_list = []
for value in final_values: for value in final_values:
@ -2714,6 +2717,9 @@ class CollectionBuilder:
if new_id: if new_id:
current_ids.append(new_id) current_ids.append(new_id)
break break
if self.sync_missing_to_trakt_list:
current_ids.extend([(mm, "tmdb") for mm in self.missing_movies])
current_ids.extend([(ms, "tvdb") for ms in self.missing_shows])
self.config.Trakt.sync_list(self.sync_to_trakt_list, current_ids) self.config.Trakt.sync_list(self.sync_to_trakt_list, current_ids)
def delete(self): def delete(self):

@ -240,13 +240,13 @@ class MyAnimeList:
mal_ids = self._ranked(mal_ranked_name[method], data) mal_ids = self._ranked(mal_ranked_name[method], data)
elif method == "mal_search": elif method == "mal_search":
logger.info(f"Processing {data[1]}") logger.info(f"Processing {data[1]}")
mal_ids = self._pagination("anime", params=data[0], limit=data[2]) mal_ids = [mal_data["mal_id"] for mal_data in self._pagination("anime", params=data[0], limit=data[2])]
elif method == "mal_genre": elif method == "mal_genre":
logger.info(f"Processing {mal_ranked_pretty[method]} ID: {data['genre_id']}") logger.info(f"Processing {mal_ranked_pretty[method]} ID: {data['genre_id']}")
mal_ids = self._pagination("anime", params={"genres": data["genre_id"]}, limit=data["limit"]) mal_ids = [mal_data["mal_id"] for mal_data in self._pagination("anime", params={"genres": data["genre_id"]}, limit=data["limit"])]
elif method == "mal_studio": elif method == "mal_studio":
logger.info(f"Processing {mal_ranked_pretty[method]} ID: {data['studio_id']}") logger.info(f"Processing {mal_ranked_pretty[method]} ID: {data['studio_id']}")
mal_ids = self._pagination("anime", params={"producers": data["studio_id"]}, limit=data["limit"]) mal_ids = [mal_data["mal_id"] for mal_data in self._pagination("anime", params={"producers": data["studio_id"]}, limit=data["limit"])]
elif method == "mal_season": elif method == "mal_season":
logger.info(f"Processing MyAnimeList Season: {data['limit']} Anime from {data['season'].title()} {data['year']} sorted by {pretty_names[data['sort_by']]}") logger.info(f"Processing MyAnimeList Season: {data['limit']} Anime from {data['season'].title()} {data['year']} sorted by {pretty_names[data['sort_by']]}")
mal_ids = self._season(data["season"], data["year"], data["sort_by"], data["limit"]) mal_ids = self._season(data["season"], data["year"], data["sort_by"], data["limit"])

@ -305,20 +305,48 @@ class Trakt:
def sync_list(self, slug, ids): def sync_list(self, slug, ids):
current_ids = self._list(slug, urlparse=False) current_ids = self._list(slug, urlparse=False)
def read_result(data, obj_type, result_type, result_str=None):
result_str = result_str if result_str else result_type.capitalize()
if data[result_type][obj_type] > 0:
logger.info(f"{data[result_type][obj_type]} {obj_type.capitalize()} {result_str}")
def read_not_found(data, result_str):
not_found = []
for item in data["not_found"]["movies"]:
not_found.append((item["ids"]["tmdb"], "tmdb"))
for item in data["not_found"]["shows"]:
not_found.append((item["ids"]["tvdb"], "tvdb"))
for item in data["not_found"]["seasons"]:
not_found.append((f"{item['ids']['tvdb']}_{item['seasons'][0]['number']}", "tvdb_season"))
for item in data["not_found"]["episodes"]:
not_found.append((f"{item['ids']['tvdb']}_{item['seasons'][0]['number']}_{item['seasons'][0]['episodes'][0]['number']}", "tvdb_episode"))
if not_found:
logger.error(f"{len(not_found)} Items Unable to {result_str}: {not_found}")
add_ids = [id_set for id_set in ids if id_set not in current_ids] add_ids = [id_set for id_set in ids if id_set not in current_ids]
if add_ids: if add_ids:
self._request(f"/users/me/lists/{slug}/items", json=self._build_item_json(add_ids)) logger.info("")
results = self._request(f"/users/me/lists/{slug}/items", json=self._build_item_json(add_ids))
for object_type in ["movies", "shows", "seasons", "episodes"]:
read_result(results, object_type, "added")
read_not_found(results, "Add")
time.sleep(1) time.sleep(1)
remove_ids = [id_set for id_set in current_ids if id_set not in ids] remove_ids = [id_set for id_set in current_ids if id_set not in ids]
if remove_ids: if remove_ids:
self._request(f"/users/me/lists/{slug}/items/remove", json=self._build_item_json(remove_ids)) logger.info("")
results = self._request(f"/users/me/lists/{slug}/items/remove", json=self._build_item_json(remove_ids))
for object_type in ["movies", "shows", "seasons", "episodes"]:
read_result(results, object_type, "deleted", "Removed")
read_not_found(results, "Remove")
time.sleep(1) time.sleep(1)
trakt_ids = self._list(slug, urlparse=False, trakt_ids=True) trakt_ids = self._list(slug, urlparse=False, trakt_ids=True)
trakt_lookup = {f"{ty}_{i_id}": t_id for t_id, i_id, ty in trakt_ids} trakt_lookup = {f"{ty}_{i_id}": t_id for t_id, i_id, ty in trakt_ids}
rank_ids = [trakt_lookup[f"{ty}_{i_id}"] for i_id, ty in ids if f"{ty}_{i_id}" in trakt_lookup] rank_ids = [trakt_lookup[f"{ty}_{i_id}"] for i_id, ty in ids if f"{ty}_{i_id}" in trakt_lookup]
self._request(f"/users/me/lists/{slug}/items/reorder", json={"rank": rank_ids}) self._request(f"/users/me/lists/{slug}/items/reorder", json={"rank": rank_ids})
logger.info("")
logger.info("Trakt List Ordered Successfully")
def all_user_lists(self, user="me"): def all_user_lists(self, user="me"):
try: try:

@ -127,7 +127,7 @@ def add_dict_list(keys, value, dict_map):
else: else:
dict_map[key] = [value] dict_map[key] = [value]
def get_list(data, lower=False, upper=False, split=True, int_list=False): def get_list(data, lower=False, upper=False, split=True, int_list=False, trim=True):
if split is True: split = "," if split is True: split = ","
if data is None: return None if data is None: return None
elif isinstance(data, list): list_data = data elif isinstance(data, list): list_data = data
@ -135,12 +135,15 @@ def get_list(data, lower=False, upper=False, split=True, int_list=False):
elif split is False: list_data = [str(data)] elif split is False: list_data = [str(data)]
else: list_data = str(data).split(split) else: list_data = str(data).split(split)
if lower is True: return [str(d).strip().lower() for d in list_data] def get_str(input_data):
elif upper is True: return [str(d).strip().upper() for d in list_data] return str(input_data).strip() if trim else str(input_data)
if lower is True: return [get_str(d).lower() for d in list_data]
elif upper is True: return [get_str(d).upper() for d in list_data]
elif int_list is True: elif int_list is True:
try: return [int(str(d).strip()) for d in list_data] try: return [int(get_str(d)) for d in list_data]
except ValueError: return [] except ValueError: return []
else: return [d if isinstance(d, dict) else str(d).strip() for d in list_data] else: return [d if isinstance(d, dict) else get_str(d) for d in list_data]
def get_int_list(data, id_type): def get_int_list(data, id_type):
int_values = [] int_values = []

Loading…
Cancel
Save