Files
addon/core/tvdb.py
Alhaziel01 47d7d52bcf Fix TVDB
2020-08-19 15:48:49 +02:00

1068 lines
38 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# tvdb
# ------------------------------------------------------------
# Scraper for thetvdb.com using API v2.1
# Used to obtain series data for the video library
# ------------------------------------------------------------
from future import standard_library
standard_library.install_aliases()
from future.builtins import object
import urllib.request, urllib.error, urllib.parse
import re, requests
from core import jsontools
from core import scrapertools
from core.item import InfoLabels
from platformcode import config, logger
from platformcode import platformtools
HOST = "https://api.thetvdb.com"
HOST_IMAGE = "http://thetvdb.com/banners/"
TOKEN = config.get_setting("tvdb_token", default="")
info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json
DEFAULT_LANG = info_language[config.get_setting("info_language", "videolibrary")]
DEFAULT_HEADERS = {
'Content-Type': 'application/json',
'Accept': 'application/json, application/vnd.thetvdb.v2.1.1',
'Accept-Language': DEFAULT_LANG,
'Authorization': 'Bearer ' + TOKEN,
}
# # Traducciones - Inicio
# DICT_STATUS = {'Continuing': 'En emisión', 'Ended': 'Finalizada'}
# DICT_GENRE = {
# 'Action': 'Acción',
# 'Adventure': 'Aventura',
# 'Animation': 'Animación',
# 'Children': 'Niños',
# 'Comedy': 'Comedia',
# 'Crime': 'Crimen',
# 'Documentary': 'Documental',
# # 'Drama': 'Drama',
# 'Family': 'Familiar',
# 'Fantasy': 'Fantasía',
# 'Food': 'Comida',
# 'Game Show': 'Concurso',
# 'Home and Garden': 'Hogar y Jardín',
# # 'Horror': 'Horror', 'Mini-Series': 'Mini-Series',
# 'Mystery': 'Misterio',
# 'News': 'Noticias',
# # 'Reality': 'Telerrealidad',
# 'Romance': 'Romántico',
# 'Science-Fiction': 'Ciencia-Ficción',
# 'Soap': 'Telenovela',
# # 'Special Interest': 'Special Interest',
# 'Sport': 'Deporte',
# # 'Suspense': 'Suspense',
# 'Talk Show': 'Programa de Entrevistas',
# # 'Thriller': 'Thriller',
# 'Travel': 'Viaje',
# # 'Western': 'Western'
# }
# DICT_MPAA = {'TV-Y': 'Público pre-infantil: niños menores de 6 años', 'TV-Y7': 'Público infantil: desde 7 años',
# 'TV-G': 'Público general: sin supervisión familiar', 'TV-PG': 'Guía paterna: Supervisión paternal',
# 'TV-14': 'Mayores de 14 años', 'TV-MA': 'Mayores de 17 años'}
# # Traducciones - Fin
otvdb_global = None
def find_and_set_infoLabels(item):
logger.log()
# logger.log("item es %s" % item)
p_dialog = None
if not item.contentSeason:
p_dialog = platformtools.dialog_progress_bg(config.get_localized_string(60296), config.get_localized_string(60293))
global otvdb_global
tvdb_result = None
title = item.contentSerieName
# If the title includes the (year) we will remove it
year = scrapertools.find_single_match(title, "^.+?\s*(\(\d{4}\))$")
if year:
title = title.replace(year, "").strip()
item.infoLabels['year'] = year[1:-1]
if not item.infoLabels.get("tvdb_id"):
if not item.infoLabels.get("imdb_id"):
otvdb_global = Tvdb(search=title, year=item.infoLabels['year'])
else:
otvdb_global = Tvdb(imdb_id=item.infoLabels.get("imdb_id"))
elif not otvdb_global or otvdb_global.get_id() != item.infoLabels['tvdb_id']:
otvdb_global = Tvdb(tvdb_id=item.infoLabels['tvdb_id'])
if not item.contentSeason:
p_dialog.update(50, config.get_localized_string(60296) + '\n' + config.get_localized_string(60295))
results, info_load = otvdb_global.get_list_results()
logger.debug("results: %s" % results)
if not item.contentSeason:
p_dialog.update(100, config.get_localized_string(60296) + '\n' + config.get_localized_string(60297) % len(results))
p_dialog.close()
if len(results) > 1:
tvdb_result = platformtools.show_video_info(results, item=item, scraper=Tvdb, caption=config.get_localized_string(60298) % title)
elif len(results) > 0:
tvdb_result = results[0]
# todo revisar
if isinstance(item.infoLabels, InfoLabels):
logger.debug("is an instance of infoLabels")
infoLabels = item.infoLabels
else:
logger.debug("NOT an instance of infoLabels")
infoLabels = InfoLabels()
if tvdb_result:
infoLabels['tvdb_id'] = tvdb_result['id']
infoLabels['url_scraper'] = ["http://thetvdb.com/index.php?tab=series&id=%s" % infoLabels['tvdb_id']]
if not info_load:
if otvdb_global.get_id() != infoLabels['tvdb_id']:
otvdb_global = Tvdb(tvdb_id=infoLabels['tvdb_id'])
otvdb_global.get_images(infoLabels['tvdb_id'], image="poster")
otvdb_global.get_images(infoLabels['tvdb_id'], image="fanart")
otvdb_global.get_tvshow_cast(infoLabels['tvdb_id'])
item.infoLabels = infoLabels
set_infoLabels_item(item)
return True
else:
item.infoLabels = infoLabels
return False
def set_infoLabels_item(item):
"""
Gets and sets (item.infoLabels) the extra data of a series, chapter or movie.
@param item: Object that represents a movie, series or chapter. The infoLabels attribute will be modified including the extra localized data.
@type item: Item
"""
global otvdb_global
def __leer_datos(otvdb_aux):
item.infoLabels = otvdb_aux.get_infoLabels(item.infoLabels)
if 'infoLabels' in item and 'thumbnail' in item.infoLabels:
item.thumbnail = item.infoLabels['thumbnail']
if 'infoLabels' in item and 'fanart' in item.infoLabels['fanart']:
item.fanart = item.infoLabels['fanart']
if 'infoLabels' in item and 'season' in item.infoLabels:
try:
int_season = int(item.infoLabels['season'])
except ValueError:
logger.debug("The season number is not valid")
item.contentType = item.infoLabels['mediatype']
return -1 * len(item.infoLabels)
if not otvdb_global or \
(item.infoLabels['tvdb_id'] and otvdb_global.get_id() != item.infoLabels['tvdb_id']) \
or (otvdb_global.search_name and otvdb_global.search_name != item.infoLabels['tvshowtitle']):
if item.infoLabels['tvdb_id']:
otvdb_global = Tvdb(tvdb_id=item.infoLabels['tvdb_id'])
else:
otvdb_global = Tvdb(search=item.infoLabels['tvshowtitle'])
__leer_datos(otvdb_global)
if item.infoLabels['episode']:
try:
int_episode = int(item.infoLabels['episode'])
except ValueError:
logger.debug("The episode number (%s) is not valid" % repr(item.infoLabels['episode']))
item.contentType = item.infoLabels['mediatype']
return -1 * len(item.infoLabels)
# We have a valid season number and episode number ...
# ... search episode data
item.infoLabels['mediatype'] = 'episode'
lang = DEFAULT_LANG
if otvdb_global.lang:
lang = otvdb_global.lang
page = 1
_id = None
while not _id:
list_episodes = otvdb_global.list_episodes.get(page)
if not list_episodes:
list_episodes = otvdb_global.get_list_episodes(otvdb_global.get_id(), page)
import threading
semaforo = threading.Semaphore(20)
l_hilo = list()
for e in list_episodes["data"]:
t = threading.Thread(target=otvdb_global.get_episode_by_id, args=(e["id"], lang, semaforo))
t.start()
l_hilo.append(t)
# wait for all the threads to end
for x in l_hilo:
x.join()
for e in list_episodes['data']:
if e['airedSeason'] == int_season and e['airedEpisodeNumber'] == int_episode:
_id = e['id']
break
_next = list_episodes['links']['next']
if isinstance(_next, int):
page = _next
else:
break
data_episode = otvdb_global.get_info_episode(otvdb_global.get_id(), int_season, int_episode, lang, _id)
# all go over values to insert into infoLabels
if data_episode:
item.infoLabels['title'] = data_episode['episodeName']
# fix en casos que el campo desde la api era null--> None
if data_episode["overview"] is not None:
item.infoLabels['plot'] = data_episode["overview"]
item.thumbnail = HOST_IMAGE + data_episode.get('filename', "")
item.infoLabels["rating"] = data_episode.get("siteRating", "")
item.infoLabels['director'] = ', '.join(sorted(data_episode.get('directors', [])))
item.infoLabels['writer'] = ', '.join(sorted(data_episode.get("writers", [])))
if data_episode["firstAired"]:
item.infoLabels['premiered'] = data_episode["firstAired"].split("-")[2] + "/" + \
data_episode["firstAired"].split("-")[1] + "/" + \
data_episode["firstAired"].split("-")[0]
item.infoLabels['aired'] = item.infoLabels['premiered']
guest_stars = data_episode.get("guestStars", [])
l_castandrole = item.infoLabels.get("castandrole", [])
l_castandrole.extend([(p, '') for p in guest_stars])
item.infoLabels['castandrole'] = l_castandrole
# data for nfo
item.season_id = data_episode["airedSeasonID"]
item.episode_id = data_episode["id"]
return len(item.infoLabels)
else:
# We have a valid season number but no episode number ...
# ... search season data
item.infoLabels['mediatype'] = 'season'
data_season = otvdb_global.get_images(otvdb_global.get_id(), "season", int_season)
if data_season and 'image_season_%s' % int_season in data_season:
item.thumbnail = HOST_IMAGE + data_season['image_season_%s' % int_season][0]['fileName']
return len(item.infoLabels)
# Search...
else:
# Search by ID ...
if (not otvdb_global or otvdb_global.get_id() != item.infoLabels['tvdb_id']) and item.infoLabels['tvdb_id']:
otvdb_global = Tvdb(tvdb_id=item.infoLabels['tvdb_id'])
elif not otvdb_global and item.infoLabels['imdb_id']:
otvdb_global = Tvdb(imdb_id=item.infoLabels['imdb_id'])
elif not otvdb_global and item.infoLabels['zap2it_id']:
otvdb_global = Tvdb(zap2it_id=item.infoLabels['zap2it_id'])
# Unable to search by ID ... done by title
if otvdb_global is None:
otvdb_global = Tvdb(search=item.infoLabels['tvshowtitle'])
if otvdb_global and otvdb_global.get_id():
__leer_datos(otvdb_global)
# The search has found a valid result
return len(item.infoLabels)
def get_nfo(item):
"""
Returns the information necessary for the result to be scraped into the kodi video library,
@param item: element that contains the data necessary to generate the info
@type item: Item
@rtype: str
@return:
"""
if "season" in item.infoLabels and "episode" in item.infoLabels:
info_nfo = "http://thetvdb.com/?tab=episode&seriesid=%s&seasonid=%s&id=%s\n" % (item.infoLabels['tvdb_id'], item.season_id, item.episode_id)
else:
info_nfo = ', '.join(item.infoLabels['url_scraper']) + "\n"
return info_nfo
def completar_codigos(item):
"""
If necessary, check if the tmdb identifier exists and if it does not exist try to find it
@param item: tipo item
@type item: Item
"""
if not item.infoLabels['tmdb_id']:
listsources = [(item.infoLabels['tvdb_id'], "tvdb_id")]
if item.infoLabels['imdb_id']:
listsources.append((item.infoLabels['imdb_id'], "imdb_id"))
from core.tmdb import Tmdb
ob = Tmdb()
for external_id, external_source in listsources:
ob.search_by_id(id=external_id, source=external_source, tipo='tv')
item.infoLabels['tmdb_id'] = ob.get_id()
if item.infoLabels['tmdb_id']:
url_scraper = "https://www.themoviedb.org/tv/%s" % item.infoLabels['tmdb_id']
item.infoLabels['url_scraper'].append(url_scraper)
break
class Tvdb(object):
def __init__(self, **kwargs):
self.__check_token()
self.result = {}
self.list_results = []
self.lang = ""
self.search_name = kwargs['search'] = \
re.sub('\[\\\?(B|I|COLOR)\s?[^\]]*\]', '', kwargs.get('search', ''))
self.list_episodes = {}
self.episodes = {}
if kwargs.get('tvdb_id', ''):
# Search by tvdb identifier
self.__get_by_id(kwargs.get('tvdb_id', ''))
if not self.list_results and config.get_setting("tvdb_retry_eng", "videolibrary"):
from platformcode import platformtools
platformtools.dialog_notification(config.get_localized_string(60299) % DEFAULT_LANG, config.get_localized_string(60302), sound=False)
self.__get_by_id(kwargs.get('tvdb_id', ''), "en")
self.lang = "en"
elif self.search_name:
# BUsqueda by text
self.__search(kwargs.get('search', ''), kwargs.get('imdb_id', ''), kwargs.get('zap2it_id', ''))
if not self.list_results and config.get_setting("tvdb_retry_eng", "videolibrary"):
from platformcode import platformtools
platformtools.dialog_notification(config.get_localized_string(60299) % DEFAULT_LANG, config.get_localized_string(60302))
self.__search(kwargs.get('search', ''), kwargs.get('imdb_id', ''), kwargs.get('zap2it_id', ''), "en")
self.lang = "en"
if not self.result:
# No search results
if kwargs.get('tvdb_id', ''):
buscando = kwargs.get('tvdb_id', '')
else:
buscando = kwargs.get('search', '')
msg = config.get_localized_string(70266) % buscando
logger.debug(msg)
@classmethod
def __check_token(cls):
# logger.log()
if TOKEN == "":
cls.__login()
else:
# if the date does not correspond to the current one we call refresh_token, since the token expires in 24 hours
from time import gmtime, strftime
current_date = strftime("%Y-%m-%d", gmtime())
if config.get_setting("tvdb_token_date", "") != current_date:
# if the token has been renewed we save the new date
if cls.__refresh_token():
config.set_setting("tvdb_token_date", current_date)
@staticmethod
def __login():
# logger.log()
global TOKEN
apikey = "106B699FDC04301C"
url = HOST + "/login"
params = {"apikey": apikey}
try:
req = urllib.request.Request(url, data=jsontools.dump(params), headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception as ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error: %s" % message)
else:
dict_html = jsontools.load(html)
# logger.debug("dict_html %s" % dict_html)
if "token" in dict_html:
token = dict_html["token"]
DEFAULT_HEADERS["Authorization"] = "Bearer " + token
TOKEN = config.set_setting("tvdb_token", token)
@classmethod
def __refresh_token(cls):
# logger.log()
global TOKEN
is_success = False
url = HOST + "/refresh_token"
try:
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except urllib.error.HTTPError as err:
logger.error("err.code %s" % err.code)
# if there is error 401 it is that the token has passed the time and we have to call login again
if err.code == 401:
cls.__login()
else:
raise
except Exception as ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error: %s" % message)
else:
dict_html = jsontools.load(html)
# logger.error("tokencito %s" % dict_html)
if "token" in dict_html:
token = dict_html["token"]
DEFAULT_HEADERS["Authorization"] = "Bearer " + token
TOKEN = config.set_setting("tvdb_token", token)
is_success = True
return is_success
def get_info_episode(self, _id, season=1, episode=1, lang=DEFAULT_LANG, id_episode=None):
"""
Returns the data of an episode.
@param _id: series identifier
@type _id: str
@param season: season number [default = 1]
@type season: int
@param episode: episode number [default = 1]
@type episode: int
@param lang: language code to search
@type lang: str
@param id_episode: episode code.
@type id_episode: int
@rtype: dict
@return:
"data": {
"id": 0,
"airedSeason": 0,
"airedEpisodeNumber": 0,
"episodeName": "string",
"firstAired": "string",
"guestStars": [
"string"
],
"director": "string", # deprecated
"directors": [
"string"
],
"writers": [
"string"
],
"overview": "string",
"productionCode": "string",
"showUrl": "string",
"lastUpdated": 0,
"dvdDiscid": "string",
"dvdSeason": 0,
"dvdEpisodeNumber": 0,
"dvdChapter": 0,
"absoluteNumber": 0,
"filename": "string",
"seriesId": "string",
"lastUpdatedBy": "string",
"airsAfterSeason": 0,
"airsBeforeSeason": 0,
"airsBeforeEpisode": 0,
"thumbAuthor": 0,
"thumbAdded": "string",
"thumbWidth": "string",
"thumbHeight": "string",
"imdbId": "string",
"siteRating": 0,
"siteRatingCount": 0
},
"errors": {
"invalidFilters": [
"string"
],
"invalidLanguage": "string",
"invalidQueryParams": [
"string"
]
}
"""
logger.log()
if id_episode and self.episodes.get(id_episode):
return self.episodes.get(id_episode)
params = {"airedSeason": "%s" % season, "airedEpisode": "%s" % episode}
try:
params = urllib.parse.urlencode(params)
url = HOST + "/series/%s/episodes/query?%s" % (_id, params)
DEFAULT_HEADERS["Accept-Language"] = lang
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception as ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error: %s" % message)
else:
dict_html = jsontools.load(html)
if "data" in dict_html and "id" in dict_html["data"][0]:
self.get_episode_by_id(dict_html["data"][0]["id"], lang)
return dict_html["data"]
def get_list_episodes(self, _id, page=1):
"""
Returns the list of episodes of a series.
@param _id: series identifier
@type _id: str
@param page: page number to search [default = 1]
@type page: int
@rtype: dict
@return:
{
"links": {
"first": 0,
"last": 0,
"next": 0,
"previous": 0
},
"data": [
{
"absoluteNumber": 0,
"airedEpisodeNumber": 0,
"airedSeason": 0,
"dvdEpisodeNumber": 0,
"dvdSeason": 0,
"episodeName": "string",
"id": 0,
"overview": "string",
"firstAired": "string",
"lastUpdated": 0
}
],
"errors": {
"invalidFilters": [
"string"
],
"invalidLanguage": "string",
"invalidQueryParams": [
"string"
]
}
}
"""
logger.log()
try:
url = HOST + "/series/%s/episodes?page=%s" % (_id, page)
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception as ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error: %s" % message)
else:
self.list_episodes[page] = jsontools.load(html)
# logger.log("dict_html %s" % self.list_episodes)
return self.list_episodes[page]
def get_episode_by_id(self, _id, lang=DEFAULT_LANG, semaforo=None):
"""
Get the data of an episode
@param _id: episode identifier
@type _id: str
@param lang: language code
@param semaforo: semaphore for multihilos
@type semaforo: threading.Semaphore
@type lang: str
@rtype: dict
@return:
{
"data": {
"id": 0,
"airedSeason": 0,
"airedEpisodeNumber": 0,
"episodeName": "string",
"firstAired": "string",
"guestStars": [
"string"
],
"director": "string",
"directors": [
"string"
],
"writers": [
"string"
],
"overview": "string",
"productionCode": "string",
"showUrl": "string",
"lastUpdated": 0,
"dvdDiscid": "string",
"dvdSeason": 0,
"dvdEpisodeNumber": 0,
"dvdChapter": 0,
"absoluteNumber": 0,
"filename": "string",
"seriesId": "string",
"lastUpdatedBy": "string",
"airsAfterSeason": 0,
"airsBeforeSeason": 0,
"airsBeforeEpisode": 0,
"thumbAuthor": 0,
"thumbAdded": "string",
"thumbWidth": "string",
"thumbHeight": "string",
"imdbId": "string",
"siteRating": 0,
"siteRatingCount": 0
},
"errors": {
"invalidFilters": [
"string"
],
"invalidLanguage": "string",
"invalidQueryParams": [
"string"
]
}
}
"""
if semaforo:
semaforo.acquire()
logger.log()
url = HOST + "/episodes/%s" % _id
try:
DEFAULT_HEADERS["Accept-Language"] = lang
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception as ex:
# if isinstance(ex, urllib).HTTPError:
logger.debug("code %s " % ex.code)
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error en: %s" % message)
else:
dict_html = jsontools.load(html)
dict_html = dict_html.pop("data")
logger.log("dict_html %s" % dict_html)
self.episodes[_id] = dict_html
if semaforo:
semaforo.release()
def __search(self, name, imdb_id, zap2it_id, lang=DEFAULT_LANG):
"""
Search for a series through a series of parameters.
@param name: name to search
@type name: str
@param imdb_id: imdb identification code
@type imdb_id: str
@param zap2it_id: zap2it identification code
@type zap2it_id: str
@param lang: language code
@type lang: str
data:{
"aliases": [
"string"
],
"banner": "string",
"firstAired": "string",
"id": 0,
"network": "string",
"overview": "string",
"seriesName": "string",
"status": "string"
}
"""
logger.log()
try:
params = {}
if name:
params["name"] = name
elif imdb_id:
params["imdbId"] = imdb_id
elif zap2it_id:
params["zap2itId"] = zap2it_id
params = urllib.parse.urlencode(params)
DEFAULT_HEADERS["Accept-Language"] = lang
url = HOST + "/search/series?%s" % params
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
logger.log(html)
response.close()
except Exception as ex:
# if isinstance(ex, urllib.parse).HTTPError:
logger.debug("code %s " % ex.code)
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error: %s" % message)
else:
dict_html = jsontools.load(html)
if "errors" in dict_html and "invalidLanguage" in dict_html["errors"]:
# no hay información en idioma por defecto
return
else:
resultado = dict_html["data"]
# todo revisar
if len(resultado) > 1:
index = 0
else:
index = 0
logger.debug("result %s" % resultado)
self.list_results = resultado
self.result = resultado[index]
def __get_by_id(self, _id, lang=DEFAULT_LANG, from_get_list=False):
"""
Gets the data for a string by identifier.
@param _id: series code
@type _id: str
@param lang: language code
@type lang: str
@rtype: dict
@return:
{
"data": {
"id": 0,
"seriesName": "string",
"aliases": [
"string"
],
"banner": "string",
"seriesId": 0,
"status": "string",
"firstAired": "string",
"network": "string",
"networkId": "string",
"runtime": "string",
"genre": [
"string"
],
"overview": "string",
"lastUpdated": 0,
"airsDayOfWeek": "string",
"airsTime": "string",
"rating": "string",
"imdbId": "string",
"zap2itId": "string",
"added": "string",
"siteRating": 0,
"siteRatingCount": 0
},
"errors": {
"invalidFilters": [
"string"
],
"invalidLanguage": "string",
"invalidQueryParams": [
"string"
]
}
}
"""
logger.log()
resultado = {}
url = HOST + "/series/%s" % _id
try:
DEFAULT_HEADERS["Accept-Language"] = lang
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception as ex:
# if isinstance(ex, urllib).HTTPError:
logger.debug("code %s " % ex.code)
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error: %s" % message)
else:
dict_html = jsontools.load(html)
if "errors" in dict_html and "invalidLanguage" in dict_html["errors"]:
return {}
else:
resultado1 = dict_html["data"]
if not resultado1 and from_get_list:
return self.__get_by_id(_id, "en")
logger.debug("Result %s" % dict_html)
resultado2 = {"image_poster": [{'keyType': 'poster', 'fileName': 'posters/%s-1.jpg' % _id}]}
resultado3 = {"image_fanart": [{'keyType': 'fanart', 'fileName': 'fanart/original/%s-1.jpg' % _id}]}
resultado = resultado1.copy()
resultado.update(resultado2)
resultado.update(resultado3)
logger.debug("total result %s" % resultado)
self.list_results = [resultado]
self.result = resultado
return resultado
def get_images(self, _id, image="poster", season=1, lang="en"):
"""
Gets an image type for a string for a language.
@param _id: series identifier
@type _id: str
@param image: search code, ["poster" (default), "fanart", "season"]
@type image: str
@type season: season number
@param lang: language code for which you are searching
@type lang: str
@return: dictionary with the type of images chosen.
@rtype: dict
"""
logger.log()
if self.result.get('image_season_%s' % season):
return self.result['image_season_%s' % season]
params = {}
if image == "poster":
params["keyType"] = "poster"
elif image == "fanart":
params["keyType"] = "fanart"
params["subKey"] = "graphical"
elif image == "season":
params["keyType"] = "season"
params["subKey"] = "%s" % season
image += "_%s" % season
try:
params = urllib.parse.urlencode(params)
DEFAULT_HEADERS["Accept-Language"] = lang
url = HOST + "/series/%s/images/query?%s" % (_id, params)
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception as ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error: %s" % message)
return {}
else:
dict_html = jsontools.load(html)
dict_html["image_" + image] = dict_html.pop("data")
self.result.update(dict_html)
return dict_html
def get_tvshow_cast(self, _id, lang=DEFAULT_LANG):
"""
gets casting for a series
@param _id: series code
@type _id: str
@param lang: language code to search
@type lang: str
@return: dictionary with actors
@rtype: dict
"""
logger.log()
url = HOST + "/series/%s/actors" % _id
DEFAULT_HEADERS["Accept-Language"] = lang
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
dict_html = jsontools.load(html)
dict_html["cast"] = dict_html.pop("data")
self.result.update(dict_html)
def get_id(self):
"""
@return: Returns the Tvdb identifier of the loaded string or an empty string in case nothing was loaded.
You can use this method to find out if a search has been successful or not.
@rtype: str
"""
return str(self.result.get('id', ""))
def get_list_results(self):
"""
Returns the results we found for a series.
@rtype: list
@return: list of results
"""
logger.log()
list_results = []
# if we have a result and it has seriesName, we already have the info of the series, it is not necessary to search again
if len(self.list_results) == 1 and "seriesName" in self.result:
list_results.append(self.result)
info_load = True
else:
import threading
semaforo = threading.Semaphore(20)
l_hilo = list()
r_list = list()
def sub_thread(_id, i):
semaforo.acquire()
ret = self.__get_by_id(_id, DEFAULT_LANG, True)
semaforo.release()
r_list.append((ret, i))
for index, e in enumerate(self.list_results):
t = threading.Thread(target=sub_thread, args=(e["id"], index))
t.start()
l_hilo.append(t)
for x in l_hilo:
x.join()
r_list.sort(key=lambda i: i[1])
list_results = [ii[0] for ii in r_list]
info_load = False
return list_results, info_load
def get_infoLabels(self, infoLabels=None, origen=None):
"""
@param infoLabels: Extra information about the movie, series, season or chapter.
@type infoLabels: dict
@param origen: Diccionario origen de donde se obtiene los infoLabels, por omision self.result
@type origen: dict
@return: Returns the extra information obtained from the current object. If the infoLables parameter was passed,
the value returned will be read as a parameter duly updated.
@rtype: dict
"""
if infoLabels:
# logger.debug("es instancia de infoLabels")
ret_infoLabels = InfoLabels(infoLabels)
else:
# logger.debug("NO ES instancia de infoLabels")
ret_infoLabels = InfoLabels()
# fix
ret_infoLabels['mediatype'] = 'tvshow'
# Start Listings
l_castandrole = ret_infoLabels.get('castandrole', [])
# logger.debug("self.result %s" % self.result)
if not origen:
origen = self.result
ret_infoLabels['title'] = origen['seriesName']
ret_infoLabels['tvdb_id'] = origen['id']
thumbs = requests.get(HOST + '/series/' + str(origen['id']) + '/images/query?keyType=poster').json()
if 'data' in thumbs:
ret_infoLabels['thumbnail'] = HOST_IMAGE + thumbs['data'][0]['fileName']
elif 'poster' in origen and origen['poster']:
ret_infoLabels['thumbnail'] = origen['poster']
fanarts = requests.get(HOST + '/series/' + str(origen['id']) + '/images/query?keyType=fanart').json()
if 'data' in fanarts:
ret_infoLabels['fanart'] = HOST_IMAGE + fanarts['data'][0]['fileName']
elif 'poster' in origen and origen['fanart']:
ret_infoLabels['thumbnail'] = origen['fanart']
if 'overview' in origen:
ret_infoLabels['plot'] = origen['overview']
if 'duration' in origen and origen['duration']:
ret_infoLabels['duration'] = int(origen['duration']) * 60
if 'firstAired' in origen and origen['firstAired']:
ret_infoLabels['year'] = int(origen['firstAired'][:4])
ret_infoLabels['premiered'] = origen['firstAired'].split("-")[2] + "/" + origen['firstAired'].split("-")[1] + "/" + origen['firstAired'].split("-")[0]
if 'siteRating' in origen:
ret_infoLabels['rating'] = float(origen['siteRating'])
if 'siteRatingCount' in origen and origen['siteRating']:
ret_infoLabels['votes'] = origen['siteRatingCount']
if 'status' in origen:
ret_infoLabels['status'] = origen['status']
if 'network' in origen:
ret_infoLabels['studio'] = origen['network']
if 'imdbId' in origen:
ret_infoLabels['imdb_id'] = origen['imdbId']
if 'rating' in origen:
ret_infoLabels['mpaa'] = origen['rating']
if 'genre' in origen:
for genre in origen['genre']:
genre_list = ""
genre_list += genre + ', '
ret_infoLabels['genre'] = genre_list.rstrip(', ')
if 'cast' in origen:
dic_aux = dict((name, character) for (name, character) in l_castandrole)
l_castandrole.extend([(p['name'], p['role']) for p in origen['cast'] if p['name'] not in list(dic_aux.keys())])
ret_infoLabels['castandrole'] = l_castandrole
return ret_infoLabels