add mdblist mass rating update options

pull/707/head
meisnate12 3 years ago
parent bbf571e79c
commit d4749eda9b

@ -1 +1 @@
1.15.1-develop50
1.15.1-develop51

@ -86,6 +86,28 @@ class Cache:
episode_num INTEGER,
expiration_date TEXT)"""
)
cursor.execute(
"""CREATE TABLE IF NOT EXISTS mdb_data (
key INTEGER PRIMARY KEY,
key_id TEXT UNIQUE,
title TEXT,
year INTEGER,
type TEXT,
imdbid TEXT,
traktid INTEGER,
tmdbid INTEGER,
score INTEGER,
imdb_rating REAL,
metacritic_rating INTEGER,
metacriticuser_rating REAL,
trakt_rating INTEGER,
tomatoes_rating INTEGER,
tomatoesaudience_rating INTEGER,
tmdb_rating INTEGER,
letterboxd_rating REAL,
commonsense TEXT,
expiration_date TEXT)"""
)
cursor.execute(
"""CREATE TABLE IF NOT EXISTS anime_map (
key INTEGER PRIMARY KEY,
@ -288,6 +310,55 @@ class Cache:
omdb.series_id, omdb.season_num, omdb.episode_num,
expiration_date.strftime("%Y-%m-%d"), omdb.imdb_id))
def query_mdb(self, key_id):
mdb_dict = {}
expired = None
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,))
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["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
mdb_dict["tmdbid"] = row["tmdbid"] if row["tmdbid"] else None
mdb_dict["score"] = row["score"] if row["score"] else None
mdb_dict["commonsense"] = row["commonsense"] if row["commonsense"] else None
mdb_dict["ratings"] = [
{"source": "imdb", "value": row["imdb_rating"] if row["imdb_rating"] else None},
{"source": "metacritic", "value": row["metacritic_rating"] if row["metacritic_rating"] else None},
{"source": "metacriticuser", "value": row["metacriticuser_rating"] if row["metacriticuser_rating"] else None},
{"source": "trakt", "value": row["trakt_rating"] if row["trakt_rating"] else None},
{"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}
]
datetime_object = datetime.strptime(row["expiration_date"], "%Y-%m-%d")
time_between_insertion = datetime.now() - datetime_object
expired = time_between_insertion.days > self.expiration
return mdb_dict, expired
def update_mdb(self, expired, key_id, mdb):
expiration_date = datetime.now() if expired is True else (datetime.now() - timedelta(days=random.randint(1, self.expiration)))
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 = ?, " \
"tmdbid = ?, score = ?, imdb_rating = ?, metacritic_rating = ?, metacriticuser_rating = ?, " \
"trakt_rating = ?, tomatoes_rating = ?, tomatoesaudience_rating = ?, tmdb_rating = ?, " \
"letterboxd_rating = ?, 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.commonsense,
expiration_date.strftime("%Y-%m-%d"), key_id
))
def query_anime_map(self, anime_id, id_type):
ids = None
expired = None

