Plex-Meta-Manager/modules/tvdb.py

164 lines
8 KiB
Python
Raw Normal View History

2021-07-14 14:47:20 +00:00
import logging, requests, time
2021-01-20 21:37:59 +00:00
from modules import util
from modules.util import Failed
logger = logging.getLogger("Plex Meta Manager")
2021-07-23 19:44:21 +00:00
builders = ["tvdb_list", "tvdb_list_details", "tvdb_movie", "tvdb_movie_details", "tvdb_show", "tvdb_show_details"]
2021-07-14 14:47:20 +00:00
base_url = "https://www.thetvdb.com"
alt_url = "https://thetvdb.com"
urls = {
2021-07-23 19:44:21 +00:00
"list": f"{base_url}/lists/", "alt_list": f"{alt_url}/lists/",
"series": f"{base_url}/series/", "alt_series": f"{alt_url}/series/",
"movies": f"{base_url}/movies/", "alt_movies": f"{alt_url}/movies/",
"series_id": f"{base_url}/dereferrer/series/", "movie_id": f"{base_url}/dereferrer/movie/"
2021-07-14 14:47:20 +00:00
}
2021-03-30 05:50:53 +00:00
2021-01-20 21:37:59 +00:00
class TVDbObj:
2021-07-14 14:47:20 +00:00
def __init__(self, tvdb_url, language, is_movie, config):
self.tvdb_url = tvdb_url.strip()
self.language = language
self.is_movie = is_movie
self.config = config
if not self.is_movie and self.tvdb_url.startswith((urls["series"], urls["alt_series"], urls["series_id"])):
2021-01-20 21:37:59 +00:00
self.media_type = "Series"
2021-07-14 14:47:20 +00:00
elif self.is_movie and self.tvdb_url.startswith((urls["movies"], urls["alt_movies"], urls["movie_id"])):
2021-01-20 21:37:59 +00:00
self.media_type = "Movie"
else:
2021-07-14 14:47:20 +00:00
raise Failed(f"TVDb Error: {self.tvdb_url} must begin with {urls['movies'] if self.is_movie else urls['series']}")
2021-01-20 21:37:59 +00:00
2021-07-14 14:47:20 +00:00
response = self.config.get_html(self.tvdb_url, headers=util.header(self.language))
2021-02-24 06:44:06 +00:00
results = response.xpath(f"//*[text()='TheTVDB.com {self.media_type} ID']/parent::node()/span/text()")
2021-01-20 21:37:59 +00:00
if len(results) > 0:
self.id = int(results[0])
2021-07-14 14:47:20 +00:00
elif self.tvdb_url.startswith(urls["movie_id"]):
raise Failed(f"TVDb Error: Could not find a TVDb Movie using TVDb Movie ID: {self.tvdb_url[len(urls['movie_id']):]}")
elif self.tvdb_url.startswith(urls["series_id"]):
raise Failed(f"TVDb Error: Could not find a TVDb Series using TVDb Series ID: {self.tvdb_url[len(urls['series_id']):]}")
2021-01-20 21:37:59 +00:00
else:
2021-07-14 14:47:20 +00:00
raise Failed(f"TVDb Error: Could not find a TVDb {self.media_type} ID at the URL {self.tvdb_url}")
2021-01-20 21:37:59 +00:00
def parse_page(xpath, fail=None, multi=False):
parse_results = response.xpath(xpath)
if len(parse_results) > 0:
parse_results = [r.strip() for r in parse_results if len(r) > 0]
if not multi and len(parse_results) > 0:
return parse_results[0]
elif len(parse_results) > 0:
return parse_results
elif fail is not None:
raise Failed(f"TVDb Error: {fail} not found from TVDb URL: {self.tvdb_url}")
else:
return None
2021-03-08 17:02:40 +00:00
self.title = parse_page("//div[@class='change_translation_text' and not(@style='display:none')]/@data-title", fail="Name")
self.poster_path = parse_page("//div[@class='row hidden-xs hidden-sm']/div/img/@src")
self.background_path = parse_page("(//h2[@class='mt-4' and text()='Backgrounds']/following::div/a/@href)[1]")
self.summary = parse_page("//div[@class='change_translation_text' and not(@style='display:none')]/p/text()[normalize-space()]")
if self.is_movie:
self.directors = parse_page("//strong[text()='Directors']/parent::li/span/a/text()[normalize-space()]")
self.writers = parse_page("//strong[text()='Writers']/parent::li/span/a/text()[normalize-space()]")
self.studios = parse_page("//strong[text()='Studio']/parent::li/span/a/text()[normalize-space()]")
else:
self.networks = parse_page("//strong[text()='Networks']/parent::li/span/a/text()[normalize-space()]")
self.genres = parse_page("//strong[text()='Genres']/parent::li/span/a/text()[normalize-space()]")
2021-03-08 17:02:40 +00:00
2021-01-20 21:37:59 +00:00
tmdb_id = None
2021-08-07 06:01:21 +00:00
imdb_id = None
2021-07-14 14:47:20 +00:00
if self.is_movie:
2021-01-21 21:42:31 +00:00
results = response.xpath("//*[text()='TheMovieDB.com']/@href")
2021-01-20 21:37:59 +00:00
if len(results) > 0:
2021-04-22 23:51:03 +00:00
try:
tmdb_id = util.regex_first_int(results[0], "TMDb ID")
2021-05-09 05:37:45 +00:00
except Failed:
pass
2021-08-07 06:01:21 +00:00
results = response.xpath("//*[text()='IMDB']/@href")
if len(results) > 0:
try:
imdb_id = util.get_id_from_imdb_url(results[0])
except Failed:
pass
if tmdb_id is None and imdb_id is None:
raise Failed(f"TVDB Error: No TMDb ID or IMDb ID found for {self.title}")
2021-01-20 21:37:59 +00:00
self.tmdb_id = tmdb_id
2021-08-07 06:01:21 +00:00
self.imdb_id = imdb_id
2021-01-20 21:37:59 +00:00
2021-06-14 15:24:11 +00:00
class TVDb:
2021-03-05 20:33:24 +00:00
def __init__(self, config):
2021-03-02 21:41:34 +00:00
self.config = config
2021-01-20 21:37:59 +00:00
2021-07-23 18:45:49 +00:00
def get_item(self, language, tvdb_url, is_movie):
2021-03-08 19:53:05 +00:00
return self.get_movie(language, tvdb_url) if is_movie else self.get_series(language, tvdb_url)
def get_series(self, language, tvdb_url):
try:
2021-07-14 14:47:20 +00:00
tvdb_url = f"{urls['series_id']}{int(tvdb_url)}"
2021-03-08 19:53:05 +00:00
except ValueError:
pass
2021-07-14 14:47:20 +00:00
return TVDbObj(tvdb_url, language, False, self.config)
2021-01-20 21:37:59 +00:00
2021-03-08 19:53:05 +00:00
def get_movie(self, language, tvdb_url):
try:
2021-07-14 14:47:20 +00:00
tvdb_url = f"{urls['movie_id']}{int(tvdb_url)}"
2021-03-08 19:53:05 +00:00
except ValueError:
pass
2021-07-14 14:47:20 +00:00
return TVDbObj(tvdb_url, language, True, self.config)
2021-01-20 21:37:59 +00:00
2021-03-08 19:53:05 +00:00
def get_list_description(self, tvdb_url, language):
2021-07-14 14:47:20 +00:00
response = self.config.get_html(tvdb_url, headers=util.header(language))
description = response.xpath("//div[@class='block']/div[not(@style='display:none')]/p/text()")
2021-03-08 17:02:40 +00:00
return description[0] if len(description) > 0 and len(description[0]) > 0 else ""
2021-05-07 19:53:54 +00:00
def _ids_from_url(self, tvdb_url, language):
2021-08-07 06:01:21 +00:00
ids = []
2021-01-20 21:37:59 +00:00
tvdb_url = tvdb_url.strip()
2021-07-14 14:47:20 +00:00
if tvdb_url.startswith((urls["list"], urls["alt_list"])):
2021-01-20 21:37:59 +00:00
try:
2021-07-14 14:47:20 +00:00
response = self.config.get_html(tvdb_url, headers=util.header(language))
items = response.xpath("//div[@class='col-xs-12 col-sm-12 col-md-8 col-lg-8 col-md-pull-4']/div[@class='row']")
2021-01-20 21:37:59 +00:00
for item in items:
title = item.xpath(".//div[@class='col-xs-12 col-sm-9 mt-2']//a/text()")[0]
item_url = item.xpath(".//div[@class='col-xs-12 col-sm-9 mt-2']//a/@href")[0]
if item_url.startswith("/series/"):
2021-04-22 23:51:03 +00:00
try:
2021-08-07 06:01:21 +00:00
ids.append((self.get_series(language, f"{base_url}{item_url}").id, "tvdb"))
2021-04-22 23:51:03 +00:00
except Failed as e:
logger.error(f"{e} for series {title}")
2021-01-20 21:37:59 +00:00
elif item_url.startswith("/movies/"):
try:
2021-08-07 06:01:21 +00:00
movie = self.get_movie(language, f"{base_url}{item_url}")
if movie.tmdb_id:
ids.append((movie.tmdb_id, "tmdb"))
elif movie.imdb_id:
ids.append((movie.imdb_id, "imdb"))
2021-01-20 21:37:59 +00:00
except Failed as e:
2021-08-07 06:01:21 +00:00
logger.error(e)
2021-01-20 21:37:59 +00:00
else:
2021-02-24 06:44:06 +00:00
logger.error(f"TVDb Error: Skipping Movie: {title}")
2021-07-14 14:47:20 +00:00
time.sleep(2)
2021-08-07 06:01:21 +00:00
if len(ids) > 0:
return ids
2021-02-24 06:44:06 +00:00
raise Failed(f"TVDb Error: No TVDb IDs found at {tvdb_url}")
2021-02-24 06:42:58 +00:00
except requests.exceptions.MissingSchema:
2021-01-20 21:37:59 +00:00
util.print_stacktrace()
2021-02-24 06:44:06 +00:00
raise Failed(f"TVDb Error: URL Lookup Failed for {tvdb_url}")
2021-01-20 21:37:59 +00:00
else:
2021-07-14 14:47:20 +00:00
raise Failed(f"TVDb Error: {tvdb_url} must begin with {urls['list']}")
2021-01-20 21:37:59 +00:00
2021-08-07 06:01:21 +00:00
def get_tvdb_ids(self, method, data, language):
2021-01-20 21:37:59 +00:00
if method == "tvdb_show":
2021-08-01 04:35:42 +00:00
logger.info(f"Processing TVDb Show: {data}")
2021-08-07 06:01:21 +00:00
return [(self.get_series(language, data).id, "tvdb")]
2021-01-20 21:37:59 +00:00
elif method == "tvdb_movie":
2021-08-01 04:35:42 +00:00
logger.info(f"Processing TVDb Movie: {data}")
2021-08-07 06:01:21 +00:00
movie = self.get_movie(language, data)
if movie.tmdb_id:
return [(movie.tmdb_id, "tmdb")]
elif movie.imdb_id:
return [(movie.imdb_id, "imdb")]
2021-01-20 21:37:59 +00:00
elif method == "tvdb_list":
2021-08-01 04:35:42 +00:00
logger.info(f"Processing TVDb List: {data}")
2021-08-07 06:01:21 +00:00
return self._ids_from_url(data, language)
2021-01-20 21:37:59 +00:00
else:
2021-02-24 06:44:06 +00:00
raise Failed(f"TVDb Error: Method {method} not supported")