-Correcciones en los idiomas -gamovideo: Mejora para obtener los enlaces -thevid: Corrección para obtener los enlaces
1655 lines
76 KiB
Python
1655 lines
76 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import copy
|
|
import re
|
|
import sqlite3
|
|
import time
|
|
|
|
from core import filetools
|
|
from core import httptools
|
|
from core import jsontools
|
|
from core import scrapertools
|
|
from core.item import InfoLabels
|
|
from platformcode import config
|
|
from platformcode import logger
|
|
|
|
# -----------------------------------------------------------------------------------------------------------
|
|
# Conjunto de funciones relacionadas con las infoLabels.
|
|
# version 1.0:
|
|
# Version inicial
|
|
#
|
|
# Incluyen:
|
|
# set_infoLabels(source, seekTmdb, idioma_busqueda): Obtiene y fija (item.infoLabels) los datos extras de una o
|
|
# varias series, capitulos o peliculas.
|
|
# set_infoLabels_item(item, seekTmdb, idioma_busqueda): Obtiene y fija (item.infoLabels) los datos extras de una
|
|
# serie, capitulo o pelicula.
|
|
# set_infoLabels_itemlist(item_list, seekTmdb, idioma_busqueda): Obtiene y fija (item.infoLabels) los datos
|
|
# extras de una lista de series, capitulos o peliculas.
|
|
# infoLabels_tostring(item): Retorna un str con la lista ordenada con los infoLabels del item
|
|
#
|
|
# Uso:
|
|
# tmdb.set_infoLabels(item, seekTmdb = True)
|
|
#
|
|
# Obtener datos basicos de una pelicula:
|
|
# Antes de llamar al metodo set_infoLabels el titulo a buscar debe estar en item.fulltitle
|
|
# o en item.contentTitle y el año en item.infoLabels['year'].
|
|
#
|
|
# Obtener datos basicos de una serie:
|
|
# Antes de llamar al metodo set_infoLabels el titulo a buscar debe estar en item.show o en
|
|
# item.contentSerieName.
|
|
#
|
|
# Obtener mas datos de una pelicula o serie:
|
|
# Despues de obtener los datos basicos en item.infoLabels['tmdb'] tendremos el codigo de la serie o pelicula.
|
|
# Tambien podriamos directamente fijar este codigo, si se conoce, o utilizar los codigo correspondientes de:
|
|
# IMDB (en item.infoLabels['IMDBNumber'] o item.infoLabels['code'] o item.infoLabels['imdb_id']), TVDB
|
|
# (solo series, en item.infoLabels['tvdb_id']),
|
|
# Freebase (solo series, en item.infoLabels['freebase_mid']),TVRage (solo series, en
|
|
# item.infoLabels['tvrage_id'])
|
|
#
|
|
# Obtener datos de una temporada:
|
|
# Antes de llamar al metodo set_infoLabels el titulo de la serie debe estar en item.show o en
|
|
# item.contentSerieName,
|
|
# el codigo TMDB de la serie debe estar en item.infoLabels['tmdb'] (puede fijarse automaticamente mediante
|
|
# la consulta de datos basica)
|
|
# y el numero de temporada debe estar en item.infoLabels['season'].
|
|
#
|
|
# Obtener datos de un episodio:
|
|
# Antes de llamar al metodo set_infoLabels el titulo de la serie debe estar en item.show o en
|
|
# item.contentSerieName,
|
|
# el codigo TMDB de la serie debe estar en item.infoLabels['tmdb'] (puede fijarse automaticamente mediante la
|
|
# consulta de datos basica),
|
|
# el numero de temporada debe estar en item.infoLabels['season'] y el numero de episodio debe estar en
|
|
# item.infoLabels['episode'].
|
|
#
|
|
#
|
|
# --------------------------------------------------------------------------------------------------------------
|
|
|
|
otmdb_global = None
|
|
fname = filetools.join(config.get_data_path(), "alfa_db.sqlite")
|
|
|
|
|
|
def create_bd():
|
|
conn = sqlite3.connect(fname)
|
|
c = conn.cursor()
|
|
c.execute('CREATE TABLE IF NOT EXISTS tmdb_cache (url TEXT PRIMARY KEY, response TEXT, added TEXT)')
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
|
|
def drop_bd():
|
|
conn = sqlite3.connect(fname)
|
|
c = conn.cursor()
|
|
c.execute('DROP TABLE IF EXISTS tmdb_cache')
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
return True
|
|
|
|
|
|
create_bd()
|
|
|
|
|
|
# El nombre de la funcion es el nombre del decorador y recibe la funcion que decora.
|
|
def cache_response(fn):
|
|
logger.info()
|
|
|
|
# import time
|
|
# start_time = time.time()
|
|
|
|
def wrapper(*args):
|
|
import base64
|
|
|
|
def check_expired(ts):
|
|
import datetime
|
|
|
|
valided = False
|
|
|
|
cache_expire = config.get_setting("tmdb_cache_expire", default=0)
|
|
|
|
saved_date = datetime.datetime.fromtimestamp(ts)
|
|
current_date = datetime.datetime.fromtimestamp(time.time())
|
|
elapsed = current_date - saved_date
|
|
|
|
# 1 day
|
|
if cache_expire == 0:
|
|
if elapsed > datetime.timedelta(days=1):
|
|
valided = False
|
|
else:
|
|
valided = True
|
|
# 7 days
|
|
elif cache_expire == 1:
|
|
if elapsed > datetime.timedelta(days=7):
|
|
valided = False
|
|
else:
|
|
valided = True
|
|
|
|
# 15 days
|
|
elif cache_expire == 2:
|
|
if elapsed > datetime.timedelta(days=15):
|
|
valided = False
|
|
else:
|
|
valided = True
|
|
|
|
# 1 month - 30 days
|
|
elif cache_expire == 3:
|
|
# no tenemos en cuenta febrero o meses con 31 días
|
|
if elapsed > datetime.timedelta(days=30):
|
|
valided = False
|
|
else:
|
|
valided = True
|
|
# no expire
|
|
elif cache_expire == 4:
|
|
valided = True
|
|
|
|
return valided
|
|
|
|
result = {}
|
|
try:
|
|
|
|
# no está activa la cache
|
|
if not config.get_setting("tmdb_cache", default=False):
|
|
result = fn(*args)
|
|
else:
|
|
|
|
conn = sqlite3.connect(fname)
|
|
c = conn.cursor()
|
|
url_base64 = base64.b64encode(args[0])
|
|
c.execute("SELECT response, added FROM tmdb_cache WHERE url=?", (url_base64,))
|
|
row = c.fetchone()
|
|
|
|
if row and check_expired(float(row[1])):
|
|
result = eval(base64.b64decode(row[0]))
|
|
|
|
# si no se ha obtenido información, llamamos a la funcion
|
|
if not result:
|
|
result = fn(*args)
|
|
result_base64 = base64.b64encode(str(result))
|
|
c.execute("INSERT OR REPLACE INTO tmdb_cache (url, response, added) VALUES (?, ?, ?)",
|
|
(url_base64, result_base64, time.time()))
|
|
|
|
conn.commit()
|
|
|
|
conn.close()
|
|
|
|
# elapsed_time = time.time() - start_time
|
|
# logger.debug("TARDADO %s" % elapsed_time)
|
|
|
|
# error al obtener los datos
|
|
except Exception, ex:
|
|
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
|
|
logger.error("error en: %s" % message)
|
|
|
|
return result
|
|
|
|
return wrapper
|
|
|
|
|
|
def set_infoLabels(source, seekTmdb=True, idioma_busqueda='es'):
|
|
"""
|
|
Dependiendo del tipo de dato de source obtiene y fija (item.infoLabels) los datos extras de una o varias series,
|
|
capitulos o peliculas.
|
|
|
|
@param source: variable que contiene la información para establecer infoLabels
|
|
@type source: list, item
|
|
@param seekTmdb: si es True hace una busqueda en www.themoviedb.org para obtener los datos, en caso contrario
|
|
obtiene los datos del propio Item.
|
|
@type seekTmdb: bool
|
|
@param idioma_busqueda: fija el valor de idioma en caso de busqueda en www.themoviedb.org
|
|
@type idioma_busqueda: str
|
|
@return: un numero o lista de numeros con el resultado de las llamadas a set_infoLabels_item
|
|
@rtype: int, list
|
|
"""
|
|
|
|
start_time = time.time()
|
|
if type(source) == list:
|
|
ret = set_infoLabels_itemlist(source, seekTmdb, idioma_busqueda)
|
|
logger.debug("Se han obtenido los datos de %i enlaces en %f segundos" % (len(source), time.time() - start_time))
|
|
else:
|
|
ret = set_infoLabels_item(source, seekTmdb, idioma_busqueda)
|
|
logger.debug("Se han obtenido los datos del enlace en %f segundos" % (time.time() - start_time))
|
|
return ret
|
|
|
|
|
|
def set_infoLabels_itemlist(item_list, seekTmdb=False, idioma_busqueda='es'):
|
|
"""
|
|
De manera concurrente, obtiene los datos de los items incluidos en la lista item_list.
|
|
|
|
La API tiene un limite de 40 peticiones por IP cada 10'' y por eso la lista no deberia tener mas de 30 items
|
|
para asegurar un buen funcionamiento de esta funcion.
|
|
|
|
@param item_list: listado de objetos Item que representan peliculas, series o capitulos. El atributo
|
|
infoLabels de cada objeto Item sera modificado incluyendo los datos extras localizados.
|
|
@type item_list: list
|
|
@param seekTmdb: Si es True hace una busqueda en www.themoviedb.org para obtener los datos, en caso contrario
|
|
obtiene los datos del propio Item si existen.
|
|
@type seekTmdb: bool
|
|
@param idioma_busqueda: Codigo del idioma segun ISO 639-1, en caso de busqueda en www.themoviedb.org.
|
|
@type idioma_busqueda: str
|
|
|
|
@return: Una lista de numeros cuyo valor absoluto representa la cantidad de elementos incluidos en el atributo
|
|
infoLabels de cada Item. Este numero sera positivo si los datos se han obtenido de www.themoviedb.org y
|
|
negativo en caso contrario.
|
|
@rtype: list
|
|
"""
|
|
import threading
|
|
|
|
threads_num = config.get_setting("tmdb_threads", default=20)
|
|
semaforo = threading.Semaphore(threads_num)
|
|
lock = threading.Lock()
|
|
r_list = list()
|
|
i = 0
|
|
l_hilo = list()
|
|
|
|
def sub_thread(_item, _i, _seekTmdb):
|
|
semaforo.acquire()
|
|
ret = set_infoLabels_item(_item, _seekTmdb, idioma_busqueda, lock)
|
|
# logger.debug(str(ret) + "item: " + _item.tostring())
|
|
semaforo.release()
|
|
r_list.append((_i, _item, ret))
|
|
|
|
for item in item_list:
|
|
t = threading.Thread(target=sub_thread, args=(item, i, seekTmdb))
|
|
t.start()
|
|
i += 1
|
|
l_hilo.append(t)
|
|
|
|
# esperar q todos los hilos terminen
|
|
for x in l_hilo:
|
|
x.join()
|
|
|
|
# Ordenar lista de resultados por orden de llamada para mantener el mismo orden q item_list
|
|
r_list.sort(key=lambda i: i[0])
|
|
|
|
# Reconstruir y devolver la lista solo con los resultados de las llamadas individuales
|
|
return [ii[2] for ii in r_list]
|
|
|
|
|
|
def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda='es', lock=None):
|
|
"""
|
|
Obtiene y fija (item.infoLabels) los datos extras de una serie, capitulo o pelicula.
|
|
|
|
@param item: Objeto Item que representa un pelicula, serie o capitulo. El atributo infoLabels sera modificado
|
|
incluyendo los datos extras localizados.
|
|
@type item: Item
|
|
@param seekTmdb: Si es True hace una busqueda en www.themoviedb.org para obtener los datos, en caso contrario
|
|
obtiene los datos del propio Item si existen.
|
|
@type seekTmdb: bool
|
|
@param idioma_busqueda: Codigo del idioma segun ISO 639-1, en caso de busqueda en www.themoviedb.org.
|
|
@type idioma_busqueda: str
|
|
@param lock: para uso de threads cuando es llamado del metodo 'set_infoLabels_itemlist'
|
|
@return: Un numero cuyo valor absoluto representa la cantidad de elementos incluidos en el atributo item.infoLabels.
|
|
Este numero sera positivo si los datos se han obtenido de www.themoviedb.org y negativo en caso contrario.
|
|
@rtype: int
|
|
"""
|
|
global otmdb_global
|
|
|
|
def __leer_datos(otmdb_aux):
|
|
item.infoLabels = otmdb_aux.get_infoLabels(item.infoLabels)
|
|
if item.infoLabels['thumbnail']:
|
|
item.thumbnail = item.infoLabels['thumbnail']
|
|
if item.infoLabels['fanart']:
|
|
item.fanart = item.infoLabels['fanart']
|
|
|
|
if seekTmdb:
|
|
# Comprobamos q tipo de contenido es...
|
|
if item.contentType == 'movie':
|
|
tipo_busqueda = 'movie'
|
|
else:
|
|
tipo_busqueda = 'tv'
|
|
|
|
if item.infoLabels['season']:
|
|
try:
|
|
numtemporada = int(item.infoLabels['season'])
|
|
except ValueError:
|
|
logger.debug("El numero de temporada no es valido")
|
|
return -1 * len(item.infoLabels)
|
|
|
|
if lock:
|
|
lock.acquire()
|
|
|
|
if not otmdb_global or (item.infoLabels['tmdb_id']
|
|
and str(otmdb_global.result.get("id")) != item.infoLabels['tmdb_id']) \
|
|
or (otmdb_global.texto_buscado and otmdb_global.texto_buscado != item.infoLabels['tvshowtitle']):
|
|
if item.infoLabels['tmdb_id']:
|
|
otmdb_global = Tmdb(id_Tmdb=item.infoLabels['tmdb_id'], tipo=tipo_busqueda,
|
|
idioma_busqueda=idioma_busqueda)
|
|
else:
|
|
otmdb_global = Tmdb(texto_buscado=item.infoLabels['tvshowtitle'], tipo=tipo_busqueda,
|
|
idioma_busqueda=idioma_busqueda, year=item.infoLabels['year'])
|
|
|
|
__leer_datos(otmdb_global)
|
|
|
|
if lock and lock.locked():
|
|
lock.release()
|
|
|
|
if item.infoLabels['episode']:
|
|
try:
|
|
episode = int(item.infoLabels['episode'])
|
|
except ValueError:
|
|
logger.debug("El número de episodio (%s) no es valido" % repr(item.infoLabels['episode']))
|
|
return -1 * len(item.infoLabels)
|
|
|
|
# Tenemos numero de temporada y numero de episodio validos...
|
|
# ... buscar datos episodio
|
|
item.infoLabels['mediatype'] = 'episode'
|
|
episodio = otmdb_global.get_episodio(numtemporada, episode)
|
|
|
|
if episodio:
|
|
# Actualizar datos
|
|
__leer_datos(otmdb_global)
|
|
item.infoLabels['title'] = episodio['episodio_titulo']
|
|
if episodio['episodio_sinopsis']:
|
|
item.infoLabels['plot'] = episodio['episodio_sinopsis']
|
|
if episodio['episodio_imagen']:
|
|
item.infoLabels['poster_path'] = episodio['episodio_imagen']
|
|
item.thumbnail = item.infoLabels['poster_path']
|
|
if episodio['episodio_air_date']:
|
|
item.infoLabels['aired'] = episodio['episodio_air_date']
|
|
if episodio['episodio_vote_average']:
|
|
item.infoLabels['rating'] = episodio['episodio_vote_average']
|
|
item.infoLabels['votes'] = episodio['episodio_vote_count']
|
|
|
|
return len(item.infoLabels)
|
|
|
|
else:
|
|
# Tenemos numero de temporada valido pero no numero de episodio...
|
|
# ... buscar datos temporada
|
|
item.infoLabels['mediatype'] = 'season'
|
|
temporada = otmdb_global.get_temporada(numtemporada)
|
|
|
|
if temporada:
|
|
# Actualizar datos
|
|
__leer_datos(otmdb_global)
|
|
item.infoLabels['title'] = temporada['name']
|
|
if temporada['overview']:
|
|
item.infoLabels['plot'] = temporada['overview']
|
|
if temporada['air_date']:
|
|
date = temporada['air_date'].split('-')
|
|
item.infoLabels['aired'] = date[2] + "/" + date[1] + "/" + date[0]
|
|
if temporada['poster_path']:
|
|
item.infoLabels['poster_path'] = 'http://image.tmdb.org/t/p/original' + temporada['poster_path']
|
|
item.thumbnail = item.infoLabels['poster_path']
|
|
return len(item.infoLabels)
|
|
|
|
# Buscar...
|
|
else:
|
|
otmdb = copy.copy(otmdb_global)
|
|
# Busquedas por ID...
|
|
if item.infoLabels['tmdb_id']:
|
|
# ...Busqueda por tmdb_id
|
|
otmdb = Tmdb(id_Tmdb=item.infoLabels['tmdb_id'], tipo=tipo_busqueda,
|
|
idioma_busqueda=idioma_busqueda)
|
|
|
|
elif item.infoLabels['imdb_id']:
|
|
# ...Busqueda por imdb code
|
|
otmdb = Tmdb(external_id=item.infoLabels['imdb_id'], external_source="imdb_id",
|
|
tipo=tipo_busqueda,
|
|
idioma_busqueda=idioma_busqueda)
|
|
|
|
elif tipo_busqueda == 'tv': # buscar con otros codigos
|
|
if item.infoLabels['tvdb_id']:
|
|
# ...Busqueda por tvdb_id
|
|
otmdb = Tmdb(external_id=item.infoLabels['tvdb_id'], external_source="tvdb_id", tipo=tipo_busqueda,
|
|
idioma_busqueda=idioma_busqueda)
|
|
elif item.infoLabels['freebase_mid']:
|
|
# ...Busqueda por freebase_mid
|
|
otmdb = Tmdb(external_id=item.infoLabels['freebase_mid'], external_source="freebase_mid",
|
|
tipo=tipo_busqueda, idioma_busqueda=idioma_busqueda)
|
|
elif item.infoLabels['freebase_id']:
|
|
# ...Busqueda por freebase_id
|
|
otmdb = Tmdb(external_id=item.infoLabels['freebase_id'], external_source="freebase_id",
|
|
tipo=tipo_busqueda, idioma_busqueda=idioma_busqueda)
|
|
elif item.infoLabels['tvrage_id']:
|
|
# ...Busqueda por tvrage_id
|
|
otmdb = Tmdb(external_id=item.infoLabels['tvrage_id'], external_source="tvrage_id",
|
|
tipo=tipo_busqueda, idioma_busqueda=idioma_busqueda)
|
|
|
|
#if otmdb is None:
|
|
if not item.infoLabels['tmdb_id'] and not item.infoLabels['imdb_id'] and not item.infoLabels['tvdb_id'] and not item.infoLabels['freebase_mid'] and not item.infoLabels['freebase_id'] and not item.infoLabels['tvrage_id']:
|
|
# No se ha podido buscar por ID...
|
|
# hacerlo por titulo
|
|
if tipo_busqueda == 'tv':
|
|
# Busqueda de serie por titulo y filtrando sus resultados si es necesario
|
|
otmdb = Tmdb(texto_buscado=item.infoLabels['tvshowtitle'], tipo=tipo_busqueda,
|
|
idioma_busqueda=idioma_busqueda, filtro=item.infoLabels.get('filtro', {}),
|
|
year=item.infoLabels['year'])
|
|
else:
|
|
# Busqueda de pelicula por titulo...
|
|
if item.infoLabels['year'] or item.infoLabels['filtro']:
|
|
# ...y año o filtro
|
|
if item.contentTitle:
|
|
titulo_buscado = item.contentTitle
|
|
else:
|
|
titulo_buscado = item.fulltitle
|
|
|
|
otmdb = Tmdb(texto_buscado=titulo_buscado, tipo=tipo_busqueda, idioma_busqueda=idioma_busqueda,
|
|
filtro=item.infoLabels.get('filtro', {}), year=item.infoLabels['year'])
|
|
if otmdb is not None:
|
|
if otmdb.get_id() and config.get_setting("tmdb_plus_info", default=False):
|
|
# Si la busqueda ha dado resultado y no se esta buscando una lista de items,
|
|
# realizar otra busqueda para ampliar la informacion
|
|
otmdb = Tmdb(id_Tmdb=otmdb.result.get("id"), tipo=tipo_busqueda, idioma_busqueda=idioma_busqueda)
|
|
|
|
if lock and lock.locked():
|
|
lock.release()
|
|
|
|
if otmdb is not None and otmdb.get_id():
|
|
# La busqueda ha encontrado un resultado valido
|
|
__leer_datos(otmdb)
|
|
return len(item.infoLabels)
|
|
|
|
# La busqueda en tmdb esta desactivada o no ha dado resultado
|
|
# item.contentType = item.infoLabels['mediatype']
|
|
return -1 * len(item.infoLabels)
|
|
|
|
|
|
def find_and_set_infoLabels(item):
|
|
logger.info()
|
|
|
|
global otmdb_global
|
|
tmdb_result = None
|
|
|
|
if item.contentType == "movie":
|
|
tipo_busqueda = "movie"
|
|
tipo_contenido = config.get_localized_string(70283)
|
|
title = item.contentTitle
|
|
else:
|
|
tipo_busqueda = "tv"
|
|
tipo_contenido = config.get_localized_string(60245)
|
|
title = item.contentSerieName
|
|
|
|
# Si el titulo incluye el (año) se lo quitamos
|
|
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("tmdb_id"):
|
|
if not item.infoLabels.get("imdb_id"):
|
|
otmdb_global = Tmdb(texto_buscado=title, tipo=tipo_busqueda, year=item.infoLabels['year'])
|
|
else:
|
|
otmdb_global = Tmdb(external_id=item.infoLabels.get("imdb_id"), external_source="imdb_id",
|
|
tipo=tipo_busqueda)
|
|
elif not otmdb_global or str(otmdb_global.result.get("id")) != item.infoLabels['tmdb_id']:
|
|
otmdb_global = Tmdb(id_Tmdb=item.infoLabels['tmdb_id'], tipo=tipo_busqueda, idioma_busqueda="es")
|
|
|
|
results = otmdb_global.get_list_resultados()
|
|
|
|
if len(results) > 1:
|
|
from platformcode import platformtools
|
|
tmdb_result = platformtools.show_video_info(results, item=item,
|
|
caption=config.get_localized_string(60247) %(title, tipo_contenido))
|
|
elif len(results) > 0:
|
|
tmdb_result = results[0]
|
|
|
|
if isinstance(item.infoLabels, InfoLabels):
|
|
infoLabels = item.infoLabels
|
|
else:
|
|
infoLabels = InfoLabels()
|
|
|
|
if tmdb_result:
|
|
infoLabels['tmdb_id'] = tmdb_result['id']
|
|
# todo mirar si se puede eliminar y obtener solo desde get_nfo()
|
|
infoLabels['url_scraper'] = ["https://www.themoviedb.org/%s/%s" % (tipo_busqueda, infoLabels['tmdb_id'])]
|
|
if infoLabels['tvdb_id']:
|
|
infoLabels['url_scraper'].append("http://thetvdb.com/index.php?tab=series&id=%s" % infoLabels['tvdb_id'])
|
|
item.infoLabels = infoLabels
|
|
set_infoLabels_item(item)
|
|
|
|
return True
|
|
|
|
else:
|
|
item.infoLabels = infoLabels
|
|
return False
|
|
|
|
|
|
def get_nfo(item):
|
|
"""
|
|
Devuelve la información necesaria para que se scrapee el resultado en la videoteca de kodi, para tmdb funciona
|
|
solo pasandole la url.
|
|
@param item: elemento que contiene los datos necesarios para generar la info
|
|
@type item: Item
|
|
@rtype: str
|
|
@return:
|
|
"""
|
|
if "season" in item.infoLabels and "episode" in item.infoLabels:
|
|
info_nfo = "https://www.themoviedb.org/tv/%s/season/%s/episode/%s\n" % \
|
|
(item.infoLabels['tmdb_id'], item.contentSeason, item.contentEpisodeNumber)
|
|
else:
|
|
info_nfo = ', '.join(item.infoLabels['url_scraper']) + "\n"
|
|
|
|
return info_nfo
|
|
|
|
|
|
def completar_codigos(item):
|
|
"""
|
|
Si es necesario comprueba si existe el identificador de tvdb y sino existe trata de buscarlo
|
|
"""
|
|
if item.contentType != "movie" and not item.infoLabels['tvdb_id']:
|
|
# Lanzar busqueda por imdb_id en tvdb
|
|
from core.tvdb import Tvdb
|
|
ob = Tvdb(imdb_id=item.infoLabels['imdb_id'])
|
|
item.infoLabels['tvdb_id'] = ob.get_id()
|
|
if item.infoLabels['tvdb_id']:
|
|
url_scraper = "http://thetvdb.com/index.php?tab=series&id=%s" % item.infoLabels['tvdb_id']
|
|
if url_scraper not in item.infoLabels['url_scraper']:
|
|
item.infoLabels['url_scraper'].append(url_scraper)
|
|
|
|
|
|
def discovery(item):
|
|
from core.item import Item
|
|
from platformcode import unify
|
|
|
|
if item.search_type == 'discover':
|
|
listado = Tmdb(discover={'url':'discover/%s' % item.type, 'with_genres':item.list_type, 'language':'es',
|
|
'page':item.page})
|
|
|
|
elif item.search_type == 'list':
|
|
if item.page == '':
|
|
item.page = '1'
|
|
listado = Tmdb(list={'url': item.list_type, 'language':'es', 'page':item.page})
|
|
|
|
logger.debug(listado.get_list_resultados())
|
|
result = listado.get_list_resultados()
|
|
|
|
return result
|
|
|
|
def get_genres(type):
|
|
lang = 'es'
|
|
genres = Tmdb(tipo=type)
|
|
|
|
return genres.dic_generos[lang]
|
|
|
|
|
|
|
|
# Clase auxiliar
|
|
class ResultDictDefault(dict):
|
|
# Python 2.4
|
|
def __getitem__(self, key):
|
|
try:
|
|
return super(ResultDictDefault, self).__getitem__(key)
|
|
except:
|
|
return self.__missing__(key)
|
|
|
|
def __missing__(self, key):
|
|
"""
|
|
valores por defecto en caso de que la clave solicitada no exista
|
|
"""
|
|
if key in ['genre_ids', 'genre', 'genres']:
|
|
return list()
|
|
elif key == 'images_posters':
|
|
posters = dict()
|
|
if 'images' in super(ResultDictDefault, self).keys() and \
|
|
'posters' in super(ResultDictDefault, self).__getitem__('images'):
|
|
posters = super(ResultDictDefault, self).__getitem__('images')['posters']
|
|
super(ResultDictDefault, self).__setattr__("images_posters", posters)
|
|
|
|
return posters
|
|
|
|
elif key == "images_backdrops":
|
|
backdrops = dict()
|
|
if 'images' in super(ResultDictDefault, self).keys() and \
|
|
'backdrops' in super(ResultDictDefault, self).__getitem__('images'):
|
|
backdrops = super(ResultDictDefault, self).__getitem__('images')['backdrops']
|
|
super(ResultDictDefault, self).__setattr__("images_backdrops", backdrops)
|
|
|
|
return backdrops
|
|
|
|
elif key == "images_profiles":
|
|
profiles = dict()
|
|
if 'images' in super(ResultDictDefault, self).keys() and \
|
|
'profiles' in super(ResultDictDefault, self).__getitem__('images'):
|
|
profiles = super(ResultDictDefault, self).__getitem__('images')['profiles']
|
|
super(ResultDictDefault, self).__setattr__("images_profiles", profiles)
|
|
|
|
return profiles
|
|
|
|
else:
|
|
# El resto de claves devuelven cadenas vacias por defecto
|
|
return ""
|
|
|
|
def __str__(self):
|
|
return self.tostring(separador=',\n')
|
|
|
|
def tostring(self, separador=',\n'):
|
|
ls = []
|
|
for i in super(ResultDictDefault, self).items():
|
|
i_str = str(i)[1:-1]
|
|
if isinstance(i[0], str):
|
|
old = i[0] + "',"
|
|
new = i[0] + "':"
|
|
else:
|
|
old = str(i[0]) + ","
|
|
new = str(i[0]) + ":"
|
|
ls.append(i_str.replace(old, new, 1))
|
|
|
|
return "{%s}" % separador.join(ls)
|
|
|
|
|
|
# ---------------------------------------------------------------------------------------------------------------
|
|
# class Tmdb:
|
|
# Scraper para el addon basado en el Api de https://www.themoviedb.org/
|
|
# version 1.4:
|
|
# - Documentada limitacion de uso de la API (ver mas abajo).
|
|
# - Añadido metodo get_temporada()
|
|
# version 1.3:
|
|
# - Corregido error al devolver None el path_poster y el backdrop_path
|
|
# - Corregido error que hacia que en el listado de generos se fueran acumulando de una llamada a otra
|
|
# - Añadido metodo get_generos()
|
|
# - Añadido parametros opcional idioma_alternativo al metodo get_sinopsis()
|
|
#
|
|
#
|
|
# Uso:
|
|
# Metodos constructores:
|
|
# Tmdb(texto_buscado, tipo)
|
|
# Parametros:
|
|
# texto_buscado:(str) Texto o parte del texto a buscar
|
|
# tipo: ("movie" o "tv") Tipo de resultado buscado peliculas o series. Por defecto "movie"
|
|
# (opcional) idioma_busqueda: (str) codigo del idioma segun ISO 639-1
|
|
# (opcional) include_adult: (bool) Se incluyen contenidos para adultos en la busqueda o no. Por defecto
|
|
# 'False'
|
|
# (opcional) year: (str) Año de lanzamiento.
|
|
# (opcional) page: (int) Cuando hay muchos resultados para una busqueda estos se organizan por paginas.
|
|
# Podemos cargar la pagina que deseemos aunque por defecto siempre es la primera.
|
|
# Return:
|
|
# Esta llamada devuelve un objeto Tmdb que contiene la primera pagina del resultado de buscar 'texto_buscado'
|
|
# en la web themoviedb.org. Cuantos mas parametros opcionales se incluyan mas precisa sera la busqueda.
|
|
# Ademas el objeto esta inicializado con el primer resultado de la primera pagina de resultados.
|
|
# Tmdb(id_Tmdb,tipo)
|
|
# Parametros:
|
|
# id_Tmdb: (str) Codigo identificador de una determinada pelicula o serie en themoviedb.org
|
|
# tipo: ("movie" o "tv") Tipo de resultado buscado peliculas o series. Por defecto "movie"
|
|
# (opcional) idioma_busqueda: (str) codigo del idioma segun ISO 639-1
|
|
# Return:
|
|
# Esta llamada devuelve un objeto Tmdb que contiene el resultado de buscar una pelicula o serie con el
|
|
# identificador id_Tmd
|
|
# en la web themoviedb.org.
|
|
# Tmdb(external_id, external_source, tipo)
|
|
# Parametros:
|
|
# external_id: (str) Codigo identificador de una determinada pelicula o serie en la web referenciada por
|
|
# 'external_source'.
|
|
# external_source: (Para series:"imdb_id","freebase_mid","freebase_id","tvdb_id","tvrage_id"; Para
|
|
# peliculas:"imdb_id")
|
|
# tipo: ("movie" o "tv") Tipo de resultado buscado peliculas o series. Por defecto "movie"
|
|
# (opcional) idioma_busqueda: (str) codigo del idioma segun ISO 639-1
|
|
# Return:
|
|
# Esta llamada devuelve un objeto Tmdb que contiene el resultado de buscar una pelicula o serie con el
|
|
# identificador 'external_id' de
|
|
# la web referenciada por 'external_source' en la web themoviedb.org.
|
|
#
|
|
# Metodos principales:
|
|
# get_id(): Retorna un str con el identificador Tmdb de la pelicula o serie cargada o una cadena vacia si no hubiese
|
|
# nada cargado.
|
|
# get_sinopsis(idioma_alternativo): Retorna un str con la sinopsis de la serie o pelicula cargada.
|
|
# get_poster (tipo_respuesta,size): Obtiene el poster o un listado de posters.
|
|
# get_backdrop (tipo_respuesta,size): Obtiene una imagen de fondo o un listado de imagenes de fondo.
|
|
# get_temporada(temporada): Obtiene un diccionario con datos especificos de la temporada.
|
|
# get_episodio (temporada, capitulo): Obtiene un diccionario con datos especificos del episodio.
|
|
# get_generos(): Retorna un str con la lista de generos a los que pertenece la pelicula o serie.
|
|
#
|
|
#
|
|
# Otros metodos:
|
|
# load_resultado(resultado, page): Cuando la busqueda devuelve varios resultados podemos seleccionar que resultado
|
|
# concreto y de que pagina cargar los datos.
|
|
#
|
|
# Limitaciones:
|
|
# El uso de la API impone un limite de 20 conexiones simultaneas (concurrencia) o 30 peticiones en 10 segundos por IP
|
|
# Informacion sobre la api : http://docs.themoviedb.apiary.io
|
|
# -------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
class Tmdb(object):
|
|
# Atributo de clase
|
|
dic_generos = {}
|
|
'''
|
|
dic_generos={"id_idioma1": {"tv": {"id1": "name1",
|
|
"id2": "name2"
|
|
},
|
|
"movie": {"id1": "name1",
|
|
"id2": "name2"
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
dic_country = {"AD": "Andorra", "AE": "Emiratos Árabes Unidos", "AF": "Afganistán", "AG": "Antigua y Barbuda",
|
|
"AI": "Anguila", "AL": "Albania", "AM": "Armenia", "AN": "Antillas Neerlandesas", "AO": "Angola",
|
|
"AQ": "Antártida", "AR": "Argentina", "AS": "Samoa Americana", "AT": "Austria", "AU": "Australia",
|
|
"AW": "Aruba", "AX": "Islas de Åland", "AZ": "Azerbayán", "BA": "Bosnia y Herzegovina",
|
|
"BD": "Bangladesh", "BE": "Bélgica", "BF": "Burkina Faso", "BG": "Bulgaria", "BI": "Burundi",
|
|
"BJ": "Benín", "BL": "San Bartolomé", "BM": "Islas Bermudas", "BN": "Brunéi", "BO": "Bolivia",
|
|
"BR": "Brasil", "BS": "Bahamas", "BT": "Bhután", "BV": "Isla Bouvet", "BW": "Botsuana",
|
|
"BY": "Bielorrusia", "BZ": "Belice", "CA": "Canadá", "CC": "Islas Cocos (Keeling)", "CD": "Congo",
|
|
"CF": "República Centroafricana", "CG": "Congo", "CH": "Suiza", "CI": "Costa de Marfil",
|
|
"CK": "Islas Cook", "CL": "Chile", "CM": "Camerún", "CN": "China", "CO": "Colombia",
|
|
"CR": "Costa Rica", "CU": "Cuba", "CV": "Cabo Verde", "CX": "Isla de Navidad", "CY": "Chipre",
|
|
"CZ": "República Checa", "DE": "Alemania", "DJ": "Yibuti", "DK": "Dinamarca", "DZ": "Algeria",
|
|
"EC": "Ecuador", "EE": "Estonia", "EG": "Egipto", "EH": "Sahara Occidental", "ER": "Eritrea",
|
|
"ES": "España", "ET": "Etiopía", "FI": "Finlandia", "FJ": "Fiyi", "FK": "Islas Malvinas",
|
|
"FM": "Micronesia", "FO": "Islas Feroe", "FR": "Francia", "GA": "Gabón", "GB": "Gran Bretaña",
|
|
"GD": "Granada", "GE": "Georgia", "GF": "Guayana Francesa", "GG": "Guernsey", "GH": "Ghana",
|
|
"GI": "Gibraltar", "GL": "Groenlandia", "GM": "Gambia", "GN": "Guinea", "GP": "Guadalupe",
|
|
"GQ": "Guinea Ecuatorial", "GR": "Grecia", "GS": "Islas Georgias del Sur y Sandwich del Sur",
|
|
"GT": "Guatemala", "GW": "Guinea-Bissau", "GY": "Guyana", "HK": "Hong kong",
|
|
"HM": "Islas Heard y McDonald", "HN": "Honduras", "HR": "Croacia", "HT": "Haití", "HU": "Hungría",
|
|
"ID": "Indonesia", "IE": "Irlanda", "IM": "Isla de Man", "IN": "India",
|
|
"IO": "Territorio Británico del Océano Índico", "IQ": "Irak", "IR": "Irán", "IS": "Islandia",
|
|
"IT": "Italia", "JE": "Jersey", "JM": "Jamaica", "JO": "Jordania", "JP": "Japón", "KG": "Kirgizstán",
|
|
"KH": "Camboya", "KM": "Comoras", "KP": "Corea del Norte", "KR": "Corea del Sur", "KW": "Kuwait",
|
|
"KY": "Islas Caimán", "KZ": "Kazajistán", "LA": "Laos", "LB": "Líbano", "LC": "Santa Lucía",
|
|
"LI": "Liechtenstein", "LK": "Sri lanka", "LR": "Liberia", "LS": "Lesoto", "LT": "Lituania",
|
|
"LU": "Luxemburgo", "LV": "Letonia", "LY": "Libia", "MA": "Marruecos", "MC": "Mónaco",
|
|
"MD": "Moldavia", "ME": "Montenegro", "MF": "San Martín (Francia)", "MG": "Madagascar",
|
|
"MH": "Islas Marshall", "MK": "Macedônia", "ML": "Mali", "MM": "Birmania", "MN": "Mongolia",
|
|
"MO": "Macao", "MP": "Islas Marianas del Norte", "MQ": "Martinica", "MR": "Mauritania",
|
|
"MS": "Montserrat", "MT": "Malta", "MU": "Mauricio", "MV": "Islas Maldivas", "MW": "Malawi",
|
|
"MX": "México", "MY": "Malasia", "NA": "Namibia", "NE": "Niger", "NG": "Nigeria", "NI": "Nicaragua",
|
|
"NL": "Países Bajos", "NO": "Noruega", "NP": "Nepal", "NR": "Nauru", "NU": "Niue",
|
|
"NZ": "Nueva Zelanda", "OM": "Omán", "PA": "Panamá", "PE": "Perú", "PF": "Polinesia Francesa",
|
|
"PH": "Filipinas", "PK": "Pakistán", "PL": "Polonia", "PM": "San Pedro y Miquelón",
|
|
"PN": "Islas Pitcairn", "PR": "Puerto Rico", "PS": "Palestina", "PT": "Portugal", "PW": "Palau",
|
|
"PY": "Paraguay", "QA": "Qatar", "RE": "Reunión", "RO": "Rumanía", "RS": "Serbia", "RU": "Rusia",
|
|
"RW": "Ruanda", "SA": "Arabia Saudita", "SB": "Islas Salomón", "SC": "Seychelles", "SD": "Sudán",
|
|
"SE": "Suecia", "SG": "Singapur", "SH": "Santa Elena", "SI": "Eslovenia",
|
|
"SJ": "Svalbard y Jan Mayen",
|
|
"SK": "Eslovaquia", "SL": "Sierra Leona", "SM": "San Marino", "SN": "Senegal", "SO": "Somalia",
|
|
"SV": "El Salvador", "SY": "Siria", "SZ": "Swazilandia", "TC": "Islas Turcas y Caicos", "TD": "Chad",
|
|
"TF": "Territorios Australes y Antárticas Franceses", "TG": "Togo", "TH": "Tailandia",
|
|
"TJ": "Tadjikistán", "TK": "Tokelau", "TL": "Timor Oriental", "TM": "Turkmenistán", "TN": "Tunez",
|
|
"TO": "Tonga", "TR": "Turquía", "TT": "Trinidad y Tobago", "TV": "Tuvalu", "TW": "Taiwán",
|
|
"TZ": "Tanzania", "UA": "Ucrania", "UG": "Uganda",
|
|
"UM": "Islas Ultramarinas Menores de Estados Unidos",
|
|
"UY": "Uruguay", "UZ": "Uzbekistán", "VA": "Ciudad del Vaticano",
|
|
"VC": "San Vicente y las Granadinas",
|
|
"VE": "Venezuela", "VG": "Islas Vírgenes Británicas", "VI": "Islas Vírgenes de los Estados Unidos",
|
|
"VN": "Vietnam", "VU": "Vanuatu", "WF": "Wallis y Futuna", "WS": "Samoa", "YE": "Yemen",
|
|
"YT": "Mayotte", "ZA": "Sudáfrica", "ZM": "Zambia", "ZW": "Zimbabue", "BB": "Barbados",
|
|
"BH": "Bahrein",
|
|
"DM": "Dominica", "DO": "República Dominicana", "GU": "Guam", "IL": "Israel", "KE": "Kenia",
|
|
"KI": "Kiribati", "KN": "San Cristóbal y Nieves", "MZ": "Mozambique", "NC": "Nueva Caledonia",
|
|
"NF": "Isla Norfolk", "PG": "Papúa Nueva Guinea", "SR": "Surinám", "ST": "Santo Tomé y Príncipe",
|
|
"US": "EEUU"}
|
|
|
|
def __init__(self, **kwargs):
|
|
self.page = kwargs.get('page', 1)
|
|
self.index_results = 0
|
|
self.results = []
|
|
self.result = ResultDictDefault()
|
|
self.total_pages = 0
|
|
self.total_results = 0
|
|
|
|
self.temporada = {}
|
|
self.texto_buscado = kwargs.get('texto_buscado', '')
|
|
|
|
self.busqueda_id = kwargs.get('id_Tmdb', '')
|
|
self.busqueda_texto = re.sub('\[\\\?(B|I|COLOR)\s?[^\]]*\]', '', self.texto_buscado).strip()
|
|
self.busqueda_tipo = kwargs.get('tipo', '')
|
|
self.busqueda_idioma = kwargs.get('idioma_busqueda', 'es')
|
|
self.busqueda_include_adult = kwargs.get('include_adult', False)
|
|
self.busqueda_year = kwargs.get('year', '')
|
|
self.busqueda_filtro = kwargs.get('filtro', {})
|
|
self.discover = kwargs.get('discover', {})
|
|
self.list = kwargs.get('list', {})
|
|
|
|
# Reellenar diccionario de generos si es necesario
|
|
if (self.busqueda_tipo == 'movie' or self.busqueda_tipo == "tv") and \
|
|
(self.busqueda_idioma not in Tmdb.dic_generos or
|
|
self.busqueda_tipo not in Tmdb.dic_generos[self.busqueda_idioma]):
|
|
self.rellenar_dic_generos(self.busqueda_tipo, self.busqueda_idioma)
|
|
|
|
if not self.busqueda_tipo:
|
|
self.busqueda_tipo = 'movie'
|
|
|
|
if self.busqueda_id:
|
|
# Busqueda por identificador tmdb
|
|
self.__by_id()
|
|
|
|
elif self.busqueda_texto:
|
|
# Busqueda por texto
|
|
self.__search(page=self.page)
|
|
|
|
elif 'external_source' in kwargs and 'external_id' in kwargs:
|
|
# Busqueda por identificador externo segun el tipo.
|
|
# TV Series: imdb_id, freebase_mid, freebase_id, tvdb_id, tvrage_id
|
|
# Movies: imdb_id
|
|
if (self.busqueda_tipo == 'movie' and kwargs.get('external_source') == "imdb_id") or \
|
|
(self.busqueda_tipo == 'tv' and kwargs.get('external_source') in (
|
|
"imdb_id", "freebase_mid", "freebase_id", "tvdb_id", "tvrage_id")):
|
|
self.busqueda_id = kwargs.get('external_id')
|
|
self.__by_id(source=kwargs.get('external_source'))
|
|
|
|
elif self.discover:
|
|
self.__discover()
|
|
|
|
elif self.list:
|
|
self.__list()
|
|
|
|
else:
|
|
logger.debug("Creado objeto vacio")
|
|
|
|
@staticmethod
|
|
@cache_response
|
|
def get_json(url):
|
|
|
|
try:
|
|
result = httptools.downloadpage(url, cookies=False)
|
|
|
|
res_headers = result.headers
|
|
# logger.debug("res_headers es %s" % res_headers)
|
|
dict_data = jsontools.load(result.data)
|
|
# logger.debug("result_data es %s" % dict_data)
|
|
|
|
if "status_code" in dict_data:
|
|
logger.debug("\nError de tmdb: %s %s" % (dict_data["status_code"], dict_data["status_message"]))
|
|
|
|
if dict_data["status_code"] == 25:
|
|
while "status_code" in dict_data and dict_data["status_code"] == 25:
|
|
wait = int(res_headers['retry-after'])
|
|
logger.debug("Limite alcanzado, esperamos para volver a llamar en ...%s" % wait)
|
|
time.sleep(wait)
|
|
# logger.debug("RE Llamada #%s" % d)
|
|
result = httptools.downloadpage(url, cookies=False)
|
|
|
|
res_headers = result.headers
|
|
# logger.debug("res_headers es %s" % res_headers)
|
|
dict_data = jsontools.load(result.data)
|
|
# logger.debug("result_data es %s" % dict_data)
|
|
|
|
# error al obtener los datos
|
|
except Exception, ex:
|
|
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
|
|
logger.error("error en: %s" % message)
|
|
dict_data = {}
|
|
|
|
return dict_data
|
|
|
|
@classmethod
|
|
def rellenar_dic_generos(cls, tipo='movie', idioma='es'):
|
|
# Rellenar diccionario de generos del tipo e idioma pasados como parametros
|
|
if idioma not in cls.dic_generos:
|
|
cls.dic_generos[idioma] = {}
|
|
|
|
if tipo not in cls.dic_generos[idioma]:
|
|
cls.dic_generos[idioma][tipo] = {}
|
|
url = ('http://api.themoviedb.org/3/genre/%s/list?api_key=a1ab8b8669da03637a4b98fa39c39228&language=%s'
|
|
% (tipo, idioma))
|
|
try:
|
|
logger.info("[Tmdb.py] Rellenando dicionario de generos")
|
|
|
|
resultado = cls.get_json(url)
|
|
lista_generos = resultado["genres"]
|
|
|
|
for i in lista_generos:
|
|
cls.dic_generos[idioma][tipo][str(i["id"])] = i["name"]
|
|
except:
|
|
logger.error("Error generando diccionarios")
|
|
|
|
def __by_id(self, source='tmdb'):
|
|
|
|
if self.busqueda_id:
|
|
if source == "tmdb":
|
|
# http://api.themoviedb.org/3/movie/1924?api_key=a1ab8b8669da03637a4b98fa39c39228&language=es
|
|
# &append_to_response=images,videos,external_ids,credits&include_image_language=es,null
|
|
# http://api.themoviedb.org/3/tv/1407?api_key=a1ab8b8669da03637a4b98fa39c39228&language=es
|
|
# &append_to_response=images,videos,external_ids,credits&include_image_language=es,null
|
|
url = ('http://api.themoviedb.org/3/%s/%s?api_key=a1ab8b8669da03637a4b98fa39c39228&language=%s'
|
|
'&append_to_response=images,videos,external_ids,credits&include_image_language=%s,null' %
|
|
(self.busqueda_tipo, self.busqueda_id, self.busqueda_idioma, self.busqueda_idioma))
|
|
buscando = "id_Tmdb: %s" % self.busqueda_id
|
|
else:
|
|
# http://api.themoviedb.org/3/find/%s?external_source=imdb_id&api_key=a1ab8b8669da03637a4b98fa39c39228
|
|
url = ('http://api.themoviedb.org/3/find/%s?external_source=%s&api_key=a1ab8b8669da03637a4b98fa39c39228'
|
|
'&language=%s' % (self.busqueda_id, source, self.busqueda_idioma))
|
|
buscando = "%s: %s" % (source.capitalize(), self.busqueda_id)
|
|
|
|
logger.info("[Tmdb.py] Buscando %s:\n%s" % (buscando, url))
|
|
resultado = self.get_json(url)
|
|
|
|
if resultado:
|
|
if source != "tmdb":
|
|
if self.busqueda_tipo == "movie":
|
|
resultado = resultado["movie_results"][0]
|
|
else:
|
|
resultado = resultado["tv_results"][0]
|
|
|
|
self.results = [resultado]
|
|
self.total_results = 1
|
|
self.total_pages = 1
|
|
self.result = ResultDictDefault(resultado)
|
|
|
|
else:
|
|
# No hay resultados de la busqueda
|
|
msg = "La busqueda de %s no dio resultados." % buscando
|
|
logger.debug(msg)
|
|
|
|
def __search(self, index_results=0, page=1):
|
|
self.result = ResultDictDefault()
|
|
results = []
|
|
total_results = 0
|
|
total_pages = 0
|
|
buscando = ""
|
|
|
|
if self.busqueda_texto:
|
|
# http://api.themoviedb.org/3/search/movie?api_key=a1ab8b8669da03637a4b98fa39c39228&query=superman&language=es
|
|
# &include_adult=false&page=1
|
|
url = ('http://api.themoviedb.org/3/search/%s?api_key=a1ab8b8669da03637a4b98fa39c39228&query=%s&language=%s'
|
|
'&include_adult=%s&page=%s' % (self.busqueda_tipo, self.busqueda_texto.replace(' ', '%20'),
|
|
self.busqueda_idioma, self.busqueda_include_adult, page))
|
|
|
|
if self.busqueda_year:
|
|
url += '&year=%s' % self.busqueda_year
|
|
|
|
buscando = self.busqueda_texto.capitalize()
|
|
logger.info("[Tmdb.py] Buscando %s en pagina %s:\n%s" % (buscando, page, url))
|
|
resultado = self.get_json(url)
|
|
|
|
total_results = resultado.get("total_results", 0)
|
|
total_pages = resultado.get("total_pages", 0)
|
|
|
|
if total_results > 0:
|
|
results = resultado["results"]
|
|
|
|
if self.busqueda_filtro and results:
|
|
# TODO documentar esta parte
|
|
for key, value in dict(self.busqueda_filtro).items():
|
|
for r in results[:]:
|
|
if key not in r or r[key] != value:
|
|
results.remove(r)
|
|
total_results -= 1
|
|
|
|
if results:
|
|
if index_results >= len(results):
|
|
# Se ha solicitado un numero de resultado mayor de los obtenidos
|
|
logger.error(
|
|
"La busqueda de '%s' dio %s resultados para la pagina %s\nImposible mostrar el resultado numero %s"
|
|
% (buscando, len(results), page, index_results))
|
|
return 0
|
|
|
|
# Retornamos el numero de resultados de esta pagina
|
|
self.results = results
|
|
self.total_results = total_results
|
|
self.total_pages = total_pages
|
|
self.result = ResultDictDefault(self.results[index_results])
|
|
return len(self.results)
|
|
|
|
else:
|
|
# No hay resultados de la busqueda
|
|
msg = "La busqueda de '%s' no dio resultados para la pagina %s" % (buscando, page)
|
|
logger.error(msg)
|
|
return 0
|
|
|
|
def __list(self, index_results=0):
|
|
self.result = ResultDictDefault()
|
|
results = []
|
|
total_results = 0
|
|
total_pages = 0
|
|
|
|
# Ejemplo self.discover: {'url': 'movie/', 'with_cast': '1'}
|
|
# url: Método de la api a ejecutar
|
|
# resto de claves: Parámetros de la búsqueda concatenados a la url
|
|
type_search = self.list.get('url', '')
|
|
if type_search:
|
|
params = []
|
|
for key, value in self.list.items():
|
|
if key != "url":
|
|
params.append("&"+key + "=" + str(value))
|
|
# http://api.themoviedb.org/3/movie/popolar?api_key=a1ab8b8669da03637a4b98fa39c39228&&language=es
|
|
url = ('http://api.themoviedb.org/3/%s?api_key=a1ab8b8669da03637a4b98fa39c39228%s'
|
|
% (type_search, ''.join(params)))
|
|
|
|
logger.info("[Tmdb.py] Buscando %s:\n%s" % (type_search, url))
|
|
resultado = self.get_json(url)
|
|
|
|
total_results = resultado.get("total_results", -1)
|
|
total_pages = resultado.get("total_pages", 1)
|
|
|
|
if total_results > 0:
|
|
results = resultado["results"]
|
|
if self.busqueda_filtro and results:
|
|
# TODO documentar esta parte
|
|
for key, value in dict(self.busqueda_filtro).items():
|
|
for r in results[:]:
|
|
if key not in r or r[key] != value:
|
|
results.remove(r)
|
|
total_results -= 1
|
|
elif total_results == -1:
|
|
results = resultado
|
|
|
|
if index_results >= len(results):
|
|
logger.error(
|
|
"La busqueda de '%s' no dio %s resultados" % (type_search, index_results))
|
|
return 0
|
|
|
|
# Retornamos el numero de resultados de esta pagina
|
|
if results:
|
|
self.results = results
|
|
self.total_results = total_results
|
|
self.total_pages = total_pages
|
|
if total_results > 0:
|
|
self.result = ResultDictDefault(self.results[index_results])
|
|
else:
|
|
self.result = results
|
|
return len(self.results)
|
|
else:
|
|
# No hay resultados de la busqueda
|
|
logger.error("La busqueda de '%s' no dio resultados" % type_search)
|
|
return 0
|
|
|
|
|
|
|
|
def __discover(self, index_results=0):
|
|
self.result = ResultDictDefault()
|
|
results = []
|
|
total_results = 0
|
|
total_pages = 0
|
|
|
|
# Ejemplo self.discover: {'url': 'discover/movie', 'with_cast': '1'}
|
|
# url: Método de la api a ejecutar
|
|
# resto de claves: Parámetros de la búsqueda concatenados a la url
|
|
type_search = self.discover.get('url', '')
|
|
if type_search:
|
|
params = []
|
|
for key, value in self.discover.items():
|
|
if key != "url":
|
|
params.append(key + "=" + str(value))
|
|
# http://api.themoviedb.org/3/discover/movie?api_key=a1ab8b8669da03637a4b98fa39c39228&query=superman&language=es
|
|
url = ('http://api.themoviedb.org/3/%s?api_key=a1ab8b8669da03637a4b98fa39c39228&%s'
|
|
% (type_search, "&".join(params)))
|
|
|
|
logger.info("[Tmdb.py] Buscando %s:\n%s" % (type_search, url))
|
|
resultado = self.get_json(url)
|
|
|
|
total_results = resultado.get("total_results", -1)
|
|
total_pages = resultado.get("total_pages", 1)
|
|
|
|
if total_results > 0:
|
|
results = resultado["results"]
|
|
if self.busqueda_filtro and results:
|
|
# TODO documentar esta parte
|
|
for key, value in dict(self.busqueda_filtro).items():
|
|
for r in results[:]:
|
|
if key not in r or r[key] != value:
|
|
results.remove(r)
|
|
total_results -= 1
|
|
elif total_results == -1:
|
|
results = resultado
|
|
|
|
if index_results >= len(results):
|
|
logger.error(
|
|
"La busqueda de '%s' no dio %s resultados" % (type_search, index_results))
|
|
return 0
|
|
|
|
# Retornamos el numero de resultados de esta pagina
|
|
if results:
|
|
self.results = results
|
|
self.total_results = total_results
|
|
self.total_pages = total_pages
|
|
if total_results > 0:
|
|
self.result = ResultDictDefault(self.results[index_results])
|
|
else:
|
|
self.result = results
|
|
return len(self.results)
|
|
else:
|
|
# No hay resultados de la busqueda
|
|
logger.error("La busqueda de '%s' no dio resultados" % type_search)
|
|
return 0
|
|
|
|
def load_resultado(self, index_results=0, page=1):
|
|
# Si no hay resultados, solo hay uno o
|
|
# si el numero de resultados de esta pagina es menor al indice buscado salir
|
|
self.result = ResultDictDefault()
|
|
num_result_page = len(self.results)
|
|
|
|
if page > self.total_pages:
|
|
return False
|
|
|
|
if page != self.page:
|
|
num_result_page = self.__search(index_results, page)
|
|
|
|
if num_result_page == 0 or num_result_page <= index_results:
|
|
return False
|
|
|
|
self.page = page
|
|
self.index_results = index_results
|
|
self.result = ResultDictDefault(self.results[index_results])
|
|
return True
|
|
|
|
def get_list_resultados(self, num_result=20):
|
|
# logger.info("self %s" % str(self))
|
|
# TODO documentar
|
|
res = []
|
|
|
|
if num_result <= 0:
|
|
num_result = self.total_results
|
|
num_result = min([num_result, self.total_results])
|
|
|
|
cr = 0
|
|
for p in range(1, self.total_pages + 1):
|
|
for r in range(0, len(self.results)):
|
|
try:
|
|
if self.load_resultado(r, p):
|
|
result = self.result.copy()
|
|
|
|
result['thumbnail'] = self.get_poster(size="w300")
|
|
result['fanart'] = self.get_backdrop()
|
|
res.append(result)
|
|
cr += 1
|
|
if cr >= num_result:
|
|
return res
|
|
except:
|
|
continue
|
|
|
|
return res
|
|
|
|
def get_generos(self, origen=None):
|
|
"""
|
|
:param origen: Diccionario origen de donde se obtiene los infoLabels, por omision self.result
|
|
:type origen: Dict
|
|
:return: Devuelve la lista de generos a los que pertenece la pelicula o serie.
|
|
:rtype: str
|
|
"""
|
|
genre_list = []
|
|
|
|
if not origen:
|
|
origen = self.result
|
|
|
|
if "genre_ids" in origen:
|
|
# Buscar lista de generos por IDs
|
|
for i in origen.get("genre_ids"):
|
|
try:
|
|
genre_list.append(Tmdb.dic_generos[self.busqueda_idioma][self.busqueda_tipo][str(i)])
|
|
except:
|
|
pass
|
|
|
|
elif "genre" in origen or "genres" in origen:
|
|
# Buscar lista de generos (lista de objetos {id,nombre})
|
|
v = origen["genre"]
|
|
v.extend(origen["genres"])
|
|
for i in v:
|
|
genre_list.append(i['name'])
|
|
|
|
return ', '.join(genre_list)
|
|
|
|
def search_by_id(self, id, source='tmdb', tipo='movie'):
|
|
self.busqueda_id = id
|
|
self.busqueda_tipo = tipo
|
|
self.__by_id(source=source)
|
|
|
|
def get_id(self):
|
|
"""
|
|
|
|
:return: Devuelve el identificador Tmdb de la pelicula o serie cargada o una cadena vacia en caso de que no
|
|
hubiese nada cargado. Se puede utilizar este metodo para saber si una busqueda ha dado resultado o no.
|
|
:rtype: str
|
|
"""
|
|
return str(self.result.get('id', ""))
|
|
|
|
def get_sinopsis(self, idioma_alternativo=""):
|
|
"""
|
|
|
|
:param idioma_alternativo: codigo del idioma, segun ISO 639-1, en el caso de que en el idioma fijado para la
|
|
busqueda no exista sinopsis.
|
|
Por defecto, se utiliza el idioma original. Si se utiliza None como idioma_alternativo, solo se buscara en
|
|
el idioma fijado.
|
|
:type idioma_alternativo: str
|
|
:return: Devuelve la sinopsis de una pelicula o serie
|
|
:rtype: str
|
|
"""
|
|
ret = ""
|
|
|
|
if 'id' in self.result:
|
|
ret = self.result.get('overview')
|
|
if ret == "" and str(idioma_alternativo).lower() != 'none':
|
|
# Vamos a lanzar una busqueda por id y releer de nuevo la sinopsis
|
|
self.busqueda_id = str(self.result["id"])
|
|
if idioma_alternativo:
|
|
self.busqueda_idioma = idioma_alternativo
|
|
else:
|
|
self.busqueda_idioma = self.result['original_language']
|
|
|
|
url = ('http://api.themoviedb.org/3/%s/%s?api_key=a1ab8b8669da03637a4b98fa39c39228&language=%s' %
|
|
(self.busqueda_tipo, self.busqueda_id, self.busqueda_idioma))
|
|
|
|
resultado = self.get_json(url)
|
|
|
|
if 'overview' in resultado:
|
|
self.result['overview'] = resultado['overview']
|
|
ret = self.result['overview']
|
|
|
|
return ret
|
|
|
|
def get_poster(self, tipo_respuesta="str", size="original"):
|
|
"""
|
|
|
|
@param tipo_respuesta: Tipo de dato devuelto por este metodo. Por defecto "str"
|
|
@type tipo_respuesta: list, str
|
|
@param size: ("w45", "w92", "w154", "w185", "w300", "w342", "w500", "w600", "h632", "w780", "w1280", "original")
|
|
Indica la anchura(w) o altura(h) de la imagen a descargar. Por defecto "original"
|
|
@return: Si el tipo_respuesta es "list" devuelve un listado con todas las urls de las imagenes tipo poster del
|
|
tamaño especificado.
|
|
Si el tipo_respuesta es "str" devuelve la url de la imagen tipo poster, mas valorada, del tamaño
|
|
especificado.
|
|
Si el tamaño especificado no existe se retornan las imagenes al tamaño original.
|
|
@rtype: list, str
|
|
"""
|
|
ret = []
|
|
if size not in ("w45", "w92", "w154", "w185", "w300", "w342", "w500", "w600", "h632", "w780", "w1280"):
|
|
size = "original"
|
|
|
|
if self.result["poster_path"] is None or self.result["poster_path"] == "":
|
|
poster_path = ""
|
|
else:
|
|
poster_path = 'http://image.tmdb.org/t/p/' + size + self.result["poster_path"]
|
|
|
|
if tipo_respuesta == 'str':
|
|
return poster_path
|
|
elif not self.result["id"]:
|
|
return []
|
|
|
|
if len(self.result['images_posters']) == 0:
|
|
# Vamos a lanzar una busqueda por id y releer de nuevo
|
|
self.busqueda_id = str(self.result["id"])
|
|
self.__by_id()
|
|
|
|
if len(self.result['images_posters']) > 0:
|
|
for i in self.result['images_posters']:
|
|
imagen_path = i['file_path']
|
|
if size != "original":
|
|
# No podemos pedir tamaños mayores que el original
|
|
if size[1] == 'w' and int(imagen_path['width']) < int(size[1:]):
|
|
size = "original"
|
|
elif size[1] == 'h' and int(imagen_path['height']) < int(size[1:]):
|
|
size = "original"
|
|
ret.append('http://image.tmdb.org/t/p/' + size + imagen_path)
|
|
else:
|
|
ret.append(poster_path)
|
|
|
|
return ret
|
|
|
|
def get_backdrop(self, tipo_respuesta="str", size="original"):
|
|
"""
|
|
Devuelve las imagenes de tipo backdrop
|
|
@param tipo_respuesta: Tipo de dato devuelto por este metodo. Por defecto "str"
|
|
@type tipo_respuesta: list, str
|
|
@param size: ("w45", "w92", "w154", "w185", "w300", "w342", "w500", "w600", "h632", "w780", "w1280", "original")
|
|
Indica la anchura(w) o altura(h) de la imagen a descargar. Por defecto "original"
|
|
@type size: str
|
|
@return: Si el tipo_respuesta es "list" devuelve un listado con todas las urls de las imagenes tipo backdrop del
|
|
tamaño especificado.
|
|
Si el tipo_respuesta es "str" devuelve la url de la imagen tipo backdrop, mas valorada, del tamaño especificado.
|
|
Si el tamaño especificado no existe se retornan las imagenes al tamaño original.
|
|
@rtype: list, str
|
|
"""
|
|
ret = []
|
|
if size not in ("w45", "w92", "w154", "w185", "w300", "w342", "w500", "w600", "h632", "w780", "w1280"):
|
|
size = "original"
|
|
|
|
if self.result["backdrop_path"] is None or self.result["backdrop_path"] == "":
|
|
backdrop_path = ""
|
|
else:
|
|
backdrop_path = 'http://image.tmdb.org/t/p/' + size + self.result["backdrop_path"]
|
|
|
|
if tipo_respuesta == 'str':
|
|
return backdrop_path
|
|
elif self.result["id"] == "":
|
|
return []
|
|
|
|
if len(self.result['images_backdrops']) == 0:
|
|
# Vamos a lanzar una busqueda por id y releer de nuevo todo
|
|
self.busqueda_id = str(self.result["id"])
|
|
self.__by_id()
|
|
|
|
if len(self.result['images_backdrops']) > 0:
|
|
for i in self.result['images_backdrops']:
|
|
imagen_path = i['file_path']
|
|
if size != "original":
|
|
# No podemos pedir tamaños mayores que el original
|
|
if size[1] == 'w' and int(imagen_path['width']) < int(size[1:]):
|
|
size = "original"
|
|
elif size[1] == 'h' and int(imagen_path['height']) < int(size[1:]):
|
|
size = "original"
|
|
ret.append('http://image.tmdb.org/t/p/' + size + imagen_path)
|
|
else:
|
|
ret.append(backdrop_path)
|
|
|
|
return ret
|
|
|
|
def get_temporada(self, numtemporada=1):
|
|
# --------------------------------------------------------------------------------------------------------------------------------------------
|
|
# Parametros:
|
|
# numtemporada: (int) Numero de temporada. Por defecto 1.
|
|
# Return: (dic)
|
|
# Devuelve un dicionario con datos sobre la temporada.
|
|
# Puede obtener mas informacion sobre los datos devueltos en:
|
|
# http://docs.themoviedb.apiary.io/#reference/tv-seasons/tvidseasonseasonnumber/get
|
|
# http://docs.themoviedb.apiary.io/#reference/tv-seasons/tvidseasonseasonnumbercredits/get
|
|
# --------------------------------------------------------------------------------------------------------------------------------------------
|
|
if not self.result["id"] or self.busqueda_tipo != "tv":
|
|
return {}
|
|
|
|
numtemporada = int(numtemporada)
|
|
if numtemporada < 0:
|
|
numtemporada = 1
|
|
|
|
if not self.temporada.get(numtemporada, {}):
|
|
# Si no hay datos sobre la temporada solicitada, consultar en la web
|
|
|
|
# http://api.themoviedb.org/3/tv/1407/season/1?api_key=a1ab8b8669da03637a4b98fa39c39228&language=es&
|
|
# append_to_response=credits
|
|
url = "http://api.themoviedb.org/3/tv/%s/season/%s?api_key=a1ab8b8669da03637a4b98fa39c39228&language=%s" \
|
|
"&append_to_response=credits" % (self.result["id"], numtemporada, self.busqueda_idioma)
|
|
|
|
buscando = "id_Tmdb: " + str(self.result["id"]) + " temporada: " + str(numtemporada) + "\nURL: " + url
|
|
logger.info("[Tmdb.py] Buscando " + buscando)
|
|
try:
|
|
self.temporada[numtemporada] = self.get_json(url)
|
|
|
|
except:
|
|
logger.error("No se ha podido obtener la temporada")
|
|
self.temporada[numtemporada] = {"status_code": 15, "status_message": "Failed"}
|
|
self.temporada[numtemporada] = {"episodes": {}}
|
|
|
|
if "status_code" in self.temporada[numtemporada]:
|
|
#Se ha producido un error
|
|
msg = config.get_localized_string(70496) + buscando + config.get_localized_string(70497)
|
|
msg += "\nError de tmdb: %s %s" % (
|
|
self.temporada[numtemporada]["status_code"], self.temporada[numtemporada]["status_message"])
|
|
logger.debug(msg)
|
|
self.temporada[numtemporada] = {"episodes": {}}
|
|
|
|
return self.temporada[numtemporada]
|
|
|
|
def get_episodio(self, numtemporada=1, capitulo=1):
|
|
# --------------------------------------------------------------------------------------------------------------------------------------------
|
|
# Parametros:
|
|
# numtemporada(opcional): (int) Numero de temporada. Por defecto 1.
|
|
# capitulo: (int) Numero de capitulo. Por defecto 1.
|
|
# Return: (dic)
|
|
# Devuelve un dicionario con los siguientes elementos:
|
|
# "temporada_nombre", "temporada_sinopsis", "temporada_poster", "temporada_num_episodios"(int),
|
|
# "temporada_air_date", "episodio_vote_count", "episodio_vote_average",
|
|
# "episodio_titulo", "episodio_sinopsis", "episodio_imagen", "episodio_air_date",
|
|
# "episodio_crew" y "episodio_guest_stars",
|
|
# Con capitulo == -1 el diccionario solo tendra los elementos referentes a la temporada
|
|
# --------------------------------------------------------------------------------------------------------------------------------------------
|
|
if not self.result["id"] or self.busqueda_tipo != "tv":
|
|
return {}
|
|
|
|
try:
|
|
capitulo = int(capitulo)
|
|
numtemporada = int(numtemporada)
|
|
except ValueError:
|
|
logger.debug("El número de episodio o temporada no es valido")
|
|
return {}
|
|
|
|
temporada = self.get_temporada(numtemporada)
|
|
if not temporada:
|
|
# Se ha producido un error
|
|
return {}
|
|
|
|
if len(temporada["episodes"]) == 0 or len(temporada["episodes"]) < capitulo:
|
|
# Se ha producido un error
|
|
logger.error("Episodio %d de la temporada %d no encontrado." % (capitulo, numtemporada))
|
|
return {}
|
|
|
|
ret_dic = dict()
|
|
# Obtener datos para esta temporada
|
|
ret_dic["temporada_nombre"] = temporada["name"]
|
|
ret_dic["temporada_sinopsis"] = temporada["overview"]
|
|
ret_dic["temporada_num_episodios"] = len(temporada["episodes"])
|
|
if temporada["air_date"]:
|
|
date = temporada["air_date"].split("-")
|
|
ret_dic["temporada_air_date"] = date[2] + "/" + date[1] + "/" + date[0]
|
|
else:
|
|
ret_dic["temporada_air_date"] = ""
|
|
if temporada["poster_path"]:
|
|
ret_dic["temporada_poster"] = 'http://image.tmdb.org/t/p/original' + temporada["poster_path"]
|
|
else:
|
|
ret_dic["temporada_poster"] = ""
|
|
dic_aux = temporada.get('credits', {})
|
|
ret_dic["temporada_cast"] = dic_aux.get('cast', [])
|
|
ret_dic["temporada_crew"] = dic_aux.get('crew', [])
|
|
if capitulo == -1:
|
|
# Si solo buscamos datos de la temporada,
|
|
# incluir el equipo tecnico que ha intervenido en algun capitulo
|
|
dic_aux = dict((i['id'], i) for i in ret_dic["temporada_crew"])
|
|
for e in temporada["episodes"]:
|
|
for crew in e['crew']:
|
|
if crew['id'] not in dic_aux.keys():
|
|
dic_aux[crew['id']] = crew
|
|
ret_dic["temporada_crew"] = dic_aux.values()
|
|
|
|
# Obtener datos del capitulo si procede
|
|
if capitulo != -1:
|
|
episodio = temporada["episodes"][capitulo - 1]
|
|
ret_dic["episodio_titulo"] = episodio["name"]
|
|
ret_dic["episodio_sinopsis"] = episodio["overview"]
|
|
if episodio["air_date"]:
|
|
date = episodio["air_date"].split("-")
|
|
ret_dic["episodio_air_date"] = date[2] + "/" + date[1] + "/" + date[0]
|
|
else:
|
|
ret_dic["episodio_air_date"] = ""
|
|
ret_dic["episodio_crew"] = episodio["crew"]
|
|
ret_dic["episodio_guest_stars"] = episodio["guest_stars"]
|
|
ret_dic["episodio_vote_count"] = episodio["vote_count"]
|
|
ret_dic["episodio_vote_average"] = episodio["vote_average"]
|
|
if episodio["still_path"]:
|
|
ret_dic["episodio_imagen"] = 'http://image.tmdb.org/t/p/original' + episodio["still_path"]
|
|
else:
|
|
ret_dic["episodio_imagen"] = ""
|
|
|
|
return ret_dic
|
|
|
|
def get_videos(self):
|
|
"""
|
|
:return: Devuelve una lista ordenada (idioma/resolucion/tipo) de objetos Dict en la que cada uno de
|
|
sus elementos corresponde con un trailer, teaser o clip de youtube.
|
|
:rtype: list of Dict
|
|
"""
|
|
ret = []
|
|
if self.result['id']:
|
|
if self.result['videos']:
|
|
self.result["videos"] = self.result["videos"]['results']
|
|
else:
|
|
# Primera búsqueda de videos en el idioma de busqueda
|
|
url = "http://api.themoviedb.org/3/%s/%s/videos?api_key=a1ab8b8669da03637a4b98fa39c39228&language=%s" \
|
|
% (self.busqueda_tipo, self.result['id'], self.busqueda_idioma)
|
|
|
|
dict_videos = self.get_json(url)
|
|
|
|
if dict_videos['results']:
|
|
dict_videos['results'] = sorted(dict_videos['results'], key=lambda x: (x['type'], x['size']))
|
|
self.result["videos"] = dict_videos['results']
|
|
|
|
# Si el idioma de busqueda no es ingles, hacer una segunda búsqueda de videos en inglés
|
|
if self.busqueda_idioma != 'en':
|
|
url = "http://api.themoviedb.org/3/%s/%s/videos?api_key=a1ab8b8669da03637a4b98fa39c39228" \
|
|
% (self.busqueda_tipo, self.result['id'])
|
|
|
|
dict_videos = self.get_json(url)
|
|
|
|
if dict_videos['results']:
|
|
dict_videos['results'] = sorted(dict_videos['results'], key=lambda x: (x['type'], x['size']))
|
|
self.result["videos"].extend(dict_videos['results'])
|
|
|
|
# Si las busqueda han obtenido resultados devolver un listado de objetos
|
|
for i in self.result['videos']:
|
|
if i['site'] == "YouTube":
|
|
ret.append({'name': i['name'],
|
|
'url': "https://www.youtube.com/watch?v=%s" % i['key'],
|
|
'size': str(i['size']),
|
|
'type': i['type'],
|
|
'language': i['iso_639_1']})
|
|
|
|
return ret
|
|
|
|
def get_infoLabels(self, infoLabels=None, origen=None):
|
|
"""
|
|
:param infoLabels: Informacion extra de la pelicula, serie, temporada o capitulo.
|
|
:type infoLabels: Dict
|
|
:param origen: Diccionario origen de donde se obtiene los infoLabels, por omision self.result
|
|
:type origen: Dict
|
|
:return: Devuelve la informacion extra obtenida del objeto actual. Si se paso el parametro infoLables, el valor
|
|
devuelto sera el leido como parametro debidamente actualizado.
|
|
:rtype: Dict
|
|
"""
|
|
|
|
if infoLabels:
|
|
ret_infoLabels = InfoLabels(infoLabels)
|
|
else:
|
|
ret_infoLabels = InfoLabels()
|
|
|
|
# Iniciar listados
|
|
l_country = [i.strip() for i in ret_infoLabels['country'].split(',') if ret_infoLabels['country']]
|
|
l_director = [i.strip() for i in ret_infoLabels['director'].split(',') if ret_infoLabels['director']]
|
|
l_writer = [i.strip() for i in ret_infoLabels['writer'].split(',') if ret_infoLabels['writer']]
|
|
l_castandrole = ret_infoLabels.get('castandrole', [])
|
|
|
|
if not origen:
|
|
origen = self.result
|
|
|
|
if 'credits' in origen.keys():
|
|
dic_origen_credits = origen['credits']
|
|
origen['credits_cast'] = dic_origen_credits.get('cast', [])
|
|
origen['credits_crew'] = dic_origen_credits.get('crew', [])
|
|
del origen['credits']
|
|
|
|
items = origen.items()
|
|
|
|
# Informacion Temporada/episodio
|
|
if ret_infoLabels['season'] and self.temporada.get(ret_infoLabels['season']):
|
|
# Si hay datos cargados de la temporada indicada
|
|
episodio = -1
|
|
if ret_infoLabels['episode']:
|
|
episodio = ret_infoLabels['episode']
|
|
|
|
items.extend(self.get_episodio(ret_infoLabels['season'], episodio).items())
|
|
|
|
# logger.info("ret_infoLabels" % ret_infoLabels)
|
|
|
|
for k, v in items:
|
|
if not v:
|
|
continue
|
|
elif type(v) == str:
|
|
v = re.sub(r"\n|\r|\t", "", v)
|
|
# fix
|
|
if v == "None":
|
|
continue
|
|
|
|
if k == 'overview':
|
|
if origen:
|
|
ret_infoLabels['plot'] = v
|
|
else:
|
|
ret_infoLabels['plot'] = self.get_sinopsis()
|
|
|
|
elif k == 'runtime': #Duration for movies
|
|
ret_infoLabels['duration'] = int(v) * 60
|
|
|
|
elif k == 'episode_run_time': #Duration for episodes
|
|
try:
|
|
for v_alt in v: #It comes as a list (?!)
|
|
ret_infoLabels['duration'] = int(v_alt) * 60
|
|
except:
|
|
pass
|
|
|
|
elif k == 'release_date':
|
|
ret_infoLabels['year'] = int(v[:4])
|
|
ret_infoLabels['release_date'] = v.split("-")[2] + "/" + v.split("-")[1] + "/" + v.split("-")[0]
|
|
|
|
elif k == 'first_air_date':
|
|
ret_infoLabels['year'] = int(v[:4])
|
|
ret_infoLabels['aired'] = v.split("-")[2] + "/" + v.split("-")[1] + "/" + v.split("-")[0]
|
|
ret_infoLabels['premiered'] = ret_infoLabels['aired']
|
|
|
|
elif k == 'original_title' or k == 'original_name':
|
|
ret_infoLabels['originaltitle'] = v
|
|
|
|
elif k == 'vote_average':
|
|
ret_infoLabels['rating'] = float(v)
|
|
|
|
elif k == 'vote_count':
|
|
ret_infoLabels['votes'] = v
|
|
|
|
elif k == 'poster_path':
|
|
ret_infoLabels['thumbnail'] = 'http://image.tmdb.org/t/p/original' + v
|
|
|
|
elif k == 'backdrop_path':
|
|
ret_infoLabels['fanart'] = 'http://image.tmdb.org/t/p/original' + v
|
|
|
|
elif k == 'id':
|
|
ret_infoLabels['tmdb_id'] = v
|
|
|
|
elif k == 'imdb_id':
|
|
ret_infoLabels['imdb_id'] = v
|
|
|
|
elif k == 'external_ids':
|
|
if 'tvdb_id' in v:
|
|
ret_infoLabels['tvdb_id'] = v['tvdb_id']
|
|
if 'imdb_id' in v:
|
|
ret_infoLabels['imdb_id'] = v['imdb_id']
|
|
|
|
elif k in ['genres', "genre_ids", "genre"]:
|
|
ret_infoLabels['genre'] = self.get_generos(origen)
|
|
|
|
elif k == 'name' or k == 'title':
|
|
ret_infoLabels['title'] = v
|
|
|
|
elif k == 'production_companies':
|
|
ret_infoLabels['studio'] = ", ".join(i['name'] for i in v)
|
|
|
|
elif k == 'credits_cast' or k == 'temporada_cast' or k == 'episodio_guest_stars':
|
|
dic_aux = dict((name, character) for (name, character) in l_castandrole)
|
|
l_castandrole.extend([(p['name'], p['character']) for p in v if p['name'] not in dic_aux.keys()])
|
|
|
|
elif k == 'videos':
|
|
if not isinstance(v, list):
|
|
v = v.get('result', [])
|
|
for i in v:
|
|
if i.get("site", "") == "YouTube":
|
|
ret_infoLabels['trailer'] = "https://www.youtube.com/watch?v=" + v[0]["key"]
|
|
break
|
|
|
|
elif k == 'production_countries' or k == 'origin_country':
|
|
if isinstance(v, str):
|
|
l_country = list(set(l_country + v.split(',')))
|
|
|
|
elif isinstance(v, list) and len(v) > 0:
|
|
if isinstance(v[0], str):
|
|
l_country = list(set(l_country + v))
|
|
elif isinstance(v[0], dict):
|
|
# {'iso_3166_1': 'FR', 'name':'France'}
|
|
for i in v:
|
|
if 'iso_3166_1' in i:
|
|
pais = Tmdb.dic_country.get(i['iso_3166_1'], i['iso_3166_1'])
|
|
l_country = list(set(l_country + [pais]))
|
|
|
|
elif k == 'credits_crew' or k == 'episodio_crew' or k == 'temporada_crew':
|
|
for crew in v:
|
|
if crew['job'].lower() == 'director':
|
|
l_director = list(set(l_director + [crew['name']]))
|
|
|
|
elif crew['job'].lower() in ('screenplay', 'writer'):
|
|
l_writer = list(set(l_writer + [crew['name']]))
|
|
|
|
elif k == 'created_by':
|
|
for crew in v:
|
|
l_writer = list(set(l_writer + [crew['name']]))
|
|
|
|
elif isinstance(v, str) or isinstance(v, int) or isinstance(v, float):
|
|
ret_infoLabels[k] = v
|
|
|
|
else:
|
|
# logger.debug("Atributos no añadidos: " + k +'= '+ str(v))
|
|
pass
|
|
|
|
# Ordenar las listas y convertirlas en str si es necesario
|
|
if l_castandrole:
|
|
ret_infoLabels['castandrole'] = sorted(l_castandrole, key=lambda tup: tup[0])
|
|
if l_country:
|
|
ret_infoLabels['country'] = ', '.join(sorted(l_country))
|
|
if l_director:
|
|
ret_infoLabels['director'] = ', '.join(sorted(l_director))
|
|
if l_writer:
|
|
ret_infoLabels['writer'] = ', '.join(sorted(l_writer))
|
|
|
|
return ret_infoLabels
|