From 24beeb8c4de7a9cbec85e12bbd17b74e5ce971ee Mon Sep 17 00:00:00 2001 From: meisnate12 Date: Mon, 14 Mar 2022 00:53:07 -0400 Subject: [PATCH] [12] #750 add mass_originally_available_update --- VERSION | 2 +- modules/cache.py | 38 +++++++++++++++------------ modules/config.py | 26 ++++++++----------- modules/library.py | 3 ++- modules/mdblist.py | 5 ++++ modules/omdb.py | 62 ++++++++++++++++++++------------------------ modules/tvdb.py | 3 +++ plex_meta_manager.py | 30 ++++++++++++++++++--- 8 files changed, 98 insertions(+), 71 deletions(-) diff --git a/VERSION b/VERSION index f0163470..63eb2b7c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.16.1-develop11 +1.16.1-develop12 diff --git a/modules/cache.py b/modules/cache.py index 6666e828..07290cd8 100644 --- a/modules/cache.py +++ b/modules/cache.py @@ -22,7 +22,9 @@ class Cache: cursor.execute("DROP TABLE IF EXISTS imdb_to_tvdb_map") 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 omdb_data") + cursor.execute("DROP TABLE IF EXISTS omdb_data2") cursor.execute( """CREATE TABLE IF NOT EXISTS guids_map ( key INTEGER PRIMARY KEY, @@ -70,11 +72,12 @@ class Cache: expiration_date TEXT)""" ) cursor.execute( - """CREATE TABLE IF NOT EXISTS omdb_data2 ( + """CREATE TABLE IF NOT EXISTS omdb_data3 ( key INTEGER PRIMARY KEY, imdb_id TEXT UNIQUE, title TEXT, year INTEGER, + released TEXT, content_rating TEXT, genres TEXT, imdb_rating REAL, @@ -87,11 +90,12 @@ class Cache: expiration_date TEXT)""" ) cursor.execute( - """CREATE TABLE IF NOT EXISTS mdb_data ( + """CREATE TABLE IF NOT EXISTS mdb_data2 ( key INTEGER PRIMARY KEY, key_id TEXT UNIQUE, title TEXT, year INTEGER, + released TEXT, type TEXT, imdbid TEXT, traktid INTEGER, @@ -326,12 +330,13 @@ 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 omdb_data2 WHERE imdb_id = ?", (imdb_id,)) + cursor.execute("SELECT * FROM omdb_data3 WHERE imdb_id = ?", (imdb_id,)) row = cursor.fetchone() if row: omdb_dict["imdbID"] = row["imdb_id"] if row["imdb_id"] else None omdb_dict["Title"] = row["title"] if row["title"] else None omdb_dict["Year"] = row["year"] if row["year"] else None + omdb_dict["Released"] = row["released"] if row["released"] else None omdb_dict["Rated"] = row["content_rating"] if row["content_rating"] else None omdb_dict["Genre"] = row["genres"] if row["genres"] else None omdb_dict["imdbRating"] = row["imdb_rating"] if row["imdb_rating"] else None @@ -352,14 +357,14 @@ 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 omdb_data2(imdb_id) VALUES(?)", (omdb.imdb_id,)) - update_sql = "UPDATE omdb_data2 SET title = ?, year = ?, content_rating = ?, genres = ?, " \ + cursor.execute("INSERT OR IGNORE INTO omdb_data3(imdb_id) VALUES(?)", (omdb.imdb_id,)) + update_sql = "UPDATE omdb_data3 SET title = ?, year = ?, released = ?, content_rating = ?, genres = ?, " \ "imdb_rating = ?, imdb_votes = ?, metacritic_rating = ?, type = ?, series_id = ?, " \ "season_num = ?, episode_num = ?, expiration_date = ? WHERE imdb_id = ?" - cursor.execute(update_sql, (omdb.title, omdb.year, omdb.content_rating, omdb.genres_str, - omdb.imdb_rating, omdb.imdb_votes, omdb.metacritic_rating, omdb.type, - omdb.series_id, omdb.season_num, omdb.episode_num, - expiration_date.strftime("%Y-%m-%d"), omdb.imdb_id)) + cursor.execute(update_sql, ( + omdb.title, omdb.year, omdb.released.strftime("%d %b %Y"), omdb.content_rating, omdb.genres_str, + omdb.imdb_rating, omdb.imdb_votes, omdb.metacritic_rating, omdb.type, omdb.series_id, omdb.season_num, + omdb.episode_num, expiration_date.strftime("%Y-%m-%d"), omdb.imdb_id)) def query_mdb(self, key_id, expiration): mdb_dict = {} @@ -367,11 +372,12 @@ 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_data WHERE key_id = ?", (key_id,)) + cursor.execute("SELECT * FROM mdb_data2 WHERE key_id = ?", (key_id,)) row = cursor.fetchone() if row: mdb_dict["title"] = row["title"] if row["title"] else None mdb_dict["year"] = row["year"] if row["year"] else None + mdb_dict["released"] = row["released"] if row["released"] else None mdb_dict["type"] = row["type"] if row["type"] else None mdb_dict["imdbid"] = row["imdbid"] if row["imdbid"] else None mdb_dict["traktid"] = row["traktid"] if row["traktid"] else None @@ -399,16 +405,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_data(key_id) VALUES(?)", (key_id,)) - update_sql = "UPDATE mdb_data SET title = ?, year = ?, type = ?, imdbid = ?, traktid = ?, " \ + 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 = ?, " \ "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 = ?" cursor.execute(update_sql, ( - mdb.title, mdb.year, 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, expiration_date.strftime("%Y-%m-%d"), key_id + mdb.title, mdb.year, mdb.released.strftime("%Y-%m-%d"), 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, expiration_date.strftime("%Y-%m-%d"), key_id )) def query_tmdb_movie(self, tmdb_id, expiration): diff --git a/modules/config.py b/modules/config.py index 9b8a0f4d..b1037ae7 100644 --- a/modules/config.py +++ b/modules/config.py @@ -33,6 +33,7 @@ logger = util.logger sync_modes = {"append": "Only Add Items to the Collection or Playlist", "sync": "Add & Remove Items from the Collection or Playlist"} mass_genre_options = {"tmdb": "Use TMDb Metadata", "omdb": "Use IMDb Metadata through OMDb", "tvdb": "Use TVDb Metadata"} mass_content_options = {"omdb": "Use IMDb Metadata through OMDb", "mdb": "Use MdbList Metadata", "mdb_commonsense": "Use Commonsense Rating through MDbList"} +mass_available_options = {"tmdb": "Use TMDb Metadata", "omdb": "Use IMDb Metadata through OMDb", "mdb": "Use MdbList Metadata", "tvdb": "Use TVDb Metadata"} mass_rating_options = { "tmdb": "Use TMDb Rating", "omdb": "Use IMDb Rating through OMDb", @@ -600,7 +601,8 @@ class ConfigFile: "metadata_backup": None, "genre_collections": None, "update_blank_track_titles": None, - "mass_content_rating_update": None + "mass_content_rating_update": None, + "mass_originally_available_update": None } display_name = f"{params['name']} ({params['mapping_name']})" if lib and "library_name" in lib and lib["library_name"] else params["mapping_name"] @@ -669,6 +671,8 @@ class ConfigFile: params["mass_critic_rating_update"] = check_for_attribute(lib["operations"], "mass_critic_rating_update", test_list=mass_rating_options, default_is_none=True, save=False) if "mass_content_rating_update" in lib["operations"]: params["mass_content_rating_update"] = check_for_attribute(lib["operations"], "mass_content_rating_update", test_list=mass_content_options, default_is_none=True, save=False) + if "mass_originally_available_update" in lib["operations"]: + params["mass_originally_available_update"] = check_for_attribute(lib["operations"], "mass_originally_available_update", test_list=mass_available_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"]: @@ -785,20 +789,12 @@ class ConfigFile: self.errors.append(err) logger.error(err) - if self.OMDb is None and params["mass_genre_update"] == "omdb": - error_check("mass_genre_update", "OMDb") - if self.OMDb is None and params["mass_audience_rating_update"] == "omdb": - error_check("mass_audience_rating_update", "OMDb") - if self.OMDb is None and params["mass_critic_rating_update"] == "omdb": - error_check("mass_critic_rating_update", "OMDb") - if self.OMDb is None and params["mass_content_rating_update"] == "omdb": - error_check("mass_content_rating_update", "OMDb") - if not self.Mdblist.has_key and params["mass_audience_rating_update"] in util.mdb_types: - error_check("mass_audience_rating_update", "MdbList API") - if not self.Mdblist.has_key and params["mass_critic_rating_update"] in util.mdb_types: - error_check("mass_critic_rating_update", "MdbList API") - if not self.Mdblist.has_key and params["mass_content_rating_update"] in ["mdb", "mdb_commonsense"]: - error_check("mass_content_rating_update", "MdbList API") + for mass_key in ["mass_genre_update", "mass_audience_rating_update", "mass_critic_rating_update", "mass_content_rating_update", "mass_originally_available_update"]: + if params[mass_key] == "omdb" and self.OMDb is None: + error_check(mass_key, "OMDb") + if params[mass_key].startswith("mdb") and not self.Mdblist.has_key: + error_check(mass_key, "MdbList API") + if self.Trakt is None and params["mass_trakt_rating_update"]: error_check("mass_trakt_rating_update", "Trakt") diff --git a/modules/library.py b/modules/library.py index 6e57f27c..d0c41f42 100644 --- a/modules/library.py +++ b/modules/library.py @@ -72,6 +72,7 @@ class Library(ABC): self.mass_audience_rating_update = params["mass_audience_rating_update"] self.mass_critic_rating_update = params["mass_critic_rating_update"] self.mass_content_rating_update = params["mass_content_rating_update"] + self.mass_originally_available_update = params["mass_originally_available_update"] self.mass_trakt_rating_update = params["mass_trakt_rating_update"] self.radarr_add_all_existing = params["radarr_add_all_existing"] self.radarr_remove_by_tag = params["radarr_remove_by_tag"] @@ -94,7 +95,7 @@ class Library(ABC): self.status = {} self.items_library_operation = True if self.assets_for_all or self.mass_genre_update or self.mass_audience_rating_update \ - or self.mass_critic_rating_update or self.mass_content_rating_update or self.mass_trakt_rating_update \ + or self.mass_critic_rating_update or self.mass_content_rating_update or self.mass_originally_available_update or self.mass_trakt_rating_update \ or self.genre_mapper or self.content_rating_mapper or self.tmdb_collections or self.radarr_add_all_existing or self.sonarr_add_all_existing else False self.library_operation = True if self.items_library_operation or self.delete_unmanaged_collections or self.delete_collections_with_less \ or self.radarr_remove_by_tag or self.sonarr_remove_by_tag or self.mass_collection_mode \ diff --git a/modules/mdblist.py b/modules/mdblist.py index a1333036..23a13460 100644 --- a/modules/mdblist.py +++ b/modules/mdblist.py @@ -1,3 +1,4 @@ +from datetime import datetime from modules import util from modules.util import Failed from urllib.parse import urlparse @@ -17,6 +18,10 @@ class MDbObj: self._data = data self.title = data["title"] self.year = util.check_num(data["year"]) + try: + self.released = datetime.strptime(data["released"], "%Y-%m-%d") + except ValueError: + self.released = None self.type = data["type"] self.imdbid = data["imdbid"] self.traktid = util.check_num(data["traktid"]) diff --git a/modules/omdb.py b/modules/omdb.py index 1cf954cc..7d7a0ca7 100644 --- a/modules/omdb.py +++ b/modules/omdb.py @@ -1,3 +1,4 @@ +from datetime import datetime from modules import util from modules.util import Failed @@ -11,40 +12,33 @@ class OMDbObj: self._data = data if data["Response"] == "False": raise Failed(f"OMDb Error: {data['Error']} IMDb ID: {imdb_id}") - self.title = data["Title"] - try: - self.year = int(data["Year"]) - except (ValueError, TypeError): - self.year = None - self.content_rating = data["Rated"] - self.genres = util.get_list(data["Genre"]) - self.genres_str = data["Genre"] - try: - self.imdb_rating = float(data["imdbRating"]) - except (ValueError, TypeError): - self.imdb_rating = None - try: - self.imdb_votes = int(str(data["imdbVotes"]).replace(',', '')) - except (ValueError, TypeError): - self.imdb_votes = None - try: - self.metacritic_rating = int(data["Metascore"]) - except (ValueError, TypeError): - self.metacritic_rating = None - self.imdb_id = data["imdbID"] - self.type = data["Type"] - try: - self.series_id = data["seriesID"] - except (ValueError, TypeError, KeyError): - self.series_id = None - try: - self.season_num = int(data["Season"]) - except (ValueError, TypeError, KeyError): - self.season_num = None - try: - self.episode_num = int(data["Episode"]) - except (ValueError, TypeError, KeyError): - self.episode_num = None + def _parse(key, is_int=False, is_float=False, is_date=False, replace=None): + try: + value = str(data[key]).replace(replace, '') if replace else data[key] + if is_int: + return int(value) + elif is_float: + return float(value) + elif is_date: + return datetime.strptime(value, "%d %b %Y") + else: + return value + except (ValueError, TypeError, KeyError): + return None + self.title = _parse("Title") + self.year = _parse("Year", is_int=True) + self.released = _parse("Released", is_date=True) + self.content_rating = _parse("Rated") + self.genres_str = _parse("Genre") + self.genres = util.get_list(self.genres_str) + self.imdb_rating = _parse("imdbRating", is_float=True) + self.imdb_votes = _parse("imdbVotes", is_int=True, replace=",") + self.metacritic_rating = _parse("Metascore", is_int=True) + self.imdb_id = _parse("imdbID") + self.type = _parse("Type") + self.series_id = _parse("seriesID") + self.season_num = _parse("Season", is_int=True) + self.episode_num = _parse("Episode", is_int=True) class OMDb: diff --git a/modules/tvdb.py b/modules/tvdb.py index e82db9a4..bde31947 100644 --- a/modules/tvdb.py +++ b/modules/tvdb.py @@ -1,4 +1,5 @@ import requests, time +from datetime import datetime from lxml.etree import ParserError from modules import util from modules.util import Failed @@ -91,8 +92,10 @@ class TVDbObj: self.directors = parse_page("//strong[text()='Directors']/parent::li/span/a/text()[normalize-space()]", is_list=True) self.writers = parse_page("//strong[text()='Writers']/parent::li/span/a/text()[normalize-space()]", is_list=True) self.studios = parse_page("//strong[text()='Studio']/parent::li/span/a/text()[normalize-space()]", is_list=True) + self.released = datetime.strptime(parse_page("//strong[text()='Released']/parent::li/span/text()[normalize-space()]"), "%B %d, %Y") else: self.networks = parse_page("//strong[text()='Networks']/parent::li/span/a/text()[normalize-space()]", is_list=True) + self.released = datetime.strptime(parse_page("//strong[text()='First Aired']/parent::li/span/text()[normalize-space()]"), "%B %d, %Y") self.genres = parse_page("//strong[text()='Genres']/parent::li/span/a/text()[normalize-space()]", is_list=True) tmdb_id = None diff --git a/plex_meta_manager.py b/plex_meta_manager.py index a835d418..a1ce95bd 100644 --- a/plex_meta_manager.py +++ b/plex_meta_manager.py @@ -407,6 +407,7 @@ def library_operations(config, library): logger.debug(f"Mass Audience Rating Update: {library.mass_audience_rating_update}") logger.debug(f"Mass Critic Rating Update: {library.mass_critic_rating_update}") logger.debug(f"Mass Content Rating Update: {library.mass_content_rating_update}") + logger.debug(f"Mass Originally Available Update: {library.mass_originally_available_update}") logger.debug(f"Mass Trakt Rating Update: {library.mass_trakt_rating_update}") logger.debug(f"Mass Collection Mode Update: {library.mass_collection_mode}") logger.debug(f"Split Duplicates: {library.split_duplicates}") @@ -483,12 +484,14 @@ def library_operations(config, library): sonarr_adds.append((tvdb_id, path)) tmdb_item = None - if library.tmdb_collections or library.mass_genre_update == "tmdb" or library.mass_audience_rating_update == "tmdb" or library.mass_critic_rating_update == "tmdb": + if library.tmdb_collections or library.mass_genre_update == "tmdb" or library.mass_audience_rating_update == "tmdb" \ + or library.mass_critic_rating_update == "tmdb" or library.mass_originally_available_update == "tmdb": tmdb_item = config.TMDb.get_item(item, tmdb_id, tvdb_id, imdb_id, is_movie=library.is_movie) omdb_item = None if library.mass_genre_update == "omdb" or library.mass_audience_rating_update == "omdb" \ - or library.mass_critic_rating_update == "omdb" or library.mass_content_rating_update == "omdb": + or library.mass_critic_rating_update == "omdb" or library.mass_content_rating_update == "omdb" \ + or library.mass_originally_available_update == "omdb": if config.OMDb.limit is False: if tmdb_id and not imdb_id: imdb_id = config.Convert.tmdb_to_imdb(tmdb_id) @@ -506,7 +509,7 @@ def library_operations(config, library): logger.info(f"{item.title[:25]:<25} | No IMDb ID for Guid: {item.guid}") tvdb_item = None - if library.mass_genre_update == "tvdb": + if library.mass_genre_update == "tvdb" or library.mass_originally_available_update == "tvdb": if tvdb_id: try: tvdb_item = config.TVDb.get_item(tvdb_id, library.is_movie) @@ -517,7 +520,7 @@ def library_operations(config, library): mdb_item = None if library.mass_audience_rating_update in util.mdb_types or library.mass_critic_rating_update in util.mdb_types \ - or library.mass_content_rating_update in ["mdb", "mdb_commonsense"]: + or library.mass_content_rating_update in ["mdb", "mdb_commonsense"] or library.mass_originally_available_update == "mdb": if config.Mdblist.limit is False: if tmdb_id and not imdb_id: imdb_id = config.Convert.tmdb_to_imdb(tmdb_id) @@ -613,6 +616,25 @@ def library_operations(config, library): logger.info(f"{item.title[:25]:<25} | Content Rating | {new_rating}") except Failed: pass + if library.mass_originally_available_update: + try: + if omdb_item and library.mass_originally_available_update == "omdb": + new_date = omdb_item.released + elif mdb_item and library.mass_originally_available_update == "mdb": + new_date = mdb_item.released + elif tvdb_item and library.mass_content_rating_update == "tvdb": + new_date = tvdb_item.released + elif tmdb_item and library.mass_content_rating_update == "tvdb": + new_date = tmdb_item.release_date if library.is_movie else tmdb_item.first_air_date + else: + raise Failed + if new_date is None: + logger.info(f"{item.title[:25]:<25} | No Originally Available Date Found") + elif str(item.rating) != str(new_date): + library.edit_query(item, {"originallyAvailableAt.value": new_date.strftime("%Y-%m-%d"), "originallyAvailableAt.locked": 1}) + logger.info(f"{item.title[:25]:<25} | Originally Available Date | {new_date.strftime('%Y-%m-%d')}") + except Failed: + pass if library.genre_mapper or library.content_rating_mapper: try: