- tanti miglioramenti sotto il cofano, supporto iniziale al futuro kodi 19
- Nuova modalità di visualizzazione per episodio successivo
- fixato wstream tramite l'aggiunta della finestra per risolvere il reCaptcha
- aggiunta sezione segnala un problema in Aiuto
- altri fix e migliorie varie a canali e server
This commit is contained in:
marco
2020-02-22 13:36:58 +01:00
parent 82b61df289
commit ca6d5eb56d
121 changed files with 13147 additions and 5448 deletions
+68 -97
View File
@@ -3,10 +3,9 @@
# channeltools - Herramientas para trabajar con canales
# ------------------------------------------------------------
import os
import jsontools
from __future__ import absolute_import
from core import jsontools
from platformcode import config, logger
DEFAULT_UPDATE_URL = "/channels/"
@@ -14,6 +13,7 @@ dict_channels_parameters = dict()
remote_path = 'https://raw.githubusercontent.com/kodiondemand/media/master/'
def is_adult(channel_name):
logger.info("channel_name=" + channel_name)
channel_parameters = get_channel_parameters(channel_name)
@@ -27,6 +27,7 @@ def is_enabled(channel_name):
def get_channel_parameters(channel_name):
from core import filetools
global dict_channels_parameters
if channel_name not in dict_channels_parameters:
@@ -35,20 +36,22 @@ def get_channel_parameters(channel_name):
# logger.debug(channel_parameters)
if channel_parameters:
# cambios de nombres y valores por defecto
channel_parameters["title"] = channel_parameters.pop("name") + (' [DEPRECATED]' if channel_parameters.has_key('deprecated') and channel_parameters['deprecated'] else '')
channel_parameters["title"] = channel_parameters.pop("name") + (' [DEPRECATED]' if 'deprecated' in channel_parameters and channel_parameters['deprecated'] else '')
channel_parameters["channel"] = channel_parameters.pop("id")
# si no existe el key se declaran valor por defecto para que no de fallos en las funciones que lo llaman
channel_parameters["adult"] = channel_parameters.get("adult", False)
logger.info(channel_parameters["adult"])
if channel_parameters["adult"]:
channel_parameters["update_url"] = channel_parameters.get("update_url", DEFAULT_UPDATE_URL+'porn/')
channel_parameters["update_url"] = channel_parameters.get("update_url",
DEFAULT_UPDATE_URL + 'porn/')
else:
channel_parameters["update_url"] = channel_parameters.get("update_url", DEFAULT_UPDATE_URL)
channel_parameters["language"] = channel_parameters.get("language", ["all"])
## channel_parameters["adult"] = channel_parameters.get("adult", False)
## channel_parameters["adult"] = channel_parameters.get("adult", False)
channel_parameters["active"] = channel_parameters.get("active", False)
channel_parameters["include_in_global_search"] = channel_parameters.get("include_in_global_search", False)
channel_parameters["include_in_global_search"] = channel_parameters.get("include_in_global_search",
False)
channel_parameters["categories"] = channel_parameters.get("categories", list())
channel_parameters["thumbnail"] = channel_parameters.get("thumbnail", "")
@@ -57,57 +60,27 @@ def get_channel_parameters(channel_name):
# Imagenes: se admiten url y archivos locales dentro de "resources/images"
if channel_parameters.get("thumbnail") and "://" not in channel_parameters["thumbnail"]:
channel_parameters["thumbnail"] = os.path.join(remote_path, 'resources', "thumb", channel_parameters["thumbnail"])
channel_parameters["thumbnail"] = filetools.join(remote_path, "resources", "thumb", channel_parameters["thumbnail"])
if channel_parameters.get("banner") and "://" not in channel_parameters["banner"]:
channel_parameters["banner"] = os.path.join(remote_path, 'resources', "banner", channel_parameters["banner"])
channel_parameters["banner"] = filetools.join(remote_path, "resources", "banner", channel_parameters["banner"])
if channel_parameters.get("fanart") and "://" not in channel_parameters["fanart"]:
channel_parameters["fanart"] = os.path.join(remote_path, 'resources', "fanart", channel_parameters["fanart"])
channel_parameters["fanart"] = filetools.join(remote_path, "resources", channel_parameters["fanart"])
# Obtenemos si el canal tiene opciones de configuración
channel_parameters["has_settings"] = False
if 'settings' in channel_parameters:
# if not isinstance(channel_parameters['settings'], list):
# channel_parameters['settings'] = [channel_parameters['settings']]
# if "include_in_global_search" in channel_parameters['settings']:
# channel_parameters["include_in_global_search"] = channel_parameters['settings']
# ["include_in_global_search"].get('default', False)
#
# found = False
# for el in channel_parameters['settings']:
# for key in el.items():
# if 'include_in' not in key:
# channel_parameters["has_settings"] = True
# found = True
# break
# if found:
# break
channel_parameters['settings'] = get_default_settings(channel_name)
for s in channel_parameters['settings']:
if 'id' in s:
if s['id'] == "include_in_global_search":
channel_parameters["include_in_global_search"] = True
elif s['id'] == "filter_languages":
channel_parameters["filter_languages"] = s.get('lvalues',[])
channel_parameters["filter_languages"] = s.get('lvalues', [])
elif s['id'].startswith("include_in_"):
channel_parameters["has_settings"] = True
del channel_parameters['settings']
# Compatibilidad
if 'compatible' in channel_parameters:
# compatible python
python_compatible = True
if 'python' in channel_parameters["compatible"]:
import sys
python_condition = channel_parameters["compatible"]['python']
if sys.version_info < tuple(map(int, (python_condition.split(".")))):
python_compatible = False
channel_parameters["compatible"] = python_compatible
else:
channel_parameters["compatible"] = True
dict_channels_parameters[channel_name] = channel_parameters
else:
@@ -115,13 +88,12 @@ def get_channel_parameters(channel_name):
# lanzamos la excepcion y asi tenemos los valores básicos
raise Exception
except Exception, ex:
except Exception as ex:
logger.error(channel_name + ".json error \n%s" % ex)
channel_parameters = dict()
channel_parameters["channel"] = ""
channel_parameters["adult"] = False
channel_parameters['active'] = False
channel_parameters["compatible"] = True
channel_parameters["language"] = ""
channel_parameters["update_url"] = DEFAULT_UPDATE_URL
return channel_parameters
@@ -131,25 +103,26 @@ def get_channel_parameters(channel_name):
def get_channel_json(channel_name):
# logger.info("channel_name=" + channel_name)
import filetools
from core import filetools
channel_json = None
try:
channel_path = filetools.join(config.get_runtime_path(), "channels", channel_name + ".json")
if not os.path.isfile(channel_path):
if not filetools.isfile(channel_path):
channel_path = filetools.join(config.get_runtime_path(), 'channels', "porn", channel_name + ".json")
if not os.path.isfile(channel_path):
if not filetools.isfile(channel_path):
channel_path = filetools.join(config.get_runtime_path(), "specials", channel_name + ".json")
if not os.path.isfile(channel_path):
if not filetools.isfile(channel_path):
channel_path = filetools.join(config.get_runtime_path(), "servers", channel_name + ".json")
if not os.path.isfile(channel_path):
channel_path = filetools.join(config.get_runtime_path(), "servers", "debriders", channel_name + ".json")
if not filetools.isfile(channel_path):
channel_path = filetools.join(config.get_runtime_path(), "servers", "debriders",
channel_name + ".json")
if filetools.isfile(channel_path):
# logger.info("channel_data=" + channel_path)
channel_json = jsontools.load(filetools.read(channel_path))
# logger.info("channel_json= %s" % channel_json)
except Exception, ex:
except Exception as ex:
template = "An exception of type %s occured. Arguments:\n%r"
message = template % (type(ex).__name__, ex.args)
logger.error(" %s" % message)
@@ -174,6 +147,7 @@ def get_channel_controls_settings(channel_name):
return list_controls, dict_settings
def get_lang(channel_name):
channel = __import__('channels.%s' % channel_name, fromlist=["channels.%s" % channel_name])
list_language = [config.get_localized_string(70522)]
@@ -199,16 +173,17 @@ def get_lang(channel_name):
list_language.append(lang)
return list_language
def get_default_settings(channel_name):
import filetools
from core import filetools
default_path = filetools.join(config.get_runtime_path(), 'default_channel_settings' + '.json')
default_file = jsontools.load(filetools.read(default_path))
channel_path = filetools.join(config.get_runtime_path(),'channels',channel_name + '.json')
adult_path = filetools.join(config.get_runtime_path(),'channels', 'porn', channel_name + '.json')
channel_path = filetools.join(config.get_runtime_path(), 'channels', channel_name + '.json')
adult_path = filetools.join(config.get_runtime_path(), 'channels', 'porn', channel_name + '.json')
# from core.support import dbg; dbg()
if os.path.exists(channel_path) or os.path.exists(adult_path):
if filetools.exists(channel_path) or filetools.exists(adult_path):
default_controls = default_file['settings']
default_controls_renumber = default_file['renumber']
channel_json = get_channel_json(channel_name)
@@ -217,33 +192,43 @@ def get_default_settings(channel_name):
channel_language = channel_json['language']
channel_controls = channel_json['settings']
categories = channel_json['categories']
not_active = channel_json['not_active'] if channel_json.has_key('not_active') else []
default_off = channel_json['default_off'] if channel_json.has_key('default_off') else []
not_active = channel_json['not_active'] if 'not_active' in channel_json else []
default_off = channel_json['default_off'] if 'default_off' in channel_json else []
# Apply default configurations if they do not exist
for control in default_controls:
if control['id'] not in str(channel_controls):
if 'include_in_newest' in control['id'] and 'include_in_newest' not in not_active and control['id'] not in not_active:
if 'include_in_newest' in control['id'] and 'include_in_newest' not in not_active and control[
'id'] not in not_active:
label = control['id'].split('_')
label = label[-1]
if label == 'peliculas':
if 'movie' in categories:
control['label'] = config.get_localized_string(70727) + ' - ' + config.get_localized_string(30122)
control['default'] = False if ('include_in_newest' in default_off) or ('include_in_newest_peliculas' in default_off) else True
control['label'] = config.get_localized_string(70727) + ' - ' + config.get_localized_string(
30122)
control['default'] = False if ('include_in_newest' in default_off) or (
'include_in_newest_peliculas' in default_off) else True
channel_controls.append(control)
else: pass
else:
pass
elif label == 'series':
if 'tvshow' in categories:
control['label'] = config.get_localized_string(70727) + ' - ' + config.get_localized_string(30123)
control['default'] = False if ('include_in_newest' in default_off) or ('include_in_newest_series' in default_off) else True
control['label'] = config.get_localized_string(70727) + ' - ' + config.get_localized_string(
30123)
control['default'] = False if ('include_in_newest' in default_off) or (
'include_in_newest_series' in default_off) else True
channel_controls.append(control)
else: pass
else:
pass
elif label == 'anime':
if 'anime' in categories:
control['label'] = config.get_localized_string(70727) + ' - ' + config.get_localized_string(30124)
control['default'] = False if ('include_in_newest' in default_off) or ('include_in_newest_anime' in default_off) else True
control['label'] = config.get_localized_string(70727) + ' - ' + config.get_localized_string(
30124)
control['default'] = False if ('include_in_newest' in default_off) or (
'include_in_newest_anime' in default_off) else True
channel_controls.append(control)
else: pass
else:
pass
else:
control['label'] = config.get_localized_string(70727) + ' - ' + label.capitalize()
@@ -259,13 +244,15 @@ def get_default_settings(channel_name):
for control in default_controls_renumber:
if control['id'] not in str(channel_controls):
channel_controls.append(control)
else: pass
else:
pass
else:
return get_channel_json(channel_name).get('settings', list())
return channel_controls
def get_channel_setting(name, channel, default=None):
from core import filetools
"""
Retorna el valor de configuracion del parametro solicitado.
@@ -288,13 +275,15 @@ def get_channel_setting(name, channel, default=None):
@rtype: any
"""
file_settings = os.path.join(config.get_data_path(), "settings_channels", channel + "_data.json")
file_settings = filetools.join(config.get_data_path(), "settings_channels", channel + "_data.json")
dict_settings = {}
dict_file = {}
if os.path.exists(file_settings):
if channel not in ['trakt']: def_settings = get_default_settings(channel)
if filetools.exists(file_settings):
# Obtenemos configuracion guardada de ../settings/channel_data.json
try:
dict_file = jsontools.load(open(file_settings, "rb").read())
dict_file = jsontools.load(filetools.read(file_settings))
if isinstance(dict_file, dict) and 'settings' in dict_file:
dict_settings = dict_file['settings']
except EnvironmentError:
@@ -313,9 +302,7 @@ def get_channel_setting(name, channel, default=None):
dict_file['settings'] = dict_settings
# Creamos el archivo ../settings/channel_data.json
json_data = jsontools.dump(dict_file)
try:
open(file_settings, "wb").write(json_data)
except EnvironmentError:
if not filetools.write(file_settings, json_data, silent=True):
logger.error("ERROR al salvar el archivo: %s" % file_settings)
# Devolvemos el valor del parametro local 'name' si existe, si no se devuelve default
@@ -323,7 +310,7 @@ def get_channel_setting(name, channel, default=None):
def set_channel_setting(name, value, channel):
import filetools
from core import filetools
"""
Fija el valor de configuracion del parametro indicado.
@@ -346,36 +333,22 @@ def set_channel_setting(name, value, channel):
"""
# Creamos la carpeta si no existe
if not os.path.exists(os.path.join(config.get_data_path(), "settings_channels")):
os.mkdir(os.path.join(config.get_data_path(), "settings_channels"))
if not filetools.exists(filetools.join(config.get_data_path(), "settings_channels")):
filetools.mkdir(filetools.join(config.get_data_path(), "settings_channels"))
file_settings = os.path.join(config.get_data_path(), "settings_channels", channel + "_data.json")
file_settings = filetools.join(config.get_data_path(), "settings_channels", channel + "_data.json")
dict_settings = {}
if channel not in ['trakt']: def_settings = get_default_settings(channel)
dict_file = None
if os.path.exists(file_settings):
if filetools.exists(file_settings):
# Obtenemos configuracion guardada de ../settings/channel_data.json
try:
dict_file = jsontools.load(open(file_settings, "r").read())
dict_file = jsontools.load(filetools.read(file_settings))
dict_settings = dict_file.get('settings', {})
except EnvironmentError:
logger.error("ERROR al leer el archivo: %s" % file_settings)
if os.path.isfile(filetools.join(config.get_runtime_path(), "channels", channel + ".json")):
# delete unused Settings
def_keys = []
del_keys = []
for key in def_settings:
def_keys.append(key['id'])
for key in dict_settings:
if key not in def_keys:
del_keys.append(key)
for key in del_keys:
del dict_settings[key]
dict_settings[name] = value
# comprobamos si existe dict_file y es un diccionario, sino lo creamos
@@ -385,10 +358,8 @@ def set_channel_setting(name, value, channel):
dict_file['settings'] = dict_settings
# Creamos el archivo ../settings/channel_data.json
try:
json_data = jsontools.dump(dict_file)
open(file_settings, "w").write(json_data)
except EnvironmentError:
json_data = jsontools.dump(dict_file)
if not filetools.write(file_settings, json_data, silent=True):
logger.error("ERROR al salvar el archivo: %s" % file_settings)
return None
+4 -4
View File
@@ -20,8 +20,8 @@ metodos:
from __future__ import division
from future import standard_library
standard_library.install_aliases()
from future.builtins import range
from future.builtins import object
from builtins import range
from builtins import object
from past.utils import old_div
#from builtins import str
import sys
@@ -243,7 +243,7 @@ class Downloader(object):
# Abrimos en modo "a+" para que cree el archivo si no existe, luego en modo "r+b" para poder hacer seek()
self.file = filetools.file_open(filetools.join(self._path, self._filename), "a+", vfs=VFS)
if self.file: self.file.close()
if self.file: self.file.close()
self.file = filetools.file_open(filetools.join(self._path, self._filename), "r+b", vfs=VFS)
if not self.file:
return
@@ -258,7 +258,7 @@ class Downloader(object):
self.__get_download_info__()
try:
logger.info("Initialized Download: Parts: %s | Path: %s | Archive: %s | Size: %s" % \
logger.info("Descarga inicializada: Partes: %s | Ruta: %s | Archivo: %s | Tamaño: %s" % \
(str(len(self._download_info["parts"])), self._pathencode('utf-8'), \
self._filenameencode('utf-8'), str(self._download_info["size"])))
except:
+15 -9
View File
@@ -110,6 +110,8 @@ def limpia_nombre_excepto_1(s):
stripped = ''.join(c for c in s if c in validchars)
# Convierte a iso
s = stripped.encode("iso-8859-1")
if PY3:
s = s.decode('utf-8')
return s
@@ -129,7 +131,7 @@ def getfilefromtitle(url, title):
logger.info("platform=" + plataforma)
# nombrefichero = xbmc.makeLegalFilename(title + url[-4:])
from . import scrapertools
from core import scrapertools
nombrefichero = title + scrapertools.get_filename_from_url(url)[-4:]
logger.info("filename=%s" % nombrefichero)
@@ -169,7 +171,10 @@ def downloadbest(video_urls, title, continuar=False):
for elemento in invertida:
# videotitle = elemento[0]
url = elemento[1]
logger.info("Downloading option " + title + " " + url.encode('ascii', 'ignore'))
if not PY3:
logger.info("Downloading option " + title + " " + url.encode('ascii', 'ignore'))
else:
logger.info("Downloading option " + title + " " + url.encode('ascii', 'ignore').decode('utf-8'))
# Calcula el fichero donde debe grabar
try:
@@ -621,7 +626,7 @@ def downloadfileGzipped(url, pathfichero):
break
except:
reintentos += 1
logger.info("ERROR in block download, retry %dd" % reintentos)
logger.info("ERROR in block download, retry %d" % reintentos)
for line in sys.exc_info():
logger.error("%s" % line)
@@ -660,7 +665,7 @@ def GetTitleFromFile(title):
# Imprime en el log lo que va a descartar
logger.info("title=" + title)
plataforma = config.get_system_platform()
logger.info("platform=" + plataforma)
logger.info("plataform=" + plataforma)
# nombrefichero = xbmc.makeLegalFilename(title + url[-4:])
nombrefichero = title
@@ -678,7 +683,7 @@ def downloadIfNotModifiedSince(url, timestamp):
# Convierte la fecha a GMT
fecha_formateada = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(timestamp))
logger.info("DateFormat=%s" % fecha_formateada)
logger.info("fechaFormateada=%s" % fecha_formateada)
# Comprueba si ha cambiado
inicio = time.clock()
@@ -700,11 +705,11 @@ def downloadIfNotModifiedSince(url, timestamp):
except urllib.error.URLError as e:
# Si devuelve 304 es que no ha cambiado
if hasattr(e, 'code'):
logger.info("HTTP response code: %d" % e.code)
logger.info("HTTP response code : %d" % e.code)
if e.code == 304:
logger.info("It has not changed")
updated = False
# Agarra los errores con codigo de respuesta del servidor externo solicitado
# Agarra los errores con codigo de respuesta del servidor externo solicitado
else:
for line in sys.exc_info():
logger.error("%s" % line)
@@ -814,6 +819,7 @@ def download_all_episodes(item, channel, first_episode="", preferred_server="vid
for mirror_item in mirrors_itemlist:
logger.info("mirror=" + mirror_item.title)
if "(Italiano)" in mirror_item.title:
idioma = "(Italiano)"
codigo_idioma = "it"
@@ -885,8 +891,8 @@ def download_all_episodes(item, channel, first_episode="", preferred_server="vid
def episodio_ya_descargado(show_title, episode_title):
from . import scrapertools
ficheros = os.listdir(".")
from core import scrapertools
ficheros = filetools.listdir(".")
for fichero in ficheros:
# logger.info("fichero="+fichero)
+41 -42
View File
@@ -87,7 +87,7 @@ def encode(path, _samba=False):
if scrapertools.find_single_match(path, '(^\w+:\/\/)') or _samba:
path = path.encode("utf-8", "ignore")
else:
if fs_encoding:
if fs_encoding and not PY3:
path = path.encode(fs_encoding, "ignore")
return path
@@ -133,13 +133,13 @@ def read(path, linea_inicio=0, total_lineas=None, whence=0, silent=False, vfs=Tr
try:
linea_inicio = int(linea_inicio)
except:
logger.error('Read: ERROR de linea_inicio: %s' % str(linea_inicio))
logger.error('Read: Start_line ERROR: %s' % str(linea_inicio))
linea_inicio = 0
if total_lineas != None and not isinstance(total_lineas, int):
try:
total_lineas = int(total_lineas)
except:
logger.error('Read: ERROR de total_lineas: %s' % str(total_lineas))
logger.error('Read: ERROR of total_lineas: %s' % str(total_lineas))
total_lineas = None
if xbmc_vfs and vfs:
if not exists(path): return False
@@ -151,7 +151,7 @@ def read(path, linea_inicio=0, total_lineas=None, whence=0, silent=False, vfs=Tr
except:
return False
f.seek(linea_inicio, whence)
logger.debug('POSICIÓN de comienzo de lectura, tell(): %s' % f.seek(0, 1))
logger.debug('POSITION of beginning of reading,, tell(): %s' % f.seek(0, 1))
if total_lineas == None:
total_lineas = 0
data = f.read(total_lineas)
@@ -169,15 +169,15 @@ def read(path, linea_inicio=0, total_lineas=None, whence=0, silent=False, vfs=Tr
f.close()
except:
if not silent:
logger.error("ERROR al leer el archivo: %s" % path)
logger.error("ERROR reading file: %s" % path)
logger.error(traceback.format_exc())
return False
else:
if not PY3:
return "".join(data)
return unicode("".join(data))
else:
return b"".join(data)
return unicode(b"".join(data))
def write(path, data, mode="wb", silent=False, vfs=True):
@@ -226,20 +226,20 @@ def file_open(path, mode="r", silent=False, vfs=True):
if xbmc_vfs and vfs:
if 'r' in mode and '+' in mode:
mode = mode.replace('r', 'w').replace('+', '')
logger.debug('Open MODE cambiado a: %s' % mode)
logger.debug('Open MODE changed to: %s' % mode)
if 'a' in mode:
mode = mode.replace('a', 'w').replace('+', '')
logger.debug('Open MODE cambiado a: %s' % mode)
logger.debug('Open MODE changed to: %s' % mode)
return xbmcvfs.File(path, mode)
elif path.lower().startswith("smb://"):
return samba.smb_open(path, mode)
else:
return open(path, mode)
except:
logger.error("ERROR al abrir el archivo: %s, %s" % (path, mode))
logger.error("ERROR when opening file: %s, %s" % (path, mode))
if not silent:
logger.error(traceback.format_exc())
platformtools.dialog_notification("Error al abrir", path)
platformtools.dialog_notification("Error Opening", path)
return False
@@ -258,7 +258,7 @@ def file_stat(path, silent=False, vfs=True):
return xbmcvfs.Stat(path)
raise
except:
logger.error("File_Stat no soportado: %s" % path)
logger.error("File_Stat not supported: %s" % path)
if not silent:
logger.error(traceback.format_exc())
return False
@@ -283,9 +283,9 @@ def rename(path, new_name, silent=False, strict=False, vfs=True):
dest = encode(join(dirname(path_end), new_name))
result = xbmcvfs.rename(path, dest)
if not result and not strict:
logger.error("ERROR al RENOMBRAR el archivo: %s. Copiando y borrando" % path)
logger.error("ERROR RENAME file: %s. Copying and deleting" % path)
if not silent:
dialogo = platformtools.dialog_progress("Copiando archivo", "")
dialogo = platformtools.dialog_progress("Copying file", "")
result = xbmcvfs.copy(path, dest)
if not result:
return False
@@ -298,10 +298,10 @@ def rename(path, new_name, silent=False, strict=False, vfs=True):
new_name = encode(new_name, False)
os.rename(path, os.path.join(os.path.dirname(path), new_name))
except:
logger.error("ERROR al renombrar el archivo: %s" % path)
logger.error("ERROR when renaming the file: %s" % path)
if not silent:
logger.error(traceback.format_exc())
platformtools.dialog_notification("Error al renombrar", path)
platformtools.dialog_notification("Error renaming", path)
return False
else:
return True
@@ -324,9 +324,9 @@ def move(path, dest, silent=False, strict=False, vfs=True):
dest = encode(dest)
result = xbmcvfs.rename(path, dest)
if not result and not strict:
logger.error("ERROR al MOVER el archivo: %s. Copiando y borrando" % path)
logger.error("ERROR when MOVING the file: %s. Copying and deleting" % path)
if not silent:
dialogo = platformtools.dialog_progress("Copiando archivo", "")
dialogo = platformtools.dialog_progress("Copying file", "")
result = xbmcvfs.copy(path, dest)
if not result:
return False
@@ -349,7 +349,7 @@ def move(path, dest, silent=False, strict=False, vfs=True):
dialogo = platformtools.dialog_progress("Copiando archivo", "")
return copy(path, dest) == True and remove(path) == True
except:
logger.error("ERROR al mover el archivo: %s a %s" % (path, dest))
logger.error("ERROR when moving file: %s to %s" % (path, dest))
if not silent:
logger.error(traceback.format_exc())
return False
@@ -376,7 +376,7 @@ def copy(path, dest, silent=False, vfs=True):
if not silent:
dialogo = platformtools.dialog_progress("Copiando archivo", "")
return bool(xbmcvfs.copy(path, dest))
fo = file_open(path, "rb")
fd = file_open(dest, "wb")
if fo and fd:
@@ -398,7 +398,7 @@ def copy(path, dest, silent=False, vfs=True):
if not silent:
dialogo.close()
except:
logger.error("ERROR al copiar el archivo: %s" % path)
logger.error("ERROR when copying the file: %s" % path)
if not silent:
logger.error(traceback.format_exc())
return False
@@ -420,13 +420,13 @@ def exists(path, silent=False, vfs=True):
result = bool(xbmcvfs.exists(path))
if not result and not path.endswith('/') and not path.endswith('\\'):
result = bool(xbmcvfs.exists(join(path, ' ').rstrip()))
return result
return result
elif path.lower().startswith("smb://"):
return samba.exists(path)
else:
return os.path.exists(path)
except:
logger.error("ERROR al comprobar la ruta: %s" % path)
logger.error("ERROR when checking the path: %s" % path)
if not silent:
logger.error(traceback.format_exc())
return False
@@ -458,7 +458,7 @@ def isfile(path, silent=False, vfs=True):
else:
return os.path.isfile(path)
except:
logger.error("ERROR al comprobar el archivo: %s" % path)
logger.error("ERROR when checking file: %s" % path)
if not silent:
logger.error(traceback.format_exc())
return False
@@ -490,7 +490,7 @@ def isdir(path, silent=False, vfs=True):
else:
return os.path.isdir(path)
except:
logger.error("ERROR al comprobar el directorio: %s" % path)
logger.error("ERROR when checking the directory: %s" % path)
if not silent:
logger.error(traceback.format_exc())
return False
@@ -517,7 +517,7 @@ def getsize(path, silent=False, vfs=True):
else:
return os.path.getsize(path)
except:
logger.error("ERROR al obtener el tamaño: %s" % path)
logger.error("ERROR when getting the size: %s" % path)
if not silent:
logger.error(traceback.format_exc())
return long(0)
@@ -540,10 +540,10 @@ def remove(path, silent=False, vfs=True):
else:
os.remove(path)
except:
logger.error("ERROR al eliminar el archivo: %s" % path)
logger.error("ERROR deleting file: %s" % path)
if not silent:
logger.error(traceback.format_exc())
platformtools.dialog_notification("Error al eliminar el archivo", path)
platformtools.dialog_notification("ERROR deleting file", path)
return False
else:
return True
@@ -580,10 +580,10 @@ def rmdirtree(path, silent=False, vfs=True):
import shutil
shutil.rmtree(path, ignore_errors=True)
except:
logger.error("ERROR al eliminar el directorio: %s" % path)
logger.error("ERROR deleting directory: %s" % path)
if not silent:
logger.error(traceback.format_exc())
platformtools.dialog_notification("Error al eliminar el directorio", path)
platformtools.dialog_notification("ERROR deleting directory", path)
return False
else:
return not exists(path)
@@ -608,10 +608,10 @@ def rmdir(path, silent=False, vfs=True):
else:
os.rmdir(path)
except:
logger.error("ERROR al eliminar el directorio: %s" % path)
logger.error("ERROR deleting directory: %s" % path)
if not silent:
logger.error(traceback.format_exc())
platformtools.dialog_notification("Error al eliminar el directorio", path)
platformtools.dialog_notification("ERROR deleting directory", path)
return False
else:
return True
@@ -641,10 +641,10 @@ def mkdir(path, silent=False, vfs=True):
else:
os.mkdir(path)
except:
logger.error("ERROR al crear el directorio: %s" % path)
logger.error("ERROR when creating directory: %s" % path)
if not silent:
logger.error(traceback.format_exc())
platformtools.dialog_notification("Error al crear el directorio", path)
platformtools.dialog_notification("ERROR when creating directory", path)
return False
else:
return True
@@ -724,7 +724,7 @@ def listdir(path, silent=False, vfs=True):
else:
return decode(os.listdir(path))
except:
logger.error("ERROR al leer el directorio: %s" % path)
logger.error("ERROR when reading the directory: %s" % path)
if not silent:
logger.error(traceback.format_exc())
return False
@@ -740,14 +740,13 @@ def join(*paths):
list_path = []
if paths[0].startswith("/"):
list_path.append("")
for path in paths:
if path:
if xbmc_vfs:
if xbmc_vfs and type(path) != str:
path = encode(path)
list_path += path.replace("\\", "/").strip("/").split("/")
if scrapertools.find_single_match(paths[0], '(^\w+:\/\/)'):
if scrapertools.find_single_match(paths[0], r'(^\w+:\/\/)'):
return str("/".join(list_path))
else:
return str(os.sep.join(list_path))
@@ -812,8 +811,8 @@ def remove_tags(title):
return title_without_tags
else:
return title
def remove_smb_credential(path):
"""
devuelve el path sin contraseña/usuario para paths de SMB
@@ -823,10 +822,10 @@ def remove_smb_credential(path):
@rtype: str
"""
logger.info()
if not scrapertools.find_single_match(path, '(^\w+:\/\/)'):
return path
protocol = scrapertools.find_single_match(path, '(^\w+:\/\/)')
path_without_credentials = scrapertools.find_single_match(path, '^\w+:\/\/(?:[^;\n]+;)?(?:[^:@\n]+[:|@])?(?:[^@\n]+@)?(.*?$)')
+8 -6
View File
@@ -31,7 +31,7 @@ cookies_file = os.path.join(config.get_data_path(), "cookies.dat")
default_headers = dict()
default_headers["User-Agent"] = "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"
default_headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
default_headers["Accept-Language"] = "es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3"
default_headers["Accept-Language"] = "it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3"
default_headers["Accept-Charset"] = "UTF-8"
default_headers["Accept-Encoding"] = "gzip"
@@ -255,13 +255,11 @@ def downloadpage(url, **opt):
domain = urlparse.urlparse(url).netloc
CF = False
if domain in ['www.guardaserie.media', 'casacinema.space', 'wstream.video', 'akvideo.stream', 'backin.net',
'dreamsub.stream', 'altadefinizione-nuovo.link', 'ilgeniodellostreaming.si', 'www.piratestreaming.gratis']:
'dreamsub.stream', 'altadefinizione-nuovo.link', 'ilgeniodellostreaming.si', 'www.piratestreaming.gratis',
'altadefinizione.style']:
from lib import cloudscraper
session = cloudscraper.create_scraper()
CF = True
elif opt.get('session', False):
session = opt['session'] # same session to speed up search
logger.info('same session')
else:
from lib import requests
session = requests.session()
@@ -360,6 +358,7 @@ def downloadpage(url, **opt):
timeout=opt['timeout'])
except Exception as e:
from lib import requests
req = requests.Response()
if not opt.get('ignore_response_code', False) and not proxy_data.get('stat', ''):
response['data'] = ''
response['sucess'] = False
@@ -371,7 +370,6 @@ def downloadpage(url, **opt):
show_infobox(info_dict)
return type('HTTPResponse', (), response)
else:
req = requests.Response()
req.status_code = str(e)
else:
@@ -384,6 +382,10 @@ def downloadpage(url, **opt):
response['data'] = req.content
response['url'] = req.url
if type(response['data']) != str:
response['data'] = response['data'].decode('UTF-8')
if not response['data']:
response['data'] = ''
try:
+54 -26
View File
@@ -3,12 +3,23 @@
# Item is the object we use for representing data
# --------------------------------------------------------------------------------
#from builtins import str
from future.builtins import object
import sys
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
if PY3:
#from future import standard_library
#standard_library.install_aliases()
import urllib.parse as urllib # Es muy lento en PY2. En PY3 es nativo
from html.parser import HTMLParser
else:
import urllib # Usamos el nativo de PY2 que es más rápido
from HTMLParser import HTMLParser
import base64
import copy
import os
import urllib
from HTMLParser import HTMLParser
from core import jsontools as json
@@ -58,12 +69,12 @@ class InfoLabels(dict):
elif key == 'code':
code = []
# Añadir imdb_id al listado de codigos
if 'imdb_id' in super(InfoLabels, self).keys() and super(InfoLabels, self).__getitem__('imdb_id'):
if 'imdb_id' in list(super(InfoLabels, self).keys()) and super(InfoLabels, self).__getitem__('imdb_id'):
code.append(super(InfoLabels, self).__getitem__('imdb_id'))
# Completar con el resto de codigos
for scr in ['tmdb_id', 'tvdb_id', 'noscrap_id']:
if scr in super(InfoLabels, self).keys() and super(InfoLabels, self).__getitem__(scr):
if scr in list(super(InfoLabels, self).keys()) and super(InfoLabels, self).__getitem__(scr):
value = "%s%s" % (scr[:-2], super(InfoLabels, self).__getitem__(scr))
code.append(value)
@@ -78,21 +89,21 @@ class InfoLabels(dict):
elif key == 'mediatype':
# "list", "movie", "tvshow", "season", "episode"
if 'tvshowtitle' in super(InfoLabels, self).keys() \
if 'tvshowtitle' in list(super(InfoLabels, self).keys()) \
and super(InfoLabels, self).__getitem__('tvshowtitle') != "":
if 'episode' in super(InfoLabels, self).keys() and super(InfoLabels, self).__getitem__('episode') != "":
if 'episode' in list(super(InfoLabels, self).keys()) and super(InfoLabels, self).__getitem__('episode') != "":
return 'episode'
if 'episodeName' in super(InfoLabels, self).keys() \
if 'episodeName' in list(super(InfoLabels, self).keys()) \
and super(InfoLabels, self).__getitem__('episodeName') != "":
return 'episode'
if 'season' in super(InfoLabels, self).keys() and super(InfoLabels, self).__getitem__('season') != "":
if 'season' in list(super(InfoLabels, self).keys()) and super(InfoLabels, self).__getitem__('season') != "":
return 'season'
else:
return 'tvshow'
elif 'title' in super(InfoLabels, self).keys() and super(InfoLabels, self).__getitem__('title') != "":
elif 'title' in list(super(InfoLabels, self).keys()) and super(InfoLabels, self).__getitem__('title') != "":
return 'movie'
else:
@@ -104,7 +115,7 @@ class InfoLabels(dict):
def tostring(self, separador=', '):
ls = []
dic = dict(super(InfoLabels, self).items())
dic = dict(list(super(InfoLabels, self).items()))
for i in sorted(dic.items()):
i_str = str(i)[1:-1]
@@ -158,6 +169,7 @@ class Item(object):
Función llamada al modificar cualquier atributo del item, modifica algunos atributos en función de los datos
modificados.
"""
if PY3: name = self.toutf8(name)
value = self.toutf8(value)
if name == "__dict__":
for key in value:
@@ -313,9 +325,13 @@ class Item(object):
valor = dic[var].tostring(',\r\t\t')
else:
valor = dic[var].tostring()
elif PY3 and isinstance(dic[var], bytes):
valor = "'%s'" % dic[var].decode('utf-8')
else:
valor = str(dic[var])
if PY3 and isinstance(var, bytes):
var = var.decode('utf-8')
ls.append(var + "= " + valor)
return separator.join(ls)
@@ -327,12 +343,12 @@ class Item(object):
Uso: url = item.tourl()
"""
dump = json.dump(self.__dict__)
dump = json.dump(self.__dict__).encode("utf8")
# if empty dict
if not dump:
# set a str to avoid b64encode fails
dump = ""
return urllib.quote(base64.b64encode(dump))
dump = "".encode("utf8")
return str(urllib.quote(base64.b64encode(dump)))
def fromurl(self, url):
"""
@@ -367,6 +383,7 @@ class Item(object):
return self
def tojson(self, path=""):
from core import filetools
"""
Crea un JSON a partir del item, para guardar archivos de favoritos, lista de descargas, etc...
Si se especifica un path, te lo guarda en la ruta especificada, si no, devuelve la cadena json
@@ -377,11 +394,13 @@ class Item(object):
@type path: str
"""
if path:
open(path, "wb").write(json.dump(self.__dict__))
#open(path, "wb").write(json.dump(self.__dict__))
res = filetools.write(path, json.dump(self.__dict__))
else:
return json.dump(self.__dict__)
def fromjson(self, json_item=None, path=""):
from core import filetools
"""
Genera un item a partir de un archivo JSON
Si se especifica un path, lee directamente el archivo, si no, lee la cadena de texto pasada.
@@ -394,8 +413,9 @@ class Item(object):
@type path: str
"""
if path:
if os.path.exists(path):
json_item = open(path, "rb").read()
if filetools.exists(path):
#json_item = open(path, "rb").read()
json_item = filetools.read(path)
else:
json_item = {}
@@ -436,6 +456,8 @@ class Item(object):
unicode_title = unicode(value, "utf8", "ignore")
return HTMLParser().unescape(unicode_title).encode("utf8")
except:
if PY3 and isinstance(value, bytes):
value = value.decode("utf8")
return value
def toutf8(self, *args):
@@ -447,13 +469,18 @@ class Item(object):
else:
value = self.__dict__
if type(value) == unicode:
return value.encode("utf8")
if isinstance(value, unicode):
value = value.encode("utf8")
if PY3: value = value.decode("utf8")
return value
elif type(value) == str:
elif not PY3 and isinstance(value, str):
return unicode(value, "utf8", "ignore").encode("utf8")
elif type(value) == list:
elif PY3 and isinstance(value, bytes):
return value.decode("utf8")
elif isinstance(value, list):
for x, key in enumerate(value):
value[x] = self.toutf8(value[x])
return value
@@ -461,11 +488,12 @@ class Item(object):
elif isinstance(value, dict):
newdct = {}
for key in value:
v = self.toutf8(value[key])
if type(key) == unicode:
key = key.encode("utf8")
value_unc = self.toutf8(value[key])
key_unc = self.toutf8(key)
#if isinstance(key, unicode):
# key = key.encode("utf8")
newdct[key] = v
newdct[key_unc] = value_unc
if len(args) > 0:
if isinstance(value, InfoLabels):
+29 -21
View File
@@ -10,24 +10,28 @@ from platformcode import logger
try:
import json
except:
logger.info("json incluido en el interprete **NO** disponible")
logger.info("json included in the interpreter **NOT** available")
try:
import simplejson as json
except:
logger.info("simplejson incluido en el interprete **NO** disponible")
logger.info("simplejson included in the interpreter **NOT** available")
try:
from lib import simplejson as json
except:
logger.info("simplejson en el directorio lib **NO** disponible")
logger.error("No se ha encontrado un parser de JSON valido")
logger.info("simplejson in lib directory **NOT** available")
logger.error("A valid JSON parser was not found")
json = None
else:
logger.info("Usando simplejson en el directorio lib")
logger.info("Using simplejson in the lib directory")
else:
logger.info("Usando simplejson incluido en el interprete")
else:
logger.info("Usando json incluido en el interprete")
logger.info("Using simplejson included in the interpreter")
# ~ else:
# ~ logger.info("Usando json incluido en el interprete")
import sys
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
def load(*args, **kwargs):
@@ -37,7 +41,7 @@ def load(*args, **kwargs):
try:
value = json.loads(*args, **kwargs)
except:
logger.error("**NO** se ha podido cargar el JSON")
logger.error("**NOT** able to load the JSON")
logger.error(traceback.format_exc())
value = {}
@@ -46,12 +50,12 @@ def load(*args, **kwargs):
def dump(*args, **kwargs):
if not kwargs:
kwargs = {"indent": 4, "skipkeys": True, "sort_keys": True, "ensure_ascii": False}
kwargs = {"indent": 4, "skipkeys": True, "sort_keys": True, "ensure_ascii": True}
try:
value = json.dumps(*args, **kwargs)
except:
logger.error("**NO** se ha podido cargar el JSON")
logger.error("JSON could **NOT** be saved")
logger.error(traceback.format_exc())
value = ""
return value
@@ -59,11 +63,15 @@ def dump(*args, **kwargs):
def to_utf8(dct):
if isinstance(dct, dict):
return dict((to_utf8(key), to_utf8(value)) for key, value in dct.iteritems())
return dict((to_utf8(key), to_utf8(value)) for key, value in dct.items())
elif isinstance(dct, list):
return [to_utf8(element) for element in dct]
elif isinstance(dct, unicode):
return dct.encode('utf-8')
dct = dct.encode("utf8")
if PY3: dct = dct.decode("utf8")
return dct
elif PY3 and isinstance(dct, bytes):
return dct.decode('utf-8')
else:
return dct
@@ -124,18 +132,18 @@ def check_to_backup(data, fname, dict_data):
logger.info()
if not dict_data:
logger.error("Error al cargar el json del fichero %s" % fname)
logger.error("Error loading json from file %s" % fname)
if data != "":
# se crea un nuevo fichero
from core import filetools
title = filetools.write("%s.bk" % fname, data)
if title != "":
logger.error("Ha habido un error al guardar el fichero: %s.bk" % fname)
logger.error("There was an error saving the file: %s.bk" % fname)
else:
logger.debug("Se ha guardado una copia con el nombre: %s.bk" % fname)
logger.debug("A copy with the name has been saved: %s.bk" % fname)
else:
logger.debug("Está vacío el fichero: %s" % fname)
logger.debug("The file is empty: %s" % fname)
def update_node(dict_node, name_file, node, path=None):
@@ -175,18 +183,18 @@ def update_node(dict_node, name_file, node, path=None):
# es un dict
if dict_data:
if node in dict_data:
logger.debug(" existe el key %s" % node)
logger.debug(" the key exists %s" % node)
dict_data[node] = dict_node
else:
logger.debug(" NO existe el key %s" % node)
logger.debug(" The key does NOT exist %s" % node)
new_dict = {node: dict_node}
dict_data.update(new_dict)
else:
logger.debug(" NO es un dict")
logger.debug(" It is NOT a dict")
dict_data = {node: dict_node}
json_data = dump(dict_data)
result = filetools.write(fname, json_data)
except:
logger.error("No se ha podido actualizar %s" % fname)
logger.error("Could not update %s" % fname)
return result, json_data
+11 -6
View File
@@ -1,5 +1,10 @@
# -*- coding: utf-8 -*-
import sys
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
#from builtins import str
from core.item import InfoLabels
from platformcode import config, logger
from platformcode import platformtools
@@ -46,7 +51,7 @@ def find_and_set_infoLabels(item):
try:
scraper = __import__('core.%s' % scraper_actual, fromlist=["core.%s" % scraper_actual])
except ImportError:
exec "import core." + scraper_actual + " as scraper"
exec("import core." + scraper_actual + " as scraper")
except:
import traceback
logger.error(traceback.format_exc())
@@ -99,9 +104,9 @@ def find_and_set_infoLabels(item):
return True
# raise
elif list_opciones_cuadro[index] in scrapers_disponibles.values():
elif list_opciones_cuadro[index] in list(scrapers_disponibles.values()):
# Obtener el nombre del modulo del scraper
for k, v in scrapers_disponibles.items():
for k, v in list(scrapers_disponibles.items()):
if list_opciones_cuadro[index] == v:
if scrapers_disponibles[scraper_actual] not in list_opciones_cuadro:
list_opciones_cuadro.append(scrapers_disponibles[scraper_actual])
@@ -111,7 +116,7 @@ def find_and_set_infoLabels(item):
scraper = None
scraper = __import__('core.%s' % scraper_actual, fromlist=["core.%s" % scraper_actual])
except ImportError:
exec "import core." + scraper_actual + " as scraper_module"
exec("import core." + scraper_actual + " as scraper_module")
break
logger.error("Error al importar el modulo scraper %s" % scraper_actual)
@@ -175,7 +180,7 @@ def cuadro_completar(item):
if not dict_default[c[0]] or dict_default[c[0]] == 'None' or dict_default[c[0]] == 0:
dict_default[c[0]] = ''
elif isinstance(dict_default[c[0]], (int, float, long)):
elif isinstance(dict_default[c[0]], (int, float)) or (not PY3 and isinstance(dict_default[c[0]], (int, float, long))):
# Si es numerico lo convertimos en str
dict_default[c[0]] = str(dict_default[c[0]])
@@ -204,7 +209,7 @@ def callback_cuadro_completar(item, dict_values):
if dict_values.get("title", None):
# Adaptar dict_values a infoLabels validos
dict_values['mediatype'] = ['movie', 'tvshow'][dict_values['mediatype']]
for k, v in dict_values.items():
for k, v in list(dict_values.items()):
if k in dict_default and dict_default[k] == dict_values[k]:
del dict_values[k]
+80 -5
View File
@@ -1,17 +1,36 @@
# -*- coding: utf-8 -*-
# --------------------------------------------------------------------------------
# Scraper tools v2 for reading and processing web elements
# Scraper tools for reading and processing web elements
# --------------------------------------------------------------------------------
#from future import standard_library
#standard_library.install_aliases()
#from builtins import str
#from builtins import chr
import sys
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
import re
import time
import urlparse
# from core import httptools
from core.entities import html5
from platformcode import logger
# def get_header_from_response(url, header_to_get="", post=None, headers=None):
# header_to_get = header_to_get.lower()
# response = httptools.downloadpage(url, post=post, headers=headers, only_headers=True)
# return response.headers.get(header_to_get)
# def read_body_and_headers(url, post=None, headers=None, follow_redirects=False, timeout=None):
# response = httptools.downloadpage(url, post=post, headers=headers, follow_redirects=follow_redirects,
# timeout=timeout)
# return response.data, response.headers
def printMatches(matches):
i = 0
for match in matches:
@@ -89,7 +108,10 @@ def unescape(text):
else:
# named entity
try:
import htmlentitydefs
if PY3:
import html.entities as htmlentitydefs
else:
import htmlentitydefs
text = unichr(htmlentitydefs.name2codepoint[text[1:-1]]).encode("utf-8")
except KeyError:
logger.error("keyerror")
@@ -103,6 +125,50 @@ def unescape(text):
# Convierte los codigos html "&ntilde;" y lo reemplaza por "ñ" caracter unicode utf-8
# def decodeHtmlentities(string):
# string = entitiesfix(string)
# entity_re = re.compile("&(#?)(\d{1,5}|\w{1,8});")
# def substitute_entity(match):
# if PY3:
# from html.entities import name2codepoint as n2cp
# else:
# from htmlentitydefs import name2codepoint as n2cp
# ent = match.group(2)
# if match.group(1) == "#":
# return unichr(int(ent)).encode('utf-8')
# else:
# cp = n2cp.get(ent)
# if cp:
# return unichr(cp).encode('utf-8')
# else:
# return match.group()
# return entity_re.subn(substitute_entity, string)[0]
# def entitiesfix(string):
# # Las entidades comienzan siempre con el símbolo & , y terminan con un punto y coma ( ; ).
# string = string.replace("&aacute", "&aacute;")
# string = string.replace("&eacute", "&eacute;")
# string = string.replace("&iacute", "&iacute;")
# string = string.replace("&oacute", "&oacute;")
# string = string.replace("&uacute", "&uacute;")
# string = string.replace("&Aacute", "&Aacute;")
# string = string.replace("&Eacute", "&Eacute;")
# string = string.replace("&Iacute", "&Iacute;")
# string = string.replace("&Oacute", "&Oacute;")
# string = string.replace("&Uacute", "&Uacute;")
# string = string.replace("&uuml", "&uuml;")
# string = string.replace("&Uuml", "&Uuml;")
# string = string.replace("&ntilde", "&ntilde;")
# string = string.replace("&#191", "&#191;")
# string = string.replace("&#161", "&#161;")
# string = string.replace(";;", ";")
# return string
def htmlclean(cadena):
cadena = re.compile("<!--.*?-->", re.DOTALL).sub("", cadena)
@@ -292,8 +358,12 @@ def remove_show_from_title(title, show):
return title
# scrapertools.get_filename_from_url(media_url)[-4:]
def get_filename_from_url(url):
if PY3:
import urllib.parse as urlparse # Es muy lento en PY2. En PY3 es nativo
else:
import urlparse # Usamos el nativo de PY2 que es más rápido
parsed_url = urlparse.urlparse(url)
try:
filename = parsed_url.path
@@ -311,6 +381,11 @@ def get_filename_from_url(url):
def get_domain_from_url(url):
if PY3:
import urllib.parse as urlparse # Es muy lento en PY2. En PY3 es nativo
else:
import urlparse # Usamos el nativo de PY2 que es más rápido
parsed_url = urlparse.urlparse(url)
try:
filename = parsed_url.netloc
+96 -65
View File
@@ -3,18 +3,32 @@
# Server management
# --------------------------------------------------------------------------------
import os
from __future__ import division
from __future__ import absolute_import
import sys
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
if PY3:
#from future import standard_library
#standard_library.install_aliases()
import urllib.parse as urlparse # Es muy lento en PY2. En PY3 es nativo
else:
import urlparse # Usamos el nativo de PY2 que es más rápido
from future.builtins import range
from past.utils import old_div
import datetime
import re
import time
import filetools
import urlparse
from core import filetools
from core import httptools
from core import jsontools
from core.item import Item
from platformcode import config, logger
from platformcode import platformtools
# from servers.decrypters import zcrypt
from lib import unshortenit
dict_servers_parameters = {}
@@ -80,7 +94,7 @@ def get_servers_itemlist(itemlist, fnc=None, sort=False):
@type sort: bool
"""
# Recorre los servidores
for serverid in get_servers_list().keys():
for serverid in list(get_servers_list().keys()):
server_parameters = get_server_parameters(serverid)
# Recorre los patrones
@@ -105,18 +119,18 @@ def get_servers_itemlist(itemlist, fnc=None, sort=False):
item.url = url
# Eliminamos los servidores desactivados
itemlist = filter(lambda i: not i.server or is_server_enabled(i.server), itemlist)
#itemlist = filter(lambda i: not i.server or is_server_enabled(i.server), itemlist)
# Filtrar si es necesario
itemlist = filter_servers(itemlist)
for item in itemlist:
# Asignamos "directo" en caso de que el server no se encuentre en pelisalcarta
# Asignamos "directo" en caso de que el server no se encuentre en Alfa
if not item.server and item.url:
item.server = 'directo'
item.server = "directo"
if fnc:
item.title = fnc(item)
# Filtrar si es necesario
itemlist = filter_servers(itemlist)
# Ordenar segun favoriteslist si es necesario
if sort:
@@ -137,7 +151,8 @@ def findvideos(data, skip=False):
logger.info()
devuelve = []
skip = int(skip)
servers_list = get_servers_list().keys()
servers_list = list(get_servers_list().keys())
# Ordenar segun favoriteslist si es necesario
servers_list = sort_servers(servers_list)
@@ -145,8 +160,8 @@ def findvideos(data, skip=False):
# Ejecuta el findvideos en cada servidor activo
for serverid in servers_list:
if not is_server_enabled(serverid):
continue
'''if not is_server_enabled(serverid):
continue'''
if config.get_setting("filter_servers") == True and config.get_setting("black_list", server=serverid):
is_filter_servers = True
continue
@@ -167,6 +182,8 @@ def findvideosbyserver(data, serverid):
return []
server_parameters = get_server_parameters(serverid)
if not server_parameters["active"]:
return []
devuelve = []
if "find_videos" in server_parameters:
# Recorre los patrones
@@ -229,6 +246,8 @@ def resolve_video_urls_for_playing(server, url, video_password="", muestra_dialo
# Si el vídeo es "directo" o "local", no hay que buscar más
if server == "directo" or server == "local":
if isinstance(video_password, list):
return video_password, len(video_password) > 0, "<br/>".join(error_messages)
logger.info("Server: %s, la url es la buena" % server)
video_urls.append(["%s [%s]" % (urlparse.urlparse(url)[2][-4:], server), url])
@@ -309,7 +328,7 @@ def resolve_video_urls_for_playing(server, url, video_password="", muestra_dialo
# Muestra el progreso
if muestra_dialogo:
progreso.update((100 / len(opciones)) * opciones.index(opcion), config.get_localized_string(70180) % server_name)
progreso.update((old_div(100, len(opciones))) * opciones.index(opcion), config.get_localized_string(70180) % server_name)
# Modo free
if opcion == "free":
@@ -377,7 +396,7 @@ def get_server_name(serverid):
serverid = serverid.lower().split(".")[0]
# Obtenemos el listado de servers
server_list = get_servers_list().keys()
server_list = list(get_servers_list().keys())
# Si el nombre está en la lista
if serverid in server_list:
@@ -445,25 +464,25 @@ def get_server_parameters(server):
if server not in dict_servers_parameters:
try:
# Servers
if os.path.isfile(os.path.join(config.get_runtime_path(), "servers", server + ".json")):
path = os.path.join(config.get_runtime_path(), "servers", server + ".json")
if filetools.isfile(filetools.join(config.get_runtime_path(), "servers", server + ".json")):
path = filetools.join(config.get_runtime_path(), "servers", server + ".json")
# Debriders
elif os.path.isfile(os.path.join(config.get_runtime_path(), "servers", "debriders", server + ".json")):
path = os.path.join(config.get_runtime_path(), "servers", "debriders", server + ".json")
elif filetools.isfile(filetools.join(config.get_runtime_path(), "servers", "debriders", server + ".json")):
path = filetools.join(config.get_runtime_path(), "servers", "debriders", server + ".json")
#
#Cuando no está bien definido el server en el canal (no existe conector), muestra error por no haber "path" y se tiene que revisar el canal
#
data = filetools.read(path)
dict_server = jsontools.load(data)
dict_server = jsontools.load(filetools.read(path))
# Imagenes: se admiten url y archivos locales dentro de "resources/images"
if dict_server.get("thumbnail") and "://" not in dict_server["thumbnail"]:
dict_server["thumbnail"] = os.path.join("https://raw.githubusercontent.com/kodiondemand/media/master/resources/servers", dict_server["thumbnail"])
dict_server["thumbnail"] = filetools.join(config.get_runtime_path(), "resources", "media",
"servers", dict_server["thumbnail"])
for k in ['premium', 'id']:
dict_server[k] = dict_server.get(k, list())
if type(dict_server[k]) == str:
if isinstance(dict_server[k], str):
dict_server[k] = [dict_server[k]]
if "find_videos" in dict_server:
@@ -497,7 +516,7 @@ def get_server_json(server_name):
server_json = jsontools.load(filetools.read(server_path))
# logger.info("server_json= %s" % server_json)
except Exception, ex:
except Exception as ex:
template = "An exception of type %s occured. Arguments:\n%r"
message = template % (type(ex).__name__, ex.args)
logger.error(" %s" % message)
@@ -554,16 +573,16 @@ def get_server_setting(name, server, default=None):
"""
# Creamos la carpeta si no existe
if not os.path.exists(os.path.join(config.get_data_path(), "settings_servers")):
os.mkdir(os.path.join(config.get_data_path(), "settings_servers"))
if not filetools.exists(filetools.join(config.get_data_path(), "settings_servers")):
filetools.mkdir(filetools.join(config.get_data_path(), "settings_servers"))
file_settings = os.path.join(config.get_data_path(), "settings_servers", server + "_data.json")
file_settings = filetools.join(config.get_data_path(), "settings_servers", server + "_data.json")
dict_settings = {}
dict_file = {}
if os.path.exists(file_settings):
if filetools.exists(file_settings):
# Obtenemos configuracion guardada de ../settings/channel_data.json
try:
dict_file = jsontools.load(open(file_settings, "rb").read())
dict_file = jsontools.load(filetools.read(file_settings))
if isinstance(dict_file, dict) and 'settings' in dict_file:
dict_settings = dict_file['settings']
except EnvironmentError:
@@ -580,10 +599,7 @@ def get_server_setting(name, server, default=None):
dict_settings = default_settings
dict_file['settings'] = dict_settings
# Creamos el archivo ../settings/channel_data.json
json_data = jsontools.dump(dict_file)
try:
open(file_settings, "wb").write(json_data)
except EnvironmentError:
if not filetools.write(file_settings, jsontools.dump(dict_file)):
logger.info("ERROR al salvar el archivo: %s" % file_settings)
# Devolvemos el valor del parametro local 'name' si existe, si no se devuelve default
@@ -592,18 +608,18 @@ def get_server_setting(name, server, default=None):
def set_server_setting(name, value, server):
# Creamos la carpeta si no existe
if not os.path.exists(os.path.join(config.get_data_path(), "settings_servers")):
os.mkdir(os.path.join(config.get_data_path(), "settings_servers"))
if not filetools.exists(filetools.join(config.get_data_path(), "settings_servers")):
filetools.mkdir(filetools.join(config.get_data_path(), "settings_servers"))
file_settings = os.path.join(config.get_data_path(), "settings_servers", server + "_data.json")
file_settings = filetools.join(config.get_data_path(), "settings_servers", server + "_data.json")
dict_settings = {}
dict_file = None
if os.path.exists(file_settings):
if filetools.exists(file_settings):
# Obtenemos configuracion guardada de ../settings/channel_data.json
try:
dict_file = jsontools.load(open(file_settings, "r").read())
dict_file = jsontools.load(filetools.read(file_settings))
dict_settings = dict_file.get('settings', {})
except EnvironmentError:
logger.info("ERROR al leer el archivo: %s" % file_settings)
@@ -617,10 +633,7 @@ def set_server_setting(name, value, server):
dict_file['settings'] = dict_settings
# Creamos el archivo ../settings/channel_data.json
try:
json_data = jsontools.dump(dict_file)
open(file_settings, "w").write(json_data)
except EnvironmentError:
if not filetools.write(file_settings, jsontools.dump(dict_file)):
logger.info("ERROR al salvar el archivo: %s" % file_settings)
return None
@@ -636,11 +649,10 @@ def get_servers_list():
@rtype: dict
"""
server_list = {}
for server in os.listdir(os.path.join(config.get_runtime_path(), "servers")):
for server in filetools.listdir(filetools.join(config.get_runtime_path(), "servers")):
if server.endswith(".json") and not server == "version.json":
server_parameters = get_server_parameters(server)
if server_parameters["active"] == True:
server_list[server.split(".")[0]] = server_parameters
server_list[server.split(".")[0]] = server_parameters
return server_list
@@ -654,7 +666,7 @@ def get_debriders_list():
@rtype: dict
"""
server_list = {}
for server in os.listdir(os.path.join(config.get_runtime_path(), "servers", "debriders")):
for server in filetools.listdir(filetools.join(config.get_runtime_path(), "servers", "debriders")):
if server.endswith(".json"):
server_parameters = get_server_parameters(server)
if server_parameters["active"] == True:
@@ -678,6 +690,7 @@ def sort_servers(servers_list):
else:
servers_list = sorted(servers_list,
key=lambda x: config.get_setting("favorites_servers_list", server=x) or 100)
return servers_list
@@ -689,18 +702,26 @@ def filter_servers(servers_list):
u objetos Item. En cuyo caso es necesario q tengan un atributo item.server del tipo str.
:return: Lista del mismo tipo de objetos que servers_list filtrada en funcion de la Lista Negra.
"""
#Eliminamos los inactivos
if servers_list:
servers_list = [i for i in servers_list if not i.server or is_server_enabled(i.server)]
if servers_list and config.get_setting('filter_servers'):
if isinstance(servers_list[0], Item):
servers_list_filter = filter(lambda x: not config.get_setting("black_list", server=x.server), servers_list)
servers_list_filter = [x for x in servers_list if not config.get_setting("black_list", server=x.server)]
else:
servers_list_filter = filter(lambda x: not config.get_setting("black_list", server=x), servers_list)
servers_list_filter = [x for x in servers_list if not config.get_setting("black_list", server=x)]
# Si no hay enlaces despues de filtrarlos
if servers_list_filter or not platformtools.dialog_yesno(config.get_localized_string(60000),
config.get_localized_string(60010),
config.get_localized_string(70281)):
servers_list = servers_list_filter
if config.get_setting("favorites_servers") == True:
servers_list = sort_servers(servers_list)
return servers_list
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -715,21 +736,31 @@ def check_list_links(itemlist, numero='', timeout=3):
El parámetro timeout indica un tope de espera para descargar la página
"""
numero = ((int(numero) + 1) * 5) if numero != '' else 10
for it in itemlist:
if numero > 0 and it.server != '' and it.url != '':
verificacion = check_video_link(it.url, it.server, timeout)
it.title = verificacion + ' ' + it.title.strip()
logger.info('VERIFICATION= '+ verificacion)
it.alive = verificacion
numero -= 1
from lib.concurrent import futures
with futures.ThreadPoolExecutor() as executor:
checked = []
for it in itemlist:
if numero > 0 and it.server != '' and it.url != '':
checked.append(executor.submit(check_video_link, it, timeout))
numero -= 1
for link in futures.as_completed(checked):
res = link.result()
if res:
it = res[0]
verificacion = res[1]
it.title = verificacion + ' ' + it.title.strip()
logger.info('VERIFICATION= ' + verificacion)
it.alive = verificacion
return itemlist
def check_video_link(url, server, timeout=3):
"""
Comprueba si el enlace a un video es valido y devuelve un string de 2 posiciones con la verificacion.
:param url, server: Link y servidor
:return: str(2) '??':No se ha podido comprobar. 'Ok':Parece que el link funciona. 'NO':Parece que no funciona.
def check_video_link(item, timeout=3):
"""
Comprueba si el enlace a un video es valido y devuelve un string de 2 posiciones con la verificacion.
:param url, server: Link y servidor
:return: str(2) '??':No se ha podido comprobar. 'Ok':Parece que el link funciona. 'NO':Parece que no funciona.
"""
url = item.url
server = item.server
NK = "[COLOR 0xFFF9B613][B]" + u"\u2022".encode('utf-8') + "[/B][/COLOR]"
OK = "[COLOR 0xFF00C289][B]" + u"\u2022".encode('utf-8') + "[/B][/COLOR]"
@@ -744,7 +775,7 @@ def check_video_link(url, server, timeout=3):
except:
server_module = None
logger.info("[check_video_link] No se puede importar el servidor! %s" % server)
return NK
return item, NK
if hasattr(server_module, 'test_video_exists'):
ant_timeout = httptools.HTTPTOOLS_DEFAULT_DOWNLOAD_TIMEOUT
@@ -764,7 +795,7 @@ def check_video_link(url, server, timeout=3):
finally:
httptools.HTTPTOOLS_DEFAULT_DOWNLOAD_TIMEOUT = ant_timeout # Restaurar tiempo de descarga
return resultado
return item, resultado
logger.info("[check_video_link] No hay test_video_exists para servidor: %s" % server)
return NK
return item, NK
+59 -26
View File
@@ -10,8 +10,10 @@ from concurrent import futures
try:
import urllib.request as urllib
import urllib.parse as urlparse
from urllib.parse import urlencode
except ImportError:
import urllib, urlparse
from urllib import urlencode
from channelselector import thumb
from core import httptools, scrapertools, servertools, tmdb, channeltools
@@ -157,7 +159,8 @@ def scrapeLang(scraped, lang, longtitle):
return language, longtitle
def cleantitle(title):
cleantitle = scrapertools.htmlclean(scrapertools.decodeHtmlentities(title).replace('"', "'").replace('×', 'x').replace('', '-')).strip()
if type(title) != str: title.decode('UTF-8')
cleantitle = title.replace('"', "'").replace('×', 'x').replace('', '-').strip()
return cleantitle
def scrapeBlock(item, args, block, patron, headers, action, pagination, debug, typeContentDict, typeActionDict, blacklist, search, pag, function, lang):
@@ -192,16 +195,17 @@ def scrapeBlock(item, args, block, patron, headers, action, pagination, debug, t
for i, match in enumerate(matches):
if pagination and (pag - 1) * pagination > i and not search: continue # pagination
if pagination and i >= pag * pagination and not search: break # pagination
listGroups = match.keys()
match = match.values()
# listGroups = match.keys()
# match = match.values()
if len(listGroups) > len(match): # to fix a bug
match = list(match)
match.extend([''] * (len(listGroups) - len(match)))
# if len(listGroups) > len(match): # to fix a bug
# match = list(match)
# match.extend([''] * (len(listGroups) - len(match)))
scraped = {}
for kk in known_keys:
val = match[listGroups.index(kk)] if kk in listGroups else ''
val = match[kk] if kk in match else ''
# val = match[listGroups.index(kk)] if kk in listGroups else ''
if val and (kk == "url" or kk == 'thumb') and 'http' not in val:
val = scrapertools.find_single_match(item.url, 'https?://[a-z0-9.-]+') + (val if val.startswith('/') else '/' + val)
scraped[kk] = val
@@ -294,8 +298,10 @@ def scrapeBlock(item, args, block, patron, headers, action, pagination, debug, t
other = scraped['other'] if scraped['other'] else ''
)
for lg in list(set(listGroups).difference(known_keys)):
it.__setattr__(lg, match[listGroups.index(lg)])
# for lg in list(set(listGroups).difference(known_keys)):
# it.__setattr__(lg, match[listGroups.index(lg)])
for lg in list(set(match.keys()).difference(known_keys)):
it.__setattr__(lg, match[lg])
if 'itemHook' in args:
it = args['itemHook'](it)
@@ -367,7 +373,7 @@ def scrape(func):
log('PATRON= ', patron)
if not data:
page = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True, session=item.session)
page = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True)
# if url may be changed and channel has findhost to update
if (not page.data or scrapertools.get_domain_from_url(page.url) != scrapertools.get_domain_from_url(item.url)) and 'findhost' in func.__globals__:
host = func.__globals__['findhost']()
@@ -376,8 +382,7 @@ def scrape(func):
jsontools.update_node(host, func.__module__.split('.')[-1], 'url')
parse[1] = scrapertools.get_domain_from_url(host)
item.url = urlparse.urlunparse(parse)
page = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True,
session=item.session)
page = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True)
data = page.data.replace("'", '"')
data = re.sub('\n|\t', ' ', data)
data = re.sub(r'>\s+<', '> <', data)
@@ -468,7 +473,7 @@ def dooplay_get_links(item, host):
ret = []
for type, post, nume, title, server in matches:
postData = urllib.urlencode({
postData = urlencode({
"action": "doo_player_ajax",
"post": post,
"nume": nume,
@@ -582,7 +587,7 @@ def swzz_get_url(item):
elif 'https://stayonline.pro' in item.url:
id = item.url.split('/')[-2]
reqUrl = 'https://stayonline.pro/ajax/linkView.php'
p = urllib.urlencode({"id": id})
p = urlencode({"id": id})
data = httptools.downloadpage(reqUrl, post=p).data
try:
import json
@@ -699,9 +704,9 @@ def menu(func):
if global_search:
menuItem(itemlist, filename, config.get_localized_string(70741) % '… bold', 'search', host + dictUrl['search'])
autoplay.init(item.channel, list_servers, list_quality)
autoplay.show_option(item.channel, itemlist)
if 'get_channel_results' not in inspect.stack()[1][3]:
autoplay.init(item.channel, list_servers, list_quality)
autoplay.show_option(item.channel, itemlist)
channel_config(item, itemlist)
return itemlist
@@ -744,7 +749,7 @@ def typo(string, typography=''):
if '{}' in string:
string = '{' + re.sub(r'\s\{\}','',string) + '}'
if 'submenu' in string:
string = u"\u2022\u2022 ".encode('utf-8') + re.sub(r'\ssubmenu','',string)
string = "•• " + re.sub(r'\ssubmenu','',string)
if 'color' in string:
color = scrapertools.find_single_match(string, 'color ([a-z]+)')
if color == 'kod' or '': color = kod_color
@@ -758,7 +763,7 @@ def typo(string, typography=''):
if '--' in string:
string = ' - ' + re.sub(r'\s--','',string)
if 'bullet' in string:
string = '[B]' + u"\u2022".encode('utf-8') + '[/B] ' + re.sub(r'\sbullet','',string)
string = '[B]' + "" + '[/B] ' + re.sub(r'\sbullet','',string)
return string
@@ -766,10 +771,33 @@ def typo(string, typography=''):
def match(item_url_string, **args):
'''
match is a function that combines httptools and scraper tools:
supports all httptools and the following arggs:
@param item_url_string: if it's a titem download the page item.url, if it's a URL download the page, if it's a string pass it to scrapertools
@type item_url_string: item or str
@param string: force item_url_string to be a string
@type string: bool
@param patronBlock: find first element in patron
@type patronBlock: str
@param patronBloks: find multiple matches
@type patronBloks: str or list
@param debugBlock: regex101.com for debug
@type debugBlock: bool
@param patron: find multiple matches on block, blocks or data
@type patron: str or list
@param debug: regex101.com for debug
@type debug: bool
Return a item with the following key:
data: data of the webpage
block: first block
blocks: all the blocks
match: first match
matches: all the matches
'''
log(item_url_string)
matches = []
matches = blocks = []
url = None
# arguments allowed for scrape
patron = args.get('patron', None)
@@ -778,12 +806,15 @@ def match(item_url_string, **args):
debug = args.get('debug', False)
debugBlock = args.get('debugBlock', False)
string = args.get('string', False)
# remove scrape arguments
args = dict([(key, val) for key, val in args.items() if key not in ['patron', 'patronBlock', 'patronBlocks', 'debug', 'debugBlock', 'string']])
# dbg()
# check type of item_url_string
if type(item_url_string) == str:
if item_url_string.startswith('http') and not string: url = item_url_string
if string:
data = item_url_string
elif type(item_url_string) == str:
if item_url_string.startswith('http'): url = item_url_string
else : data = item_url_string
else:
# if item_url_string is an item use item.url as url
@@ -803,7 +834,9 @@ def match(item_url_string, **args):
if patronBlock:
blocks = [scrapertools.find_single_match(data, patronBlock)]
elif patronBlocks:
blocks = scrapertools.find_multiple_matches(data, patronBlock)
if type(patronBlock) == str: patron = [patronBlock]
for p in patronBlock:
blocks += scrapertools.find_multiple_matches(data, p)
else:
blocks = [data]
@@ -1010,7 +1043,7 @@ def server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=Tru
item.title = typo(item.contentTitle.strip(),'bold') if item.contentType == 'movie' or (config.get_localized_string(30161) in item.title) else item.title
videoitem.plot= typo(videoitem.title, 'bold')
videoitem.plot= typo(videoitem.title, 'bold') + typo(videoitem.quality, '_ [] bold')
videoitem.title = item.title + (typo(videoitem.title, '_ color kod [] bold') if videoitem.title else "") + (typo(videoitem.quality, '_ color kod []') if videoitem.quality else "")
videoitem.fulltitle = item.fulltitle
videoitem.show = item.show
@@ -1036,7 +1069,7 @@ def controls(itemlist, item, AutoPlay=True, CheckLinks=True, down_load=True):
channel_node = autoplay_node.get(item.channel, {})
settings_node = channel_node.get('settings', {})
AP = get_setting('autoplay') or settings_node['active']
HS = config.get_setting('hide_servers') or (settings_node['hide_servers'] if settings_node.has_key('hide_server') else False)
HS = config.get_setting('hide_servers') or (settings_node['hide_servers'] if 'hide_server' in settings_node else False)
if CL and not AP:
if get_setting('checklinks', item.channel):
+75 -39
View File
@@ -1,10 +1,26 @@
# -*- coding: utf-8 -*-
#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
else:
import urllib # Usamos el nativo de PY2 que es más rápido
from future.builtins import range
from future.builtins import object
import ast
import copy
import re
import sqlite3
import time
import urllib
import xbmcaddon
@@ -37,8 +53,8 @@ def_lang = addon.getSetting('language')
# tmdb.set_infoLabels(item, seekTmdb = True)
#
# Obtener datos basicos de una pelicula:
# Antes de llamar al metodo set_infoLabels el titulo a buscar debe estar en item.fulltitle
# o en item.contentTitle y el año en item.infoLabels['year'].
# Antes de llamar al metodo set_infoLabels el titulo a buscar debe estar en item.contentTitle
# y el año en item.infoLabels['year'].
#
# Obtener datos basicos de una serie:
# Antes de llamar al metodo set_infoLabels el titulo a buscar debe estar en item.show o en
@@ -73,7 +89,6 @@ def_lang = addon.getSetting('language')
otmdb_global = None
fname = filetools.join(config.get_data_path(), "kod_db.sqlite")
def create_bd():
conn = sqlite3.connect(fname)
c = conn.cursor()
@@ -160,7 +175,7 @@ def cache_response(fn):
conn = sqlite3.connect(fname, timeout=15)
c = conn.cursor()
url = re.sub('&year=-', '', args[0])
# logger.error('la url %s' % url)
if PY3: url = str.encode(url)
url_base64 = base64.b64encode(url)
c.execute("SELECT response, added FROM tmdb_cache WHERE url=?", (url_base64,))
row = c.fetchone()
@@ -171,7 +186,9 @@ def cache_response(fn):
# si no se ha obtenido información, llamamos a la funcion
if not result:
result = fn(*args)
result_base64 = base64.b64encode(str(result))
result = str(result)
if PY3: result = str.encode(result)
result_base64 = base64.b64encode(result)
c.execute("INSERT OR REPLACE INTO tmdb_cache (url, response, added) VALUES (?, ?, ?)",
(url_base64, result_base64, time.time()))
@@ -375,17 +392,19 @@ def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda=def_lang, lock=None
# ... buscar datos temporada
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
__leer_datos(otmdb_global)
item.infoLabels['title'] = temporada['name'] if temporada.has_key('name') else ''
if temporada.has_key('overview') and temporada['overview']:
item.infoLabels['title'] = temporada['name'] if 'name' in temporada else ''
if 'overview' in temporada and temporada['overview']:
item.infoLabels['plot'] = temporada['overview']
if temporada.has_key('air_date') and temporada['air_date']:
if 'air_date' in temporada and temporada['air_date']:
date = temporada['air_date'].split('-')
item.infoLabels['aired'] = date[2] + "/" + date[1] + "/" + date[0]
if temporada.has_key('poster_path') and temporada['poster_path']:
if 'poster_path' in temporada and temporada['poster_path']:
item.infoLabels['poster_path'] = 'http://image.tmdb.org/t/p/original' + temporada['poster_path']
item.thumbnail = item.infoLabels['poster_path']
@@ -445,12 +464,8 @@ def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda=def_lang, lock=None
# Busqueda de pelicula por titulo...
if item.infoLabels['year'] or item.infoLabels['filtro']:
# ...y año o filtro
if item.contentTitle:
titulo_buscado = item.contentTitle
else:
titulo_buscado = item.fulltitle
otmdb = Tmdb(texto_buscado=titulo_buscado, tipo=tipo_busqueda, idioma_busqueda=idioma_busqueda,
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):
@@ -492,7 +507,7 @@ def find_and_set_infoLabels(item):
title = title.replace(year, "").strip()
item.infoLabels['year'] = year[1:-1]
if not item.infoLabels.get("tmdb_id"):
if not item.infoLabels.get("tmdb_id") or not item.infoLabels.get("tmdb_id")[0].isdigit():
if not item.infoLabels.get("imdb_id"):
otmdb_global = Tmdb(texto_buscado=title, tipo=tipo_busqueda, year=item.infoLabels['year'])
else:
@@ -588,7 +603,6 @@ def get_genres(type):
return genres.dic_generos[lang]
# Clase auxiliar
class ResultDictDefault(dict):
# Python 2.4
@@ -606,7 +620,7 @@ class ResultDictDefault(dict):
return list()
elif key == 'images_posters':
posters = dict()
if 'images' in super(ResultDictDefault, self).keys() and \
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)
@@ -615,7 +629,7 @@ class ResultDictDefault(dict):
elif key == "images_backdrops":
backdrops = dict()
if 'images' in super(ResultDictDefault, self).keys() and \
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)
@@ -624,7 +638,7 @@ class ResultDictDefault(dict):
elif key == "images_profiles":
profiles = dict()
if 'images' in super(ResultDictDefault, self).keys() and \
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)
@@ -640,7 +654,7 @@ class ResultDictDefault(dict):
def tostring(self, separador=',\n'):
ls = []
for i in super(ResultDictDefault, self).items():
for i in list(super(ResultDictDefault, self).items()):
i_str = str(i)[1:-1]
if isinstance(i[0], str):
old = i[0] + "',"
@@ -899,12 +913,16 @@ class Tmdb(object):
logger.info("[Tmdb.py] Filling in dictionary of genres")
resultado = cls.get_json(url)
if not isinstance(resultado, dict):
resultado = ast.literal_eval(resultado.decode('utf-8'))
lista_generos = resultado["genres"]
for i in lista_generos:
cls.dic_generos[idioma][tipo][str(i["id"])] = i["name"]
except:
logger.error("Error generating dictionaries")
import traceback
logger.error(traceback.format_exc())
def __by_id(self, source='tmdb'):
@@ -926,6 +944,8 @@ class Tmdb(object):
logger.info("[Tmdb.py] Searching %s:\n%s" % (buscando, url))
resultado = self.get_json(url)
if not isinstance(resultado, dict):
resultado = ast.literal_eval(resultado.decode('utf-8'))
if resultado:
if source != "tmdb":
@@ -942,14 +962,14 @@ class Tmdb(object):
else:
# No hay resultados de la busqueda
msg = "The search of %s gave no results" % buscando
# logger.debug(msg)
logger.debug(msg)
def __search(self, index_results=0, page=1):
self.result = ResultDictDefault()
results = []
total_results = 0
text_simple = self.busqueda_texto.lower()
text_quote = urllib.quote(text_simple)
total_results = 0
total_pages = 0
buscando = ""
@@ -957,15 +977,17 @@ class Tmdb(object):
# http://api.themoviedb.org/3/search/movie?api_key=a1ab8b8669da03637a4b98fa39c39228&query=superman&language=es
# &include_adult=false&page=1
url = ('http://api.themoviedb.org/3/search/%s?api_key=a1ab8b8669da03637a4b98fa39c39228&query=%s&language=%s'
'&include_adult=%s&page=%s' % (self.busqueda_tipo, text_quote.replace(' ', '%20'),
'&include_adult=%s&page=%s' % (self.busqueda_tipo, text_quote,
self.busqueda_idioma, self.busqueda_include_adult, page))
if self.busqueda_year:
url += '&year=%s' % self.busqueda_year
buscando = self.busqueda_texto.capitalize()
logger.info("[Tmdb.py] Searching %s on page %s:\n%s" % (buscando, page, url))
logger.info("[Tmdb.py] Buscando %s en pagina %s:\n%s" % (buscando, page, url))
resultado = self.get_json(url)
if not isinstance(resultado, dict):
resultado = ast.literal_eval(resultado.decode('utf-8'))
total_results = resultado.get("total_results", 0)
total_pages = resultado.get("total_pages", 0)
@@ -973,11 +995,13 @@ class Tmdb(object):
if total_results > 0:
results = resultado["results"]
if self.busqueda_filtro and results:
if self.busqueda_filtro and total_results > 1:
# TODO documentar esta parte
for key, value in dict(self.busqueda_filtro).items():
for key, value in list(dict(self.busqueda_filtro).items()):
for r in results[:]:
if key not in r or r[key] != value:
if not r[key]:
r[key] = str(r[key])
if key not in r or value not in r[key]:
results.remove(r)
total_results -= 1
@@ -1015,7 +1039,7 @@ class Tmdb(object):
type_search = self.discover.get('url', '')
if type_search:
params = []
for key, value in self.discover.items():
for key, value in list(self.discover.items()):
if key != "url":
params.append(key + "=" + str(value))
# http://api.themoviedb.org/3/discover/movie?api_key=a1ab8b8669da03637a4b98fa39c39228&query=superman&language=es
@@ -1024,6 +1048,8 @@ class Tmdb(object):
logger.info("[Tmdb.py] Searcing %s:\n%s" % (type_search, url))
resultado = self.get_json(url)
if not isinstance(resultado, dict):
resultado = ast.literal_eval(resultado.decode('utf-8'))
total_results = resultado.get("total_results", -1)
total_pages = resultado.get("total_pages", 1)
@@ -1036,7 +1062,7 @@ class Tmdb(object):
results = resultado["results"]
if self.busqueda_filtro and results:
# TODO documentar esta parte
for key, value in dict(self.busqueda_filtro).items():
for key, value in list(dict(self.busqueda_filtro).items()):
for r in results[:]:
if key not in r or r[key] != value:
results.remove(r)
@@ -1184,6 +1210,8 @@ class Tmdb(object):
(self.busqueda_tipo, self.busqueda_id, self.busqueda_idioma))
resultado = self.get_json(url)
if not isinstance(resultado, dict):
resultado = ast.literal_eval(resultado.decode('utf-8'))
if 'overview' in resultado:
self.result['overview'] = resultado['overview']
@@ -1316,6 +1344,8 @@ class Tmdb(object):
logger.info("[Tmdb.py] Searcing " + buscando)
try:
self.temporada[numtemporada] = self.get_json(url)
if not isinstance(self.temporada[numtemporada], dict):
self.temporada[numtemporada] = ast.literal_eval(self.temporada[numtemporada].decode('utf-8'))
except:
logger.error("Unable to get the season")
@@ -1356,6 +1386,8 @@ class Tmdb(object):
return {}
temporada = self.get_temporada(numtemporada)
if not isinstance(temporada, dict):
temporada = ast.literal_eval(temporada.decode('utf-8'))
if not temporada:
# Se ha producido un error
return {}
@@ -1388,9 +1420,9 @@ class Tmdb(object):
dic_aux = dict((i['id'], i) for i in ret_dic["temporada_crew"])
for e in temporada["episodes"]:
for crew in e['crew']:
if crew['id'] not in dic_aux.keys():
if crew['id'] not in list(dic_aux.keys()):
dic_aux[crew['id']] = crew
ret_dic["temporada_crew"] = dic_aux.values()
ret_dic["temporada_crew"] = list(dic_aux.values())
# Obtener datos del capitulo si procede
if capitulo != -1:
@@ -1429,6 +1461,8 @@ class Tmdb(object):
% (self.busqueda_tipo, self.result['id'], self.busqueda_idioma)
dict_videos = self.get_json(url)
if not isinstance(dict_videos, dict):
dict_videos = ast.literal_eval(dict_videos.decode('utf-8'))
if dict_videos['results']:
dict_videos['results'] = sorted(dict_videos['results'], key=lambda x: (x['type'], x['size']))
@@ -1440,6 +1474,8 @@ class Tmdb(object):
% (self.busqueda_tipo, self.result['id'])
dict_videos = self.get_json(url)
if not isinstance(dict_videos, dict):
dict_videos = ast.literal_eval(dict_videos.decode('utf-8'))
if dict_videos['results']:
dict_videos['results'] = sorted(dict_videos['results'], key=lambda x: (x['type'], x['size']))
@@ -1481,13 +1517,13 @@ class Tmdb(object):
if not origen:
origen = self.result
if 'credits' in origen.keys():
if 'credits' in list(origen.keys()):
dic_origen_credits = origen['credits']
origen['credits_cast'] = dic_origen_credits.get('cast', [])
origen['credits_crew'] = dic_origen_credits.get('crew', [])
del origen['credits']
items = origen.items()
items = list(origen.items())
# Informacion Temporada/episodio
if ret_infoLabels['season'] and self.temporada.get(ret_infoLabels['season']):
@@ -1496,14 +1532,14 @@ class Tmdb(object):
if ret_infoLabels['episode']:
episodio = ret_infoLabels['episode']
items.extend(self.get_episodio(ret_infoLabels['season'], episodio).items())
items.extend(list(self.get_episodio(ret_infoLabels['season'], episodio).items()))
# logger.info("ret_infoLabels" % ret_infoLabels)
for k, v in items:
if not v:
continue
elif type(v) == str:
elif isinstance(v, str):
v = re.sub(r"\n|\r|\t", "", v)
# fix
if v == "None":
@@ -1517,7 +1553,7 @@ class Tmdb(object):
elif k == 'runtime': #Duration for movies
ret_infoLabels['duration'] = int(v) * 60
elif k == 'episode_run_time': #Duration for episodes
try:
for v_alt in v: #It comes as a list (?!)
@@ -1572,7 +1608,7 @@ class Tmdb(object):
elif k == 'credits_cast' or k == 'temporada_cast' or k == 'episodio_guest_stars':
dic_aux = dict((name, character) for (name, character) in l_castandrole)
l_castandrole.extend([(p['name'], p['character']) for p in v if p['name'] not in dic_aux.keys()])
l_castandrole.extend([(p['name'], p['character']) for p in v if p['name'] not in list(dic_aux.keys())])
elif k == 'videos':
if not isinstance(v, list):
+44 -42
View File
@@ -7,9 +7,14 @@
# del addon y también Kodi.
# ------------------------------------------------------------
import re
from future import standard_library
standard_library.install_aliases()
#from builtins import str
from future.builtins import object
import urllib2
import urllib.request, urllib.error, urllib.parse
import re
from core import jsontools
from core import scrapertools
@@ -218,7 +223,7 @@ def set_infoLabels_item(item):
break
_next = list_episodes['links']['next']
if type(_next) == int:
if isinstance(_next, int):
page = _next
else:
break
@@ -330,7 +335,7 @@ def completar_codigos(item):
break
class Tvdb:
class Tvdb(object):
def __init__(self, **kwargs):
self.__check_token()
@@ -398,12 +403,12 @@ class Tvdb:
params = {"apikey": apikey}
try:
req = urllib2.Request(url, data=jsontools.dump(params), headers=DEFAULT_HEADERS)
response = urllib2.urlopen(req)
req = urllib.request.Request(url, data=jsontools.dump(params), headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception, ex:
except Exception as ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error en: %s" % message)
@@ -426,12 +431,12 @@ class Tvdb:
url = HOST + "/refresh_token"
try:
req = urllib2.Request(url, headers=DEFAULT_HEADERS)
response = urllib2.urlopen(req)
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except urllib2.HTTPError, err:
except urllib.error.HTTPError as err:
logger.error("err.code es %s" % err.code)
# si hay error 401 es que el token se ha pasado de tiempo y tenemos que volver a llamar a login
if err.code == 401:
@@ -439,7 +444,7 @@ class Tvdb:
else:
raise
except Exception, ex:
except Exception as ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error en: %s" % message)
@@ -525,19 +530,18 @@ class Tvdb:
params = {"airedSeason": "%s" % season, "airedEpisode": "%s" % episode}
try:
import urllib
params = urllib.urlencode(params)
params = urllib.parse.urlencode(params)
url = HOST + "/series/%s/episodes/query?%s" % (_id, params)
DEFAULT_HEADERS["Accept-Language"] = lang
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib2.Request(url, headers=DEFAULT_HEADERS)
response = urllib2.urlopen(req)
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception, ex:
except Exception as ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error en: %s" % message)
@@ -595,12 +599,12 @@ class Tvdb:
url = HOST + "/series/%s/episodes?page=%s" % (_id, page)
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib2.Request(url, headers=DEFAULT_HEADERS)
response = urllib2.urlopen(req)
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception, ex:
except Exception as ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error en: %s" % message)
@@ -682,13 +686,13 @@ class Tvdb:
try:
DEFAULT_HEADERS["Accept-Language"] = lang
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib2.Request(url, headers=DEFAULT_HEADERS)
response = urllib2.urlopen(req)
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception, ex:
if type(ex) == urllib2.HTTPError:
except Exception as ex:
if isinstance(ex, urllib).HTTPError:
logger.debug("code es %s " % ex.code)
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
@@ -741,20 +745,19 @@ class Tvdb:
elif zap2it_id:
params["zap2itId"] = zap2it_id
import urllib
params = urllib.urlencode(params)
params = urllib.parse.urlencode(params)
DEFAULT_HEADERS["Accept-Language"] = lang
url = HOST + "/search/series?%s" % params
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib2.Request(url, headers=DEFAULT_HEADERS)
response = urllib2.urlopen(req)
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception, ex:
if type(ex) == urllib2.HTTPError:
except Exception as ex:
if isinstance(ex, urllib).HTTPError:
logger.debug("code es %s " % ex.code)
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
@@ -835,15 +838,15 @@ class Tvdb:
try:
DEFAULT_HEADERS["Accept-Language"] = lang
req = urllib2.Request(url, headers=DEFAULT_HEADERS)
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
response = urllib2.urlopen(req)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception, ex:
if type(ex) == urllib2.HTTPError:
except Exception as ex:
if isinstance(ex, urllib).HTTPError:
logger.debug("code es %s " % ex.code)
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
@@ -905,18 +908,17 @@ class Tvdb:
try:
import urllib
params = urllib.urlencode(params)
params = urllib.parse.urlencode(params)
DEFAULT_HEADERS["Accept-Language"] = lang
url = HOST + "/series/%s/images/query?%s" % (_id, params)
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib2.Request(url, headers=DEFAULT_HEADERS)
response = urllib2.urlopen(req)
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
except Exception, ex:
except Exception as ex:
message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
logger.error("error en: %s" % message)
@@ -946,8 +948,8 @@ class Tvdb:
DEFAULT_HEADERS["Accept-Language"] = lang
logger.debug("url: %s, \nheaders: %s" % (url, DEFAULT_HEADERS))
req = urllib2.Request(url, headers=DEFAULT_HEADERS)
response = urllib2.urlopen(req)
req = urllib.request.Request(url, headers=DEFAULT_HEADERS)
response = urllib.request.urlopen(req)
html = response.read()
response.close()
@@ -1039,7 +1041,7 @@ class Tvdb:
# origen['credits_crew'] = dic_origen_credits.get('crew', [])
# del origen['credits']
items = origen.items()
items = list(origen.items())
for k, v in items:
if not v:
@@ -1118,7 +1120,7 @@ class Tvdb:
elif k == 'cast':
dic_aux = dict((name, character) for (name, character) in l_castandrole)
l_castandrole.extend([(p['name'], p['role']) for p in v if p['name'] not in dic_aux.keys()])
l_castandrole.extend([(p['name'], p['role']) for p in v if p['name'] not in list(dic_aux.keys())])
else:
logger.debug("Atributos no añadidos: %s=%s" % (k, v))
+122 -179
View File
@@ -3,6 +3,11 @@
# Common Library Tools
# ------------------------------------------------------------
#from builtins import str
import sys
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
import errno
import math
import traceback
@@ -130,7 +135,10 @@ def save_movie(item):
else:
base_name = item.contentTitle
base_name = unicode(filetools.validate_path(base_name.replace('/', '-')), "utf8").encode("utf8")
if not PY3:
base_name = unicode(filetools.validate_path(base_name.replace('/', '-')), "utf8").encode("utf8")
else:
base_name = filetools.validate_path(base_name.replace('/', '-'))
if config.get_setting("lowerize_title", "videolibrary") == 0:
base_name = base_name.lower()
@@ -191,9 +199,12 @@ def save_movie(item):
# 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
try:
headers = {}
if item.headers:
headers = item.headers
channel = generictools.verify_channel(item.channel)
if config.get_setting("emergency_urls", channel) in [1, 3]:
item = emergency_urls(item, None, json_path)
item = emergency_urls(item, None, json_path, headers=headers)
if item_nfo.emergency_urls and not isinstance(item_nfo.emergency_urls, dict):
del item_nfo.emergency_urls
if not item_nfo.emergency_urls:
@@ -224,7 +235,7 @@ def save_movie(item):
return 0, 0, -1
def filter_list(episodelist, action=None, path=None):
if path: path = path.decode('utf8')
# if path: path = path.decode('utf8')
# import xbmc
# if xbmc.getCondVisibility('system.platform.windows') > 0: path = path.replace('smb:','').replace('/','\\')
channel_prefs = {}
@@ -397,17 +408,29 @@ def save_tvshow(item, episodelist):
return 0, 0, -1, path
_id = item.infoLabels['code'][0]
if not item.infoLabels['code'][0] or item.infoLabels['code'][0] == 'None':
if item.infoLabels['code'][1] and item.infoLabels['code'][1] != 'None':
_id = item.infoLabels['code'][1]
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'])
return 0, 0, -1, path
if config.get_setting("original_title_folder", "videolibrary") == 1 and item.infoLabels['originaltitle']:
base_name = item.infoLabels[u'originaltitle']
base_name = item.infoLabels['originaltitle']
elif item.infoLabels['tvshowtitle']:
base_name = item.infoLabels[u'tvshowtitle']
base_name = item.infoLabels['tvshowtitle']
elif item.infoLabels['title']:
base_name = item.infoLabels[u'title']
base_name = item.infoLabels['title']
else:
base_name = u'%s' % item.contentSerieName
base_name = item.contentSerieName
base_name = unicode(filetools.validate_path(base_name.replace('/', '-')), "utf8").encode("utf8")
if not PY3:
base_name = unicode(filetools.validate_path(base_name.replace('/', '-')), "utf8").encode("utf8")
else:
base_name = filetools.validate_path(base_name.replace('/', '-'))
if config.get_setting("lowerize_title", "videolibrary") == 0:
base_name = base_name.lower()
@@ -415,7 +438,7 @@ def save_tvshow(item, episodelist):
for raiz, subcarpetas, ficheros in filetools.walk(TVSHOWS_PATH):
for c in subcarpetas:
code = scrapertools.find_single_match(c, '\[(.*?)\]')
if code and code in item.infoLabels['code']:
if code and code != 'None' and code in item.infoLabels['code']:
path = filetools.join(raiz, c)
_id = code
break
@@ -425,7 +448,7 @@ def save_tvshow(item, episodelist):
logger.info("Creating series directory: " + path)
try:
filetools.mkdir(path)
except OSError, exception:
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
@@ -518,7 +541,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
news_in_playcounts = {}
# Listamos todos los ficheros de la serie, asi evitamos tener que comprobar si existe uno por uno
raiz, carpetas_series, ficheros = filetools.walk(path).next()
raiz, carpetas_series, ficheros = next(filetools.walk(path))
ficheros = [filetools.join(path, f) for f in ficheros]
nostrm_episodelist = []
@@ -550,7 +573,11 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
tags = []
if config.get_setting("enable_filter", "videolibrary"):
tags = [x.strip() for x in config.get_setting("filters", "videolibrary").lower().split(",")]
for e in episodelist:
headers = {}
if e.headers:
headers = e.headers
if tags != [] and tags != None and any(tag in e.title.lower() for tag in tags):
continue
@@ -567,31 +594,34 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
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) #... las generamos
e.emergency_urls = json_epi.emergency_urls #... las copiamos
else: #y si no...
e = emergency_urls(e, channel, json_path, headers=headers) #... las generamos
else:
e = emergency_urls(e, channel, json_path) #Si el episodio no existe, generamos las urls
if e.emergency_urls: #Si ya tenemos urls...
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?
elif emergency_urls_stat == 2 and e.contentType == 'episode': #Borramos urls de emergencia?
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?
if not silent:
p_dialog.update(0, 'Cacheando enlaces y archivos .torrent...', e.title) #progress dialog
e = emergency_urls(e, channel, json_path) #generamos las urls
if e.emergency_urls: #Si ya tenemos urls...
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
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...
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.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
new_episodelist.append(e)
except:
if e.contentType == 'episode':
logger.error("Unable to save %s emergency urls in the video library" % e.contentTitle)
logger.error(traceback.format_exc())
continue
# No hay lista de episodios, no hay nada que guardar
@@ -600,18 +630,35 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
return 0, 0, 0
# fix float porque la division se hace mal en python 2.x
t = float(100) / len(new_episodelist)
try:
t = float(100) / len(new_episodelist)
except:
t = 0
last_season_episode = ''
for i, e in enumerate(scraper.sort_episode_list(new_episodelist)):
if not silent:
p_dialog.update(int(math.ceil((i + 1) * t)), config.get_localized_string(60064), e.title)
high_sea = e.contentSeason
high_epi = e.contentEpisodeNumber
if scrapertools.find_single_match(e.title, '[a|A][l|L]\s*(\d+)'):
high_epi = int(scrapertools.find_single_match(e.title, 'al\s*(\d+)'))
max_sea = e.infoLabels["number_of_seasons"]
max_epi = 0
if e.infoLabels["number_of_seasons"] and (e.infoLabels["temporada_num_episodios"] or e.infoLabels["number_of_seasons"] == 1):
if e.infoLabels["number_of_seasons"] == 1 and e.infoLabels["number_of_episodes"]:
max_epi = e.infoLabels["number_of_episodes"]
else:
max_epi = e.infoLabels["temporada_num_episodios"]
season_episode = "%sx%s" % (e.contentSeason, str(e.contentEpisodeNumber).zfill(2))
strm_path = filetools.join(path, "%s.strm" % season_episode)
nfo_path = filetools.join(path, "%s.nfo" % season_episode)
json_path = filetools.join(path, ("%s [%s].json" % (season_episode, e.channel)).lower())
if season_episode in nostrm_episodelist:
logger.error('Error in the structure of the Video Library: Seriese ' + serie.contentSerieName + ' ' + season_episode)
continue
strm_exists = strm_path in ficheros
nfo_exists = nfo_path in ficheros
@@ -659,8 +706,10 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
if not item_nfo:
head_nfo, item_nfo = read_nfo(nfo_path)
if not e.infoLabels["tmdb_id"] or (item_nfo.infoLabels["tmdb_id"] and e.infoLabels["tmdb_id"] != item_nfo.infoLabels["tmdb_id"]): #en series multicanal, prevalece el infolabels...
e.infoLabels = item_nfo.infoLabels #... del canal actual y no el del original
# 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"]):
e.infoLabels = item_nfo.infoLabels
if filetools.write(json_path, e.tojson()):
if not json_exists:
@@ -688,10 +737,12 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
if not silent and p_dialog.iscanceled():
break
#logger.debug('high_sea x high_epi: %sx%s' % (str(high_sea), str(high_epi)))
#logger.debug('max_sea x max_epi: %sx%s' % (str(max_sea), str(max_epi)))
if not silent:
p_dialog.close()
if news_in_playcounts:
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 ...
tvshow_path = filetools.join(path, "tvshow.nfo")
try:
@@ -703,16 +754,27 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True):
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]: #Operación de guardar/actualizar enlaces
if not tvshow_item.emergency_urls:
tvshow_item.emergency_urls = dict()
tvshow_item.emergency_urls.update({serie.channel: True})
elif emergency_urls_stat == 2: #Operación de Borrar enlaces
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
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) #borramos la entrada del .nfo
if tvshow_item.active == 30:
tvshow_item.active = 1
if tvshow_item.infoLabels["tmdb_id"] == serie.infoLabels["tmdb_id"]:
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:
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))
update_last = datetime.date.today()
tvshow_item.update_last = update_last.strftime('%Y-%m-%d')
update_next = datetime.date.today() + datetime.timedelta(days=int(tvshow_item.active))
@@ -819,10 +881,10 @@ def add_tvshow(item, channel=None):
if not channel:
try:
#channel = __import__('channels.%s' % item.channel, fromlist=["channels.%s" % item.channel])
# channel = __import__('channels.%s' % item.channel, fromlist=["channels.%s" % item.channel])
channel = __import__('specials.%s' % channel_alt, fromlist=["specials.%s" % channel_alt])
except ImportError:
exec "import channels." + item.channel + " as channel"
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
@@ -836,15 +898,15 @@ def add_tvshow(item, channel=None):
# del item.tmdb_stat #Limpiamos el status para que no se grabe en la Videoteca
# Obtiene el listado de episodios
#if item.channel == 'community':
itemlist = getattr(channel, item.action)(item)
global magnet_caching
magnet_caching = False
insertados, sobreescritos, fallidos, path = save_tvshow(item, itemlist)
if not insertados and not sobreescritos and not fallidos:
platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60067))
logger.error("The %s series could not be added to the video library. Could not get any episode"
% item.show)
logger.error("The %s series could not be added to the video library. Could not get any episode" % item.show)
elif fallidos == -1:
platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60068))
@@ -856,8 +918,7 @@ def add_tvshow(item, channel=None):
else:
platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60070))
logger.info("%s episodes of the %s series have been added to the video library" %
(insertados, item.show))
logger.info("%s episodes of the %s series 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
@@ -872,10 +933,16 @@ def add_tvshow(item, channel=None):
xbmc_videolibrary.sync_trakt_addon(path)
def emergency_urls(item, channel=None, path=None):
def emergency_urls(item, channel=None, path=None, headers={}):
logger.info()
import re
"""
from servers import torrent
try:
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.
@@ -890,17 +957,28 @@ def emergency_urls(item, channel=None, path=None):
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 = channel_save.capitalize() #... y la categoría
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 item.videolibray_emergency_urls:
del item.videolibray_emergency_urls #... y se borra la marca de lookup original
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
if item_res.videolibray_emergency_urls:
del item_res.videolibray_emergency_urls #... y se borra la marca de lookup
if item.videolibray_emergency_urls:
del item.videolibray_emergency_urls #... y se borra la marca de lookup original
#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...
try:
@@ -921,7 +999,9 @@ def emergency_urls(item, channel=None, path=None):
if item_res.post: post = item_res.post
for url in item_res.emergency_urls[0]: #Recorremos las urls de emergencia...
torrents_path = re.sub(r'(?:\.\w+$)', '_%s.torrent' % str(i).zfill(2), path)
path_real = caching_torrents(url, referer, post, torrents_path=torrents_path) #... para descargar los .torrents
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
i += 1
@@ -944,140 +1024,3 @@ def emergency_urls(item, channel=None, path=None):
#logger.debug(item_res.emergency_urls)
return item_res #Devolvemos el Item actualizado con los enlaces de emergencia
def caching_torrents(url, referer=None, post=None, torrents_path=None, timeout=10, lookup=False, data_torrent=False):
if torrents_path != None:
logger.info("path = " + torrents_path)
else:
logger.info()
if referer and post:
logger.info('REFERER: ' + referer)
from core import httptools
torrent_file = ''
headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Referer': referer} #Necesario para el Post del .Torrent
"""
Descarga en el path recibido el .torrent de la url recibida, y pasa el decode
Devuelve el path real del .torrent, o el path vacío si la operación no ha tenido éxito
"""
videolibrary_path = config.get_videolibrary_path() #Calculamos el path absoluto a partir de la Videoteca
if torrents_path == None:
if not videolibrary_path:
torrents_path = ''
if data_torrent:
return (torrents_path, torrent_file)
return torrents_path #Si hay un error, devolvemos el "path" vacío
torrents_path = filetools.join(videolibrary_path, 'temp_torrents_Alfa', 'cliente_torrent_Alfa.torrent') #path de descarga temporal
if '.torrent' not in torrents_path:
torrents_path += '.torrent' #path para dejar el .torrent
torrents_path_encode = filetools.encode(torrents_path) #encode utf-8 del path
if url.endswith(".rar") or url.startswith("magnet:"): #No es un archivo .torrent
logger.error('It is not a Torrent file: ' + url)
torrents_path = ''
if data_torrent:
return (torrents_path, torrent_file)
return torrents_path #Si hay un error, devolvemos el "path" vacío
try:
#Descargamos el .torrent
if referer and post: #Descarga con POST
response = httptools.downloadpage(url, headers=headers, post=post, follow_redirects=False, timeout=timeout)
else: #Descarga sin post
response = httptools.downloadpage(url, timeout=timeout)
if not response.sucess:
logger.error('.Torrent file not found: ' + url)
torrents_path = ''
if data_torrent:
return (torrents_path, torrent_file)
return torrents_path #Si hay un error, devolvemos el "path" vacío
torrent_file = response.data
if "used CloudFlare" in torrent_file: #Si tiene CloudFlare, usamos este proceso
response = httptools.downloadpage("http://anonymouse.org/cgi-bin/anon-www.cgi/" + url.strip(), timeout=timeout)
if not response.sucess:
logger.error('Archivo .torrent no encontrado: ' + url)
torrents_path = ''
if data_torrent:
return (torrents_path, torrent_file)
return torrents_path #Si hay un error, devolvemos el "path" vacío
torrent_file = response.data
#Si es un archivo .ZIP tratamos de extraer el contenido
if torrent_file.startswith("PK"):
logger.info('It is a .ZIP file: ' + url)
torrents_path_zip = filetools.join(videolibrary_path, 'temp_torrents_zip') #Carpeta de trabajo
torrents_path_zip = filetools.encode(torrents_path_zip)
torrents_path_zip_file = filetools.join(torrents_path_zip, 'temp_torrents_zip.zip') #Nombre del .zip
import time
filetools.rmdirtree(torrents_path_zip) #Borramos la carpeta temporal
time.sleep(1) #Hay que esperar, porque si no da error
filetools.mkdir(torrents_path_zip) #La creamos de nuevo
if filetools.write(torrents_path_zip_file, torrent_file): #Salvamos el .zip
torrent_file = '' #Borramos el contenido en memoria
try: #Extraemos el .zip
from core import ziptools
unzipper = ziptools.ziptools()
unzipper.extract(torrents_path_zip_file, torrents_path_zip)
except:
import xbmc
xbmc.executebuiltin('XBMC.Extract("%s", "%s")' % (torrents_path_zip_file, torrents_path_zip))
time.sleep(1)
import os
for root, folders, files in os.walk(torrents_path_zip): #Recorremos la carpeta para leer el .torrent
for file in files:
if file.endswith(".torrent"):
input_file = filetools.join(root, file) #nombre del .torrent
torrent_file = filetools.read(input_file) #leemos el .torrent
filetools.rmdirtree(torrents_path_zip) #Borramos la carpeta temporal
#Si no es un archivo .torrent (RAR, HTML,..., vacío) damos error
if not scrapertools.find_single_match(torrent_file, '^d\d+:.*?\d+:'):
logger.error('It is not a Torrent file: ' + url)
torrents_path = ''
if data_torrent:
return (torrents_path, torrent_file)
return torrents_path #Si hay un error, devolvemos el "path" vacío
#Salvamos el .torrent
if not lookup:
if not filetools.write(torrents_path_encode, torrent_file):
logger.error('ERROR: Unwritten .torrent file: ' + torrents_path_encode)
torrents_path = '' #Si hay un error, devolvemos el "path" vacío
torrent_file = '' #... y el buffer del .torrent
if data_torrent:
return (torrents_path, torrent_file)
return torrents_path
except:
torrents_path = '' #Si hay un error, devolvemos el "path" vacío
torrent_file = '' #... y el buffer del .torrent
logger.error('ERROR: .Torrent download process failed: ' + url + ' / ' + torrents_path_encode)
logger.error(traceback.format_exc())
#logger.debug(torrents_path)
if data_torrent:
return (torrents_path, torrent_file)
return torrents_path
def verify_url_torrent(url, timeout=5):
"""
Verifica si el archivo .torrent al que apunta la url está disponible, descargándolo en un area temporal
Entrada: url
Salida: True o False dependiendo del resultado de la operación
"""
if not url or url == 'javascript:;': #Si la url viene vacía...
return False #... volvemos con error
torrents_path = caching_torrents(url, timeout=timeout, lookup=True) #Descargamos el .torrent
if torrents_path: #Si ha tenido éxito...
return True
else:
return False
+35 -25
View File
@@ -3,22 +3,26 @@
# Zip Tools
# --------------------------------------------------------------------------------
import io
import os
from builtins import object
import sys
PY3 = False
VFS = True
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int; VFS = False
import zipfile
from platformcode import config, logger
from core import filetools
class ziptools:
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)
if not dir.endswith(':') and not os.path.exists(dir):
os.mkdir(dir)
if not dir.endswith(':') and not filetools.exists(dir):
filetools.mkdir(dir)
file = io.FileIO(file)
zf = zipfile.ZipFile(file)
if not folder_to_extract:
self._createstructure(file, dir)
@@ -30,60 +34,66 @@ class ziptools:
if not name.endswith('/'):
logger.info("no es un directorio")
try:
(path, filename) = os.path.split(os.path.join(dir, name))
(path, filename) = filetools.split(filetools.join(dir, name))
logger.info("path=%s" % path)
logger.info("name=%s" % name)
if folder_to_extract:
if path != os.path.join(dir, folder_to_extract):
if path != filetools.join(dir, folder_to_extract):
break
else:
os.makedirs(path)
filetools.mkdir(path)
except:
pass
if folder_to_extract:
outfilename = os.path.join(dir, filename)
outfilename = filetools.join(dir, filename)
else:
outfilename = os.path.join(dir, name)
outfilename = filetools.join(dir, name)
logger.info("outfilename=%s" % outfilename)
try:
if os.path.exists(outfilename) and overwrite_question:
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?" \
% os.path.basename(outfilename))
% filetools.basename(outfilename))
if not dyesno:
break
if backup:
import time
import shutil
hora_folder = "Copia seguridad [%s]" % time.strftime("%d-%m_%H-%M", time.localtime())
backup = os.path.join(config.get_data_path(), 'backups', hora_folder, folder_to_extract)
if not os.path.exists(backup):
os.makedirs(backup)
shutil.copy2(outfilename, os.path.join(backup, os.path.basename(outfilename)))
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)))
outfile = open(outfilename, 'wb')
outfile.write(zf.read(nameo))
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)
except:
import traceback
logger.error(traceback.format_exc())
logger.error("Error en fichero " + nameo)
try:
zf.close()
except:
logger.info("Error cerrando .zip " + file)
def _createstructure(self, file, dir):
self._makedirs(self._listdirs(file), dir)
def create_necessary_paths(filename):
try:
(path, name) = os.path.split(filename)
os.makedirs(path)
(path, name) = filetools.split(filename)
filetools.mkdir(path)
except:
pass
def _makedirs(self, directories, basedir):
for dir in directories:
curdir = os.path.join(basedir, dir)
if not os.path.exists(curdir):
os.mkdir(curdir)
curdir = filetools.join(basedir, dir)
if not filetools.exists(curdir):
filetools.mkdir(curdir)
def _listdirs(self, file):
zf = zipfile.ZipFile(file)