@ -32,6 +32,19 @@ logger = logging.getLogger("Plex Meta Manager")
sync_modes = {"append": "Only Add Items to the Collection or Playlist", "sync": "Add & Remove Items from the Collection or Playlist"}
mass_update_options = {"tmdb": "Use TMDb Metadata", "omdb": "Use IMDb Metadata through OMDb"}
mass_rating_options = {
"tmdb": "Use TMDb Rating",
"omdb": "Use IMDb Rating through OMDb",
"mdb": "Use MdbList Average 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"
}
class ConfigFile:
def __init__(self, default_dir, attrs, read_only):
@ -149,6 +162,7 @@ class ConfigFile:
if "tmdb" in new_config: new_config["tmdb"] = new_config.pop("tmdb")
if "tautulli" in new_config: new_config["tautulli"] = new_config.pop("tautulli")
if "omdb" in new_config: new_config["omdb"] = new_config.pop("omdb")
if "mdblist" in new_config: new_config["mdblist"] = new_config.pop("mdblist")
if "notifiarr" in new_config: new_config["notifiarr"] = new_config.pop("notifiarr")
if "anidb" in new_config: new_config["anidb"] = new_config.pop("anidb")
if "radarr" in new_config:
@ -372,6 +386,21 @@ class ConfigFile:
util.separator()
self.Mdblist = Mdblist(self)
if "mdblist" in self.data:
logger.info("Connecting to Mdblist...")
try:
self.Mdblist.add_key(check_for_attribute(self.data, "apikey", parent="mdblist", throw=True))
logger.info("Mdblist Connection Successful")
except Failed as e:
self.errors.append(e)
logger.error(e)
logger.info("Mdblist Connection Failed")
else:
logger.warning("mdblist attribute not found")
util.separator()
self.Trakt = None
if "trakt" in self.data:
logger.info("Connecting to Trakt...")
@ -492,7 +521,6 @@ class ConfigFile:
self.ICheckMovies = ICheckMovies(self)
self.Letterboxd = Letterboxd(self)
self.StevenLu = StevenLu(self)
self.Mdblist = Mdblist(self)
util.separator()
@ -605,8 +633,8 @@ class ConfigFile:
params["changes_webhooks"] = check_for_attribute(lib, "changes", parent="webhooks", var_type="list", default=self.webhooks["changes"], do_print=False, save=False, default_is_none=True)
params["assets_for_all"] = check_for_attribute(lib, "assets_for_all", parent="settings", var_type="bool", default=self.general["assets_for_all"], do_print=False, save=False)
params["mass_genre_update"] = check_for_attribute(lib, "mass_genre_update", test_list=mass_update_options, default_is_none=True, save=False, do_print=False)
params["mass_audience_rating_update"] = check_for_attribute(lib, "mass_audience_rating_update", test_list=mass_update_options, default_is_none=True, save=False, do_print=False)
params["mass_critic_rating_update"] = check_for_attribute(lib, "mass_critic_rating_update", test_list=mass_update_options, default_is_none=True, save=False, do_print=False)
params["mass_audience_rating_update"] = check_for_attribute(lib, "mass_audience_rating_update", test_list=mass_rating_options, default_is_none=True, save=False, do_print=False)
params["mass_critic_rating_update"] = check_for_attribute(lib, "mass_critic_rating_update", test_list=mass_rating_options, default_is_none=True, save=False, do_print=False)
params["mass_trakt_rating_update"] = check_for_attribute(lib, "mass_trakt_rating_update", var_type="bool", default=False, save=False, do_print=False)
params["split_duplicates"] = check_for_attribute(lib, "split_duplicates", var_type="bool", default=False, save=False, do_print=False)
params["radarr_add_all_existing"] = check_for_attribute(lib, "radarr_add_all_existing", var_type="bool", default=False, save=False, do_print=False)
@ -624,9 +652,9 @@ class ConfigFile:
if "mass_genre_update" in lib["operations"]:
params["mass_genre_update"] = check_for_attribute(lib["operations"], "mass_genre_update", test_list=mass_update_options, default_is_none=True, save=False)
if "mass_audience_rating_update" in lib["operations"]:
params["mass_audience_rating_update"] = check_for_attribute(lib["operations"], "mass_audience_rating_update", test_list=mass_update_options, default_is_none=True, save=False)
params["mass_audience_rating_update"] = check_for_attribute(lib["operations"], "mass_audience_rating_update", test_list=mass_rating_options, default_is_none=True, save=False)
if "mass_critic_rating_update" in lib["operations"]:
params["mass_critic_rating_update"] = check_for_attribute(lib["operations"], "mass_critic_rating_update", test_list=mass_update_options, default_is_none=True, save=False)
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_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"]:
@ -724,8 +752,8 @@ class ConfigFile:
logger.error("Config Error: operations must be a dictionary")
def error_check(attr, service):
err = f"Config Error: {attr} cannot be {params[attr]} without a successful {service} Connection"
params[attr] = None
err = f"Config Error: {attr} cannot be omdb without a successful {service} Connection"
self.errors.append(err)
logger.error(err)
@ -735,6 +763,10 @@ class ConfigFile:
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 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 self.Trakt is None and params["mass_trakt_rating_update"]:
error_check("mass_trakt_rating_update", "Trakt")

