From 1f4c1f8e35e3be18970d6c8c6eb345b9850591f1 Mon Sep 17 00:00:00 2001 From: meisnate12 Date: Mon, 1 Aug 2022 11:55:00 -0400 Subject: [PATCH] [16] add mdb_myanimelist as a mass rating option --- VERSION | 2 +- docs/config/operations.md | 44 +++++++++++++++++++-------------------- modules/cache.py | 17 ++++++++------- modules/config.py | 1 + modules/mdblist.py | 14 +++++++++---- modules/meta.py | 5 ++--- modules/operations.py | 26 +++++++++++++++++------ modules/overlay.py | 2 +- modules/plex.py | 5 ++++- 9 files changed, 71 insertions(+), 45 deletions(-) diff --git a/VERSION b/VERSION index c48b6951..c402a380 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.17.2-develop15 +1.17.2-develop16 diff --git a/docs/config/operations.md b/docs/config/operations.md index daf2a1f0..746ebb1c 100644 --- a/docs/config/operations.md +++ b/docs/config/operations.md @@ -16,28 +16,28 @@ libraries: The available attributes for the operations attribute are as follows -| Attribute | Description | -|:--------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `assets_for_all` | Search in assets for images for every item in your library.
**Values:** `true` or `false` | -| `delete_collections_with_less` | Deletes every collection with less than the given number of items.
**Values:** number greater than 0 | -| `delete_unmanaged_collections` | Deletes every unmanaged collection
**Values:** `true` or `false` | -| `mass_genre_update` | Updates every item's genres in the library to the chosen site's genres
**Values:**
`tmdb`Use TMDb for Genres
`tvdb`Use TVDb for Genres
`imdb`Use IMDb for Genres
`omdb`Use IMDb through OMDb for Genres
`anidb`Use AniDB Tags for Genres
| -| `mass_content_rating_update` | Updates every item's content rating in the library to the chosen site's content rating
**Values:**
`mdb`Use MdbList for Content Ratings
`mdb_commonsense`Use Commonsense Rating through MDbList for Content Ratings
`omdb`Use IMDb through OMDb for Content Ratings
| -| `mass_originally_available_update` | Updates every item's originally available date in the library to the chosen site's date
**Values:**
`tmdb`Use TMDb Release Date
`tvdb`Use TVDb Release Date
`omdb`Use IMDb Release Date through OMDb
`mdb`Use MdbList Release Date
`anidb`Use AniDB Release Date
| -| `mass_audience_rating_update`/
`mass_critic_rating_update`/
`mass_user_rating_update` | Updates every item's audience/critic/user rating in the library to the chosen site's rating
**Values:**
`tmdb`Use TMDb Rating
`imdb`Use IMDb Rating
`trakt_user`Use Trakt User's Personal Rating
`omdb`Use IMDbRating through OMDb
`mdb`Use MdbList Score
`mdb_imdb`Use IMDb Rating through MDbList
`mdb_metacritic`Use Metacritic Rating through MDbList
`mdb_metacriticuser`Use Metacritic User Rating through MDbList
`mdb_trakt`Use Trakt Rating through MDbList
`mdb_tomatoes`Use Rotten Tomatoes Rating through MDbList
`mdb_tomatoesaudience`Use Rotten Tomatoes Audience Rating through MDbList
`mdb_tmdb`Use TMDb Rating through MDbList
`mdb_letterboxd`Use Letterboxd Rating through MDbList
`anidb_rating`Use AniDB Rating
`anidb_average`Use AniDB Average
| -| `mass_episode_audience_rating_update`/
`mass_episode_critic_rating_update`/
`mass_episode_user_rating_update` | Updates every item's episode's audience/critic/user rating in the library to the chosen site's rating
**Values:**
`tmdb`Use TMDb Rating
`imdb`Use IMDb Rating
| -| `mass_imdb_parental_labels` | Updates every item's labels in the library to match the IMDb Parental Guide
**Values** `with_none` or `without_none` | -| `mass_collection_mode` | Updates every Collection in your library to the specified Collection Mode
**Values:** `default`: Library default
`hide`: Hide Collection
`hide_items`: Hide Items in this Collection
`show_items`: Show this Collection and its Items
`default`Library default
`hide`Hide Collection
`hide_items`Hide Items in this Collection
`show_items`Show this Collection and its Items
| -| `update_blank_track_titles` | Search though every track in a music library and replace any blank track titles with the tracks sort title
**Values:** `true` or `false` | -| `remove_title_parentheses` | Search through every title and remove all ending parentheses in an items title if the title isn not locked.
**Values:** `true` or `false` | -| `split_duplicates` | Splits all duplicate movies/shows found in this library
**Values:** `true` or `false` | -| `radarr_add_all` | Adds every item in the library to Radarr. The existing paths in plex will be used as the root folder of each item, if the paths in Plex are not the same as your Radarr paths you can use the `plex_path` and `radarr_path` [Radarr](radarr) details to convert the paths.
**Values:** `true` or `false` | -| `radarr_remove_by_tag` | Removes every item from Radarr with the Tags given
**Values:** List or comma separated string of tags | -| `sonarr_add_all` | Adds every item in the library to Sonarr. The existing paths in plex will be used as the root folder of each item, if the paths in Plex are not the same as your Sonarr paths you can use the `plex_path` and `sonarr_path` [Sonarr](sonarr) details to convert the paths.
**Values:** `true` or `false` | -| `sonarr_remove_by_tag` | Removes every item from Sonarr with the Tags given
**Values:** List or comma separated string of tags | -| [`genre_mapper`](#genre-mapper) | Allows genres to be changed to other genres or be removed from every item in your library.
**Values:** [see below for usage](#genre-mapper) | -| [`content_rating_mapper`](#content-rating-mapper) | Allows content ratings to be changed to other content ratings or be removed from every item in your library.
**Values:** [see below for usage](#content-rating-mapper) | -| [`metadata_backup`](#metadata-backup) | Creates/Maintains a PMM [Metadata File](../metadata/metadata) with a full `metadata` mapping based on the library's items locked attributes.
**Values:** [see below for usage](#metadata-backup) | +| Attribute | Description | +|:--------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `assets_for_all` | Search in assets for images for every item in your library.
**Values:** `true` or `false` | +| `delete_collections_with_less` | Deletes every collection with less than the given number of items.
**Values:** number greater than 0 | +| `delete_unmanaged_collections` | Deletes every unmanaged collection
**Values:** `true` or `false` | +| `mass_genre_update` | Updates every item's genres in the library to the chosen site's genres
**Values:**
`tmdb`Use TMDb for Genres
`tvdb`Use TVDb for Genres
`imdb`Use IMDb for Genres
`omdb`Use IMDb through OMDb for Genres
`anidb`Use AniDB Tags for Genres
| +| `mass_content_rating_update` | Updates every item's content rating in the library to the chosen site's content rating
**Values:**
`mdb`Use MdbList for Content Ratings
`mdb_commonsense`Use Commonsense Rating through MDbList for Content Ratings
`omdb`Use IMDb through OMDb for Content Ratings
| +| `mass_originally_available_update` | Updates every item's originally available date in the library to the chosen site's date
**Values:**
`tmdb`Use TMDb Release Date
`tvdb`Use TVDb Release Date
`omdb`Use IMDb Release Date through OMDb
`mdb`Use MdbList Release Date
`anidb`Use AniDB Release Date
| +| `mass_audience_rating_update`/
`mass_critic_rating_update`/
`mass_user_rating_update` | Updates every item's audience/critic/user rating in the library to the chosen site's rating
**Values:**
`tmdb`Use TMDb Rating
`imdb`Use IMDb Rating
`trakt_user`Use Trakt User's Personal Rating
`omdb`Use IMDbRating through OMDb
`mdb`Use MdbList Score
`mdb_imdb`Use IMDb Rating through MDbList
`mdb_metacritic`Use Metacritic Rating through MDbList
`mdb_metacriticuser`Use Metacritic User Rating through MDbList
`mdb_trakt`Use Trakt Rating through MDbList
`mdb_tomatoes`Use Rotten Tomatoes Rating through MDbList
`mdb_tomatoesaudience`Use Rotten Tomatoes Audience Rating through MDbList
`mdb_tmdb`Use TMDb Rating through MDbList
`mdb_letterboxd`Use Letterboxd Rating through MDbList
`mdb_myanimelist`Use MyAnimeList Rating through MDbList
`anidb_rating`Use AniDB Rating
`anidb_average`Use AniDB Average
| +| `mass_episode_audience_rating_update`/
`mass_episode_critic_rating_update`/
`mass_episode_user_rating_update` | Updates every item's episode's audience/critic/user rating in the library to the chosen site's rating
**Values:**
`tmdb`Use TMDb Rating
`imdb`Use IMDb Rating
| +| `mass_imdb_parental_labels` | Updates every item's labels in the library to match the IMDb Parental Guide
**Values** `with_none` or `without_none` | +| `mass_collection_mode` | Updates every Collection in your library to the specified Collection Mode
**Values:** `default`: Library default
`hide`: Hide Collection
`hide_items`: Hide Items in this Collection
`show_items`: Show this Collection and its Items
`default`Library default
`hide`Hide Collection
`hide_items`Hide Items in this Collection
`show_items`Show this Collection and its Items
| +| `update_blank_track_titles` | Search though every track in a music library and replace any blank track titles with the tracks sort title
**Values:** `true` or `false` | +| `remove_title_parentheses` | Search through every title and remove all ending parentheses in an items title if the title isn not locked.
**Values:** `true` or `false` | +| `split_duplicates` | Splits all duplicate movies/shows found in this library
**Values:** `true` or `false` | +| `radarr_add_all` | Adds every item in the library to Radarr. The existing paths in plex will be used as the root folder of each item, if the paths in Plex are not the same as your Radarr paths you can use the `plex_path` and `radarr_path` [Radarr](radarr) details to convert the paths.
**Values:** `true` or `false` | +| `radarr_remove_by_tag` | Removes every item from Radarr with the Tags given
**Values:** List or comma separated string of tags | +| `sonarr_add_all` | Adds every item in the library to Sonarr. The existing paths in plex will be used as the root folder of each item, if the paths in Plex are not the same as your Sonarr paths you can use the `plex_path` and `sonarr_path` [Sonarr](sonarr) details to convert the paths.
**Values:** `true` or `false` | +| `sonarr_remove_by_tag` | Removes every item from Sonarr with the Tags given
**Values:** List or comma separated string of tags | +| [`genre_mapper`](#genre-mapper) | Allows genres to be changed to other genres or be removed from every item in your library.
**Values:** [see below for usage](#genre-mapper) | +| [`content_rating_mapper`](#content-rating-mapper) | Allows content ratings to be changed to other content ratings or be removed from every item in your library.
**Values:** [see below for usage](#content-rating-mapper) | +| [`metadata_backup`](#metadata-backup) | Creates/Maintains a PMM [Metadata File](../metadata/metadata) with a full `metadata` mapping based on the library's items locked attributes.
**Values:** [see below for usage](#metadata-backup) | ## Genre Mapper diff --git a/modules/cache.py b/modules/cache.py index 50247df5..5f880fa8 100644 --- a/modules/cache.py +++ b/modules/cache.py @@ -23,6 +23,7 @@ class Cache: cursor.execute("DROP TABLE IF EXISTS tmdb_to_tvdb_map") cursor.execute("DROP TABLE IF EXISTS imdb_map") cursor.execute("DROP TABLE IF EXISTS mdb_data") + cursor.execute("DROP TABLE IF EXISTS mdb_data2") cursor.execute("DROP TABLE IF EXISTS omdb_data") cursor.execute("DROP TABLE IF EXISTS omdb_data2") cursor.execute("DROP TABLE IF EXISTS tvdb_data") @@ -93,7 +94,7 @@ class Cache: expiration_date TEXT)""" ) cursor.execute( - """CREATE TABLE IF NOT EXISTS mdb_data2 ( + """CREATE TABLE IF NOT EXISTS mdb_data3 ( key INTEGER PRIMARY KEY, key_id TEXT UNIQUE, title TEXT, @@ -112,6 +113,7 @@ class Cache: tomatoesaudience_rating INTEGER, tmdb_rating INTEGER, letterboxd_rating REAL, + myanimelist_rating REAL, commonsense TEXT, certification TEXT, expiration_date TEXT)""" @@ -422,7 +424,7 @@ class Cache: with sqlite3.connect(self.cache_path) as connection: connection.row_factory = sqlite3.Row with closing(connection.cursor()) as cursor: - cursor.execute("SELECT * FROM mdb_data2 WHERE key_id = ?", (key_id,)) + cursor.execute("SELECT * FROM mdb_data3 WHERE key_id = ?", (key_id,)) row = cursor.fetchone() if row: mdb_dict["title"] = row["title"] if row["title"] else None @@ -443,7 +445,8 @@ class Cache: {"source": "tomatoes", "value": row["tomatoes_rating"] if row["tomatoes_rating"] else None}, {"source": "tomatoesaudience", "value": row["tomatoesaudience_rating"] if row["tomatoesaudience_rating"] else None}, {"source": "tmdb", "value": row["tmdb_rating"] if row["tmdb_rating"] else None}, - {"source": "letterboxd", "value": row["letterboxd_rating"] if row["letterboxd_rating"] else None} + {"source": "letterboxd", "value": row["letterboxd_rating"] if row["letterboxd_rating"] else None}, + {"source": "myanimelist_rating", "value": row["myanimelist_rating"] if row["myanimelist_rating"] else None} ] datetime_object = datetime.strptime(row["expiration_date"], "%Y-%m-%d") time_between_insertion = datetime.now() - datetime_object @@ -455,16 +458,16 @@ class Cache: with sqlite3.connect(self.cache_path) as connection: connection.row_factory = sqlite3.Row with closing(connection.cursor()) as cursor: - cursor.execute("INSERT OR IGNORE INTO mdb_data2(key_id) VALUES(?)", (key_id,)) - update_sql = "UPDATE mdb_data2 SET title = ?, year = ?, released = ?, type = ?, imdbid = ?, traktid = ?, " \ + cursor.execute("INSERT OR IGNORE INTO mdb_data3(key_id) VALUES(?)", (key_id,)) + update_sql = "UPDATE mdb_data3 SET title = ?, year = ?, released = ?, type = ?, imdbid = ?, traktid = ?, " \ "tmdbid = ?, score = ?, imdb_rating = ?, metacritic_rating = ?, metacriticuser_rating = ?, " \ "trakt_rating = ?, tomatoes_rating = ?, tomatoesaudience_rating = ?, tmdb_rating = ?, " \ - "letterboxd_rating = ?, certification = ?, commonsense = ?, expiration_date = ? WHERE key_id = ?" + "letterboxd_rating = ?, myanimelist_rating = ?, certification = ?, commonsense = ?, expiration_date = ? WHERE key_id = ?" cursor.execute(update_sql, ( mdb.title, mdb.year, mdb.released.strftime("%Y-%m-%d") if mdb.released else None, mdb.type, mdb.imdbid, mdb.traktid, mdb.tmdbid, mdb.score, mdb.imdb_rating, mdb.metacritic_rating, mdb.metacriticuser_rating, mdb.trakt_rating, mdb.tomatoes_rating, mdb.tomatoesaudience_rating, - mdb.tmdb_rating, mdb.letterboxd_rating, mdb.content_rating, mdb.commonsense, + mdb.tmdb_rating, mdb.letterboxd_rating, mdb.myanimelist_rating, mdb.content_rating, mdb.commonsense, expiration_date.strftime("%Y-%m-%d"), key_id )) diff --git a/modules/config.py b/modules/config.py index 447846f7..08c526c0 100644 --- a/modules/config.py +++ b/modules/config.py @@ -52,6 +52,7 @@ mass_rating_options = { "mdb_tomatoesaudience": "Use Rotten Tomatoes Audience Rating through MDbList", "mdb_tmdb": "Use TMDb Rating through MDbList", "mdb_letterboxd": "Use Letterboxd Rating through MDbList", + "mdb_myanimelist": "Use MyAnimeList Rating through MDbList", "anidb_rating": "Use AniDB Rating", "anidb_average": "Use AniDB Average" } diff --git a/modules/mdblist.py b/modules/mdblist.py index 497ad0d9..6e085448 100644 --- a/modules/mdblist.py +++ b/modules/mdblist.py @@ -53,6 +53,8 @@ class MDbObj: self.tmdb_rating = util.check_num(rating["value"]) elif rating["source"] == "letterboxd": self.letterboxd_rating = util.check_num(rating["value"], is_int=False) + elif rating["source"] == "myanimelist": + self.myanimelist_rating = util.check_num(rating["value"], is_int=False) self.content_rating = data["certification"] self.commonsense = data["commonsense"] @@ -78,7 +80,7 @@ class Mdblist: def has_key(self): return self.apikey is not None - def _request(self, imdb_id=None, tmdb_id=None, is_movie=True, ignore_cache=False): + def _request(self, imdb_id=None, tmdb_id=None, tvdb_id=None, is_movie=True, ignore_cache=False): params = {"apikey": self.apikey} if imdb_id: params["i"] = imdb_id @@ -87,8 +89,12 @@ class Mdblist: params["tm"] = tmdb_id params["m"] = "movie" if is_movie else "show" key = f"{'tm' if is_movie else 'ts'}{tmdb_id}" + elif tvdb_id: + params["tv"] = tvdb_id + params["m"] = "movie" if is_movie else "show" + key = f"{'tvm' if is_movie else 'tvs'}{tmdb_id}" else: - raise Failed("MdbList Error: Either IMDb ID or TMDb ID and TMDb Type Required") + raise Failed("MdbList Error: Either IMDb ID, TVDb ID, or TMDb ID and TMDb Type Required") expired = None if self.config.Cache and not ignore_cache: mdb_dict, expired = self.config.Cache.query_mdb(key, self.expiration) @@ -110,8 +116,8 @@ class Mdblist: def get_imdb(self, imdb_id): return self._request(imdb_id=imdb_id) - def get_series(self, tmdb_id): - return self._request(tmdb_id=tmdb_id, is_movie=False) + def get_series(self, tvdb_id): + return self._request(tvdb_id=tvdb_id, is_movie=False) def get_movie(self, tmdb_id): return self._request(tmdb_id=tmdb_id, is_movie=True) diff --git a/modules/meta.py b/modules/meta.py index ed4a42ac..89506bde 100644 --- a/modules/meta.py +++ b/modules/meta.py @@ -509,10 +509,9 @@ class MetadataFile(DataFile): logger.ghost(f"Processing: {i}/{len(all_items)} {item.title}") tmdb_id, tvdb_id, imdb_id = library.get_ids(item) tmdb_item = config.TMDb.get_item(item, tmdb_id, tvdb_id, imdb_id, is_movie=True) - if tmdb_item and tmdb_item.collection_id and tmdb_item.collection_name: + if tmdb_item and tmdb_item.collection_id and tmdb_item.collection_name and str(tmdb_item.collection_id) not in exclude and tmdb_item.collection_name not in exclude: all_keys.append(str(tmdb_item.collection_id)) - if str(tmdb_item.collection_id) not in exclude and tmdb_item.collection_name not in exclude: - auto_list[str(tmdb_item.collection_id)] = tmdb_item.collection_name + auto_list[str(tmdb_item.collection_id)] = tmdb_item.collection_name logger.exorcise() elif auto_type == "original_language": all_items = library.get_all() diff --git a/modules/operations.py b/modules/operations.py index 0f3685f5..57262d33 100644 --- a/modules/operations.py +++ b/modules/operations.py @@ -173,11 +173,23 @@ class Operations: mdb_item = None if any([o and o.startswith("mdb") for o in self.library.meta_operations]): if self.config.Mdblist.limit is False: - if tmdb_id and not imdb_id: - imdb_id = self.config.Convert.tmdb_to_imdb(tmdb_id) - elif tvdb_id and not imdb_id: - imdb_id = self.config.Convert.tvdb_to_imdb(tvdb_id) - if imdb_id: + if tmdb_id: + try: + mdb_item = self.config.Mdblist.get_movie(tmdb_id) + except Failed as e: + logger.error(str(e)) + except Exception: + logger.error(f"TMDb ID: {tmdb_id}") + raise + elif tvdb_id: + try: + mdb_item = self.config.Mdblist.get_series(tvdb_id) + except Failed as e: + logger.error(str(e)) + except Exception: + logger.error(f"TVDb ID: {tvdb_id}") + raise + elif imdb_id: try: mdb_item = self.config.Mdblist.get_imdb(imdb_id) except Failed as e: @@ -186,7 +198,7 @@ class Operations: logger.error(f"IMDb ID: {imdb_id}") raise else: - logger.info(f"No IMDb ID for Guid: {item.guid}") + logger.info(f"No TMDb ID, TVDb ID, or IMDb ID for Guid: {item.guid}") def get_rating(attribute): if tmdb_item and attribute == "tmdb": @@ -217,6 +229,8 @@ class Operations: found_rating = mdb_item.tmdb_rating / 10 if mdb_item.tmdb_rating else None elif mdb_item and attribute == "mdb_letterboxd": found_rating = mdb_item.letterboxd_rating * 2 if mdb_item.letterboxd_rating else None + elif mdb_item and attribute == "mdb_myanimelist": + found_rating = mdb_item.myanimelist_rating if mdb_item.myanimelist_rating else None elif anidb_item and attribute == "anidb_rating": found_rating = anidb_item.rating elif anidb_item and attribute == "anidb_average": diff --git a/modules/overlay.py b/modules/overlay.py index b0e33414..f1f1bd30 100644 --- a/modules/overlay.py +++ b/modules/overlay.py @@ -263,7 +263,7 @@ class Overlay: if not os.path.exists(font): fonts = util.get_system_fonts() if font not in fonts: - raise Failed(f"Overlay Error: font: {font} not found. Options: {', '.join(fonts)}") + raise Failed(f"Overlay Error: font: {os.path.abspath(font)} not found. Options: {', '.join(fonts)}") self.font_name = font self.font = ImageFont.truetype(self.font_name, self.font_size) if "font_style" in self.data and self.data["font_style"]: diff --git a/modules/plex.py b/modules/plex.py index 862c8be6..77feb043 100644 --- a/modules/plex.py +++ b/modules/plex.py @@ -556,7 +556,10 @@ class Plex(Library): @retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_plex) def item_labels(self, item): - return item.labels + try: + return item.labels + except BadRequest: + raise Failed(f"Item: {item.title} Labels failed to load") @retry(stop_max_attempt_number=6, wait_fixed=10000, retry_on_exception=util.retry_if_not_plex) def reload(self, item, force=False):