Plex-Meta-Manager/modules/mdblist.py

231 lines
11 KiB
Python
Raw Normal View History

2024-01-09 20:56:49 +00:00
import time
from datetime import datetime
2022-03-23 16:06:00 +00:00
from json import JSONDecodeError
2022-01-24 09:16:45 +00:00
from modules import util
2024-05-28 20:22:51 +00:00
from modules.request import urlparse
2022-10-17 16:06:32 +00:00
from modules.util import Failed, LimitReached
2022-01-15 22:40:59 +00:00
logger = util.logger
2022-01-15 22:40:59 +00:00
builders = ["mdblist_list"]
2022-11-11 03:52:42 +00:00
sort_names = [
"rank", "score", "score_average", "released", "imdbrating", "imdbvotes", "imdbpopular", "tmdbpopular",
2023-04-01 14:11:15 +00:00
"rogerebert", "rtomatoes", "rtaudience", "metacritic", "myanimelist", "letterrating", "lettervotes",
"updated", "last_air_date", "watched", "rating", "usort", "added", "runtime", "budget", "revenue", "title"
2022-11-11 03:52:42 +00:00
]
2022-03-03 14:43:00 +00:00
list_sorts = [f"{s}.asc" for s in sort_names] + [f"{s}.desc" for s in sort_names]
2022-01-15 22:40:59 +00:00
base_url = "https://mdblist.com/lists"
2022-02-06 07:33:09 +00:00
api_url = "https://mdblist.com/api/"
2022-01-15 22:40:59 +00:00
2024-04-22 14:20:12 +00:00
headers = {"User-Agent": "Kometa"}
2022-01-15 22:40:59 +00:00
2022-02-06 07:33:09 +00:00
class MDbObj:
def __init__(self, data):
self._data = data
self.title = data["title"]
self.year = util.check_num(data["year"])
try:
self.released = datetime.strptime(data["released"], "%Y-%m-%d")
2022-03-18 13:01:12 +00:00
except (ValueError, TypeError):
self.released = None
try:
self.released_digital = datetime.strptime(data["released_digital"], "%Y-%m-%d")
except (ValueError, TypeError):
self.released_digital = None
2022-02-06 07:33:09 +00:00
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"])
2022-11-11 03:52:42 +00:00
self.average = util.check_num(data["score_average"])
2022-02-06 07:33:09 +00:00
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
2022-08-01 20:26:10 +00:00
self.myanimelist_rating = None
2022-02-06 07:33:09 +00:00
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)
elif rating["source"] == "myanimelist":
self.myanimelist_rating = util.check_num(rating["value"], is_int=False)
2022-02-07 22:46:24 +00:00
self.content_rating = data["certification"]
2022-02-06 07:33:09 +00:00
self.commonsense = data["commonsense"]
self.age_rating = data["age_rating"]
2022-02-06 07:33:09 +00:00
2024-05-01 16:17:46 +00:00
class MDBList:
2024-05-28 20:22:51 +00:00
def __init__(self, requests, cache):
self.requests = requests
self.cache = cache
2022-02-06 07:33:09 +00:00
self.apikey = None
self.expiration = 60
2022-02-06 07:33:09 +00:00
self.limit = False
2024-01-09 20:56:49 +00:00
self.supporter = False
self.rating_id_limit = 10
2022-02-06 07:33:09 +00:00
def add_key(self, apikey, expiration):
2022-02-06 07:33:09 +00:00
self.apikey = apikey
logger.secret(self.apikey)
self.expiration = expiration
2022-02-06 07:33:09 +00:00
try:
2024-01-09 20:56:49 +00:00
response = self._request(f"{api_url}user")
self.supporter = response["limits"]["supporter"]
self.rating_id_limit = response["limits"]["rating_ids"]
self.get_item(imdb_id="tt0080684", ignore_cache=True)
2022-10-17 16:06:32 +00:00
except LimitReached:
self.limit = True
2022-02-06 07:33:09 +00:00
except Failed:
self.apikey = None
raise
@property
def has_key(self):
return self.apikey is not None
2024-01-09 20:56:49 +00:00
def _request(self, url, params=None):
logger.trace(url)
final_params = {"apikey": self.apikey}
if params:
logger.trace(f"Params: {params}")
for k, v in params.items():
final_params[k] = v
try:
time.sleep(0.2 if self.supporter else 1)
2024-05-28 20:22:51 +00:00
response = self.requests.get_json(url, params=final_params)
2024-01-09 20:56:49 +00:00
except JSONDecodeError:
2024-05-01 16:17:46 +00:00
raise Failed("MDBList Error: JSON Decoding Failed")
2024-01-09 21:09:29 +00:00
if "response" in response and (response["response"] is False or response["response"] == "False"):
2024-01-09 20:56:49 +00:00
if response["error"] in ["API Limit Reached!", "API Rate Limit Reached!"]:
self.limit = True
2024-05-01 16:17:46 +00:00
raise LimitReached(f"MDBList Error: {response['error']}")
raise Failed(f"MDBList Error: {response['error']}")
2024-01-09 20:56:49 +00:00
return response
def get_item(self, imdb_id=None, tmdb_id=None, tvdb_id=None, is_movie=True, ignore_cache=False):
params = {}
2022-02-06 07:33:09 +00:00
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}"
elif tvdb_id:
params["tv"] = tvdb_id
params["m"] = "movie" if is_movie else "show"
2022-09-07 18:38:14 +00:00
key = f"{'tvm' if is_movie else 'tvs'}{tvdb_id}"
2022-02-06 07:33:09 +00:00
else:
2024-05-01 16:17:46 +00:00
raise Failed("MDBList Error: Either IMDb ID, TVDb ID, or TMDb ID and TMDb Type Required")
2022-02-06 07:33:09 +00:00
expired = None
2024-05-28 20:22:51 +00:00
if self.cache and not ignore_cache:
mdb_dict, expired = self.cache.query_mdb(key, self.expiration)
2022-02-06 07:33:09 +00:00
if mdb_dict and expired is False:
return MDbObj(mdb_dict)
2022-09-07 19:32:52 +00:00
logger.trace(f"ID: {key}")
2024-01-09 20:56:49 +00:00
mdb = MDbObj(self._request(api_url, params=params))
2024-05-28 20:22:51 +00:00
if self.cache and not ignore_cache:
self.cache.update_mdb(expired, key, mdb, self.expiration)
2024-01-09 20:56:49 +00:00
return mdb
2022-02-06 07:33:09 +00:00
def get_imdb(self, imdb_id):
2024-01-09 20:56:49 +00:00
return self.get_item(imdb_id=imdb_id)
2022-02-06 07:33:09 +00:00
def get_series(self, tvdb_id):
2024-01-09 20:56:49 +00:00
return self.get_item(tvdb_id=tvdb_id, is_movie=False)
2022-02-06 07:33:09 +00:00
def get_movie(self, tmdb_id):
2024-01-09 20:56:49 +00:00
return self.get_item(tmdb_id=tmdb_id, is_movie=True)
2022-01-15 22:40:59 +00:00
2022-03-03 14:43:00 +00:00
def validate_mdblist_lists(self, error_type, mdb_lists):
2022-01-24 09:16:45 +00:00
valid_lists = []
for mdb_dict in util.get_list(mdb_lists, split=False):
if not isinstance(mdb_dict, dict):
mdb_dict = {"url": mdb_dict}
dict_methods = {dm.lower(): dm for dm in mdb_dict}
if "url" not in dict_methods:
2022-03-03 14:43:00 +00:00
raise Failed(f"{error_type} Error: mdb_list url attribute not found")
2022-01-24 09:16:45 +00:00
elif mdb_dict[dict_methods["url"]] is None:
2022-03-03 14:43:00 +00:00
raise Failed(f"{error_type} Error: mdb_list url attribute is blank")
2022-01-24 09:16:45 +00:00
else:
mdb_url = mdb_dict[dict_methods["url"]].strip()
if not mdb_url.startswith(base_url):
2022-03-03 14:43:00 +00:00
raise Failed(f"{error_type} Error: {mdb_url} must begin with: {base_url}")
2022-01-24 09:16:45 +00:00
list_count = None
if "limit" in dict_methods:
if mdb_dict[dict_methods["limit"]] is None:
2022-03-03 14:43:00 +00:00
logger.warning(f"{error_type} Warning: mdb_list limit attribute is blank using 0 as default")
2022-01-24 09:16:45 +00:00
else:
try:
value = int(str(mdb_dict[dict_methods["limit"]]))
if 0 <= value:
list_count = value
except ValueError:
pass
if list_count is None:
2022-03-03 14:43:00 +00:00
logger.warning(f"{error_type} Warning: mdb_list limit attribute must be an integer 0 or greater using 0 as default")
2022-01-24 09:16:45 +00:00
if list_count is None:
list_count = 0
2022-04-19 15:46:11 +00:00
sort_by = "rank.asc"
2022-02-06 03:52:54 +00:00
if "sort_by" in dict_methods:
if mdb_dict[dict_methods["sort_by"]] is None:
2022-03-03 14:43:00 +00:00
logger.warning(f"{error_type} Warning: mdb_list sort_by attribute is blank using score as default")
elif mdb_dict[dict_methods["sort_by"]].lower() in sort_names:
logger.warning(f"{error_type} Warning: mdb_list sort_by attribute {mdb_dict[dict_methods['sort_by']]} is missing .desc or .asc defaulting to .desc")
sort_by = f"{mdb_dict[dict_methods['sort_by']].lower()}.desc"
2022-02-06 03:52:54 +00:00
elif mdb_dict[dict_methods["sort_by"]].lower() not in list_sorts:
2022-03-03 14:43:00 +00:00
logger.warning(f"{error_type} Warning: mdb_list sort_by attribute {mdb_dict[dict_methods['sort_by']]} not valid score as default. Options: {', '.join(list_sorts)}")
2022-02-06 03:52:54 +00:00
else:
sort_by = mdb_dict[dict_methods["sort_by"]].lower()
valid_lists.append({"url": mdb_url, "limit": list_count, "sort_by": sort_by})
2022-01-24 09:16:45 +00:00
return valid_lists
2022-06-03 05:51:16 +00:00
2022-08-09 05:35:21 +00:00
def get_tmdb_ids(self, method, data, is_movie=None):
2022-01-15 22:40:59 +00:00
if method == "mdblist_list":
2024-05-01 16:17:46 +00:00
logger.info(f"Processing MDBList.com List: {data['url']}")
2022-02-06 03:52:54 +00:00
logger.info(f"Sort By: {data['sort_by']}")
2022-03-03 14:43:00 +00:00
sort, direction = data["sort_by"].split(".")
params = {"sort": sort, "sortorder": direction}
2022-08-09 05:35:21 +00:00
if is_movie is not None:
params["mediatype"] = "movie" if is_movie else "show"
2022-02-06 03:52:54 +00:00
if data["limit"] > 0:
logger.info(f"Limit: {data['limit']} items")
params["limit"] = data["limit"]
2022-01-25 07:45:31 +00:00
parsed_url = urlparse(data["url"])
2023-04-28 03:43:26 +00:00
url_base = str(parsed_url._replace(query=None).geturl()) # noqa
2022-02-02 09:47:34 +00:00
url_base = url_base if url_base.endswith("/") else f"{url_base}/"
url_base = url_base if url_base.endswith("json/") else f"{url_base}json/"
2022-03-23 16:06:00 +00:00
try:
2024-05-28 20:22:51 +00:00
response = self.requests.get_json(url_base, headers=headers, params=params)
2022-11-01 18:20:00 +00:00
if (isinstance(response, dict) and "error" in response) or (isinstance(response, list) and response and "error" in response[0]):
err = response["error"] if isinstance(response, dict) else response[0]["error"]
2022-11-02 03:10:43 +00:00
if err in ["empty", "empty or private list"]:
2024-05-01 16:17:46 +00:00
raise Failed(f"MDBList Error: No Items Returned. Lists can take 24 hours to update so try again later.")
raise Failed(f"MDBList Error: Invalid Response {response}")
2022-06-03 05:51:16 +00:00
results = []
for item in response:
if item["mediatype"] in ["movie", "show"] and item["id"]:
2022-06-03 05:51:16 +00:00
results.append((item["id"], "tmdb" if item["mediatype"] == "movie" else "tmdb_show"))
return results
2022-03-23 16:06:00 +00:00
except JSONDecodeError:
2024-05-01 16:17:46 +00:00
raise Failed(f"MDBList Error: Invalid JSON Response received")
2022-01-15 22:40:59 +00:00
else:
2024-05-01 16:17:46 +00:00
raise Failed(f"MDBList Error: Method {method} not supported")