@ -8,12 +8,103 @@ logger = logging.getLogger("Plex Meta Manager")
builders = ["mdblist_list"]
list_sorts = ["score", "released", "updated", "imdbrating", "rogerebert", "imdbvotes", "budget", "revenue"]
base_url = "https://mdblist.com/lists"
api_url = "https://mdblist.com/api/"
headers = {"User-Agent": "Plex-Meta-Manager"}
class MDbObj:
def __init__(self, data):
self._data = data
self.title = data["title"]
self.year = util.check_num(data["year"])
self.type = data["type"]
self.imdbid = data["imdbid"]
self.traktid = util.check_num(data["traktid"])
self.tmdbid = util.check_num(data["tmdbid"])
self.score = util.check_num(data["score"])
self.imdb_rating = None
self.metacritic_rating = None
self.metacriticuser_rating = None
self.trakt_rating = None
self.tomatoes_rating = None
self.tomatoesaudience_rating = None
self.tmdb_rating = None
self.letterboxd_rating = None
for rating in data["ratings"]:
if rating["source"] == "imdb":
self.imdb_rating = util.check_num(rating["value"], is_int=False)
elif rating["source"] == "metacritic":
self.metacritic_rating = util.check_num(rating["value"])
elif rating["source"] == "metacriticuser":
self.metacriticuser_rating = util.check_num(rating["value"], is_int=False)
elif rating["source"] == "trakt":
self.trakt_rating = util.check_num(rating["value"])
elif rating["source"] == "tomatoes":
self.tomatoes_rating = util.check_num(rating["value"])
elif rating["source"] == "tomatoesaudience":
self.tomatoesaudience_rating = util.check_num(rating["value"])
elif rating["source"] == "tmdb":
self.tmdb_rating = util.check_num(rating["value"])
elif rating["source"] == "letterboxd":
self.letterboxd_rating = util.check_num(rating["value"], is_int=False)
self.commonsense = data["commonsense"]
class Mdblist:
def __init__(self, config):
self.config = config
self.apikey = None
self.limit = False
def add_key(self, apikey):
self.apikey = apikey
try:
self._request(imdb_id="tt0080684", ignore_cache=True)
except Failed:
self.apikey = None
raise
@property
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):
params = {"apikey": self.apikey}
if imdb_id:
params["i"] = imdb_id
key = imdb_id
elif tmdb_id:
params["tm"] = tmdb_id
params["m"] = "movie" if is_movie else "show"
key = f"{'tm' if is_movie else 'ts'}{tmdb_id}"
else:
raise Failed("MdbList Error: Either IMDb 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)
if mdb_dict and expired is False:
return MDbObj(mdb_dict)
if self.config.trace_mode:
logger.debug(f"ID: {key}")
response = self.config.get_json(api_url, params=params)
if "response" in response and response["response"] is False:
if response["error"] == "API Limit Reached!":
self.limit = True
raise Failed(f"MdbList Error: {response['error']}")
else:
mdb = MDbObj(response)
if self.config.Cache and not ignore_cache:
self.config.Cache.update_mdb(expired, key, mdb)
return mdb
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_movie(self, tmdb_id):
return self._request(tmdb_id=tmdb_id, is_movie=True)
def validate_mdblist_lists(self, mdb_lists):
valid_lists = []

@ -81,12 +81,12 @@ advance_tags_to_edit = {
"metadata_language", "use_original_title"],
"Artist": ["album_sorting"]
}
tags_to_edit = {
"Movie": ["genre", "label", "collection", "country", "director", "producer", "writer"],
"Show": ["genre", "label", "collection"],
"Artist": ["genre", "style", "mood", "country", "collection", "similar_artist"]
}
mdb_types = ["mdb", "mdb_imdb", "mdb_metacritic", "mdb_metacriticuser", "mdb_trakt", "mdb_tomatoes", "mdb_tomatoesaudience", "mdb_tmdb", "mdb_letterboxd"]
def tab_new_lines(data):
return str(data).replace("\n", "\n ") if "\n" in str(data) else str(data)
@ -323,6 +323,12 @@ def time_window(tw):
else:
return tw
def check_num(num, is_int=True):
try:
return int(str(num)) if is_int else float(str(num))
except (ValueError, TypeError):
return None
def glob_filter(filter_in):
filter_in = filter_in.translate({ord("["): "[[]", ord("]"): "[]]"}) if "[" in filter_in else filter_in
return glob.glob(filter_in)

