From 2e8d950775dabf9fe95576b090eb774494d8685a Mon Sep 17 00:00:00 2001 From: Alhaziel01 Date: Wed, 27 May 2020 15:25:08 +0200 Subject: [PATCH] Ultime traduzioni Core --- core/tmdb.py | 583 +++++++++++++++++--------------------- core/videolibrarytools.py | 417 +++++++++++++-------------- core/ziptools.py | 19 +- 3 files changed, 460 insertions(+), 559 deletions(-) diff --git a/core/tmdb.py b/core/tmdb.py index 9fa9e655..4f796b1c 100644 --- a/core/tmdb.py +++ b/core/tmdb.py @@ -1,90 +1,65 @@ # -*- coding: utf-8 -*- -#from future import standard_library -#standard_library.install_aliases() -#from builtins import str +# from future import standard_library +# standard_library.install_aliases() +# from builtins import str import sys PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int if PY3: - import urllib.parse as urllib # Es muy lento en PY2. En PY3 es nativo + import urllib.parse as urllib # It is very slow in PY2. In PY3 it is native else: - import urllib # Usamos el nativo de PY2 que es más rápido + import urllib # We use the native of PY2 which is faster from future.builtins import range from future.builtins import object -import ast +import ast, copy, re, sqlite3, time, xbmcaddon -import copy -import re -import sqlite3 -import time - -import xbmcaddon - -from core import filetools -from core import httptools -from core import jsontools -from core import scrapertools +from core import filetools, httptools, jsontools, scrapertools from core.item import InfoLabels -from platformcode import config -from platformcode import logger +from platformcode import config, logger info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json def_lang = info_language[config.get_setting("info_language", "videolibrary")] -# ----------------------------------------------------------------------------------------------------------- -# Conjunto de funciones relacionadas con las infoLabels. -# version 1.0: -# Version inicial +# ------------------------------------------------- -------------------------------------------------- -------- +# Set of functions related to infoLabels. +# version 1.0: +# Initial version # -# 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 +# Include: +# - set_infoLabels (source, seekTmdb, search_language): Gets and sets (item.infoLabels) the extra data of one or several series, chapters or movies. +# - set_infoLabels_item (item, seekTmdb, search_language): Gets and sets (item.infoLabels) the extra data of a series, chapter or movie. +# - set_infoLabels_itemlist (item_list, seekTmdb, search_language): Gets and sets (item.infoLabels) the data extras from a list of series, chapters or movies. +# - infoLabels_tostring (item): Returns a str with the list ordered with the item's infoLabels # -# Uso: -# tmdb.set_infoLabels(item, seekTmdb = True) +# Usage: +# - 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.contentTitle -# y el año en item.infoLabels['year']. +# Get basic data from a movie: +# Before calling the set_infoLabels method the title to search for must be in item.contentTitle and the year in 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. +# Obtain basic data from a series: +# Before calling the set_infoLabels method the title to search for must be in item.show or in 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']) +# Get more data from a movie or series: +# After obtaining the basic data in item.infoLabels ['tmdb'] we will have the code of the series or movie. +# We could also directly set this code, if known, or use the corresponding code of: +# IMDB (in item.infoLabels ['IMDBNumber'] or item.infoLabels ['code'] or item.infoLabels ['imdb_id']), TVDB (only series, in item.infoLabels ['tvdb_id']), +# Freebase (series only, on item.infoLabels ['freebase_mid']), TVRage (series only, on 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']. +# Get data from a season: +# Before calling the set_infoLabels method the series title must be in item.show or in item.contentSerieName, +# the series TMDB code must be in item.infoLabels ['tmdb'] (it can be set automatically by the basic data query) +# and the season number must be in 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']. -# -# -# -------------------------------------------------------------------------------------------------------------- +# Get data from an episode: +# Before calling the set_infoLabels method the series title must be in item.show or in item.contentSerieName, +# the TMDB code of the series must be in item.infoLabels ['tmdb'] (it can be set automatically using the basic data query), +# the season number must be in item.infoLabels ['season'] and the episode number must be in item.infoLabels ['episode']. +# ------------------------------------------------- -------------------------------------------------- ----------- otmdb_global = None fname = filetools.join(config.get_data_path(), "kod_db.sqlite") @@ -110,7 +85,7 @@ def drop_bd(): create_bd() -# El nombre de la funcion es el nombre del decorador y recibe la funcion que decora. +# The function name is the name of the decorator and receives the function that decorates. def cache_response(fn): logger.info() @@ -153,7 +128,7 @@ def cache_response(fn): # 1 month - 30 days elif cache_expire == 3: - # no tenemos en cuenta febrero o meses con 31 días + # we do not take into account February or months with 31 days if elapsed > datetime.timedelta(days=30): valided = False else: @@ -167,7 +142,7 @@ def cache_response(fn): result = {} try: - # no está activa la cache + # cache is not active if not config.get_setting("tmdb_cache", default=False): result = fn(*args) else: @@ -199,7 +174,7 @@ def cache_response(fn): # elapsed_time = time.time() - start_time # logger.debug("TARDADO %s" % elapsed_time) - # error al obtener los datos + # error getting data except Exception as ex: message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args)) logger.error("error in: %s" % message) @@ -211,17 +186,15 @@ def cache_response(fn): def set_infoLabels(source, seekTmdb=True, idioma_busqueda=def_lang, forced=False): """ - Dependiendo del tipo de dato de source obtiene y fija (item.infoLabels) los datos extras de una o varias series, - capitulos o peliculas. + Depending on the data type of source, it obtains and sets (item.infoLabels) the extra data of one or more series, chapters or movies. - @param source: variable que contiene la información para establecer infoLabels + @param source: variable that contains the information to set 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. + @param seekTmdb: if it is True, it searches www.themoviedb.org to obtain the data, otherwise it obtains the data of the Item itself. @type seekTmdb: bool - @param idioma_busqueda: fija el valor de idioma en caso de busqueda en www.themoviedb.org + @param idioma_busqueda: set the language value in case of search at www.themoviedb.org @type idioma_busqueda: str - @return: un numero o lista de numeros con el resultado de las llamadas a set_infoLabels_item + @return: a number or list of numbers with the result of the calls to set_infoLabels_item @rtype: int, list """ @@ -240,23 +213,18 @@ def set_infoLabels(source, seekTmdb=True, idioma_busqueda=def_lang, forced=False def set_infoLabels_itemlist(item_list, seekTmdb=False, idioma_busqueda=def_lang, forced=False): """ - De manera concurrente, obtiene los datos de los items incluidos en la lista item_list. + Concurrently, it gets the data of the items included in the 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. + The API has a limit of 40 requests per IP every 10 '' and that is why the list should not have more than 30 items to ensure the proper functioning of this function. - @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. + @param item_list: list of Item objects that represent movies, series or chapters. The infoLabels attribute of each Item object will be modified including the extra localized data. @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. + @param seekTmdb: If it is True, it searches www.themoviedb.org to obtain the data, otherwise it obtains the data of the Item itself if they exist. @type seekTmdb: bool - @param idioma_busqueda: Codigo del idioma segun ISO 639-1, en caso de busqueda en www.themoviedb.org. + @param idioma_busqueda: Language code according to ISO 639-1, in case of search at 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. + @return: A list of numbers whose absolute value represents the number of elements included in the infoLabels attribute of each Item. This number will be positive if the data has been obtained from www.themoviedb.org and negative otherwise. @rtype: list """ @@ -284,32 +252,29 @@ def set_infoLabels_itemlist(item_list, seekTmdb=False, idioma_busqueda=def_lang, i += 1 l_hilo.append(t) - # esperar q todos los hilos terminen + # wait for all the threads to end for x in l_hilo: x.join() - # Ordenar lista de resultados por orden de llamada para mantener el mismo orden q item_list + # Sort results list by call order to keep the same order q item_list r_list.sort(key=lambda i: i[0]) - # Reconstruir y devolver la lista solo con los resultados de las llamadas individuales + # Rebuild and return list only with results of individual calls return [ii[2] for ii in r_list] def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda=def_lang, lock=None): """ - Obtiene y fija (item.infoLabels) los datos extras de una serie, capitulo o pelicula. + Gets and sets (item.infoLabels) the extra data of a series, chapter or movie. - @param item: Objeto Item que representa un pelicula, serie o capitulo. El atributo infoLabels sera modificado - incluyendo los datos extras localizados. + @param item: Item object that represents a movie, series or chapter. The infoLabels attribute will be modified including the extra localized data. @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. + @param seekTmdb: If it is True, it searches www.themoviedb.org to obtain the data, otherwise it obtains the data of the Item itself if they exist. @type seekTmdb: bool - @param idioma_busqueda: Codigo del idioma segun ISO 639-1, en caso de busqueda en www.themoviedb.org. + @param idioma_busqueda: Language code according to ISO 639-1, in case of search at 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. + @param lock: For use of threads when calling the 'set_infoLabels_itemlist' method + @return: A number whose absolute value represents the number of elements included in the item.infoLabels attribute. This number will be positive if the data has been obtained from www.themoviedb.org and negative otherwise. @rtype: int """ global otmdb_global @@ -322,7 +287,7 @@ def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda=def_lang, lock=None item.fanart = item.infoLabels['fanart'] if seekTmdb: - # Comprobamos q tipo de contenido es... + # We check what type of content it is... if item.contentType == 'movie': tipo_busqueda = 'movie' else: @@ -338,15 +303,12 @@ def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda=def_lang, lock=None if lock: lock.acquire() - if not otmdb_global or (item.infoLabels['tmdb_id'] - and str(otmdb_global.result.get("id")) != item.infoLabels['tmdb_id']) \ + 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) + 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']) + otmdb_global = Tmdb(texto_buscado=item.infoLabels['tvshowtitle'], tipo=tipo_busqueda, idioma_busqueda=idioma_busqueda, year=item.infoLabels['year']) __leer_datos(otmdb_global) @@ -361,13 +323,13 @@ def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda=def_lang, lock=None logger.debug("The episode number (%s) is not valid" % repr(item.infoLabels['episode'])) return -1 * len(item.infoLabels) - # Tenemos numero de temporada y numero de episodio validos... - # ... buscar datos episodio + # We have valid season number and episode number... + # ... search episode data item.infoLabels['mediatype'] = 'episode' episodio = otmdb_global.get_episodio(numtemporada, episode) if episodio: - # Actualizar datos + # Update data __leer_datos(otmdb_global) item.infoLabels['title'] = episodio['episodio_titulo'] if episodio['episodio_sinopsis']: @@ -388,15 +350,15 @@ def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda=def_lang, lock=None return len(item.infoLabels) else: - # Tenemos numero de temporada valido pero no numero de episodio... - # ... buscar datos temporada + # We have a valid season number but no episode number... + # ... search season data item.infoLabels['mediatype'] = 'season' temporada = otmdb_global.get_temporada(numtemporada) if not isinstance(temporada, dict): temporada = ast.literal_eval(temporada.decode('utf-8')) if temporada: - # Actualizar datos + # Update data __leer_datos(otmdb_global) item.infoLabels['title'] = temporada['name'] if 'name' in temporada else '' if 'overview' in temporada and temporada['overview']: @@ -418,69 +380,62 @@ def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda=def_lang, lock=None if lock and lock.locked(): lock.release() - # Buscar... + # Search... else: otmdb = copy.copy(otmdb_global) - # Busquedas por ID... + # Search by 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) + # ...Search for 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) + # ...Search by 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 + elif tipo_busqueda == 'tv': # bsearch with other codes 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) + # ...Search for 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) + # ...Search for 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) + # ...Search by 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) + # ...Search by 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 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 + # Could not search by ID ... + # do it by title if tipo_busqueda == 'tv': - # Busqueda de serie por titulo y filtrando sus resultados si es necesario + # Serial search by title and filtering your results if necessary 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... + # Movie search by title ... # if item.infoLabels['year'] or item.infoLabels['filtro']: - # ...y año o filtro + # ...and year or filter searched_title = item.contentTitle if item.contentTitle else item.fulltitle otmdb = Tmdb(texto_buscado=searched_title, 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 + # If the search has been successful and you are not looking for a list of items, + # carry out another search to expand the information 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 + # The search has found a valid result __leer_datos(otmdb) return len(item.infoLabels) - # La busqueda en tmdb esta desactivada o no ha dado resultado + # Search in tmdb is deactivated or has not given result # item.contentType = item.infoLabels['mediatype'] return -1 * len(item.infoLabels) @@ -500,7 +455,7 @@ def find_and_set_infoLabels(item): tipo_contenido = config.get_localized_string(60298) title = item.contentSerieName - # Si el titulo incluye el (año) se lo quitamos + # 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() @@ -510,8 +465,7 @@ def find_and_set_infoLabels(item): 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) + 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=def_lang) @@ -519,8 +473,7 @@ def find_and_set_infoLabels(item): if len(results) > 1: from platformcode import platformtools - tmdb_result = platformtools.show_video_info(results, item=item, - caption= tipo_contenido % title) + tmdb_result = platformtools.show_video_info(results, item=item, caption= tipo_contenido % title) elif len(results) > 0: tmdb_result = results[0] @@ -531,7 +484,7 @@ def find_and_set_infoLabels(item): if tmdb_result: infoLabels['tmdb_id'] = tmdb_result['id'] - # todo mirar si se puede eliminar y obtener solo desde get_nfo() + # all look if it can be removed and get only from 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']) @@ -547,16 +500,14 @@ def find_and_set_infoLabels(item): 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 + Returns the information necessary for the result to be scraped into the kodi video library, for tmdb it works only by passing it the url. + @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 = "https://www.themoviedb.org/tv/%s/season/%s/episode/%s\n" % \ - (item.infoLabels['tmdb_id'], item.contentSeason, item.contentEpisodeNumber) + 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" @@ -565,10 +516,10 @@ def get_nfo(item): def completar_codigos(item): """ - Si es necesario comprueba si existe el identificador de tvdb y sino existe trata de buscarlo + If necessary, check if the tvdb identifier exists and if it does not exist try to find it """ if item.contentType != "movie" and not item.infoLabels['tvdb_id']: - # Lanzar busqueda por imdb_id en tvdb + # Launch search for imdb_id on tvdb from core.tvdb import Tvdb ob = Tvdb(imdb_id=item.infoLabels['imdb_id']) item.infoLabels['tvdb_id'] = ob.get_id() @@ -585,8 +536,7 @@ def discovery(item, dict_=False, cast=False): listado = Tmdb(discover = dict_, cast=cast) elif item.search_type == 'discover': - listado = Tmdb(discover={'url':'discover/%s' % item.type, 'with_genres':item.list_type, 'language':def_lang, - 'page':item.page}) + listado = Tmdb(discover={'url':'discover/%s' % item.type, 'with_genres':item.list_type, 'language':def_lang, 'page':item.page}) elif item.search_type == 'list': if item.page == '': @@ -602,7 +552,7 @@ def get_genres(type): return genres.dic_generos[lang] -# Clase auxiliar +# Auxiliary class class ResultDictDefault(dict): # Python 2.4 def __getitem__(self, key): @@ -613,14 +563,13 @@ class ResultDictDefault(dict): def __missing__(self, key): """ - valores por defecto en caso de que la clave solicitada no exista + default values ​​in case the requested key does not exist """ if key in ['genre_ids', 'genre', 'genres']: return list() elif key == 'images_posters': posters = dict() - if 'images' in list(super(ResultDictDefault, self).keys()) and \ - 'posters' in super(ResultDictDefault, self).__getitem__('images'): + if 'images' in list(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) @@ -628,8 +577,7 @@ class ResultDictDefault(dict): elif key == "images_backdrops": backdrops = dict() - if 'images' in list(super(ResultDictDefault, self).keys()) and \ - 'backdrops' in super(ResultDictDefault, self).__getitem__('images'): + if 'images' in list(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) @@ -637,15 +585,14 @@ class ResultDictDefault(dict): elif key == "images_profiles": profiles = dict() - if 'images' in list(super(ResultDictDefault, self).keys()) and \ - 'profiles' in super(ResultDictDefault, self).__getitem__('images'): + if 'images' in list(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 + # The rest of the keys return empty strings by default return "" def __str__(self): @@ -668,78 +615,78 @@ class ResultDictDefault(dict): # --------------------------------------------------------------------------------------------------------------- # 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() +# Scraper for the API based addon from https://www.themoviedb.org/ +# version 1.4: +# - Documented limitation of API use (see below). +# - Added get_temporada () method +# version 1.3: +# - Fixed error when returning None the path_poster and backdrop_path +# - Fixed a bug that caused the list of genres to accumulate from one call to another +# - Added get_generos () method +# - Added optional parameters alternative_language to the get_sinopsis () method # # -# 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 +# Usage: +# Construction methods: +# Tmdb (search_text, type) +# Parameters: +# searched_text: (str) Text or part of the text to search +# type: ("movie" or "tv") Type of result searched for movies or series. Default "movie" +# (optional) language_search: (str) language code according to ISO 639-1 +# (optional) include_adult: (bool) Adult content is included in the search or not. Default # '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 +# (optional) year: (str) Release year. +# (optional) page: (int) When there are many results for a search these are organized by pages. +# We can load the page we want, although by default it is always the first page. +# Return: +# This call returns a Tmdb object containing the first page of the search result 'search_text' +# on the themoviedb.org website. The more optional parameters are included, the more precise the search will be. +# Also the object is initialized with the first result of the first page of results. +# Tmdb (id_Tmdb, type) +# Parameters: +# id_Tmdb: (str) Identifier code of a certain movie or series at themoviedb.org +# type: ("movie" or "tv") Type of result searched for movies or series. Default "movie" +# (optional) language_search: (str) language code according to ISO 639-1 +# Return: +# This call returns a Tmdb object that contains the result of searching for a movie or series with the +# identifier id_Tmd +# on the themoviedb.org website. +# Tmdb (external_id, external_source, type) +# Parameters: +# external_id: (str) Identifier code of a certain movie or series on the web referenced by # '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. +# external_source: (For series: "imdb_id", "freebase_mid", "freebase_id", "tvdb_id", "tvrage_id"; For +# movies: "imdb_id") +# type: ("movie" or "tv") Type of result searched for movies or series. Default "movie" +# (optional) language_search: (str) language code according to ISO 639-1 +# Return: +# This call returns a Tmdb object that contains the result of searching for a movie or series with the +# identifier 'external_id' of +# the website referenced by 'external_source' on the themoviedb.org website. # -# 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. +# Main methods: +# get_id (): Returns a str with the Tmdb identifier of the loaded movie or series or an empty string if there were no +# nothing loaded. +# get_sinopsis (alternate_language): Returns a str with the synopsis of the series or movie loaded. +# get_poster (response_type, size): Get the poster or a list of posters. +# get_backdrop (response_type, size): Get a background image or a list of background images. +# get_temporada (season): Get a dictionary with season-specific data. +# get_episodio (season, episode): Get a dictionary with specific data of the episode. +# get_generos (): Returns a str with the list of genres to which the movie or series belongs. # # -# Otros metodos: -# load_resultado(resultado, page): Cuando la busqueda devuelve varios resultados podemos seleccionar que resultado -# concreto y de que pagina cargar los datos. +# Other methods: +# load_resultado (result, page): When the search returns several results we can select which result +# concrete and from which page to load the data. # -# 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 +# Limitations: +# The use of the API imposes a limit of 20 simultaneous connections (concurrency) or 30 requests in 10 seconds per IP +# Information about the api: http://docs.themoviedb.apiary.io # ------------------------------------------------------------------------------------------------------------------- class Tmdb(object): - # Atributo de clase + # Class attribute dic_generos = {} ''' dic_generos={"id_idioma1": {"tv": {"id1": "name1", @@ -830,17 +777,15 @@ class Tmdb(object): self.busqueda_filtro = kwargs.get('filtro', {}) self.discover = kwargs.get('discover', {}) - # 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]): + # Refill gender dictionary if necessary + 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 + #Search by tmdb identifier self.__by_id() elif self.busqueda_texto: @@ -848,12 +793,10 @@ class Tmdb(object): self.__search(page=self.page) elif 'external_source' in kwargs and 'external_id' in kwargs: - # Busqueda por identificador externo segun el tipo. + # Search by external identifier according to type. # 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")): + 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')) @@ -880,9 +823,9 @@ class Tmdb(object): 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.error("Limite alcanzado, esperamos para volver a llamar en ...%s" % wait) + #logger.error("Limit reached, we wait to call back on ...%s" % wait) time.sleep(wait) - # logger.debug("RE Llamada #%s" % d) + # logger.debug("RE Call #%s" % d) result = httptools.downloadpage(url, cookies=False) res_headers = result.headers @@ -890,7 +833,7 @@ class Tmdb(object): dict_data = jsontools.load(result.data) # logger.debug("result_data es %s" % dict_data) - # error al obtener los datos + # error getting data except Exception as ex: message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args)) logger.error("error in: %s" % message) @@ -900,14 +843,13 @@ class Tmdb(object): @classmethod def rellenar_dic_generos(cls, tipo='movie', idioma=def_lang): - # Rellenar diccionario de generos del tipo e idioma pasados como parametros + # Fill dictionary of genres of the type and language passed as parameters 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)) + url = ('http://api.themoviedb.org/3/genre/%s/list?api_key=a1ab8b8669da03637a4b98fa39c39228&language=%s' % (tipo, idioma)) try: logger.info("[Tmdb.py] Filling in dictionary of genres") @@ -959,7 +901,7 @@ class Tmdb(object): self.result = ResultDictDefault(resultado) else: - # No hay resultados de la busqueda + # No search results msg = "The search of %s gave no results" % buscando logger.debug(msg) @@ -995,7 +937,6 @@ class Tmdb(object): results = resultado["results"] if self.busqueda_filtro and total_results > 1: - # TODO documentar esta parte for key, value in list(dict(self.busqueda_filtro).items()): for r in results[:]: if not r[key]: @@ -1006,13 +947,13 @@ class Tmdb(object): if results: if index_results >= len(results): - # Se ha solicitado un numero de resultado mayor de los obtenidos + # A higher number of results has been requested than those obtained logger.error( "The search for '%s' gave %s results for the page %s \n It is impossible to show the result number %s" % (buscando, len(results), page, index_results)) return 0 - # Retornamos el numero de resultados de esta pagina + # We return the number of results of this page self.results = results self.total_results = total_results self.total_pages = total_pages @@ -1020,7 +961,7 @@ class Tmdb(object): return len(self.results) else: - # No hay resultados de la busqueda + # No search results msg = "The search for '%s' gave no results for page %s" % (buscando, page) logger.error(msg) return 0 @@ -1033,8 +974,8 @@ class Tmdb(object): 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 + # url: API method to run + # rest of keys: Search parameters concatenated to the url type_search = self.discover.get('url', '') if type_search: params = [] @@ -1074,7 +1015,7 @@ class Tmdb(object): "The search for '%s' did not give %s results" % (type_search, index_results)) return 0 - # Retornamos el numero de resultados de esta pagina + # We return the number of results of this page if results: self.results = results self.total_results = total_results @@ -1086,13 +1027,12 @@ class Tmdb(object): self.result = results return len(self.results) else: - # No hay resultados de la busqueda + # No search results logger.error("The search for '%s' gave no results" % 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 + # If there are no results, there is only one or if the number of results on this page is less than the index sought to exit self.result = ResultDictDefault() num_result_page = len(self.results) @@ -1112,7 +1052,6 @@ class Tmdb(object): def get_list_resultados(self, num_result=20): # logger.info("self %s" % str(self)) - # TODO documentar res = [] if num_result <= 0: @@ -1141,9 +1080,9 @@ class Tmdb(object): def get_generos(self, origen=None): """ - :param origen: Diccionario origen de donde se obtiene los infoLabels, por omision self.result + :param origen: Source dictionary where the infoLabels are obtained, by default self.result :type origen: Dict - :return: Devuelve la lista de generos a los que pertenece la pelicula o serie. + :return: Returns the list of genres to which the movie or series belongs. :rtype: str """ genre_list = [] @@ -1152,7 +1091,7 @@ class Tmdb(object): origen = self.result if "genre_ids" in origen: - # Buscar lista de generos por IDs + # Search list of genres by IDs for i in origen.get("genre_ids"): try: genre_list.append(Tmdb.dic_generos[self.busqueda_idioma][self.busqueda_tipo][str(i)]) @@ -1160,7 +1099,7 @@ class Tmdb(object): pass elif "genre" in origen or "genres" in origen: - # Buscar lista de generos (lista de objetos {id,nombre}) + # Search genre list (object list {id, name}) v = origen["genre"] v.extend(origen["genres"]) for i in v: @@ -1175,9 +1114,7 @@ class Tmdb(object): 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. + :return: Returns the Tmdb identifier of the loaded movie or series 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', "")) @@ -1185,12 +1122,10 @@ class Tmdb(object): 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. + :param idioma_alternativo: Language code, according to ISO 639-1, if there is no synopsis in the language set for the search. + By default, the original language is used. If None is used as the alternative_language, it will only search in the set language. :type idioma_alternativo: str - :return: Devuelve la sinopsis de una pelicula o serie + :return: Returns the synopsis of a movie or series :rtype: str """ ret = "" @@ -1198,15 +1133,14 @@ class Tmdb(object): 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 + # Let's launch a search for id and reread the synopsis again 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)) + 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 not isinstance(resultado, dict): @@ -1221,15 +1155,13 @@ class Tmdb(object): def get_poster(self, tipo_respuesta="str", size="original"): """ - @param tipo_respuesta: Tipo de dato devuelto por este metodo. Por defecto "str" + @param tipo_respuesta: Data type returned by this method. Default "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. + Indicates the width (w) or height (h) of the image to download. Default "original" + @return: If the response_type is "list" it returns a list with all the urls of the poster images of the specified size. + If the response_type is "str" ​​it returns the url of the poster image, most valued, of the specified size. + If the specified size does not exist, the images are returned to the original size. @rtype: list, str """ ret = [] @@ -1247,7 +1179,7 @@ class Tmdb(object): return [] if len(self.result['images_posters']) == 0: - # Vamos a lanzar una busqueda por id y releer de nuevo + # We are going to launch a search by id and reread again self.busqueda_id = str(self.result["id"]) self.__by_id() @@ -1255,7 +1187,7 @@ class Tmdb(object): for i in self.result['images_posters']: imagen_path = i['file_path'] if size != "original": - # No podemos pedir tamaños mayores que el original + # We cannot order sizes larger than the 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:]): @@ -1268,16 +1200,15 @@ class Tmdb(object): 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" + Returns the images of type backdrop + @param tipo_respuesta: Data type returned by this method. Default "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" + Indicates the width (w) or height (h) of the image to download. Default "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. + @return: If the response_type is "list" it returns a list with all the urls of the backdrop images of the specified size. + If the response_type is "str" ​​it returns the url of the backdrop type image, most valued, of the specified size. + If the specified size does not exist, the images are returned to the original size. @rtype: list, str """ ret = [] @@ -1295,7 +1226,7 @@ class Tmdb(object): return [] if len(self.result['images_backdrops']) == 0: - # Vamos a lanzar una busqueda por id y releer de nuevo todo + # Let's launch a search by id and reread everything self.busqueda_id = str(self.result["id"]) self.__by_id() @@ -1303,7 +1234,7 @@ class Tmdb(object): for i in self.result['images_backdrops']: imagen_path = i['file_path'] if size != "original": - # No podemos pedir tamaños mayores que el original + # We cannot order sizes larger than the 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:]): @@ -1316,13 +1247,13 @@ class Tmdb(object): 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 + # Parameters: +        # season number: (int) Season number. Default 1. +        # Return: (Dec) +        # Returns a dictionary with data about the season. +        # You can get more information about the returned data at: +        # 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 {} @@ -1332,7 +1263,7 @@ class Tmdb(object): numtemporada = 1 if not self.temporada.get(numtemporada, {}): - # Si no hay datos sobre la temporada solicitada, consultar en la web + # If there is no information about the requested season, check the website # http://api.themoviedb.org/3/tv/1407/season/1?api_key=a1ab8b8669da03637a4b98fa39c39228&language=es& # append_to_response=credits @@ -1352,7 +1283,7 @@ class Tmdb(object): self.temporada[numtemporada] = {"episodes": {}} if "status_code" in self.temporada[numtemporada]: - #Se ha producido un error + # An error has occurred msg = config.get_localized_string(70496) + buscando + config.get_localized_string(70497) msg += "\nTmdb error: %s %s" % ( self.temporada[numtemporada]["status_code"], self.temporada[numtemporada]["status_message"]) @@ -1363,16 +1294,16 @@ class Tmdb(object): 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 + # Parameters: +        # season number (optional): (int) Season number. Default 1. +        # chapter: (int) Chapter number. Default 1. +        # Return: (Dec) +        # Returns a dictionary with the following elements: +        # "season_name", "season_synopsis", "season_poster", "season_num_ episodes" (int), +        # "season_air_date", "episode_vote_count", "episode_vote_average", +        # "episode_title", "episode_synopsis", "episode_image", "episode_air_date", +        # "episode_crew" and "episode_guest_stars", +        # With chapter == -1 the dictionary will only have the elements referring to the season # -------------------------------------------------------------------------------------------------------------------------------------------- if not self.result["id"] or self.busqueda_tipo != "tv": return {} @@ -1388,16 +1319,16 @@ class Tmdb(object): if not isinstance(temporada, dict): temporada = ast.literal_eval(temporada.decode('utf-8')) if not temporada: - # Se ha producido un error + # An error has occurred return {} if len(temporada["episodes"]) == 0 or len(temporada["episodes"]) < capitulo: - # Se ha producido un error + # An error has occurred logger.error("Episode %d of the season %d not found." % (capitulo, numtemporada)) return {} ret_dic = dict() - # Obtener datos para esta temporada + # Get data for this season ret_dic["temporada_nombre"] = temporada["name"] ret_dic["temporada_sinopsis"] = temporada["overview"] ret_dic["temporada_num_episodios"] = len(temporada["episodes"]) @@ -1414,8 +1345,7 @@ class Tmdb(object): 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 + # If we only look for season data, include the technical team that has intervened in any chapter dic_aux = dict((i['id'], i) for i in ret_dic["temporada_crew"]) for e in temporada["episodes"]: for crew in e['crew']: @@ -1423,7 +1353,7 @@ class Tmdb(object): dic_aux[crew['id']] = crew ret_dic["temporada_crew"] = list(dic_aux.values()) - # Obtener datos del capitulo si procede + # Obtain chapter data if applicable if capitulo != -1: episodio = temporada["episodes"][capitulo - 1] ret_dic["episodio_titulo"] = episodio["name"] @@ -1446,8 +1376,7 @@ class Tmdb(object): 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. + :return: Returns an ordered list (language / resolution / type) of Dict objects in which each of its elements corresponds to a trailer, teaser or clip from youtube. :rtype: list of Dict """ ret = [] @@ -1455,7 +1384,7 @@ class Tmdb(object): if self.result['videos']: self.result["videos"] = self.result["videos"]['results'] else: - # Primera búsqueda de videos en el idioma de busqueda + # First video search in the search language url = "http://api.themoviedb.org/3/%s/%s/videos?api_key=a1ab8b8669da03637a4b98fa39c39228&language=%s" \ % (self.busqueda_tipo, self.result['id'], self.busqueda_idioma) @@ -1467,10 +1396,9 @@ class Tmdb(object): 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 the search language is not English, do a second video search in English if self.busqueda_idioma != 'en': - url = "http://api.themoviedb.org/3/%s/%s/videos?api_key=a1ab8b8669da03637a4b98fa39c39228" \ - % (self.busqueda_tipo, self.result['id']) + 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 not isinstance(dict_videos, dict): @@ -1480,7 +1408,7 @@ class Tmdb(object): 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 + # If the searches have obtained results, return a list of objects for i in self.result['videos']: if i['site'] == "YouTube": ret.append({'name': i['name'], @@ -1493,12 +1421,11 @@ class Tmdb(object): def get_infoLabels(self, infoLabels=None, origen=None): """ - :param infoLabels: Informacion extra de la pelicula, serie, temporada o capitulo. + :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 + :param origen: Source dictionary where the infoLabels are obtained, by default 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. + :return: Returns the extra information obtained from the current object. If the infoLables parameter was passed, the returned value will be read as a duly updated parameter. :rtype: Dict """ @@ -1507,7 +1434,7 @@ class Tmdb(object): else: ret_infoLabels = InfoLabels() - # Iniciar listados + # Start Listings 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']] @@ -1524,9 +1451,9 @@ class Tmdb(object): items = list(origen.items()) - # Informacion Temporada/episodio + # Season / episode information if ret_infoLabels['season'] and self.temporada.get(ret_infoLabels['season']): - # Si hay datos cargados de la temporada indicada + # If there is data loaded for the indicated season episodio = -1 if ret_infoLabels['episode']: episodio = ret_infoLabels['episode'] @@ -1550,12 +1477,12 @@ class Tmdb(object): else: ret_infoLabels['plot'] = self.get_sinopsis() - elif k == 'runtime': #Duration for movies + elif k == 'runtime': # Duration for movies ret_infoLabels['duration'] = int(v) * 60 - elif k == 'episode_run_time': #Duration for episodes + elif k == 'episode_run_time': # Duration for episodes try: - for v_alt in v: #It comes as a list (?!) + for v_alt in v: # It comes as a list (?!) ret_infoLabels['duration'] = int(v_alt) * 60 except: pass @@ -1650,7 +1577,7 @@ class Tmdb(object): # logger.debug("Atributos no añadidos: " + k +'= '+ str(v)) pass - # Ordenar las listas y convertirlas en str si es necesario + # Sort the lists and convert them to str if necessary if l_castandrole: ret_infoLabels['castandrole'] = sorted(l_castandrole, key=lambda tup: tup[0]) if l_country: diff --git a/core/videolibrarytools.py b/core/videolibrarytools.py index 006f631b..736ced36 100644 --- a/core/videolibrarytools.py +++ b/core/videolibrarytools.py @@ -8,19 +8,12 @@ import sys PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int -import errno -import math -import traceback -import re -import os +import errno, math, traceback, re, os -from core import filetools -from core import scraper -from core import scrapertools +from core import filetools, scraper, scrapertools from core.item import Item from lib import generictools -from platformcode import config, logger -from platformcode import platformtools +from platformcode import config, logger, platformtools FOLDER_MOVIES = config.get_setting("folder_movies") FOLDER_TVSHOWS = config.get_setting("folder_tvshows") @@ -37,15 +30,13 @@ addon_name = "plugin://plugin.video.%s/" % config.PLUGIN_NAME def read_nfo(path_nfo, item=None): """ - Metodo para leer archivos nfo. - Los arcivos nfo tienen la siguiente extructura: url_scraper | xml + item_json - [url_scraper] y [xml] son opcionales, pero solo uno de ellos ha de existir siempre. - @param path_nfo: ruta absoluta al archivo nfo + Method to read nfo files. + Nfo files have the following structure: url_scraper | xml + item_json [url_scraper] and [xml] are optional, but only one of them must always exist. + @param path_nfo: absolute path to nfo file @type path_nfo: str - @param item: Si se pasa este parametro el item devuelto sera una copia de este con - los valores de 'infoLabels', 'library_playcounts' y 'path' leidos del nfo + @param item: If this parameter is passed the returned item will be a copy of it with the values ​​of 'infoLabels', 'library_playcounts' and 'path' read from the nfo @type: Item - @return: Una tupla formada por la cabecera (head_nfo ='url_scraper'|'xml') y el objeto 'item_json' + @return: A tuple consisting of the header (head_nfo = 'url_scraper' | 'xml') and the object 'item_json' @rtype: tuple (str, Item) """ head_nfo = "" @@ -77,15 +68,15 @@ def read_nfo(path_nfo, item=None): def save_movie(item, silent=False): """ - guarda en la libreria de peliculas el elemento item, con los valores que contiene. + saves the item element in the movie library, with the values ​​it contains. @type item: item - @param item: elemento que se va a guardar. + @param item: item to be saved. @rtype insertados: int - @return: el número de elementos insertados + @return: the number of elements inserted @rtype sobreescritos: int - @return: el número de elementos sobreescritos + @return: the number of overwritten elements @rtype fallidos: int - @return: el número de elementos fallidos o -1 si ha fallado todo + @return: the number of failed items or -1 if all failed """ logger.info() # logger.debug(item.tostring('\n')) @@ -94,34 +85,32 @@ def save_movie(item, silent=False): fallidos = 0 path = "" - # Itentamos obtener el titulo correcto: - # 1. contentTitle: Este deberia ser el sitio correcto, ya que title suele contener "Añadir a la videoteca..." + # We try to obtain the correct title: + # 1. contentTitle: This should be the correct site, since the title usually contains "Add to the video library..." # 2. fulltitle # 3. title # if item.contentTitle: item.title = item.contentTitle # elif item.fulltitle: item.title = item.fulltitle if not item.contentTitle: - # Colocamos el titulo correcto en su sitio para que scraper lo localize + # We put the correct title on your site so that scraper can locate it if item.fulltitle: item.contentTitle = item.fulltitle else: item.contentTitle = item.title - # Si llegados a este punto no tenemos titulo, salimos + # If at this point we do not have a title, we leave if not item.contentTitle or not item.channel: logger.debug("contentTitle NOT FOUND") return 0, 0, -1, path # Salimos sin guardar scraper_return = scraper.find_and_set_infoLabels(item) - # Llegados a este punto podemos tener: - # scraper_return = True: Un item con infoLabels con la información actualizada de la peli - # scraper_return = False: Un item sin información de la peli (se ha dado a cancelar en la ventana) - # item.infoLabels['code'] == "" : No se ha encontrado el identificador de IMDB necesario para continuar, salimos + # At this point we can have: + # scraper_return = True: An item with infoLabels with the updated information of the movie + # scraper_return = False: An item without movie information (it has been canceled in the window) + # item.infoLabels['code'] == "" : The required IMDB identifier was not found to continue, we quit if not scraper_return or not item.infoLabels['code']: - # TODO de momento si no hay resultado no añadimos nada, - # aunq podriamos abrir un cuadro para introducir el identificador/nombre a mano logger.debug("NOT FOUND IN SCRAPER OR DO NOT HAVE code") return 0, 0, -1, path @@ -153,7 +142,7 @@ def save_movie(item, silent=False): break if not path: - # Crear carpeta + # Create folder path = filetools.join(MOVIES_PATH, ("%s [%s]" % (base_name, _id)).strip()) logger.info("Creating movie directory:" + path) if not filetools.mkdir(path): @@ -169,7 +158,7 @@ def save_movie(item, silent=False): json_exists = filetools.exists(json_path) if not nfo_exists: - # Creamos .nfo si no existe + # We create .nfo if it doesn't exist logger.info("Creating .nfo: " + nfo_path) head_nfo = scraper.get_nfo(item) @@ -178,18 +167,18 @@ def save_movie(item, silent=False): library_urls={}) else: - # Si existe .nfo, pero estamos añadiendo un nuevo canal lo abrimos + # If .nfo exists, but we are adding a new channel we open it head_nfo, item_nfo = read_nfo(nfo_path) if not strm_exists: - # Crear base_name.strm si no existe + # Create base_name.strm if you do not exist item_strm = Item(channel='videolibrary', action='play_from_library', strm_path=strm_path.replace(MOVIES_PATH, ""), contentType='movie', contentTitle=item.contentTitle) strm_exists = filetools.write(strm_path, '%s?%s' % (addon_name, item_strm.tourl())) item_nfo.strm_path = strm_path.replace(MOVIES_PATH, "") - # Solo si existen item_nfo y .strm continuamos + # Only if item_nfo and .strm exist we continue if item_nfo and strm_exists: if json_exists: @@ -198,7 +187,7 @@ def save_movie(item, silent=False): else: insertados += 1 - # Si se ha marcado la opción de url de emergencia, se añade ésta a la película después de haber ejecutado Findvideos del canal + # If the emergency url option has been checked, it is added to the movie after running Findvideos from the channel try: headers = {} if item.headers: @@ -221,7 +210,7 @@ def save_movie(item, silent=False): if filetools.write(nfo_path, head_nfo + item_nfo.tojson()): #logger.info("FOLDER_MOVIES : %s" % FOLDER_MOVIES) - # actualizamos la videoteca de Kodi con la pelicula + # We update the Kodi video library with the movie if config.is_xbmc() and config.get_setting("videolibrary_kodi") and not silent: from platformcode import xbmc_videolibrary xbmc_videolibrary.update() @@ -229,7 +218,7 @@ def save_movie(item, silent=False): if not silent: p_dialog.close() return insertados, sobreescritos, fallidos, path - # Si llegamos a este punto es por q algo ha fallado + # If we get to this point it is because something has gone wrong logger.error("Could not save %s in the video library" % item.contentTitle) if not silent: p_dialog.update(100, config.get_localized_string(60063), item.contentTitle) @@ -423,37 +412,35 @@ def filter_list(episodelist, action=None, path=None): def save_tvshow(item, episodelist, silent=False): """ - guarda en la libreria de series la serie con todos los capitulos incluidos en la lista episodelist + stores in the series library the series with all the chapters included in the episodelist @type item: item - @param item: item que representa la serie a guardar + @param item: item that represents the series to save @type episodelist: list - @param episodelist: listado de items que representan los episodios que se van a guardar. + @param episodelist: list of items that represent the episodes to be saved. @rtype insertados: int - @return: el número de episodios insertados + @return: the number of episodes inserted @rtype sobreescritos: int - @return: el número de episodios sobreescritos + @return: the number of overwritten episodes @rtype fallidos: int - @return: el número de episodios fallidos o -1 si ha fallado toda la serie + @return: the number of failed episodes or -1 if the entire series has failed @rtype path: str - @return: directorio serie + @return: serial directory """ logger.info() # logger.debug(item.tostring('\n')) path = "" - # Si llegados a este punto no tenemos titulo o code, salimos + # If at this point we do not have a title or code, we leave if not (item.contentSerieName or item.infoLabels['code']) or not item.channel: logger.debug("NOT FOUND contentSerieName or code") return 0, 0, -1, path # Salimos sin guardar scraper_return = scraper.find_and_set_infoLabels(item) - # Llegados a este punto podemos tener: - # scraper_return = True: Un item con infoLabels con la información actualizada de la serie - # scraper_return = False: Un item sin información de la peli (se ha dado a cancelar en la ventana) - # item.infoLabels['code'] == "" : No se ha encontrado el identificador de IMDB necesario para continuar, salimos + # At this point we can have: + # scraper_return = True: An item with infoLabels with the updated information of the series + # scraper_return = False: An item without movie information (it has been canceled in the window) + # item.infoLabels['code'] == "" :T he required IMDB identifier was not found to continue, we quit if not scraper_return or not item.infoLabels['code']: - # TODO de momento si no hay resultado no añadimos nada, - # aunq podriamos abrir un cuadro para introducir el identificador/nombre a mano logger.debug("NOT FOUND IN SCRAPER OR DO NOT HAVE code") return 0, 0, -1, path @@ -464,8 +451,7 @@ def save_tvshow(item, episodelist, silent=False): elif item.infoLabels['code'][2] and item.infoLabels['code'][2] != 'None': _id = item.infoLabels['code'][2] else: - logger.error("NO ENCONTRADO EN SCRAPER O NO TIENE code: " + item.url - + ' / ' + item.infoLabels['code']) + logger.error("NOT FOUND IN SCRAPER OR HAS NO CODE: " + item.url + ' / ' + item.infoLabels['code']) return 0, 0, -1, path if config.get_setting("original_title_folder", "videolibrary") and item.infoLabels['originaltitle']: @@ -504,7 +490,7 @@ def save_tvshow(item, episodelist, silent=False): tvshow_path = filetools.join(path, "tvshow.nfo") if not filetools.exists(tvshow_path): - # Creamos tvshow.nfo, si no existe, con la head_nfo, info de la serie y marcas de episodios vistos + # We create tvshow.nfo, if it does not exist, with the head_nfo, series info and watched episode marks logger.info("Creating tvshow.nfo: " + tvshow_path) head_nfo = scraper.get_nfo(item) item.infoLabels['mediatype'] = "tvshow" @@ -516,7 +502,7 @@ def save_tvshow(item, episodelist, silent=False): item_tvshow.library_urls = {item.channel: item.url} else: - # Si existe tvshow.nfo, pero estamos añadiendo un nuevo canal actualizamos el listado de urls + # If tvshow.nfo exists, but we are adding a new channel we update the list of urls head_nfo, item_tvshow = read_nfo(tvshow_path) item_tvshow.fulltitle = item.fulltitle item_tvshow.channel = "videolibrary" @@ -524,15 +510,15 @@ def save_tvshow(item, episodelist, silent=False): item_tvshow.library_urls[item.channel] = item.url # FILTERTOOLS - # si el canal tiene filtro de idiomas, añadimos el canal y el show + # if the channel has a language filter, we add the channel and the show if episodelist and "list_language" in episodelist[0]: - # si ya hemos añadido un canal previamente con filtro, añadimos o actualizamos el canal y show + # if we have already added a previously filtered channel, we add or update the channel and show if "library_filter_show" in item_tvshow: if item.title_from_channel: item_tvshow.library_filter_show[item.channel] = item.title_from_channel else: item_tvshow.library_filter_show[item.channel] = item.show - # no habia ningún canal con filtro y lo generamos por primera vez + # there was no filter channel and we generated it for the first time else: if item.title_from_channel: item_tvshow.library_filter_show = {item.channel: item.title_from_channel} @@ -540,15 +526,15 @@ def save_tvshow(item, episodelist, silent=False): item_tvshow.library_filter_show = {item.channel: item.show} if item.channel != "downloads": - item_tvshow.active = 1 # para que se actualice a diario cuando se llame a service + item_tvshow.active = 1 # to be updated daily when service is called filetools.write(tvshow_path, head_nfo + item_tvshow.tojson()) if not episodelist: - # La lista de episodios esta vacia + # The episode list is empty return 0, 0, 0, path - # Guardar los episodios + # Save the episodes '''import time start_time = time.time()''' insertados, sobreescritos, fallidos = save_episodes(path, episodelist, item, silent=silent) @@ -561,27 +547,27 @@ def save_tvshow(item, episodelist, silent=False): def save_episodes(path, episodelist, serie, silent=False, overwrite=True): """ - guarda en la ruta indicada todos los capitulos incluidos en la lista episodelist + saves in the indicated path all the chapters included in the episodelist @type path: str - @param path: ruta donde guardar los episodios + @param path: path to save the episodes @type episodelist: list - @param episodelist: listado de items que representan los episodios que se van a guardar. + @param episodelist: list of items that represent the episodes to be saved. @type serie: item - @param serie: serie de la que se van a guardar los episodios + @param serie: series from which to save the episodes @type silent: bool - @param silent: establece si se muestra la notificación - @param overwrite: permite sobreescribir los ficheros existentes + @param silent: sets whether notification is displayed + @param overwrite: allows to overwrite existing files @type overwrite: bool @rtype insertados: int - @return: el número de episodios insertados + @return: the number of episodes inserted @rtype sobreescritos: int - @return: el número de episodios sobreescritos + @return: the number of overwritten episodes @rtype fallidos: int - @return: el número de episodios fallidos + @return: the number of failed episodes """ logger.info() episodelist = filter_list(episodelist, serie.action, path) - # No hay lista de episodios, no hay nada que guardar + # No episode list, nothing to save if not len(episodelist): logger.info("There is no episode list, we go out without creating strm") return 0, 0, 0 @@ -606,27 +592,27 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): sobreescritos = 0 fallidos = 0 news_in_playcounts = {} - # Listamos todos los ficheros de la serie, asi evitamos tener que comprobar si existe uno por uno + # We list all the files in the series, so we avoid having to check if they exist one by one raiz, carpetas_series, ficheros = next(filetools.walk(path)) ficheros = [filetools.join(path, f) for f in ficheros] - # Silent es para no mostrar progreso (para service) + # Silent is to show no progress (for service) if not silent: # progress dialog p_dialog = platformtools.dialog_progress(config.get_localized_string(20000), config.get_localized_string(60064)) p_dialog.update(0, config.get_localized_string(60065)) - channel_alt = generictools.verify_channel(serie.channel) #Preparamos para añadir las urls de emergencia - emergency_urls_stat = config.get_setting("emergency_urls", channel_alt) #El canal quiere urls de emergencia? + channel_alt = generictools.verify_channel(serie.channel) # We prepare to add the emergency urls + emergency_urls_stat = config.get_setting("emergency_urls", channel_alt) # Does the channel want emergency urls? emergency_urls_succ = False try: channel = __import__('specials.%s' % channel_alt, fromlist=["specials.%s" % channel_alt]) except: channel = __import__('channels.%s' % channel_alt, fromlist=["channels.%s" % channel_alt]) - if serie.torrent_caching_fail: #Si el proceso de conversión ha fallado, no se cachean + if serie.torrent_caching_fail: # If the conversion process has failed, they are not cached emergency_urls_stat = 0 del serie.torrent_caching_fail new_episodelist = [] - # Obtenemos el numero de temporada y episodio y descartamos los q no lo sean + # We obtain the season and episode number and discard those that are not for e in episodelist: headers = {} @@ -636,52 +622,52 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): try: season_episode = scrapertools.get_season_and_episode(e.title) - # Si se ha marcado la opción de url de emergencia, se añade ésta a cada episodio después de haber ejecutado Findvideos del canal - if e.emergency_urls and isinstance(e.emergency_urls, dict): del e.emergency_urls #Borramos trazas anteriores - json_path = filetools.join(path, ("%s [%s].json" % (season_episode, e.channel)).lower()) #Path del .json del episodio - if emergency_urls_stat == 1 and not e.emergency_urls and e.contentType == 'episode': #Guardamos urls de emergencia? + # If the emergency url option has been checked, it is added to each episode after running Findvideos from the channel + if e.emergency_urls and isinstance(e.emergency_urls, dict): del e.emergency_urls # We erase previous traces + json_path = filetools.join(path, ("%s [%s].json" % (season_episode, e.channel)).lower()) # Path of the episode .json + if emergency_urls_stat == 1 and not e.emergency_urls and e.contentType == 'episode': # Do we keep emergency urls? if not silent: - p_dialog.update(0, 'Cacheando enlaces y archivos .torrent...', e.title) #progress dialog - if json_path in ficheros: #Si existe el .json sacamos de ahí las urls - if overwrite: #pero solo si se se sobrescriben los .json - json_epi = Item().fromjson(filetools.read(json_path)) #Leemos el .json - if json_epi.emergency_urls: #si existen las urls de emergencia... - e.emergency_urls = json_epi.emergency_urls #... las copiamos - else: #y si no... - e = emergency_urls(e, channel, json_path, headers=headers) #... las generamos + p_dialog.update(0, 'Caching links and .torren filest...', e.title) # progress dialog + if json_path in ficheros: # If there is the .json we get the urls from there + if overwrite: # but only if .json are overwritten + json_epi = Item().fromjson(filetools.read(json_path)) #We read the .json + if json_epi.emergency_urls: # if there are emergency urls ... + e.emergency_urls = json_epi.emergency_urls # ... we copy them + else: # if not... + e = emergency_urls(e, channel, json_path, headers=headers) # ... we generate them else: - e = emergency_urls(e, channel, json_path, headers=headers) #Si el episodio no existe, generamos las urls - if e.emergency_urls: #Si ya tenemos urls... - emergency_urls_succ = True #... es un éxito y vamos a marcar el .nfo - elif emergency_urls_stat == 2 and e.contentType == 'episode': #Borramos urls de emergencia? + e = emergency_urls(e, channel, json_path, headers=headers) # If the episode does not exist, we generate the urls + if e.emergency_urls: #If we already have urls... + emergency_urls_succ = True # ... is a success and we are going to mark the .nfo + elif emergency_urls_stat == 2 and e.contentType == 'episode': # Do we delete emergency urls? if e.emergency_urls: del e.emergency_urls - emergency_urls_succ = True #... es un éxito y vamos a marcar el .nfo - elif emergency_urls_stat == 3 and e.contentType == 'episode': #Actualizamos urls de emergencia? + emergency_urls_succ = True # ... is a success and we are going to mark the .nfo + elif emergency_urls_stat == 3 and e.contentType == 'episode': # Do we update emergency urls? if not silent: - p_dialog.update(0, 'Cacheando enlaces y archivos .torrent...', e.title) #progress dialog - e = emergency_urls(e, channel, json_path, headers=headers) #generamos las urls - if e.emergency_urls: #Si ya tenemos urls... - emergency_urls_succ = True #... es un éxito y vamos a marcar el .nfo + p_dialog.update(0, 'Caching links and .torrent files...', e.title) # progress dialog + e = emergency_urls(e, channel, json_path, headers=headers) # we generate the urls + if e.emergency_urls: # If we already have urls... + emergency_urls_succ = True # ... is a success and we are going to mark the .nfo if not e.infoLabels["tmdb_id"] or (serie.infoLabels["tmdb_id"] and e.infoLabels["tmdb_id"] != serie.infoLabels["tmdb_id"]): #en series multicanal, prevalece el infolabels... - e.infoLabels = serie.infoLabels #... del canal actual y no el del original + e.infoLabels = serie.infoLabels # ... dthe current channel and not the original one e.contentSeason, e.contentEpisodeNumber = season_episode.split("x") if e.videolibray_emergency_urls: del e.videolibray_emergency_urls if e.channel_redir: - del e.channel_redir #... y se borran las marcas de redirecciones + del e.channel_redir # ... and redirect marks are erased new_episodelist.append(e) except: if e.contentType == 'episode': logger.error("Unable to save %s emergency urls in the video library" % e.contentTitle) continue - # No hay lista de episodios, no hay nada que guardar + # No episode list, nothing to save if not len(new_episodelist): logger.info("There is no episode list, we go out without creating strm") return 0, 0, 0 - # fix float porque la division se hace mal en python 2.x + # fix float because division is done poorly in python 2.x try: t = float(100) / len(new_episodelist) except: @@ -718,9 +704,8 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): json_exists = json_path in ficheros if not strm_exists: - # Si no existe season_episode.strm añadirlo - item_strm = Item(action='play_from_library', channel='videolibrary', - strm_path=strm_path.replace(TVSHOWS_PATH, ""), infoLabels={}) + # If there is no season_episode.strm add it + item_strm = Item(action='play_from_library', channel='videolibrary', strm_path=strm_path.replace(TVSHOWS_PATH, ""), infoLabels={}) item_strm.contentSeason = e.contentSeason item_strm.contentEpisodeNumber = e.contentEpisodeNumber item_strm.contentType = e.contentType @@ -728,7 +713,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): # FILTERTOOLS if item_strm.list_language: - # si tvshow.nfo tiene filtro se le pasa al item_strm que se va a generar + # if tvshow.nfo has a filter it is passed to the item_strm to be generated if "library_filter_show" in serie: item_strm.library_filter_show = serie.library_filter_show @@ -741,38 +726,36 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): item_nfo = None if not nfo_exists and e.infoLabels["code"]: - # Si no existe season_episode.nfo añadirlo + # If there is no season_episode.nfo add it scraper.find_and_set_infoLabels(e) head_nfo = scraper.get_nfo(e) - item_nfo = e.clone(channel="videolibrary", url="", action='findvideos', - strm_path=strm_path.replace(TVSHOWS_PATH, "")) + item_nfo = e.clone(channel="videolibrary", url="", action='findvideos', strm_path=strm_path.replace(TVSHOWS_PATH, "")) if item_nfo.emergency_urls: - del item_nfo.emergency_urls #Solo se mantiene en el .json del episodio + del item_nfo.emergency_urls # It only stays in the episode's .json nfo_exists = filetools.write(nfo_path, head_nfo + item_nfo.tojson()) - # Solo si existen season_episode.nfo y season_episode.strm continuamos + # Only if there are season_episode.nfo and season_episode.strm we continue if nfo_exists and strm_exists: if not json_exists or overwrite: - # Obtenemos infoLabel del episodio + # We get infoLabel from the episode if not item_nfo: head_nfo, item_nfo = read_nfo(nfo_path) - # En series multicanal, prevalece el infolabels del canal actual y no el del original - if not e.infoLabels["tmdb_id"] or (item_nfo.infoLabels["tmdb_id"] \ - and e.infoLabels["tmdb_id"] != item_nfo.infoLabels["tmdb_id"]): + # In multichannel series, the infolabels of the current channel prevail and not that of the original + if not e.infoLabels["tmdb_id"] or (item_nfo.infoLabels["tmdb_id"] and e.infoLabels["tmdb_id"] != item_nfo.infoLabels["tmdb_id"]): e.infoLabels = item_nfo.infoLabels if filetools.write(json_path, e.tojson()): if not json_exists: logger.info("Inserted: %s" % json_path) insertados += 1 - # Marcamos episodio como no visto + # We mark episode as unseen news_in_playcounts[season_episode] = 0 - # Marcamos la temporada como no vista + # We mark the season as unseen news_in_playcounts["season %s" % e.contentSeason] = 0 - # Marcamos la serie como no vista + # We mark the series as unseen # logger.debug("serie " + serie.tostring('\n')) news_in_playcounts[serie.contentSerieName] = 0 @@ -796,25 +779,25 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): p_dialog.close() if news_in_playcounts or emergency_urls_succ or serie.infoLabels["status"] == "Ended" or serie.infoLabels["status"] == "Canceled": - # Si hay nuevos episodios los marcamos como no vistos en tvshow.nfo ... + # If there are new episodes we mark them as unseen on tvshow.nfo ... tvshow_path = filetools.join(path, "tvshow.nfo") try: import datetime head_nfo, tvshow_item = read_nfo(tvshow_path) tvshow_item.library_playcounts.update(news_in_playcounts) - #Si la operación de insertar/borrar urls de emergencia en los .jsons de los episodios ha tenido éxito, se marca el .nfo + # If the emergency url insert / delete operation in the .jsons of the episodes was successful, the .nfo is checked if emergency_urls_succ: if tvshow_item.emergency_urls and not isinstance(tvshow_item.emergency_urls, dict): del tvshow_item.emergency_urls - if emergency_urls_stat in [1, 3]: #Operación de guardar/actualizar enlaces + if emergency_urls_stat in [1, 3]: # Save / update links operation if not tvshow_item.emergency_urls: tvshow_item.emergency_urls = dict() if tvshow_item.library_urls.get(serie.channel, False): tvshow_item.emergency_urls.update({serie.channel: True}) - elif emergency_urls_stat == 2: #Operación de Borrar enlaces + elif emergency_urls_stat == 2: # Delete links operation if tvshow_item.emergency_urls and tvshow_item.emergency_urls.get(serie.channel, False): - tvshow_item.emergency_urls.pop(serie.channel, None) #borramos la entrada del .nfo + tvshow_item.emergency_urls.pop(serie.channel, None) # delete the entry of the .nfo if tvshow_item.active == 30: tvshow_item.active = 1 @@ -822,12 +805,9 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): tvshow_item.infoLabels = serie.infoLabels tvshow_item.infoLabels["title"] = tvshow_item.infoLabels["tvshowtitle"] - if max_sea == high_sea and max_epi == high_epi and (tvshow_item.infoLabels["status"] == "Ended" - or tvshow_item.infoLabels["status"] == "Canceled") and insertados == 0 and fallidos == 0 \ - and not tvshow_item.local_episodes_path: - tvshow_item.active = 0 # ... no la actualizaremos más - logger.debug("%s [%s]: serie 'Terminada' o 'Cancelada'. Se desactiva la actualización periódica" % \ - (serie.contentSerieName, serie.channel)) + if max_sea == high_sea and max_epi == high_epi and (tvshow_item.infoLabels["status"] == "Ended" or tvshow_item.infoLabels["status"] == "Canceled") and insertados == 0 and fallidos == 0 and not tvshow_item.local_episodes_path: + tvshow_item.active = 0 # ... nor we will update it more + logger.debug("%s [%s]: 'Finished' or 'Canceled' series. Periodic update is disabled" % (serie.contentSerieName, serie.channel)) update_last = datetime.date.today() tvshow_item.update_last = update_last.strftime('%Y-%m-%d') @@ -841,7 +821,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): logger.error(traceback.format_exc()) fallidos = -1 else: - # ... si ha sido correcto actualizamos la videoteca de Kodi + # ... if it was correct we update the Kodi video library if config.is_xbmc() and config.get_setting("videolibrary_kodi") and not silent: from platformcode import xbmc_videolibrary xbmc_videolibrary.update() @@ -849,8 +829,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): if fallidos == len(episodelist): fallidos = -1 - logger.debug("%s [%s]: inserted= %s, overwritten= %s, failed= %s" % - (serie.contentSerieName, serie.channel, insertados, sobreescritos, fallidos)) + logger.debug("%s [%s]: inserted= %s, overwritten= %s, failed= %s" % (serie.contentSerieName, serie.channel, insertados, sobreescritos, fallidos)) return insertados, sobreescritos, fallidos @@ -924,65 +903,63 @@ def process_local_episodes(local_episodes_path, path): def add_movie(item): """ - guarda una pelicula en la libreria de cine. La pelicula puede ser un enlace dentro de un canal o un video - descargado previamente. + Keep a movie at the movie library. The movie can be a link within a channel or a previously downloaded video. - Para añadir episodios descargados en local, el item debe tener exclusivamente: - - contentTitle: titulo de la pelicula - - title: titulo a mostrar junto al listado de enlaces -findvideos- ("Reproducir video local HD") - - infoLabels["tmdb_id"] o infoLabels["imdb_id"] + To add locally downloaded episodes, the item must have exclusively: + - contentTitle: title of the movie + - title: title to show next to the list of links -findvideos- ("Play local HD video") + - infoLabels ["tmdb_id"] o infoLabels ["imdb_id"] - contentType == "movie" - channel = "downloads" - - url : ruta local al video + - url: local path to the video @type item: item - @param item: elemento que se va a guardar. + @param item: item to be saved. """ logger.info() - #Para desambiguar títulos, se provoca que TMDB pregunte por el título realmente deseado - #El usuario puede seleccionar el título entre los ofrecidos en la primera pantalla - #o puede cancelar e introducir un nuevo título en la segunda pantalla - #Si lo hace en "Introducir otro nombre", TMDB buscará automáticamente el nuevo título - #Si lo hace en "Completar Información", cambia parcialmente al nuevo título, pero no busca en TMDB. Hay que hacerlo - #Si se cancela la segunda pantalla, la variable "scraper_return" estará en False. El usuario no quiere seguir + # To disambiguate titles, TMDB is caused to ask for the really desired title + # The user can select the title among those offered on the first screen + # or you can cancel and enter a new title on the second screen + # If you do it in "Enter another name", TMDB will automatically search for the new title + # If you do it in "Complete Information", it partially changes to the new title, but does not search TMDB. We have to do it + # If the second screen is canceled, the variable "scraper_return" will be False. The user does not want to continue - item = generictools.update_title(item) #Llamamos al método que actualiza el título con tmdb.find_and_set_infoLabels + item = generictools.update_title(item) # We call the method that updates the title with tmdb.find_and_set_infoLabels #if item.tmdb_stat: - # del item.tmdb_stat #Limpiamos el status para que no se grabe en la Videoteca + # del item.tmdb_stat # We clean the status so that it is not recorded in the Video Library new_item = item.clone(action="findvideos") insertados, sobreescritos, fallidos, path = save_movie(new_item) if fallidos == 0: platformtools.dialog_ok(config.get_localized_string(30131), - config.get_localized_string(30135) % new_item.contentTitle) # 'se ha añadido a la videoteca' + config.get_localized_string(30135) % new_item.contentTitle) # 'has been added to the video library' else: filetools.rmdirtree(path) platformtools.dialog_ok(config.get_localized_string(30131), - config.get_localized_string(60066) % new_item.contentTitle) #"ERROR, la pelicula NO se ha añadido a la videoteca") + config.get_localized_string(60066) % new_item.contentTitle) # "ERROR, the movie has NOT been added to the video library") def add_tvshow(item, channel=None): """ - Guarda contenido en la libreria de series. Este contenido puede ser uno de estos dos: - - La serie con todos los capitulos incluidos en la lista episodelist. - - Un solo capitulo descargado previamente en local. + Save content in the series library. This content can be one of these two: + - The series with all the chapters included in the episodelist. + - A single chapter previously downloaded locally. - Para añadir episodios descargados en local, el item debe tener exclusivamente: - - contentSerieName (o show): Titulo de la serie - - contentTitle: titulo del episodio para extraer season_and_episode ("1x01 Piloto") - - title: titulo a mostrar junto al listado de enlaces -findvideos- ("Reproducir video local") - - infoLabels["tmdb_id"] o infoLabels["imdb_id"] + To add locally downloaded episodes, the item must have exclusively: + - contentSerieName (or show): Title of the series + - contentTitle: title of the episode to extract season_and_episode ("1x01 Pilot") + - title: title to show next to the list of links -findvideos- ("Play local video") + - infoLabels ["tmdb_id"] o infoLabels ["imdb_id"] - contentType != "movie" - channel = "downloads" - - url : ruta local al video + - url: local path to the video @type item: item - @param item: item que representa la serie a guardar + @param item: item that represents the series to save @type channel: modulo - @param channel: canal desde el que se guardara la serie. - Por defecto se importara item.from_channel o item.channel + @param channel: channel from which the series will be saved. By default, item.from_channel or item.channel will be imported. """ logger.info("show=#" + item.show + "#") @@ -991,7 +968,7 @@ def add_tvshow(item, channel=None): itemlist = [item.clone()] else: - # Esta marca es porque el item tiene algo más aparte en el atributo "extra" + # This mark is because the item has something else apart in the "extra" attribute item.action = item.extra if item.extra else item.action if isinstance(item.extra, str) and "###" in item.extra: item.action = item.extra.split("###")[0] @@ -1009,18 +986,18 @@ def add_tvshow(item, channel=None): except ImportError: exec("import channels." + item.channel + " as channel") - #Para desambiguar títulos, se provoca que TMDB pregunte por el título realmente deseado - #El usuario puede seleccionar el título entre los ofrecidos en la primera pantalla - #o puede cancelar e introducir un nuevo título en la segunda pantalla - #Si lo hace en "Introducir otro nombre", TMDB buscará automáticamente el nuevo título - #Si lo hace en "Completar Información", cambia parcialmente al nuevo título, pero no busca en TMDB. Hay que hacerlo - #Si se cancela la segunda pantalla, la variable "scraper_return" estará en False. El usuario no quiere seguir + # To disambiguate titles, TMDB is caused to ask for the really desired title + # The user can select the title among those offered on the first screen + # or you can cancel and enter a new title on the second screen + # If you do it in "Enter another name", TMDB will automatically search for the new title + # If you do it in "Complete Information", it partially changes to the new title, but does not search TMDB. We have to do it + # If the second screen is canceled, the variable "scraper_return" will be False. The user does not want to continue - item = generictools.update_title(item) #Llamamos al método que actualiza el título con tmdb.find_and_set_infoLabels + item = generictools.update_title(item) # We call the method that updates the title with tmdb.find_and_set_infoLabels #if item.tmdb_stat: - # del item.tmdb_stat #Limpiamos el status para que no se grabe en la Videoteca + # del item.tmdb_stat # We clean the status so that it is not recorded in the Video Library - # Obtiene el listado de episodios + # Get the episode list itemlist = getattr(channel, item.action)(item) if itemlist and not scrapertools.find_single_match(itemlist[0].title, r'(\d+.\d+)'): @@ -1040,34 +1017,34 @@ def add_tvshow(item, channel=None): if not insertados and not sobreescritos and not fallidos: filetools.rmdirtree(path) platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60067) % item.show) - logger.error("La serie %s no se ha podido añadir a la videoteca. No se ha podido obtener ningun episodio" % item.show) + logger.error("The string %s could not be added to the video library. Could not get any episode" % item.show) elif fallidos == -1: filetools.rmdirtree(path) platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60068) % item.show) - logger.error("La serie %s no se ha podido añadir a la videoteca" % item.show) + logger.error("The string %s could not be added to the video library" % item.show) elif fallidos == -2: filetools.rmdirtree(path) elif fallidos > 0: platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60069) % item.show) - logger.error("No se han podido añadir %s episodios de la serie %s a la videoteca" % (fallidos, item.show)) + logger.error("Could not add %s episodes of series %s to the video library" % (fallidos, item.show)) else: platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60070) % item.show) - logger.info("Se han añadido %s episodios de la serie %s a la videoteca" % (insertados, item.show)) + logger.info("%s episodes of series %s have been added to the video library" % (insertados, item.show)) if config.is_xbmc(): if config.get_setting("sync_trakt_new_tvshow", "videolibrary"): import xbmc from platformcode import xbmc_videolibrary if config.get_setting("sync_trakt_new_tvshow_wait", "videolibrary"): - # Comprobar que no se esta buscando contenido en la videoteca de Kodi + # Check that you are not looking for content in the Kodi video library while xbmc.getCondVisibility('Library.IsScanningVideo()'): xbmc.sleep(1000) - # Se lanza la sincronizacion para la videoteca de Kodi + # Synchronization for Kodi video library launched xbmc_videolibrary.sync_trakt_kodi() - # Se lanza la sincronización para la videoteca del addon + # Synchronization for the addon video library is launched xbmc_videolibrary.sync_trakt_addon(path) @@ -1079,52 +1056,52 @@ def emergency_urls(item, channel=None, path=None, headers={}): magnet_caching_e = magnet_caching except: magnet_caching_e = True - - """ - Llamamos a Findvideos del canal con la variable "item.videolibray_emergency_urls = True" para obtener la variable - "item.emergency_urls" con la lista de listas de tuplas de los enlaces torrent y de servidores directos para ese episodio o película - En la lista [0] siempre deben ir los enlaces torrents, si los hay. Si se desea cachear los .torrents, la búsqueda va contra esa lista. - En la lista dos irán los enlaces de servidores directos, pero también pueden ir enlaces magnet (que no son cacheables) + """ - #lanazamos un "lookup" en el "findvideos" del canal para obtener los enlaces de emergencia + We call Findvideos of the channel with the variable "item.videolibray_emergency_urls = True" to get the variable + "item.emergency_urls" with the list of tuple lists of torrent links and direct servers for that episode or movie + Torrents should always go in list [0], if any. If you want to cache the .torrents, the search goes against that list. + List two will include direct server links, but also magnet links (which are not cacheable). + """ + # we launched a "lookup" in the "findvideos" of the channel to obtain the emergency links try: - if channel == None: #Si el llamador no ha aportado la estructura de channel, se crea - channel = generictools.verify_channel(item.channel) #Se verifica si es un clon, que devuelva "newpct1" + if channel == None: # If the caller has not provided the channel structure, it is created + channel = generictools.verify_channel(item.channel) # It is verified if it is a clone, which returns "newpct1" #channel = __import__('channels.%s' % channel, fromlist=["channels.%s" % channel]) channel = __import__('specials.%s' % channel_alt, fromlist=["specials.%s" % channel_alt]) - if hasattr(channel, 'findvideos'): #Si el canal tiene "findvideos"... - item.videolibray_emergency_urls = True #... se marca como "lookup" - channel_save = item.channel #... guarda el canal original por si hay fail-over en Newpct1 - category_save = item.category #... guarda la categoría original por si hay fail-over o redirección en Newpct1 - if item.channel_redir: #... si hay un redir, se restaura temporamente el canal alternativo - item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').lower() - item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() - item_res = getattr(channel, 'findvideos')(item) #... se procesa Findvideos - item_res.channel = channel_save #... restaura el canal original por si hay fail-over en Newpct1 - item_res.category = category_save #... restaura la categoría original por si hay fail-over o redirección en Newpct1 - item.category = category_save #... restaura la categoría original por si hay fail-over o redirección en Newpct1 - del item_res.videolibray_emergency_urls #... y se borra la marca de lookup + if hasattr(channel, 'findvideos'): # If the channel has "findvideos" ... + item.videolibray_emergency_urls = True # ... marks itself as "lookup" + channel_save = item.channel # ... save the original channel in case of fail-over in Newpct1 + category_save = item.category # ... save the original category in case of fail-over or redirection in Newpct1 + if item.channel_redir: # ... if there is a redir, the alternate channel is temporarily restored + item.channel = scrapertools.find_single_match(item.url, r'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').lower() + item.category = scrapertools.find_single_match(item.url, r'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() + item_res = getattr(channel, 'findvideos')(item) # ... the process of Findvideos + item_res.channel = channel_save # ... restore the original channel in case there is a fail-over in Newpct1 + item_res.category = category_save # ... restore the original category in case there is a fail-over or redirection in Newpct1 + item.category = category_save # ... restore the original category in case there is a fail-over or redirection in Newpct1 + del item_res.videolibray_emergency_urls # ... and the lookup mark is erased if item.videolibray_emergency_urls: - del item.videolibray_emergency_urls #... y se borra la marca de lookup original + del item.videolibray_emergency_urls # ... and the original lookup mark is erased except: logger.error('ERROR when processing the title in Findvideos del Canal: ' + item.channel + ' / ' + item.title) logger.error(traceback.format_exc()) - item.channel = channel_save #... restaura el canal original por si hay fail-over o redirección en Newpct1 - item.category = category_save #... restaura la categoría original por si hay fail-over o redirección en Newpct1 - item_res = item.clone() #Si ha habido un error, se devuelve el Item original + item.channel = channel_save # ... restore the original channel in case of fail-over or redirection in Newpct1 + item.category = category_save # ... restore the original category in case there is a fail-over or redirection in Newpct1 + item_res = item.clone() # If there has been an error, the original Item is returned if item_res.videolibray_emergency_urls: - del item_res.videolibray_emergency_urls #... y se borra la marca de lookup + del item_res.videolibray_emergency_urls # ... and the lookup mark is erased if item.videolibray_emergency_urls: - del item.videolibray_emergency_urls #... y se borra la marca de lookup original + del item.videolibray_emergency_urls # ... and the original lookup mark is erased - #Si el usuario ha activado la opción "emergency_urls_torrents", se descargarán los archivos .torrent de cada título - else: #Si se han cacheado con éxito los enlaces... + # If the user has activated the option "emergency_urls_torrents", the .torrent files of each title will be downloaded + else: # If the links have been successfully cached ... try: referer = None post = None channel_bis = generictools.verify_channel(item.channel) if config.get_setting("emergency_urls_torrents", channel_bis) and item_res.emergency_urls and path != None: - videolibrary_path = config.get_videolibrary_path() #detectamos el path absoluto del título + videolibrary_path = config.get_videolibrary_path() # we detect the absolute path of the title movies = config.get_setting("folder_movies") series = config.get_setting("folder_tvshows") if movies in path: @@ -1135,16 +1112,16 @@ def emergency_urls(item, channel=None, path=None, headers={}): i = 1 if item_res.referer: referer = item_res.referer if item_res.post: post = item_res.post - for url in item_res.emergency_urls[0]: #Recorremos las urls de emergencia... + for url in item_res.emergency_urls[0]: # We go through the emergency urls ... torrents_path = re.sub(r'(?:\.\w+$)', '_%s.torrent' % str(i).zfill(2), path) path_real = '' if magnet_caching_e or not url.startswith('magnet'): - path_real = torrent.caching_torrents(url, referer, post, torrents_path=torrents_path, headers=headers) #... para descargar los .torrents - if path_real: #Si ha tenido éxito... - item_res.emergency_urls[0][i-1] = path_real.replace(videolibrary_path, '') #se guarda el "path" relativo + path_real = torrent.caching_torrents(url, referer, post, torrents_path=torrents_path, headers=headers) # ... to download the .torrents + if path_real: # If you have been successful ... + item_res.emergency_urls[0][i-1] = path_real.replace(videolibrary_path, '') # if it looks at the relative "path" i += 1 - #Restauramos variables originales + # We restore original variables if item.referer: item_res.referer = item.referer elif item_res.referer: @@ -1158,7 +1135,7 @@ def emergency_urls(item, channel=None, path=None, headers={}): except: logger.error('ERROR when caching the .torrent of: ' + item.channel + ' / ' + item.title) logger.error(traceback.format_exc()) - item_res = item.clone() #Si ha habido un error, se devuelve el Item original + item_res = item.clone() # If there has been an error, the original Item is returned #logger.debug(item_res.emergency_urls) - return item_res #Devolvemos el Item actualizado con los enlaces de emergencia + return item_res # We return the updated Item with the emergency links diff --git a/core/ziptools.py b/core/ziptools.py index 1154e8f7..f95750b7 100644 --- a/core/ziptools.py +++ b/core/ziptools.py @@ -17,8 +17,8 @@ from core import filetools class ziptools(object): def extract(self, file, dir, folder_to_extract="", overwrite_question=False, backup=False): - logger.info("file=%s" % file) - logger.info("dir=%s" % dir) + logger.info("file= %s" % file) + logger.info("dir= %s" % dir) if not dir.endswith(':') and not filetools.exists(dir): filetools.mkdir(dir) @@ -32,7 +32,7 @@ class ziptools(object): name = nameo.replace(':', '_').replace('<', '_').replace('>', '_').replace('|', '_').replace('"', '_').replace('?', '_').replace('*', '_') logger.info("name=%s" % nameo) if not name.endswith('/'): - logger.info("no es un directorio") + logger.info("it's not a directory") try: (path, filename) = filetools.split(filetools.join(dir, name)) logger.info("path=%s" % path) @@ -53,31 +53,28 @@ class ziptools(object): try: if filetools.exists(outfilename) and overwrite_question: from platformcode import platformtools - dyesno = platformtools.dialog_yesno("El archivo ya existe", - "El archivo %s a descomprimir ya existe" \ - ", ¿desea sobrescribirlo?" \ - % filetools.basename(outfilename)) + dyesno = platformtools.dialog_yesno("File already exists "," File %s to unzip already exists, do you want to overwrite it?" % filetools.basename(outfilename)) if not dyesno: break if backup: import time - hora_folder = "Copia seguridad [%s]" % time.strftime("%d-%m_%H-%M", time.localtime()) + hora_folder = "Backup [%s]" % time.strftime("%d-%m_%H-%M", time.localtime()) backup = filetools.join(config.get_data_path(), 'backups', hora_folder, folder_to_extract) if not filetools.exists(backup): filetools.mkdir(backup) filetools.copy(outfilename, filetools.join(backup, filetools.basename(outfilename))) if not filetools.write(outfilename, zf.read(nameo), silent=True, vfs=VFS): #TRUNCA en FINAL en Kodi 19 con VFS - logger.error("Error en fichero " + nameo) + logger.error("File error " + nameo) except: import traceback logger.error(traceback.format_exc()) - logger.error("Error en fichero " + nameo) + logger.error("File error " + nameo) try: zf.close() except: - logger.info("Error cerrando .zip " + file) + logger.info("Error closing .zip " + file) def _createstructure(self, file, dir): self._makedirs(self._listdirs(file), dir)