@ -536,9 +536,53 @@ def library_operations(config, library):
else:
logger.info(util.adjust_space(f"{item.title[:25]:<25} | No TVDb ID for Guid: {item.guid}"))
mdb_item = None
if library.mass_audience_rating_update in util.mdb_types or library.mass_critic_rating_update in util.mdb_types:
if config.Mdblist.limit is False:
if tmdb_id and not imdb_id:
imdb_id = config.Convert.tmdb_to_imdb(tmdb_id)
elif tvdb_id and not imdb_id:
imdb_id = config.Convert.tvdb_to_imdb(tvdb_id)
if imdb_id:
try:
mdb_item = config.Mdblist.get_imdb(imdb_id)
except Failed as e:
logger.error(util.adjust_space(str(e)))
except Exception:
logger.error(f"IMDb ID: {imdb_id}")
raise
else:
logger.info(util.adjust_space(f"{item.title[:25]:<25} | No IMDb ID for Guid: {item.guid}"))
if library.tmdb_collections and tmdb_item and tmdb_item.collection:
tmdb_collections[tmdb_item.collection.id] = tmdb_item.collection.name
def get_rating(attribute):
if tmdb_item and attribute == "tmdb":
return tmdb_item.vote_average
elif omdb_item and attribute in ["omdb", "imdb"]:
return omdb_item.imdb_rating
elif mdb_item and attribute == "mdb":
return mdb_item.score / 10 if mdb_item.score else None
elif mdb_item and attribute == "mdb_imdb":
return mdb_item.imdb_rating if mdb_item.imdb_rating else None
elif mdb_item and attribute == "mdb_metacritic":
return mdb_item.metacritic_rating / 10 if mdb_item.metacritic_rating else None
elif mdb_item and attribute == "mdb_metacriticuser":
return mdb_item.metacriticuser_rating if mdb_item.metacriticuser_rating else None
elif mdb_item and attribute == "mdb_trakt":
return mdb_item.trakt_rating / 10 if mdb_item.trakt_rating else None
elif mdb_item and attribute == "mdb_tomatoes":
return mdb_item.tmdb_rating / 10 if mdb_item.tomatoes_rating else None
elif mdb_item and attribute == "mdb_tomatoesaudience":
return mdb_item.tomatoesaudience_rating / 10 if mdb_item.tomatoesaudience_rating else None
elif mdb_item and attribute == "mdb_tmdb":
return mdb_item.tmdb_rating / 10 if mdb_item.tmdb_rating else None
elif mdb_item and attribute == "mdb_letterboxd":
return mdb_item.letterboxd_rating * 2 if mdb_item.letterboxd_rating else None
else:
raise Failed
if library.mass_genre_update:
try:
if tmdb_item and library.mass_genre_update == "tmdb":
@ -554,34 +598,22 @@ def library_operations(config, library):
pass
if library.mass_audience_rating_update:
try:
if tmdb_item and library.mass_audience_rating_update == "tmdb":
new_rating = tmdb_item.vote_average
elif omdb_item and library.mass_audience_rating_update in ["omdb", "imdb"]:
new_rating = omdb_item.imdb_rating
else:
raise Failed
new_rating = get_rating(library.mass_audience_rating_update)
if new_rating is None:
logger.info(util.adjust_space(f"{item.title[:25]:<25} | No Rating Found"))
else:
if library.mass_audience_rating_update and str(item.audienceRating) != str(new_rating):
library.edit_query(item, {"audienceRating.value": new_rating, "audienceRating.locked": 1})
logger.info(util.adjust_space(f"{item.title[:25]:<25} | Audience Rating | {new_rating}"))
elif str(item.audienceRating) != str(new_rating):
library.edit_query(item, {"audienceRating.value": new_rating, "audienceRating.locked": 1})
logger.info(util.adjust_space(f"{item.title[:25]:<25} | Audience Rating | {new_rating}"))
except Failed:
pass
if library.mass_critic_rating_update:
try:
if tmdb_item and library.mass_critic_rating_update == "tmdb":
new_rating = tmdb_item.vote_average
elif omdb_item and library.mass_critic_rating_update in ["omdb", "imdb"]:
new_rating = omdb_item.imdb_rating
else:
raise Failed
new_rating = get_rating(library.mass_critic_rating_update)
if new_rating is None:
logger.info(util.adjust_space(f"{item.title[:25]:<25} | No Rating Found"))
else:
if library.mass_critic_rating_update and str(item.rating) != str(new_rating):
library.edit_query(item, {"rating.value": new_rating, "rating.locked": 1})
logger.info(util.adjust_space(f"{item.title[:25]:<25} | Critic Rating | {new_rating}"))
elif str(item.rating) != str(new_rating):
library.edit_query(item, {"rating.value": new_rating, "rating.locked": 1})
logger.info(util.adjust_space(f"{item.title[:25]:<25} | Critic Rating | {new_rating}"))
except Failed:
pass
if library.genre_mapper:

Loading…
Cancel
Save