From 68b5f77e93ae77183a2540b1acfc9559651f41d9 Mon Sep 17 00:00:00 2001 From: Kevin Date: Thu, 21 Jun 2018 17:25:43 +0200 Subject: [PATCH 01/37] Multilang support --- mediaserver/platformcode/config.py | 3 +-- mediaserver/resources/settings.xml | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mediaserver/platformcode/config.py b/mediaserver/platformcode/config.py index 832bc738..cd810bd2 100644 --- a/mediaserver/platformcode/config.py +++ b/mediaserver/platformcode/config.py @@ -368,9 +368,8 @@ menufilepath = os.path.join(get_runtime_path(), "resources", "settings.xml") configfilepath = os.path.join(get_data_path(), "settings.xml") if not os.path.exists(get_data_path()): os.mkdir(get_data_path()) -# Literales -TRANSLATION_FILE_PATH = os.path.join(get_runtime_path(), "resources", "language", "Spanish", "strings.po") load_settings() +TRANSLATION_FILE_PATH = os.path.join(get_runtime_path(), "resources", "language", settings_dic["mediacenter_language"], "strings.po") # modo adulto: # sistema actual 0: Nunca, 1:Siempre, 2:Solo hasta que se reinicie sesión diff --git a/mediaserver/resources/settings.xml b/mediaserver/resources/settings.xml index 5fe48645..8a7e6746 100644 --- a/mediaserver/resources/settings.xml +++ b/mediaserver/resources/settings.xml @@ -7,7 +7,8 @@ - + + From 7f2d99238ce6364036383ea6a74c3d2bcea34087 Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 26 Jun 2018 23:06:41 +0200 Subject: [PATCH 02/37] Fix Localized Strings in JSON Files (Mediaserver) --- mediaserver/platformcode/controllers/html.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mediaserver/platformcode/controllers/html.py b/mediaserver/platformcode/controllers/html.py index 573171a1..6268f13f 100644 --- a/mediaserver/platformcode/controllers/html.py +++ b/mediaserver/platformcode/controllers/html.py @@ -696,15 +696,17 @@ class platform(Platformtools): c["value"] = dict_values[c["id"]] # Translation - if c['label'].startswith('@') and unicode(c['label'][1:]).isnumeric(): - c['label'] = str(config.get_localized_string(c['label'][1:])) + string_id = re.findall(r'\$ADDON\[[^\d]+(\d+)]', c['label'], flags=re.DOTALL) + if c['label'].startswith('$') and len(string_id) > 0: + c['label'] = str(config.get_localized_string(string_id[0])) if c["label"].endswith(":"): c["label"] = c["label"][:-1] if c['type'] == 'list': lvalues = [] for li in c['lvalues']: - if li.startswith('@') and unicode(li[1:]).isnumeric(): - lvalues.append(str(config.get_localized_string(li[1:]))) + string_id = re.findall(r'\$ADDON\[[^\d]+(\d+)]', li, flags=re.DOTALL) + if li.startswith('$') and len(string_id) > 0: + lvalues.append(str(config.get_localized_string(string_id[0]))) else: lvalues.append(li) c['lvalues'] = lvalues From 5e5459337cf2348b202ed1fc29ed221f3f6c1d75 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Sat, 30 Jun 2018 08:27:19 -0500 Subject: [PATCH 03/37] config.py: add get_addon_version() --- plugin.video.alfa/platformcode/config.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/plugin.video.alfa/platformcode/config.py b/plugin.video.alfa/platformcode/config.py index ac49a136..ad13942b 100644 --- a/plugin.video.alfa/platformcode/config.py +++ b/plugin.video.alfa/platformcode/config.py @@ -15,6 +15,27 @@ __settings__ = xbmcaddon.Addon(id="plugin.video." + PLUGIN_NAME) __language__ = __settings__.getLocalizedString +def get_addon_version(linea_inicio=0, total_lineas=2): + ''' + Devuelve el número de de versión del addon, obtenido desde el archivo addon.xml + ''' + path = get_runtime_path() + "\\addon.xml" + f = open(path, "rb") + data = [] + for x, line in enumerate(f): + if x < linea_inicio: continue + if len(data) == total_lineas: break + data.append(line) + f.close() + data1 = "".join(data) + # + aux = re.findall(' 0: + version = aux[0] + return version + + def get_platform(full_version=False): """ Devuelve la información la version de xbmc o kodi sobre el que se ejecuta el plugin From ac1b346019718c767fecbd5095ab58c1adeed231 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Sat, 30 Jun 2018 08:41:34 -0500 Subject: [PATCH 04/37] config.py: add get_addon.version() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Método para obtener la versión de alfa --- mediaserver/platformcode/config.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/mediaserver/platformcode/config.py b/mediaserver/platformcode/config.py index 12b0c80b..4caf5486 100644 --- a/mediaserver/platformcode/config.py +++ b/mediaserver/platformcode/config.py @@ -14,6 +14,27 @@ settings_dic = {} adult_setting = {} +def get_addon_version(linea_inicio=0, total_lineas=2): + ''' + Devuelve el número de de versión del addon, obtenido desde el archivo addon.xml + ''' + path = get_runtime_path() + "\\addon.xml" + f = open(path, "rb") + data = [] + for x, line in enumerate(f): + if x < linea_inicio: continue + if len(data) == total_lineas: break + data.append(line) + f.close() + data1 = "".join(data) + # + aux = re.findall(' 0: + version = aux[0] + return version + + def get_platform(full_version=False): # full_version solo es util en xbmc/kodi ret = { From ca83da0350ce716164edbda525790f331947dd16 Mon Sep 17 00:00:00 2001 From: pipcat Date: Mon, 2 Jul 2018 09:32:17 +0200 Subject: [PATCH 05/37] Modificaciones gktools y timeout --- plugin.video.alfa/channels/animeyt.py | 359 +++++++++++++++-- plugin.video.alfa/channels/pelispedia.py | 53 ++- plugin.video.alfa/channels/setting.py | 2 + plugin.video.alfa/core/httptools.py | 6 + plugin.video.alfa/core/servertools.py | 28 +- plugin.video.alfa/lib/gktools.py | 374 +++++++++--------- plugin.video.alfa/lib/rijndael/__init__.py | 23 ++ plugin.video.alfa/lib/rijndael/rijndael.py | 361 +++++++++++++++++ .../lib/rijndael/rijndael_cbc.py | 71 ++++ 9 files changed, 1068 insertions(+), 209 deletions(-) create mode 100644 plugin.video.alfa/lib/rijndael/__init__.py create mode 100644 plugin.video.alfa/lib/rijndael/rijndael.py create mode 100644 plugin.video.alfa/lib/rijndael/rijndael_cbc.py diff --git a/plugin.video.alfa/channels/animeyt.py b/plugin.video.alfa/channels/animeyt.py index c8810dca..85925a62 100644 --- a/plugin.video.alfa/channels/animeyt.py +++ b/plugin.video.alfa/channels/animeyt.py @@ -11,7 +11,7 @@ from core.item import Item from core import tmdb from platformcode import config,logger -import gktools +import gktools, random, time, urllib __modo_grafico__ = config.get_setting('modo_grafico', 'animeyt') @@ -32,6 +32,10 @@ def mainlist(item): itemlist = renumbertools.show_option(item.channel, itemlist) + # ~ prova = 'EIpStovt0/tFerZM4pviHBzddH308TWRR41XnHv9N4tUNih6r+GjCDa/cV1uVUQXEmZd1Hsu2ABzESzBMGiK6XUdRgYZYHImmrIWcn3tfYPCuSWBc2UgwxUtR+WOsov6YiGM5AdgJGFunoN' + # ~ aux = gktools.decode_rijndael(prova, preIV = 'b3512f4972d314da9', key='3e1a854e7d5835ab99d99a29afec8bbb') + # ~ itemlist.append(Item(channel=item.channel, title=aux, action="novedades", url=HOST)) + return itemlist @@ -160,20 +164,24 @@ def findvideos(item): data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t| |
", "", data) - # ~ patron = 'Player\("(.*?)"' - patron = 'iframe src="([^"]*)"' + from collections import OrderedDict # cambiado dict por OrderedDict para mantener el mismo orden que en la web - matches = scrapertools.find_multiple_matches(data, patron) + matches = scrapertools.find_multiple_matches(data, '
  • ([^<]*)') + d_links = OrderedDict(matches) + + matches = scrapertools.find_multiple_matches(data, 'if \(mirror == (\d*)\).*?iframe src="([^"]*)"') + d_frames = OrderedDict(matches) + + for k in d_links: + if k in d_frames and d_frames[k] != '': + tit = scrapertools.find_single_match(d_frames[k], '/([^\./]*)\.php\?') + if tit == '': + tit = 'mega' if 'mega.nz/' in d_frames[k] else 'dailymotion' if 'dailymotion.com/' in d_frames[k] else'noname' + if tit == 'id' and 'yourupload.com/' in d_frames[k]: tit = 'yourupload' + title = 'Opción %s (%s)' % (d_links[k], tit) + + itemlist.append(item.clone(channel=item.channel, folder=False, title=title, action="play", url=d_frames[k], referer=item.url)) - for url in matches: - title = scrapertools.find_single_match(url, '/([^\.]*)\.php\?') - # ~ title = 'PDT' - # ~ if "cldup" in url: - # ~ title = "Opcion Cldup" - # ~ if "chumi" in url: - # ~ title = "Opcion Chumi" - if title == 'rakuten': # de momento es el único resuelto - itemlist.append(item.clone(channel=item.channel, folder=False, title=title, action="play", url=url, referer=item.url)) if item.extra != "library": if config.get_videolibrary_support() and item.extra: @@ -186,14 +194,321 @@ def play(item): logger.info() itemlist = [] - if 'https://s2.animeyt.tv/rakuten.php?' in item.url: - itemlist = gktools.gk_play(item) + if item.url.startswith('https://www.dailymotion.com/'): + itemlist.append(item.clone(url=item.url, server='dailymotion')) + + elif item.url.startswith('https://mega.nz/'): + itemlist.append(item.clone(url=item.url.replace('embed',''), server='mega')) + + elif item.url.startswith('https://s2.animeyt.tv/rakuten.php?'): + # 1- Descargar + data, ck = gktools.get_data_and_cookie(item) + + # 2- Calcular datos + gsv = scrapertools.find_single_match(data, ' 0 and it.server != '' and it.url != '': - verificacion = check_video_link(it.url, it.server) + verificacion = check_video_link(it.url, it.server, timeout) it.title = verificacion + ', ' + it.title.strip() it.alive = verificacion numero -= 1 return itemlist -def check_video_link(url, server): +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 @@ -734,17 +740,23 @@ def check_video_link(url, server): return "??" if hasattr(server_module, 'test_video_exists'): + ant_timeout = httptools.HTTPTOOLS_DEFAULT_DOWNLOAD_TIMEOUT + httptools.HTTPTOOLS_DEFAULT_DOWNLOAD_TIMEOUT = timeout # Limitar tiempo de descarga try: video_exists, message = server_module.test_video_exists(page_url=url) if not video_exists: logger.info("[check_video_link] No existe! %s %s %s" % (message, server, url)) - return "NO" + resultado = "NO" else: - logger.info("[check_video_link] comprovacion OK %s %s" % (server, url)) - return "Ok" + logger.info("[check_video_link] comprobacion OK %s %s" % (server, url)) + resultado = "Ok" except: logger.info("[check_video_link] No se puede comprobar ahora! %s %s" % (server, url)) - return "??" + resultado = "??" + + finally: + httptools.HTTPTOOLS_DEFAULT_DOWNLOAD_TIMEOUT = ant_timeout # Restaurar tiempo de descarga + return resultado logger.info("[check_video_link] No hay test_video_exists para servidor: %s" % server) return "??" diff --git a/plugin.video.alfa/lib/gktools.py b/plugin.video.alfa/lib/gktools.py index c71c0909..59585389 100644 --- a/plugin.video.alfa/lib/gktools.py +++ b/plugin.video.alfa/lib/gktools.py @@ -1,145 +1,164 @@ # -*- coding: utf-8 -*- ''' +gktools son un conjunto de funciones para ayudar a resolver enlaces a videos con "protección GK". +Lo de protección gk dudo que exista, le he llamado así pq los primeros ejemplos vistos se eran gkpluginsphp y gkpedia. + Características "GK" : - Utiliza una cookie __cfduid -- Utiliza meta name="google-site-verification" como texto a encriptar -- La clave para encriptar se calcula en los js -- Se calcula un token criptográfico en función del texto y clave +- Calcula un token criptográfico en función de un texto y una clave +- El texto se saca del html (por ejemplo de meta name="google-site-verification", pero puede ser más complejo) +- La clave para encriptar se calcula en js ofuscados que carga el html +- Se llama a otra url con una serie de parámetros, como el token, y de allí se obtienen los videos finales. -A partir de aquí 2 opciones: +Howto: +1- descargar página +2- extraer datos y calcular los necesarios +3- descargar segunda página con el token calculado +4- extraer videos -a) Si la url indica que hay un /embed/ - - se cambia /embed/ por /stream/ y se añade /token - - se descarga la página, dónde se pueden extraer los videos - -b) Sino (enlaces directos) - - se busca un identificador - - si hay una llamada a Play() en el js, el id se saca de allí - - sino el id puede estar en la url - - con el identificador y el token se llama a un php (gkpluginsphp, gkpedia) - - el php devuelve la lista de enlaces a los videos +El paso 2 es con diferencia el más variable y depende mucho de cada web/servidor! +Desofuscando los js se pueden ver los datos propios que necesita cada uno +(el texto a encriptar, la clave a usar, la url dónde hay que llamar y los parámetros) -Notas: -- Creado a partir de lo visto en pelispedia y animeyt, que utilizan este sistema. -- Para otros canales habrá que añadir sus datos en las funciones calcular_* - o hacer que estas funciones puedan extraer lo necesario de los js. +Ver ejemplos en el código de los canales animeyt y pelispedia + +Created for Alfa-addon by Alfa Developers Team 2018 ''' # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -import urlparse +import os, base64, json, hashlib, urlparse from core import httptools from core import scrapertools -# ~ from platformcode import logger +from platformcode import logger +from aadecode import decode as aadecode -def gk_play(item): +# Descarga página y captura la petición de cookie +# ----------------------------------------------- +def get_data_and_cookie(item, ck_name='__cfduid'): - itemlist = [] - - # Descargar para tratar header y data por separado - # ------------------------------------------------ headers = {'Referer': item.referer} resp = httptools.downloadpage(item.url, headers=headers, cookies=False) # ~ with open('gk_play1.html', 'w') as f: f.write(resp.data); f.close() - # Obtener cookie __cfduid - # ----------------------- - for h in resp.headers: - ck = scrapertools.find_single_match(resp.headers[h], '__cfduid=([^;]*)') - if ck: - break - if not ck: return itemlist + ck_value = '' + if ck_name != '': + for h in resp.headers: + ck = scrapertools.find_single_match(resp.headers[h], '%s=([^;]*)' % ck_name) + if ck: + ck_value = ck + break - # Extraer datos y calcular token - # ------------------------------ - gsv = scrapertools.find_single_match(resp.data, 'Vidoza' in data or '|fastplay|' in data: - if '|fastplay|' in data: - packed = scrapertools.find_single_match(data, "") - from lib import jsunpack - data = jsunpack.unpack(packed) - data = data.replace("\\'", "'") - - matches = scrapertools.find_multiple_matches(data, 'file\s*:\s*"([^"]+)"\s*,\s*label\s*:\s*"([^"]+)"') - subtitle = '' - for fil, lbl in matches: - if fil.endswith('.srt') and not fil.endswith('empty.srt'): - subtitle = fil - if not subtitle.startswith('http'): - domi = scrapertools.find_single_match(data, 'aboutlink\s*:\s*"([^"]*)') - subtitle = domi + subtitle - break - - for fil, lbl in matches: - if not fil.endswith('.srt'): - itemlist.append([lbl, fil, 0, subtitle]) + return data +# Descarga json usando una cookie concreta +# ---------------------------------------- +def get_data_json(url, post, ck_value='', referer='', ck_name='__cfduid'): + + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Cookie': ck_name+'='+ck_value} + if referer != '': headers['referer'] = referer + + data = httptools.downloadpage(url, post=post, headers=headers, cookies=False).data + # ~ with open('gk_play3.html', 'w') as f: f.write(data); f.close() + + return data + + +# Obtiene link de una llamada javascript Play() o de la url +# --------------------------------------------------------- +def get_play_link_id(data, url): + + playparms = scrapertools.find_single_match(data, 'Play\("([^"]*)","([^"]*)","([^"]*)"') + if playparms: + link = playparms[0] + subtitle = '' if playparms[1] == '' or playparms[2] == '' else playparms[2] + playparms[1] + '.srt' else: - playparms = scrapertools.find_single_match(resp.data, 'Play\("([^"]*)","([^"]*)","([^"]*)"') - if playparms: - link = playparms[0] - subtitle = '' if playparms[1] == '' or playparms[2] == '' else playparms[2] + playparms[1] + '.srt' + subtitle = '' + link = scrapertools.find_single_match(data, 'Play\("([^"]*)"') + if not link: + link = scrapertools.find_single_match(url, 'id=([^;]*)') + + return link, subtitle + + +# Extraer enlaces a videos de datos json +# -------------------------------------- +def extraer_enlaces_json(data, referer, subtitle=''): + itemlist = [] + + # Ejemplos: + # {"Animeyt":[{"file":"https:\/\/storage.googleapis.com\/my-project-yt-195318.appspot.com\/slow.mp4","type":"mp4","label":"1080p"}]} + # {"link":[{"link":"http:\/\/video8.narusaku.tv\/static\/720p\/2.1208982.2039540?md5=B64FKYNbFuWvxkGcSbtz2Q&expires=1528839657","label":"720p","type":"mp4"},{"link":"http:\/\/video5.narusaku.tv\/static\/480p\/2.1208982.2039540?md5=yhLG_3VghEUSd5YlCXOTBQ&expires=1528839657","label":"480p","type":"mp4","default":true},{"link":"http:\/\/video3.narusaku.tv\/static\/360p\/2.1208982.2039540?md5=vC0ZJkxRwV1rVBdeF7D4iA&expires=1528839657","label":"360p","type":"mp4"},{"link":"http:\/\/video2.narusaku.tv\/static\/240p\/2.1208982.2039540?md5=b-y_-rgrLMW7hJwFQSD8Tw&expires=1528839657","label":"240p","type":"mp4"}]} + # {"link":"https:\/\/storage.googleapis.com\/cloudflare-caching-pelispedia.appspot.com\/cache\/16050.mp4","type":"mp4"} + # {"Harbinger":[{"Harbinger":"...","type":"...","label":"..."}], ...} + + data = data.replace('"Harbinger"', '"file"') + + # Intentar como json + # ------------------ + try: + json_data = json.loads(data) + enlaces = analizar_enlaces_json(json_data) + for enlace in enlaces: + url = enlace['link'] if 'link' in enlace else enlace['file'] + if not url.startswith('http'): url = aadecode(base64.b64decode(url)) # necesario para "Harbinger" + if not url.startswith('http'): url = decode_rijndael(url) # post-"Harbinger" en algunos casos + tit = '' + if 'type' in enlace: tit += '[%s]' % enlace['type'] + if 'label' in enlace: tit += '[%s]' % enlace['label'] + if tit == '': tit = '.mp4' + + itemlist.append([tit, corregir_url(url, referer), 0, subtitle]) + + # Sino, intentar como texto + # ------------------------- + except: + matches = scrapertools.find_multiple_matches(data, '"link"\s*:\s*"([^"]*)"\s*,\s*"label"\s*:\s*"([^"]*)"\s*,\s*"type"\s*:\s*"([^"]*)"') + if matches: + for url, lbl, typ in matches: + itemlist.append(['[%s][%s]' % (typ, lbl), corregir_url(url, referer), 0, subtitle]) else: - subtitle = '' - link = scrapertools.find_single_match(resp.data, 'Play\("([^"]*)"') - if not link: - link = scrapertools.find_single_match(item.url, 'id=([^;]*)') - - if link: - # ~ logger.info('%s %s %s' % (item.url, link, token)) - url_gk = calcular_url_gk(item.url) - - post = "link=%s&token=%s" % (link, token) - headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Cookie': '__cfduid=' + ck} - - data = httptools.downloadpage(url_gk, post=post, headers=headers, cookies=False).data - # ~ with open('gk_play3.html', 'w') as f: f.write(resp.data); f.close() - - # Extraer enlaces de la respuesta - # ------------------------------- - matches = scrapertools.find_multiple_matches(data, '"link"\s*:\s*"([^"]*)"\s*,\s*"label"\s*:\s*"([^"]*)"\s*,\s*"type"\s*:\s*"([^"]*)"') - if matches: - for url, lbl, typ in matches: - itemlist.append(['[%s][%s]' % (typ, lbl), corregir_url(url, item.referer), 0, subtitle]) - else: - url = scrapertools.find_single_match(data, '"link"\s*:\s*"([^"]*)"') - if url: - itemlist.append(['.mp4', corregir_url(url, item.referer), 0, subtitle]) + url = scrapertools.find_single_match(data, '"link"\s*:\s*"([^"]*)"') + if url: + itemlist.append(['.mp4', corregir_url(url, referer), 0, subtitle]) return itemlist -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Función recursiva que busca videos en un diccionario +# ---------------------------------------------------- +def analizar_enlaces_json(d): + itemlist = [] + found = {} + for k, v in d.iteritems(): + if k in ['file','link','type','label'] and not isinstance(v, list): + found[k] = v + + if isinstance(v, list): + for l in v: + if isinstance(l, dict): itemlist += analizar_enlaces_json(l) + + if 'file' in found or 'link' in found: + itemlist.append(found) + + return itemlist + # Correcciones en las urls finales obtenidas # ------------------------------------------ @@ -149,6 +168,66 @@ def corregir_url(url, referer): return url + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +# Conversion tipo hexa que hay en el js +# ------------------------------------- +def toHex(txt): + ret = '' + for i in range(len(txt)): + ret += str(hex(ord(txt[i]))).replace('x','')[-2:] + return ret + + +# Subrutinas de encriptación +# -------------------------- + +def md5_dominio(url): # sutorimux/kubechi + h = hashlib.md5(urlparse.urlparse(url).netloc) + return h.hexdigest() + + +def transforma_gsv(gsv, valor): + llista = range(256) + a = 0 + for i in range(256): + a = (a + llista[i] + ord(gsv[i % len(gsv)]) ) % 256 + b = llista[i] + llista[i] = llista[a] + llista[a] = b + + ret = '' + a = 0; b= 0 + for i in range(len(valor)): + a = (a + 1) % 256 + b = (b + llista[a]) % 256 + c = llista[a] + llista[a] = llista[b] + llista[b] = c + ret += chr(ord(valor[i]) ^ llista[(llista[a] + llista[b]) % 256]) + + return base64.b64encode(ret) + + + +# Codificar/Decodificar con Rijndael +# ---------------------------------- + +def encode_rijndael(msg, IV, key): + import rijndael + return rijndael.cbc_encrypt(msg, IV, key) + + +def decode_rijndael(txt, preIV='b3512f4972d314da9', key='3e1a854e7d5835ab99d99a29afec8bbb'): + import rijndael + msg = base64.b64decode(txt[:-15]) + IV = preIV + txt[-15:] + deco = rijndael.cbc_decrypt(msg, IV, key) + return deco.replace(chr(0), '') + + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -159,6 +238,7 @@ def corregir_url(url, referer): # pwd: Password def generar_token(gsv, pwd): txt = obtener_cripto(pwd, gsv) + # ~ logger.info('Texto pre token %s' % txt) _0x382d28 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' @@ -182,18 +262,17 @@ def generar_token(gsv, pwd): def obtener_cripto(password, plaintext): - import os, base64, json - SALT_LENGTH = 8 - BLOCK_SIZE = 16 - KEY_SIZE = 32 - - salt = os.urandom(SALT_LENGTH) - iv = os.urandom(BLOCK_SIZE) - - paddingLength = 16 - (len(plaintext) % 16) - paddedPlaintext = plaintext+chr(paddingLength)*paddingLength + salt = os.urandom(8) + paddingLength = len(plaintext) % 16 + if paddingLength == 0: + paddedPlaintext = plaintext + else: + dif = 16 - paddingLength + paddedPlaintext = plaintext + chr(dif)*dif + kdf = evpKDF(password, salt) + iv = kdf['iv'] try: # Intentar con librería AES del sistema from Crypto.Cipher import AES @@ -207,7 +286,6 @@ def obtener_cripto(password, plaintext): def evpKDF(passwd, salt, key_size=8, iv_size=4, iterations=1, hash_algorithm="md5"): - import hashlib target_key_size = key_size + iv_size derived_bytes = "" number_of_derived_words = 0 @@ -235,63 +313,3 @@ def evpKDF(passwd, salt, key_size=8, iv_size=4, iterations=1, hash_algorithm="md "key": derived_bytes[0: key_size * 4], "iv": derived_bytes[key_size * 4:] } - - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -# Valores extraídos de los js para los dominios tratados (pendiente automatizar!) -# Ej: https://pelispedia.video/plugins/gkpluginsphp.js?v=3.3 -# Ej: https://s2.animeyt.tv/rakuten/plugins/rakuten676.js?v=200000000 - -def calcular_sutorimux(url): - dominio = urlparse.urlparse(url).netloc - claves = { - 'pelispedia.video': 'b0a8c83650f18ccc7c87b16e3c460474', - 'load.pelispedia.vip': '4fe554b59d760c9986c903b07af8b7a4', - - 's1.animeyt.tv': '0cdf0d0302091bc22a0afdc3f13c0773', - 's2.animeyt.tv': '079c3ee3ca289af95d819d93b852ed94', - 's3.animeyt.tv': '6c21a435bce9f5926d26db567fee1241', - 's4.animeyt.tv': '38546fb4797f2f7c5b6690a5b4a47e34', - 's10.animeyt.tv': 'be88e4cc014c0ae6f9f2d1f947b3b23b', - 's.animeyt.tv': '49f911abffe682820dc5b54777713974', - 'server.animeyt.tv': '2c60637d7f7aa54225c20aea61a2b468', - 'api.animeyt.tv': '54092dea9fd2e163aaa59ad0c4351866', - } - return '' if dominio not in claves else claves[dominio] - - -def calcular_sufijo(url): - dominio = urlparse.urlparse(url).netloc - claves = { - 'pelispedia.video': '2653', - 'load.pelispedia.vip': '785446346', - - 's1.animeyt.tv': '', - 's2.animeyt.tv': '3497510', - 's3.animeyt.tv': '', - 's4.animeyt.tv': '', - 's10.animeyt.tv': '', - 's.animeyt.tv': '', - 'server.animeyt.tv': '', - 'api.animeyt.tv': '', - } - return '' if dominio not in claves else claves[dominio] - - -def calcular_url_gk(url): - dominio = urlparse.urlparse(url).netloc - claves = { - 'pelispedia.video': 'https://pelispedia.video/plugins/cloupedia.php', # plugins/gkpedia.php - 'load.pelispedia.vip': '', - - 's1.animeyt.tv': '', - 's2.animeyt.tv': 'https://s2.animeyt.tv/rakuten/plugins/gkpluginsphp.php', - 's3.animeyt.tv': '', - 's4.animeyt.tv': '', - 's10.animeyt.tv': '', - 's.animeyt.tv': '', - 'server.animeyt.tv': '', - 'api.animeyt.tv': '', - } - return '' if dominio not in claves else claves[dominio] diff --git a/plugin.video.alfa/lib/rijndael/__init__.py b/plugin.video.alfa/lib/rijndael/__init__.py new file mode 100644 index 00000000..776f8091 --- /dev/null +++ b/plugin.video.alfa/lib/rijndael/__init__.py @@ -0,0 +1,23 @@ +from rijndael import rijndael +from rijndael_cbc import zeropad, cbc + +import base64 + + +def cbc_encrypt(msg, IV, key, size=32): + + r = rijndael(key, size) + pad = zeropad(size) + cri = cbc(pad, r, IV) + encod = cri.encrypt(msg) + + return encod #.encode('hex') + + +def cbc_decrypt(msg, IV, key, size=32): + + r = rijndael(key, size) + pad = zeropad(size) + cri = cbc(pad, r, IV) + + return cri.decrypt(msg) diff --git a/plugin.video.alfa/lib/rijndael/rijndael.py b/plugin.video.alfa/lib/rijndael/rijndael.py new file mode 100644 index 00000000..d185d952 --- /dev/null +++ b/plugin.video.alfa/lib/rijndael/rijndael.py @@ -0,0 +1,361 @@ +""" +A pure python (slow) implementation of rijndael with a decent interface + +To include - + +from rijndael import rijndael + +To do a key setup - + +r = rijndael(key, block_size = 16) + +key must be a string of length 16, 24, or 32 +blocksize must be 16, 24, or 32. Default is 16 + +To use - + +ciphertext = r.encrypt(plaintext) +plaintext = r.decrypt(ciphertext) + +If any strings are of the wrong length a ValueError is thrown +""" + +# ported from the Java reference code by Bram Cohen, April 2001 +# this code is public domain, unless someone makes +# an intellectual property claim against the reference +# code, in which case it can be made public domain by +# deleting all the comments and renaming all the variables + +import copy +import string + +shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]], + [[0, 0], [1, 5], [2, 4], [3, 3]], + [[0, 0], [1, 7], [3, 5], [4, 4]]] + +# [keysize][block_size] +num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}} + +A = [[1, 1, 1, 1, 1, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 0], + [0, 0, 0, 1, 1, 1, 1, 1], + [1, 0, 0, 0, 1, 1, 1, 1], + [1, 1, 0, 0, 0, 1, 1, 1], + [1, 1, 1, 0, 0, 0, 1, 1], + [1, 1, 1, 1, 0, 0, 0, 1]] + +# produce log and alog tables, needed for multiplying in the +# field GF(2^m) (generator = 3) +alog = [1] +for i in range(255): + j = (alog[-1] << 1) ^ alog[-1] + if j & 0x100 != 0: + j ^= 0x11B + alog.append(j) + +log = [0] * 256 +for i in range(1, 255): + log[alog[i]] = i + +# multiply two elements of GF(2^m) +def mul(a, b): + if a == 0 or b == 0: + return 0 + return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255] + +# substitution box based on F^{-1}(x) +box = [[0] * 8 for i in range(256)] +box[1][7] = 1 +for i in range(2, 256): + j = alog[255 - log[i]] + for t in range(8): + box[i][t] = (j >> (7 - t)) & 0x01 + +B = [0, 1, 1, 0, 0, 0, 1, 1] + +# affine transform: box[i] <- B + A*box[i] +cox = [[0] * 8 for i in range(256)] +for i in range(256): + for t in range(8): + cox[i][t] = B[t] + for j in range(8): + cox[i][t] ^= A[t][j] * box[i][j] + +# S-boxes and inverse S-boxes +S = [0] * 256 +Si = [0] * 256 +for i in range(256): + S[i] = cox[i][0] << 7 + for t in range(1, 8): + S[i] ^= cox[i][t] << (7-t) + Si[S[i] & 0xFF] = i + +# T-boxes +G = [[2, 1, 1, 3], + [3, 2, 1, 1], + [1, 3, 2, 1], + [1, 1, 3, 2]] + +AA = [[0] * 8 for i in range(4)] + +for i in range(4): + for j in range(4): + AA[i][j] = G[i][j] + AA[i][i+4] = 1 + +for i in range(4): + pivot = AA[i][i] + if pivot == 0: + t = i + 1 + while AA[t][i] == 0 and t < 4: + t += 1 + assert t != 4, 'G matrix must be invertible' + for j in range(8): + AA[i][j], AA[t][j] = AA[t][j], AA[i][j] + pivot = AA[i][i] + for j in range(8): + if AA[i][j] != 0: + AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255] + for t in range(4): + if i != t: + for j in range(i+1, 8): + AA[t][j] ^= mul(AA[i][j], AA[t][i]) + AA[t][i] = 0 + +iG = [[0] * 4 for i in range(4)] + +for i in range(4): + for j in range(4): + iG[i][j] = AA[i][j + 4] + +def mul4(a, bs): + if a == 0: + return 0 + r = 0 + for b in bs: + r <<= 8 + if b != 0: + r = r | mul(a, b) + return r + +T1 = [] +T2 = [] +T3 = [] +T4 = [] +T5 = [] +T6 = [] +T7 = [] +T8 = [] +U1 = [] +U2 = [] +U3 = [] +U4 = [] + +for t in range(256): + s = S[t] + T1.append(mul4(s, G[0])) + T2.append(mul4(s, G[1])) + T3.append(mul4(s, G[2])) + T4.append(mul4(s, G[3])) + + s = Si[t] + T5.append(mul4(s, iG[0])) + T6.append(mul4(s, iG[1])) + T7.append(mul4(s, iG[2])) + T8.append(mul4(s, iG[3])) + + U1.append(mul4(t, iG[0])) + U2.append(mul4(t, iG[1])) + U3.append(mul4(t, iG[2])) + U4.append(mul4(t, iG[3])) + +# round constants +rcon = [1] +r = 1 +for t in range(1, 30): + r = mul(2, r) + rcon.append(r) + +del A +del AA +del pivot +del B +del G +del box +del log +del alog +del i +del j +del r +del s +del t +del mul +del mul4 +del cox +del iG + +class rijndael: + def __init__(self, key, block_size = 16): + if block_size != 16 and block_size != 24 and block_size != 32: + raise ValueError('Invalid block size: ' + str(block_size)) + if len(key) != 16 and len(key) != 24 and len(key) != 32: + raise ValueError('Invalid key size: ' + str(len(key))) + self.block_size = block_size + + ROUNDS = num_rounds[len(key)][block_size] + BC = block_size // 4 + # encryption round keys + Ke = [[0] * BC for i in range(ROUNDS + 1)] + # decryption round keys + Kd = [[0] * BC for i in range(ROUNDS + 1)] + ROUND_KEY_COUNT = (ROUNDS + 1) * BC + KC = len(key) // 4 + + # copy user material bytes into temporary ints + tk = [] + for i in range(0, KC): + tk.append((ord(key[i * 4]) << 24) | (ord(key[i * 4 + 1]) << 16) | + (ord(key[i * 4 + 2]) << 8) | ord(key[i * 4 + 3])) + + # copy values into round key arrays + t = 0 + j = 0 + while j < KC and t < ROUND_KEY_COUNT: + Ke[t // BC][t % BC] = tk[j] + Kd[ROUNDS - (t // BC)][t % BC] = tk[j] + j += 1 + t += 1 + tt = 0 + rconpointer = 0 + while t < ROUND_KEY_COUNT: + # extrapolate using phi (the round key evolution function) + tt = tk[KC - 1] + tk[0] ^= (S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^ \ + (S[(tt >> 8) & 0xFF] & 0xFF) << 16 ^ \ + (S[ tt & 0xFF] & 0xFF) << 8 ^ \ + (S[(tt >> 24) & 0xFF] & 0xFF) ^ \ + (rcon[rconpointer] & 0xFF) << 24 + rconpointer += 1 + if KC != 8: + for i in range(1, KC): + tk[i] ^= tk[i-1] + else: + for i in range(1, KC // 2): + tk[i] ^= tk[i-1] + tt = tk[KC // 2 - 1] + tk[KC // 2] ^= (S[ tt & 0xFF] & 0xFF) ^ \ + (S[(tt >> 8) & 0xFF] & 0xFF) << 8 ^ \ + (S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \ + (S[(tt >> 24) & 0xFF] & 0xFF) << 24 + for i in range(KC // 2 + 1, KC): + tk[i] ^= tk[i-1] + # copy values into round key arrays + j = 0 + while j < KC and t < ROUND_KEY_COUNT: + Ke[t // BC][t % BC] = tk[j] + Kd[ROUNDS - (t // BC)][t % BC] = tk[j] + j += 1 + t += 1 + # inverse MixColumn where needed + for r in range(1, ROUNDS): + for j in range(BC): + tt = Kd[r][j] + Kd[r][j] = U1[(tt >> 24) & 0xFF] ^ \ + U2[(tt >> 16) & 0xFF] ^ \ + U3[(tt >> 8) & 0xFF] ^ \ + U4[ tt & 0xFF] + self.Ke = Ke + self.Kd = Kd + + def encrypt(self, plaintext): + if len(plaintext) != self.block_size: + raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext))) + Ke = self.Ke + + BC = self.block_size // 4 + ROUNDS = len(Ke) - 1 + if BC == 4: + SC = 0 + elif BC == 6: + SC = 1 + else: + SC = 2 + s1 = shifts[SC][1][0] + s2 = shifts[SC][2][0] + s3 = shifts[SC][3][0] + a = [0] * BC + # temporary work array + t = [] + # plaintext to ints + key + for i in range(BC): + t.append((ord(plaintext[i * 4 ]) << 24 | + ord(plaintext[i * 4 + 1]) << 16 | + ord(plaintext[i * 4 + 2]) << 8 | + ord(plaintext[i * 4 + 3]) ) ^ Ke[0][i]) + # apply round transforms + for r in range(1, ROUNDS): + for i in range(BC): + a[i] = (T1[(t[ i ] >> 24) & 0xFF] ^ + T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^ + T3[(t[(i + s2) % BC] >> 8) & 0xFF] ^ + T4[ t[(i + s3) % BC] & 0xFF] ) ^ Ke[r][i] + t = copy.copy(a) + # last round is special + result = [] + for i in range(BC): + tt = Ke[ROUNDS][i] + result.append((S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((S[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((S[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF) + return ''.join(map(chr, result)) + + def decrypt(self, ciphertext): + if len(ciphertext) != self.block_size: + raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(ciphertext))) + Kd = self.Kd + + BC = self.block_size // 4 + ROUNDS = len(Kd) - 1 + if BC == 4: + SC = 0 + elif BC == 6: + SC = 1 + else: + SC = 2 + s1 = shifts[SC][1][1] + s2 = shifts[SC][2][1] + s3 = shifts[SC][3][1] + a = [0] * BC + # temporary work array + t = [0] * BC + # ciphertext to ints + key + for i in range(BC): + t[i] = (ord(ciphertext[i * 4 ]) << 24 | + ord(ciphertext[i * 4 + 1]) << 16 | + ord(ciphertext[i * 4 + 2]) << 8 | + ord(ciphertext[i * 4 + 3]) ) ^ Kd[0][i] + # apply round transforms + for r in range(1, ROUNDS): + for i in range(BC): + a[i] = (T5[(t[ i ] >> 24) & 0xFF] ^ + T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^ + T7[(t[(i + s2) % BC] >> 8) & 0xFF] ^ + T8[ t[(i + s3) % BC] & 0xFF] ) ^ Kd[r][i] + t = copy.copy(a) + # last round is special + result = [] + for i in range(BC): + tt = Kd[ROUNDS][i] + result.append((Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((Si[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((Si[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF) + return ''.join(map(chr, result)) + +def encrypt(key, block): + return rijndael(key, len(block)).encrypt(block) + +def decrypt(key, block): + return rijndael(key, len(block)).decrypt(block) \ No newline at end of file diff --git a/plugin.video.alfa/lib/rijndael/rijndael_cbc.py b/plugin.video.alfa/lib/rijndael/rijndael_cbc.py new file mode 100644 index 00000000..ce12c68b --- /dev/null +++ b/plugin.video.alfa/lib/rijndael/rijndael_cbc.py @@ -0,0 +1,71 @@ +# https://stackoverflow.com/questions/8356689/python-equivalent-of-phps-mcrypt-rijndael-256-cbc + +class zeropad: + + def __init__(self, block_size): + assert block_size > 0 and block_size < 256 + self.block_size = block_size + + def pad(self, pt): + ptlen = len(pt) + padsize = self.block_size - ((ptlen + self.block_size - 1) % self.block_size + 1) + return pt + "\0" * padsize + + def unpad(self, ppt): + assert len(ppt) % self.block_size == 0 + offset = len(ppt) + if (offset == 0): + return '' + end = offset - self.block_size + 1 + while (offset > end): + offset -= 1; + if (ppt[offset] != "\0"): + return ppt[:offset + 1] + assert false + +class cbc: + + def __init__(self, padding, cipher, iv): + assert padding.block_size == cipher.block_size; + assert len(iv) == cipher.block_size; + self.padding = padding + self.cipher = cipher + self.iv = iv + + def encrypt(self, pt): + ppt = self.padding.pad(pt) + offset = 0 + ct = '' + v = self.iv + while (offset < len(ppt)): + block = ppt[offset:offset + self.cipher.block_size] + block = self.xorblock(block, v) + block = self.cipher.encrypt(block) + ct += block + offset += self.cipher.block_size + v = block + return ct; + + def decrypt(self, ct): + assert len(ct) % self.cipher.block_size == 0 + ppt = '' + offset = 0 + v = self.iv + while (offset < len(ct)): + block = ct[offset:offset + self.cipher.block_size] + decrypted = self.cipher.decrypt(block) + ppt += self.xorblock(decrypted, v) + offset += self.cipher.block_size + v = block + pt = self.padding.unpad(ppt) + return pt; + + def xorblock(self, b1, b2): + # sorry, not very Pythonesk + i = 0 + r = ''; + while (i < self.cipher.block_size): + r += chr(ord(b1[i]) ^ ord(b2[i])) + i += 1 + return r + From 4d97c85495f951d97fa9f0679b2b06af203b6d03 Mon Sep 17 00:00:00 2001 From: alaquepasa <39385022+alaquepasa@users.noreply.github.com> Date: Mon, 2 Jul 2018 11:41:29 +0200 Subject: [PATCH 06/37] Update URL --- mediaserver/platformcode/template/js/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediaserver/platformcode/template/js/ui.js b/mediaserver/platformcode/template/js/ui.js index 65fa15a7..106f574c 100644 --- a/mediaserver/platformcode/template/js/ui.js +++ b/mediaserver/platformcode/template/js/ui.js @@ -94,7 +94,7 @@ function focus_element(element) { function image_error(thumbnail) { var src = thumbnail.src; if (thumbnail.src.indexOf(domain) == 0) { - thumbnail.src = "https://github.com/alfa-addon/addon/raw/master/plugin.video.alfa/resources/media/general/default/thumb_folder.png"; + thumbnail.src = "https://github.com/alfa-addon/addon/raw/master/plugin.video.alfa/resources/media/themes/default/thumb_folder.png" } else { thumbnail.src = domain + "/proxy/" + encodeURIComponent(btoa(thumbnail.src)); From ba1523f2fc2a405eb9f15ae49aa3acd5c8135d8f Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Mon, 2 Jul 2018 08:35:54 -0500 Subject: [PATCH 07/37] =?UTF-8?q?httptools:=20Agregado=20versi=C3=B3n=20de?= =?UTF-8?q?l=20addon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin.video.alfa/core/httptools.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugin.video.alfa/core/httptools.py b/plugin.video.alfa/core/httptools.py index 460f4f37..9829f714 100755 --- a/plugin.video.alfa/core/httptools.py +++ b/plugin.video.alfa/core/httptools.py @@ -18,6 +18,9 @@ from core.cloudflare import Cloudflare from platformcode import config, logger from platformcode.logger import WebErrorException +## Obtiene la versión del addon +__version = config.get_addon_version() + cookies_lock = Lock() cj = cookielib.MozillaCookieJar() @@ -123,7 +126,7 @@ def downloadpage(url, post=None, headers=None, timeout=None, follow_redirects=Tr url = urllib.quote(url, safe="%/:=&?~#+!$,;'@()*[]") logger.info("----------------------------------------------") - logger.info("downloadpage") + logger.info("downloadpage Alfa: %s" %__version) logger.info("----------------------------------------------") logger.info("Timeout: %s" % timeout) logger.info("URL: " + url) @@ -270,3 +273,5 @@ class NoRedirectHandler(urllib2.HTTPRedirectHandler): http_error_301 = http_error_302 http_error_303 = http_error_302 http_error_307 = http_error_302 + + From 3fca1d07fad7dc5aee3f60e2f5f1aecd2f69b503 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Mon, 2 Jul 2018 08:39:52 -0500 Subject: [PATCH 08/37] =?UTF-8?q?html.py:=20Actualizado=20obtenci=C3=B3n?= =?UTF-8?q?=20de=20la=20versi=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mediaserver/platformcode/controllers/html.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/mediaserver/platformcode/controllers/html.py b/mediaserver/platformcode/controllers/html.py index 573171a1..77dfe820 100644 --- a/mediaserver/platformcode/controllers/html.py +++ b/mediaserver/platformcode/controllers/html.py @@ -15,14 +15,9 @@ from platformcode import config from core.item import Item from core.tmdb import Tmdb from platformcode import launcher, logger -from core import filetools -# -data = filetools.read(filetools.join(config.get_runtime_path(), "addon.xml")) -aux = re.findall(' 0: - version = aux[0] +## Obtiene la versión del addon +version = config.get_addon_version() class html(Controller): pattern = re.compile("##") From f4198b61c2e05dbb95ecad5b505854c508163496 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Mon, 2 Jul 2018 08:43:40 -0500 Subject: [PATCH 09/37] alfa.py: Agregado version al show_info --- mediaserver/alfa.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediaserver/alfa.py b/mediaserver/alfa.py index f90710ee..87b61dc2 100644 --- a/mediaserver/alfa.py +++ b/mediaserver/alfa.py @@ -20,6 +20,7 @@ import WebSocket http_port = config.get_setting("server.port") websocket_port = config.get_setting("websocket.port") myip = config.get_local_ip() +version = config.get_addon_version() def thread_name_wrap(func): @@ -43,7 +44,7 @@ if sys.version_info < (2, 7, 11): def show_info(): os.system('cls' if os.name == 'nt' else 'clear') print ("--------------------------------------------------------------------") - print ("Alfa Iniciado") + print ("Alfa %s Iniciado" %version) print ("La URL para acceder es http://%s:%s" % (myip, http_port)) print ("WebSocket Server iniciado en ws://%s:%s" % (myip, websocket_port)) print ("--------------------------------------------------------------------") From a7dccc0f361be3b808a2c561fbac535ceaaabde8 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Mon, 2 Jul 2018 08:53:06 -0500 Subject: [PATCH 10/37] allcalidad: cambios cosmeticos --- plugin.video.alfa/channels/allcalidad.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugin.video.alfa/channels/allcalidad.py b/plugin.video.alfa/channels/allcalidad.py index 8c607370..7a84ae36 100755 --- a/plugin.video.alfa/channels/allcalidad.py +++ b/plugin.video.alfa/channels/allcalidad.py @@ -147,10 +147,12 @@ def findvideos(item): match = scrapertools.find_multiple_matches(bloque, '(?is)(?:iframe|script) .*?src="([^"]+)') for url in match: titulo = "Ver en: %s" + text_color = "white" if "goo.gl" in url: url = httptools.downloadpage(url, follow_redirects=False, only_headers=True).headers.get("location", "") if "youtube" in url: - titulo = "[COLOR = yellow]Ver trailer: %s[/COLOR]" + titulo = "Ver trailer: %s" + text_color = "yellow" if "ad.js" in url or "script" in url or "jstags.js" in url: continue elif "vimeo" in url: @@ -158,6 +160,7 @@ def findvideos(item): itemlist.append( item.clone(channel = item.channel, action = "play", + text_color = text_color, title = titulo, url = url )) From 4e8d1437742b86b4a1add51a4f1665a4b0a3e4ee Mon Sep 17 00:00:00 2001 From: alaquepasa <39385022+alaquepasa@users.noreply.github.com> Date: Mon, 2 Jul 2018 16:41:37 +0200 Subject: [PATCH 11/37] Usar un handler HTTP que gestiona WebSockets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Con un handler HTTP que también gestione WebSockets podemos gestionar los WebSockets en el mismo puerto HTTP, así no es necesario usar / abrir dos puertos. Para eso he usado el handler creado por SevenW en: https://github.com/SevenW/httpwebsockethandler y que extiende el SimpleHTTPServer. Aunque ha sido ligeralmente modificado: - He creado un wrapper para las peticiones HTTP GET, el antiguo do_GET ahora es do_GET_HTTP - He desactivado una parte de autenticación que tenía (ni he mirado en intentar mantelerlo, aunque si mantenemos el del do_GET_HTTP, pero supongo que también debería protegerse el de las querys WS y seguramente sería muy muy sencillo reactivarle esa funcionaliad y quitarle el comentario) En el server mantenemos el antiguo do_GET pero renombrado a do_GET_HTTP, y se han movido los métodos del WebSocketServer a este handler. He quitado las cosas que configuran un puerto WebSocket ya que ahora es el mismo que HTTP. Había pensado en enviarlo en otra carpetita (mediaserver-alt) o algo así, por si acaso usar lo otro tiene algún setido (como que no se usen ciertas clases por compatibilidad con pythons antiguos), pero bueno, por ahora lo dejo aquí, siempre se puede hacer rollback + crear una nueva carpeta. --- mediaserver/HTTPAndWSServer.py | 150 ++++ mediaserver/WebSocket.py | 89 --- mediaserver/alfa.py | 10 +- mediaserver/lib/HTTPWebSocketsHandler.py | 229 +++++++ mediaserver/lib/WebSocketServer.py | 648 ------------------ .../platformcode/controllers/fileserver.py | 1 - mediaserver/platformcode/controllers/html.py | 5 +- mediaserver/platformcode/template/page.html | 2 +- 8 files changed, 387 insertions(+), 747 deletions(-) create mode 100644 mediaserver/HTTPAndWSServer.py delete mode 100644 mediaserver/WebSocket.py create mode 100644 mediaserver/lib/HTTPWebSocketsHandler.py delete mode 100644 mediaserver/lib/WebSocketServer.py diff --git a/mediaserver/HTTPAndWSServer.py b/mediaserver/HTTPAndWSServer.py new file mode 100644 index 00000000..9703ddf1 --- /dev/null +++ b/mediaserver/HTTPAndWSServer.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- + +import random +import re +import threading +import time +import traceback +from BaseHTTPServer import HTTPServer +from HTTPWebSocketsHandler import HTTPWebSocketsHandler + +from platformcode import config, logger +from core import jsontools as json + +class MyHTTPServer(HTTPServer): + daemon_threads = True + + def process_request_thread(self, request, client_address): + try: + self.finish_request(request, client_address) + self.shutdown_request(request) + except: + self.handle_error(request, client_address) + self.shutdown_request(request) + + def process_request(self, request, client_address): + ID = "%032x" % (random.getrandbits(128)) + t = threading.Thread(target=self.process_request_thread, + args=(request, client_address), name=ID) + t.daemon = self.daemon_threads + t.start() + + def handle_error(self, request, client_address): + import traceback + if not "socket.py" in traceback.format_exc(): + logger.error(traceback.format_exc()) + + +class Handler(HTTPWebSocketsHandler): + def log_message(self, format, *args): + # sys.stderr.write("%s - - [%s] %s\n" %(self.client_address[0], self.log_date_time_string(), format%args)) + pass + + def sendMessage(self, message): + self.send_message(message) + + def do_GET_HTTP(self): + from platformcode import platformtools + from platformcode import controllers + # Control de accesos + Usuario = "user" + Password = "password" + ControlAcceso = False + import base64 + # Comprueba la clave + if ControlAcceso and self.headers.getheader('Authorization') <> "Basic " + base64.b64encode( + Usuario + ":" + Password): + self.send_response(401) + self.send_header('WWW-Authenticate', + 'Basic realm=\"Introduce el nombre de usuario y clave para acceder a alfa\"') + self.send_header('Content-type', 'text/html; charset=utf-8') + self.end_headers() + self.wfile.write('¡Los datos introducidos no son correctos!') + return + + data = re.compile('/data/([^/]+)/([^/]+)/([^/]+)', re.DOTALL).findall(self.path) + if data: + data = data[0] + if data[0] in platformtools.requests: + c = platformtools.requests[data[0]] + response = {"id": data[1], "result": data[2]} + print response + c.handler = self + c.set_data(response) + while data[0] in platformtools.requests and not self.wfile.closed: + time.sleep(1) + else: + if self.path == "": self.path = "/" + + # Busca el controller para la url + controller = controllers.find_controller(self.path) + if controller: + try: + c = controller(self) + c.run(self.path) + except: + if not "socket.py" in traceback.format_exc(): + logger.error(traceback.format_exc()) + finally: + c.__del__() + del c + return + + def on_ws_message(self, message): + try: + if message: + json_message = json.load(message) + + if "request" in json_message: + t = threading.Thread(target=run, args=[self.controller, json_message["request"].encode("utf8")], name=self.ID) + t.setDaemon(True) + t.start() + + elif "data" in json_message: + if type(json_message["data"]["result"]) == unicode: + json_message["data"]["result"] = json_message["data"]["result"].encode("utf8") + + self.controller.data = json_message["data"] + + except: + logger.error(traceback.format_exc()) + show_error_message(traceback.format_exc()) + + def on_ws_connected(self): + try: + self.ID = "%032x" % (random.getrandbits(128)) + from platformcode.controllers.html import html + self.controller = html(self, self.ID) + self.server.fnc_info() + except: + logger.error(traceback.format_exc()) + + def on_ws_closed(self): + self.controller.__del__() + del self.controller + self.server.fnc_info() + + def address_string(self): + # Disable reverse name lookups + return self.client_address[:2][0] + + +PORT = config.get_setting("server.port") +server = MyHTTPServer(('', int(PORT)), Handler) + +def run(controller, path): + try: + controller.run(path) + except: + logger.error(traceback.format_exc()) + show_error_message(traceback.format_exc()) + + +def start(fnc_info): + server.fnc_info = fnc_info + threading.Thread(target=server.serve_forever).start() + + +def stop(): + server.socket.close() + server.shutdown() diff --git a/mediaserver/WebSocket.py b/mediaserver/WebSocket.py deleted file mode 100644 index 083f692d..00000000 --- a/mediaserver/WebSocket.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------ -# HTTPServer -# ------------------------------------------------------------ -import os -import random -import traceback -from threading import Thread - -import WebSocketServer - -from core import jsontools as json -from platformcode import config, platformtools, logger - - -class HandleWebSocket(WebSocketServer.WebSocket): - def handleMessage(self): - try: - if self.data: - json_message = json.load(str(self.data)) - - if "request" in json_message: - t = Thread(target=run, args=[self.controller, json_message["request"].encode("utf8")], name=self.ID) - t.setDaemon(True) - t.start() - - elif "data" in json_message: - if type(json_message["data"]["result"]) == unicode: - json_message["data"]["result"] = json_message["data"]["result"].encode("utf8") - - self.controller.data = json_message["data"] - - except: - logger.error(traceback.format_exc()) - show_error_message(traceback.format_exc()) - - def handleConnected(self): - try: - self.ID = "%032x" % (random.getrandbits(128)) - from platformcode.controllers.html import html - self.controller = html(self, self.ID) - self.server.fnc_info() - except: - logger.error(traceback.format_exc()) - self.close() - - def handleClose(self): - self.controller.__del__() - del self.controller - self.server.fnc_info() - - -port = config.get_setting("websocket.port") -server = WebSocketServer.SimpleWebSocketServer("", int(port), HandleWebSocket) - - -def start(fnc_info): - server.fnc_info = fnc_info - Thread(target=server.serveforever).start() - - -def stop(): - server.close() - - -def run(controller, path): - try: - controller.run(path) - except: - logger.error(traceback.format_exc()) - show_error_message(traceback.format_exc()) - - -def show_error_message(err_info): - from core import scrapertools - patron = 'File "' + os.path.join(config.get_runtime_path(), "channels", "").replace("\\", "\\\\") + '([^.]+)\.py"' - canal = scrapertools.find_single_match(err_info, patron) - if canal: - platformtools.dialog_ok( - "Se ha producido un error en el canal " + canal, - "Esto puede ser devido a varias razones: \n \ - - El servidor no está disponible, o no esta respondiendo.\n \ - - Cambios en el diseño de la web.\n \ - - Etc...\n \ - Comprueba el log para ver mas detalles del error.") - else: - platformtools.dialog_ok( - "Se ha producido un error en Alfa", - "Comprueba el log para ver mas detalles del error.") diff --git a/mediaserver/alfa.py b/mediaserver/alfa.py index f90710ee..8a6392c9 100644 --- a/mediaserver/alfa.py +++ b/mediaserver/alfa.py @@ -14,8 +14,7 @@ from platformcode import config sys.path.append(os.path.join(config.get_runtime_path(), 'lib')) from platformcode import platformtools, logger -import HTTPServer -import WebSocket +import HTTPAndWSServer http_port = config.get_setting("server.port") websocket_port = config.get_setting("websocket.port") @@ -67,8 +66,7 @@ def start(): logger.info("server init...") config.verify_directories_created() try: - HTTPServer.start(show_info) - WebSocket.start(show_info) + HTTPAndWSServer.start(show_info) # Da por levantado el servicio logger.info("--------------------------------------------------------------------") @@ -91,9 +89,7 @@ def start(): except KeyboardInterrupt: print 'Deteniendo el servidor HTTP...' - HTTPServer.stop() - print 'Deteniendo el servidor WebSocket...' - WebSocket.stop() + HTTPAndWSServer.stop() print 'Alfa Detenido' flag = False diff --git a/mediaserver/lib/HTTPWebSocketsHandler.py b/mediaserver/lib/HTTPWebSocketsHandler.py new file mode 100644 index 00000000..3e89b503 --- /dev/null +++ b/mediaserver/lib/HTTPWebSocketsHandler.py @@ -0,0 +1,229 @@ +''' +The MIT License (MIT) + +Copyright (C) 2014, 2015 Seven Watt + + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +''' + +# HTTPWebSocketHandler from SevenW: https://github.com/SevenW/httpwebsockethandler + +from SimpleHTTPServer import SimpleHTTPRequestHandler +import struct +from base64 import b64encode +from hashlib import sha1 +from mimetools import Message +from StringIO import StringIO +import errno, socket #for socket exceptions +import threading + +class WebSocketError(Exception): + pass + +class HTTPWebSocketsHandler(SimpleHTTPRequestHandler): + _ws_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' + _opcode_continu = 0x0 + _opcode_text = 0x1 + _opcode_binary = 0x2 + _opcode_close = 0x8 + _opcode_ping = 0x9 + _opcode_pong = 0xa + + mutex = threading.Lock() + + def on_ws_message(self, message): + """Override this handler to process incoming websocket messages.""" + pass + + def on_ws_connected(self): + """Override this handler.""" + pass + + def on_ws_closed(self): + """Override this handler.""" + pass + + def do_GET_HTTP(self): + """Override this handler.""" + SimpleHTTPRequestHandler.do_GET(self) + pass + + def send_message(self, message): + self._send_message(self._opcode_text, message) + + def setup(self): + SimpleHTTPRequestHandler.setup(self) + self.connected = False + + # def finish(self): + # #needed when wfile is used, or when self.close_connection is not used + # # + # #catch errors in SimpleHTTPRequestHandler.finish() after socket disappeared + # #due to loss of network connection + # try: + # SimpleHTTPRequestHandler.finish(self) + # except (socket.error, TypeError) as err: + # self.log_message("finish(): Exception: in SimpleHTTPRequestHandler.finish(): %s" % str(err.args)) + + # def handle(self): + # #needed when wfile is used, or when self.close_connection is not used + # # + # #catch errors in SimpleHTTPRequestHandler.handle() after socket disappeared + # #due to loss of network connection + # try: + # SimpleHTTPRequestHandler.handle(self) + # except (socket.error, TypeError) as err: + # self.log_message("handle(): Exception: in SimpleHTTPRequestHandler.handle(): %s" % str(err.args)) + + def checkAuthentication(self): + auth = self.headers.get('Authorization') + if auth != "Basic %s" % self.server.auth: + self.send_response(401) + self.send_header("WWW-Authenticate", 'Basic realm="Plugwise"') + self.end_headers(); + return False + return True + + def do_GET(self): + # if self.server.auth and not self.checkAuthentication(): + # return + if self.headers.get("Upgrade", None) == "websocket": + self._handshake() + #This handler is in websocket mode now. + #do_GET only returns after client close or socket error. + self._read_messages() + else: + self.do_GET_HTTP() + + def _read_messages(self): + while self.connected == True: + try: + self._read_next_message() + except (socket.error, WebSocketError), e: + #websocket content error, time-out or disconnect. + self.log_message("RCV: Close connection: Socket Error %s" % str(e.args)) + self._ws_close() + except Exception as err: + #unexpected error in websocket connection. + self.log_error("RCV: Exception: in _read_messages: %s" % str(err.args)) + self._ws_close() + + def _read_next_message(self): + #self.rfile.read(n) is blocking. + #it returns however immediately when the socket is closed. + try: + self.opcode = ord(self.rfile.read(1)) & 0x0F + length = ord(self.rfile.read(1)) & 0x7F + if length == 126: + length = struct.unpack(">H", self.rfile.read(2))[0] + elif length == 127: + length = struct.unpack(">Q", self.rfile.read(8))[0] + masks = [ord(byte) for byte in self.rfile.read(4)] + decoded = "" + for char in self.rfile.read(length): + decoded += chr(ord(char) ^ masks[len(decoded) % 4]) + self._on_message(decoded) + except (struct.error, TypeError) as e: + #catch exceptions from ord() and struct.unpack() + if self.connected: + raise WebSocketError("Websocket read aborted while listening") + else: + #the socket was closed while waiting for input + self.log_error("RCV: _read_next_message aborted after closed connection") + pass + + def _send_message(self, opcode, message): + try: + #use of self.wfile.write gives socket exception after socket is closed. Avoid. + self.request.send(chr(0x80 + opcode)) + length = len(message) + if length <= 125: + self.request.send(chr(length)) + elif length >= 126 and length <= 65535: + self.request.send(chr(126)) + self.request.send(struct.pack(">H", length)) + else: + self.request.send(chr(127)) + self.request.send(struct.pack(">Q", length)) + if length > 0: + self.request.send(message) + except socket.error, e: + #websocket content error, time-out or disconnect. + self.log_message("SND: Close connection: Socket Error %s" % str(e.args)) + self._ws_close() + except Exception as err: + #unexpected error in websocket connection. + self.log_error("SND: Exception: in _send_message: %s" % str(err.args)) + self._ws_close() + + def _handshake(self): + headers=self.headers + if headers.get("Upgrade", None) != "websocket": + return + key = headers['Sec-WebSocket-Key'] + digest = b64encode(sha1(key + self._ws_GUID).hexdigest().decode('hex')) + self.send_response(101, 'Switching Protocols') + self.send_header('Upgrade', 'websocket') + self.send_header('Connection', 'Upgrade') + self.send_header('Sec-WebSocket-Accept', str(digest)) + self.end_headers() + self.connected = True + #self.close_connection = 0 + self.on_ws_connected() + + def _ws_close(self): + #avoid closing a single socket two time for send and receive. + self.mutex.acquire() + try: + if self.connected: + self.connected = False + #Terminate BaseHTTPRequestHandler.handle() loop: + self.close_connection = 1 + #send close and ignore exceptions. An error may already have occurred. + try: + self._send_close() + except: + pass + self.on_ws_closed() + else: + self.log_message("_ws_close websocket in closed state. Ignore.") + pass + finally: + self.mutex.release() + + def _on_message(self, message): + #self.log_message("_on_message: opcode: %02X msg: %s" % (self.opcode, message)) + + # close + if self.opcode == self._opcode_close: + self.connected = False + #Terminate BaseHTTPRequestHandler.handle() loop: + self.close_connection = 1 + try: + self._send_close() + except: + pass + self.on_ws_closed() + # ping + elif self.opcode == self._opcode_ping: + _send_message(self._opcode_pong, message) + # pong + elif self.opcode == self._opcode_pong: + pass + # data + elif (self.opcode == self._opcode_continu or + self.opcode == self._opcode_text or + self.opcode == self._opcode_binary): + self.on_ws_message(message) + + def _send_close(self): + #Dedicated _send_close allows for catch all exception handling + msg = bytearray() + msg.append(0x80 + self._opcode_close) + msg.append(0x00) + self.request.send(msg) diff --git a/mediaserver/lib/WebSocketServer.py b/mediaserver/lib/WebSocketServer.py deleted file mode 100644 index ff20570c..00000000 --- a/mediaserver/lib/WebSocketServer.py +++ /dev/null @@ -1,648 +0,0 @@ -''' -The MIT License (MIT) - -Copyright (c) 2013 Dave P. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -''' - -import SocketServer -import hashlib -import base64 -import socket -import struct -import ssl -import time -import sys -import errno -import logging -from BaseHTTPServer import BaseHTTPRequestHandler -from StringIO import StringIO -from select import select - - -class HTTPRequest(BaseHTTPRequestHandler): - def __init__(self, request_text): - self.rfile = StringIO(request_text) - self.raw_requestline = self.rfile.readline() - self.error_code = self.error_message = None - self.parse_request() - - -class WebSocket(object): - - handshakeStr = ( - "HTTP/1.1 101 Switching Protocols\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Accept: %(acceptstr)s\r\n\r\n" - ) - - hixiehandshakedStr = ( - "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Origin: %(origin)s\r\n" - "Sec-WebSocket-Location: %(type)s://%(host)s%(location)s\r\n\r\n" - ) - - hixie75handshakedStr = ( - "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "WebSocket-Origin: %(origin)s\r\n" - "WebSocket-Location: %(type)s://%(host)s%(location)s\r\n\r\n" - ) - GUIDStr = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' - - STREAM = 0x0 - TEXT = 0x1 - BINARY = 0x2 - CLOSE = 0x8 - PING = 0x9 - PONG = 0xA - - HEADERB1 = 1 - HEADERB2 = 3 - LENGTHSHORT = 4 - LENGTHLONG = 5 - MASK = 6 - PAYLOAD = 7 - - def __init__(self, server, sock, address): - self.server = server - self.client = sock - self.address = address - - self.handshaked = False - self.headerbuffer = '' - self.readdraftkey = False - self.draftkey = '' - self.headertoread = 2048 - self.hixie76 = False - - self.fin = 0 - self.data = None - self.opcode = 0 - self.hasmask = 0 - self.maskarray = None - self.length = 0 - self.lengtharray = None - self.index = 0 - self.request = None - self.usingssl = False - - self.state = self.HEADERB1 - - # restrict the size of header and payload for security reasons - self.maxheader = 65536 - self.maxpayload = 4194304 - - def close(self): - self.client.close() - self.state = self.HEADERB1 - self.hasmask = False - self.handshaked = False - self.readdraftkey = False - self.hixie76 = False - self.headertoread = 2048 - self.headerbuffer = '' - self.data = '' - - - def handleMessage(self): - pass - - def handleConnected(self): - pass - - def handleClose(self): - pass - - def handlePacket(self): - # close - if self.opcode == self.CLOSE: - self.sendClose() - raise Exception("received client close") - # ping - elif self.opcode == self.PING: - pass - - # pong - elif self.opcode == self.PONG: - pass - - # data - elif self.opcode == self.STREAM or self.opcode == self.TEXT or self.opcode == self.BINARY: - self.handleMessage() - - - def handleData(self): - - # do the HTTP header and handshake - if self.handshaked is False: - - data = self.client.recv(self.headertoread) - - if data: - # accumulate - self.headerbuffer += data - - if len(self.headerbuffer) >= self.maxheader: - raise Exception('header exceeded allowable size') - - # we need to read the entire 8 bytes of after the HTTP header, ensure we do - if self.readdraftkey is True: - self.draftkey += self.headerbuffer - read = self.headertoread - len(self.headerbuffer) - - if read != 0: - self.headertoread = read - else: - # complete hixie76 handshake - self.handshake_hixie76() - - # indicates end of HTTP header - elif '\r\n\r\n' in self.headerbuffer: - self.request = HTTPRequest(self.headerbuffer) - # hixie handshake - if self.request.headers.has_key('Sec-WebSocket-Key1'.lower()) and self.request.headers.has_key('Sec-WebSocket-Key2'.lower()): - # check if we have the key in our buffer - index = self.headerbuffer.find('\r\n\r\n') + 4 - # determine how much of the 8 byte key we have - read = len(self.headerbuffer) - index - # do we have all the 8 bytes we need? - if read < 8: - self.headertoread = 8 - read - self.readdraftkey = True - if read > 0: - self.draftkey += self.headerbuffer[index:index+read] - - else: - # get the key - self.draftkey += self.headerbuffer[index:index+8] - # complete hixie handshake - self.handshake_hixie76() - - # handshake rfc 6455 - elif self.request.headers.has_key('Sec-WebSocket-Key'.lower()): - key = self.request.headers['Sec-WebSocket-Key'.lower()] - hStr = self.handshakeStr % { 'acceptstr' : base64.b64encode(hashlib.sha1(key + self.GUIDStr).digest()) } - self.sendBuffer(hStr) - self.handshaked = True - self.headerbuffer = '' - - try: - self.handleConnected() - except: - pass - # hixie 75 - else: - self.handshake_hixie75() - #raise Exception('Sec-WebSocket-Key does not exist') - - # remote connection has been closed - else: - raise Exception("remote socket closed") - - # else do normal data - else: - data = self.client.recv(2048) - if data: - for val in data: - if self.hixie76 is False: - self.parseMessage(ord(val)) - else: - self.parseMessage_hixie76(ord(val)) - else: - raise Exception("remote socket closed") - - - def handshake_hixie75(self): - typestr = 'ws' - if self.usingssl is True: - typestr = 'wss' - - response = self.hixie75handshakedStr % { 'type' : typestr, 'origin' : self.request.headers['Origin'.lower()], 'host' : self.request.headers['Host'.lower()], 'location' : self.request.path } - - self.sendBuffer(response) - - - self.handshaked = True - self.headerbuffer = '' - self.hixie76 = True - - try: - self.handleConnected() - except: - pass - - def handshake_hixie76(self): - - k1 = self.request.headers['Sec-WebSocket-Key1'.lower()] - k2 = self.request.headers['Sec-WebSocket-Key2'.lower()] - - spaces1 = k1.count(" ") - spaces2 = k2.count(" ") - num1 = int("".join([c for c in k1 if c.isdigit()])) / spaces1 - num2 = int("".join([c for c in k2 if c.isdigit()])) / spaces2 - - key = '' - key += struct.pack('>I', num1) - key += struct.pack('>I', num2) - key += self.draftkey - - typestr = 'ws' - if self.usingssl is True: - typestr = 'wss' - - response = self.hixiehandshakedStr % { 'type' : typestr, 'origin' : self.request.headers['Origin'.lower()], 'host' : self.request.headers['Host'.lower()], 'location' : self.request.path } - - self.sendBuffer(response) - self.sendBuffer(hashlib.md5(key).digest()) - - self.handshaked = True - self.hixie76 = True - self.headerbuffer = '' - - try: - self.handleConnected() - except: - pass - - - def sendClose(self): - - msg = bytearray() - if self.hixie76 is False: - msg.append(0x88) - msg.append(0x00) - self.sendBuffer(msg) - else: - pass - - def sendBuffer(self, buff): - size = len(buff) - tosend = size - index = 0 - - while tosend > 0: - try: - # i should be able to send a bytearray - sent = self.client.send(str(buff[index:size])) - if sent == 0: - raise RuntimeError("socket connection broken") - - index += sent - tosend -= sent - - except socket.error as e: - # if we have full buffers then wait for them to drain and try again - if e.errno == errno.EAGAIN: - time.sleep(0.001) - else: - raise e - - - #if s is a string then websocket TEXT is sent else BINARY - def sendMessage(self, s): - - if self.hixie76 is False: - - header = bytearray() - isString = isinstance(s, str) - - if isString is True: - header.append(0x81) - else: - header.append(0x82) - - b2 = 0 - length = len(s) - - if length <= 125: - b2 |= length - header.append(b2) - - elif length >= 126 and length <= 65535: - b2 |= 126 - header.append(b2) - header.extend(struct.pack("!H", length)) - - else: - b2 |= 127 - header.append(b2) - header.extend(struct.pack("!Q", length)) - - if length > 0: - self.sendBuffer(header + s) - else: - self.sendBuffer(header) - header = None - - else: - msg = bytearray() - msg.append(0) - if len(s) > 0: - msg.extend(str(s).encode("UTF8")) - msg.append(0xFF) - - self.sendBuffer(msg) - msg = None - - - def parseMessage_hixie76(self, byte): - - if self.state == self.HEADERB1: - if byte == 0: - self.state = self.PAYLOAD - self.data = bytearray() - - elif self.state == self.PAYLOAD: - if byte == 0xFF: - self.opcode = 1 - self.length = len(self.data) - try: - self.handlePacket() - finally: - self.data = None - self.state = self.HEADERB1 - else : - self.data.append(byte) - # if length exceeds allowable size then we except and remove the connection - if len(self.data) >= self.maxpayload: - raise Exception('payload exceeded allowable size') - - - def parseMessage(self, byte): - # read in the header - if self.state == self.HEADERB1: - # fin - self.fin = (byte & 0x80) - # get opcode - self.opcode = (byte & 0x0F) - - self.state = self.HEADERB2 - - elif self.state == self.HEADERB2: - mask = byte & 0x80 - length = byte & 0x7F - - if mask == 128: - self.hasmask = True - else: - self.hasmask = False - - if length <= 125: - self.length = length - - # if we have a mask we must read it - if self.hasmask is True: - self.maskarray = bytearray() - self.state = self.MASK - else: - # if there is no mask and no payload we are done - if self.length <= 0: - try: - self.handlePacket() - finally: - self.state = self.HEADERB1 - self.data = None - - # we have no mask and some payload - else: - self.index = 0 - self.data = bytearray() - self.state = self.PAYLOAD - - elif length == 126: - self.lengtharray = bytearray() - self.state = self.LENGTHSHORT - - elif length == 127: - self.lengtharray = bytearray() - self.state = self.LENGTHLONG - - - elif self.state == self.LENGTHSHORT: - self.lengtharray.append(byte) - - if len(self.lengtharray) > 2: - raise Exception('short length exceeded allowable size') - - if len(self.lengtharray) == 2: - self.length = struct.unpack_from('!H', str(self.lengtharray))[0] - - if self.hasmask is True: - self.maskarray = bytearray() - self.state = self.MASK - else: - # if there is no mask and no payload we are done - if self.length <= 0: - try: - self.handlePacket() - finally: - self.state = self.HEADERB1 - self.data = None - - # we have no mask and some payload - else: - self.index = 0 - self.data = bytearray() - self.state = self.PAYLOAD - - elif self.state == self.LENGTHLONG: - - self.lengtharray.append(byte) - - if len(self.lengtharray) > 8: - raise Exception('long length exceeded allowable size') - - if len(self.lengtharray) == 8: - self.length = struct.unpack_from('!Q', str(self.lengtharray))[0] - - if self.hasmask is True: - self.maskarray = bytearray() - self.state = self.MASK - else: - # if there is no mask and no payload we are done - if self.length <= 0: - try: - self.handlePacket() - finally: - self.state = self.HEADERB1 - self.data = None - - # we have no mask and some payload - else: - self.index = 0 - self.data = bytearray() - self.state = self.PAYLOAD - - # MASK STATE - elif self.state == self.MASK: - self.maskarray.append(byte) - - if len(self.maskarray) > 4: - raise Exception('mask exceeded allowable size') - - if len(self.maskarray) == 4: - # if there is no mask and no payload we are done - if self.length <= 0: - try: - self.handlePacket() - finally: - self.state = self.HEADERB1 - self.data = None - - # we have no mask and some payload - else: - self.index = 0 - self.data = bytearray() - self.state = self.PAYLOAD - - # PAYLOAD STATE - elif self.state == self.PAYLOAD: - if self.hasmask is True: - self.data.append( byte ^ self.maskarray[self.index % 4] ) - else: - self.data.append( byte ) - - # if length exceeds allowable size then we except and remove the connection - if len(self.data) >= self.maxpayload: - raise Exception('payload exceeded allowable size') - - # check if we have processed length bytes; if so we are done - if (self.index+1) == self.length: - try: - self.handlePacket() - finally: - self.state = self.HEADERB1 - self.data = None - else: - self.index += 1 - - -class SimpleWebSocketServer(object): - def __init__(self, host, port, websocketclass): - self.websocketclass = websocketclass - self.serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.serversocket.bind((host, port)) - self.serversocket.listen(5) - self.connections = {} - self.listeners = [self.serversocket] - - - def decorateSocket(self, sock): - return sock - - def constructWebSocket(self, sock, address): - return self.websocketclass(self, sock, address) - - def close(self): - self.serversocket.close() - - for conn in self.connections.itervalues(): - try: - conn.handleClose() - except: - pass - - conn.close() - - - def serveforever(self): - while True: - try: - rList, wList, xList = select(self.listeners, [], self.listeners, 1) - - for ready in rList: - if ready == self.serversocket: - try: - sock, address = self.serversocket.accept() - newsock = self.decorateSocket(sock) - newsock.setblocking(0) - fileno = newsock.fileno() - self.listeners.append(fileno) - self.connections[fileno] = self.constructWebSocket(newsock, address) - - except Exception as n: - - #logging.debug(str(address) + ' ' + str(n)) - - if sock is not None: - sock.close() - else: - client = self.connections[ready] - - try: - client.handleData() - - except Exception as n: - - #logging.debug(str(client.address) + ' ' + str(n)) - - try: - client.handleClose() - except: - pass - - client.close() - - del self.connections[ready] - self.listeners.remove(ready) - - for failed in xList: - if failed == self.serversocket: - self.close() - raise Exception("server socket failed") - else: - client = self.connections[failed] - - try: - client.handleClose() - except: - pass - - client.close() - - del self.connections[failed] - self.listeners.remove(failed) - except: - break - -class SimpleSSLWebSocketServer(SimpleWebSocketServer): - - def __init__(self, host, port, websocketclass, certfile, keyfile, version = ssl.PROTOCOL_TLSv1): - - SimpleWebSocketServer.__init__(self, host, port, websocketclass) - - self.cerfile = certfile - self.keyfile = keyfile - self.version = version - - def close(self): - super(SimpleSSLWebSocketServer, self).close() - - def decorateSocket(self, sock): - sslsock = ssl.wrap_socket(sock, - server_side=True, - certfile=self.cerfile, - keyfile=self.keyfile, - ssl_version=self.version) - return sslsock - - def constructWebSocket(self, sock, address): - ws = self.websocketclass(self, sock, address) - ws.usingssl = True - return ws - - def serveforever(self): - super(SimpleSSLWebSocketServer, self).serveforever() - - diff --git a/mediaserver/platformcode/controllers/fileserver.py b/mediaserver/platformcode/controllers/fileserver.py index 11ac6df1..41b7dbb0 100644 --- a/mediaserver/platformcode/controllers/fileserver.py +++ b/mediaserver/platformcode/controllers/fileserver.py @@ -20,7 +20,6 @@ class fileserver(Controller): self.handler.send_header('Content-type', 'text/html') self.handler.end_headers() respuesta = f.read() - respuesta = respuesta.replace("{$WSPORT}", str(config.get_setting("websocket.port"))) self.handler.wfile.write(respuesta) f.close() diff --git a/mediaserver/platformcode/controllers/html.py b/mediaserver/platformcode/controllers/html.py index 573171a1..bac18322 100644 --- a/mediaserver/platformcode/controllers/html.py +++ b/mediaserver/platformcode/controllers/html.py @@ -33,7 +33,10 @@ class html(Controller): self.platformtools = platform(self) self.data = {} if self.handler: - self.client_ip = handler.client.getpeername()[0] + if hasattr(handler, "client"): + self.client_ip = handler.client.getpeername()[0] + else: + self.client_ip = handler.client_address[0] self.send_message({"action": "connect", "data": {"version": "Alfa %s" % version, "date": "--/--/----"}}) diff --git a/mediaserver/platformcode/template/page.html b/mediaserver/platformcode/template/page.html index 50fe256a..72c53cee 100644 --- a/mediaserver/platformcode/template/page.html +++ b/mediaserver/platformcode/template/page.html @@ -30,7 +30,7 @@ From ef81d4f320783265e625116ac290acc421b80dc1 Mon Sep 17 00:00:00 2001 From: alaquepasa <39385022+alaquepasa@users.noreply.github.com> Date: Mon, 2 Jul 2018 17:01:06 +0200 Subject: [PATCH 12/37] Borrar referencia de WebSocket server / port --- mediaserver/alfa.py | 3 --- mediaserver/resources/settings.xml | 1 - 2 files changed, 4 deletions(-) diff --git a/mediaserver/alfa.py b/mediaserver/alfa.py index 8a6392c9..a7962200 100644 --- a/mediaserver/alfa.py +++ b/mediaserver/alfa.py @@ -17,7 +17,6 @@ from platformcode import platformtools, logger import HTTPAndWSServer http_port = config.get_setting("server.port") -websocket_port = config.get_setting("websocket.port") myip = config.get_local_ip() @@ -44,7 +43,6 @@ def show_info(): print ("--------------------------------------------------------------------") print ("Alfa Iniciado") print ("La URL para acceder es http://%s:%s" % (myip, http_port)) - print ("WebSocket Server iniciado en ws://%s:%s" % (myip, websocket_port)) print ("--------------------------------------------------------------------") print ("Runtime Path : " + config.get_runtime_path()) print ("Data Path : " + config.get_data_path()) @@ -72,7 +70,6 @@ def start(): logger.info("--------------------------------------------------------------------") logger.info("Alfa Iniciado") logger.info("La URL para acceder es http://%s:%s" % (myip, http_port)) - logger.info("WebSocket Server iniciado en ws://%s:%s" % (myip, websocket_port)) logger.info("--------------------------------------------------------------------") logger.info("Runtime Path : " + config.get_runtime_path()) logger.info("Data Path : " + config.get_data_path()) diff --git a/mediaserver/resources/settings.xml b/mediaserver/resources/settings.xml index 5fe48645..31e666ef 100644 --- a/mediaserver/resources/settings.xml +++ b/mediaserver/resources/settings.xml @@ -3,7 +3,6 @@ - From cf5c6e540ba6e228d53386b1cafcd196977085f1 Mon Sep 17 00:00:00 2001 From: alaquepasa <39385022+alaquepasa@users.noreply.github.com> Date: Mon, 2 Jul 2018 20:07:11 +0200 Subject: [PATCH 13/37] Delete HTTPServer.py --- mediaserver/HTTPServer.py | 106 -------------------------------------- 1 file changed, 106 deletions(-) delete mode 100644 mediaserver/HTTPServer.py diff --git a/mediaserver/HTTPServer.py b/mediaserver/HTTPServer.py deleted file mode 100644 index 92cf680e..00000000 --- a/mediaserver/HTTPServer.py +++ /dev/null @@ -1,106 +0,0 @@ -# -*- coding: utf-8 -*- - -import random -import re -import threading -import time -import traceback -from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer - -from platformcode import config, logger - - -class MyHTTPServer(HTTPServer): - daemon_threads = True - - def process_request_thread(self, request, client_address): - try: - - self.finish_request(request, client_address) - self.shutdown_request(request) - except: - self.handle_error(request, client_address) - self.shutdown_request(request) - - def process_request(self, request, client_address): - ID = "%032x" % (random.getrandbits(128)) - t = threading.Thread(target=self.process_request_thread, - args=(request, client_address), name=ID) - t.daemon = self.daemon_threads - t.start() - - def handle_error(self, request, client_address): - import traceback - if not "socket.py" in traceback.format_exc(): - logger.error(traceback.format_exc()) - - -class Handler(BaseHTTPRequestHandler): - def log_message(self, format, *args): - # sys.stderr.write("%s - - [%s] %s\n" %(self.client_address[0], self.log_date_time_string(), format%args)) - pass - - def do_GET(self): - from platformcode import platformtools - from platformcode import controllers - # Control de accesos - Usuario = "user" - Password = "password" - ControlAcceso = False - import base64 - # Comprueba la clave - if ControlAcceso and self.headers.getheader('Authorization') <> "Basic " + base64.b64encode( - Usuario + ":" + Password): - self.send_response(401) - self.send_header('WWW-Authenticate', - 'Basic realm=\"Introduce el nombre de usuario y clave para acceder a alfa\"') - self.send_header('Content-type', 'text/html; charset=utf-8') - self.end_headers() - self.wfile.write('¡Los datos introducidos no son correctos!') - return - - data = re.compile('/data/([^/]+)/([^/]+)/([^/]+)', re.DOTALL).findall(self.path) - if data: - data = data[0] - if data[0] in platformtools.requests: - c = platformtools.requests[data[0]] - response = {"id": data[1], "result": data[2]} - print response - c.handler = self - c.set_data(response) - while data[0] in platformtools.requests and not self.wfile.closed: - time.sleep(1) - else: - if self.path == "": self.path = "/" - - # Busca el controller para la url - controller = controllers.find_controller(self.path) - if controller: - try: - c = controller(self) - c.run(self.path) - except: - if not "socket.py" in traceback.format_exc(): - logger.error(traceback.format_exc()) - finally: - c.__del__() - del c - return - - def address_string(self): - # Disable reverse name lookups - return self.client_address[:2][0] - - -PORT = config.get_setting("server.port") -server = MyHTTPServer(('', int(PORT)), Handler) - - -def start(fnc_info): - server.fnc_info = fnc_info - threading.Thread(target=server.serve_forever).start() - - -def stop(): - server.socket.close() - server.shutdown() From 7c25db464402d72c7c156da127f2be0f35b5f6d3 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Tue, 3 Jul 2018 08:55:49 -0500 Subject: [PATCH 14/37] url: tengourl cambios cosmeticos --- plugin.video.alfa/channels/url.json | 4 ++-- plugin.video.alfa/channels/url.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin.video.alfa/channels/url.json b/plugin.video.alfa/channels/url.json index 9c22b22b..2ae39f42 100755 --- a/plugin.video.alfa/channels/url.json +++ b/plugin.video.alfa/channels/url.json @@ -3,6 +3,6 @@ "name": "Tengo una URL", "active": false, "adult": false, - "thumbnail": "url.png", - "banner": "url.png" + "thumbnail": "tengourl.png", + "banner": "tengourl.png" } \ No newline at end of file diff --git a/plugin.video.alfa/channels/url.py b/plugin.video.alfa/channels/url.py index db9879dc..6e0e61e9 100755 --- a/plugin.video.alfa/channels/url.py +++ b/plugin.video.alfa/channels/url.py @@ -24,7 +24,7 @@ def mainlist(item): def search(item, texto): logger.info("texto=" + texto) - if not texto.startswith("http://"): + if not texto.startswith("http"): texto = "http://" + texto itemlist = [] @@ -38,7 +38,7 @@ def search(item, texto): itemlist.append( Item(channel=item.channel, action="play", url=texto, server="directo", title="Ver enlace directo")) else: - data = scrapertools.downloadpage(texto) + data = httptools.downloadpage(texto).data itemlist = servertools.find_video_items(data=data) for item in itemlist: item.channel = "url" From a1cb798faa4f3c15b79918213e0fa0abbf1cdea7 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Tue, 3 Jul 2018 09:02:16 -0500 Subject: [PATCH 15/37] Add files via upload --- plugin.video.alfa/channels/url.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin.video.alfa/channels/url.py b/plugin.video.alfa/channels/url.py index 6e0e61e9..44ab2769 100755 --- a/plugin.video.alfa/channels/url.py +++ b/plugin.video.alfa/channels/url.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from core import httptools from core import scrapertools from core import servertools from core.item import Item From 708548e7f3a37cd3a821e7c0a717700c98c922bd Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Tue, 3 Jul 2018 09:33:34 -0500 Subject: [PATCH 16/37] poseidonhd: fix --- plugin.video.alfa/channels/poseidonhd.py | 32 +++++++++++++++--------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/plugin.video.alfa/channels/poseidonhd.py b/plugin.video.alfa/channels/poseidonhd.py index ded2a793..b9e9dbf0 100644 --- a/plugin.video.alfa/channels/poseidonhd.py +++ b/plugin.video.alfa/channels/poseidonhd.py @@ -256,24 +256,30 @@ def findvideos(item): for url in urls: final_url = httptools.downloadpage('https:'+url).data - if 'vip' in url: + + if language == 'VOSE': + sub = scrapertools.find_single_match(url, 'sub=(.*?)&') + subs = 'https:%s' % sub + + if 'index' in url: file_id = scrapertools.find_single_match(url, 'file=(.*?)&') - if language=='VOSE': - sub = scrapertools.find_single_match(url, 'sub=(.*?)&') - subs = 'https:%s' % sub - post = {'link':file_id} + post = {'link': file_id} post = urllib.urlencode(post) - hidden_url = 'https://streamango.poseidonhd.com/repro//plugins/gkpluginsphp.php' + hidden_url = 'https://streamango.poseidonhd.com/repro/plugins/gkpluginsphp.php' data_url = httptools.downloadpage(hidden_url, post=post).data dict_vip_url = jsontools.load(data_url) url = dict_vip_url['link'] else: - url = 'https:%s' % url - new_url = url.replace('embed','stream') - url = httptools.downloadpage(new_url, follow_redirects=False).headers.get('location') - #title = '%s [%s]' % (item.title, language) - itemlist.append(item.clone(title='[%s] [%s]', url=url, action='play', subtitle=subs, - language=language, quality=quality, infoLabels = item.infoLabels)) + file_id = scrapertools.find_single_match(url, 'url=(.*?)&') + post = {'url': file_id} + post = urllib.urlencode(post) + hidden_url = 'https://streamango.poseidonhd.com/repro/r.php' + data_url = httptools.downloadpage(hidden_url, post=post, follow_redirects=False) + url = data_url.headers['location'] + + itemlist.append(item.clone(title = '[%s] [%s]', url=url, action='play', subtitle=subs, + language=language, quality=quality, infoLabels=item.infoLabels)) + itemlist = servertools.get_servers_itemlist(itemlist, lambda x: x.title % (x.server.capitalize(), x.language)) # Requerido para Filtrar enlaces @@ -289,6 +295,8 @@ def findvideos(item): autoplay.start(itemlist, item) + itemlist = sorted(itemlist, key=lambda it: it.language) + if item.contentType != 'episode': if config.get_videolibrary_support() and len(itemlist) > 0 and item.extra != 'findvideos': itemlist.append( From 89744269900bbb88397bdb3dcdbb98f58b0a7466 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Tue, 3 Jul 2018 09:55:59 -0500 Subject: [PATCH 17/37] html: fix erorr thumbs --- mediaserver/platformcode/controllers/html.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/mediaserver/platformcode/controllers/html.py b/mediaserver/platformcode/controllers/html.py index 77dfe820..f44554a2 100644 --- a/mediaserver/platformcode/controllers/html.py +++ b/mediaserver/platformcode/controllers/html.py @@ -105,7 +105,7 @@ class platform(Platformtools): thumbnail=channelselector.get_thumb("back.png", "banner_"))) else: itemlist.insert(0, Item(title="Atrás", action="go_back", - thumbnail=channelselector.get_thumb("back.png"))) + thumbnail=channelselector.get_thumb("back.png", "banner_"))) JsonData = {} JsonData["action"] = "EndItems" @@ -119,17 +119,9 @@ class platform(Platformtools): # Recorremos el itemlist for item in itemlist: - if not item.thumbnail and item.action == "search": item.thumbnail = channelselector.get_thumb("search.png") - if not item.thumbnail and item.folder == True: item.thumbnail = channelselector.get_thumb("folder.png", "banner") - if not item.thumbnail and item.folder == False: item.thumbnail = channelselector.get_thumb("nofolder.png") - if "http://media.xxxxx/" in item.thumbnail and not item.thumbnail.startswith( - "http://media.xxxxxxxx/thumb_"): - - if parent_item.viewmode in ["banner", "channel"]: - item.thumbnail = channelselector.get_thumbnail_path("banner") + os.path.basename(item.thumbnail) - else: - item.thumbnail = channelselector.get_thumbnail_path() + os.path.basename(item.thumbnail) - + if not item.thumbnail and item.action == "search": item.thumbnail = channelselector.get_thumb("search.png", "banner_") + #if not item.thumbnail and item.folder == True: item.thumbnail = channelselector.get_thumb("folder.png", "banner_") + if not item.thumbnail and item.folder == False: item.thumbnail = channelselector.get_thumb("nofolder.png", "banner_") # Estas imagenes no estan en banner, asi que si queremos banner, para que no se vean mal las quitamos elif parent_item.viewmode in ["banner", "channel"] and item.thumbnail.startswith( "http://media.xxxxx/thumb_"): From f31a46f5d7762191a62d2edeba302c63e8ff426e Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Tue, 3 Jul 2018 09:57:30 -0500 Subject: [PATCH 18/37] alfa.py: agregado version a alfa.log --- mediaserver/alfa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediaserver/alfa.py b/mediaserver/alfa.py index 87b61dc2..119c192b 100644 --- a/mediaserver/alfa.py +++ b/mediaserver/alfa.py @@ -73,7 +73,7 @@ def start(): # Da por levantado el servicio logger.info("--------------------------------------------------------------------") - logger.info("Alfa Iniciado") + logger.info("Alfa %s Iniciado" %version) logger.info("La URL para acceder es http://%s:%s" % (myip, http_port)) logger.info("WebSocket Server iniciado en ws://%s:%s" % (myip, websocket_port)) logger.info("--------------------------------------------------------------------") From ba66e4106b3d4704ee469aad7cb5e4077d41e224 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Tue, 3 Jul 2018 10:12:07 -0500 Subject: [PATCH 19/37] tvvip: fix --- plugin.video.alfa/channels/tvvip.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugin.video.alfa/channels/tvvip.py b/plugin.video.alfa/channels/tvvip.py index 4487b3bc..4b47bd66 100644 --- a/plugin.video.alfa/channels/tvvip.py +++ b/plugin.video.alfa/channels/tvvip.py @@ -612,8 +612,9 @@ def play(item): uri_request = host + "/video-prod/s/uri?uri=%s&_=%s" % (uri, int(time.time())) data = httptools.downloadpage(uri_request).data data = jsontools.load(data) - url = item.url.replace(".tv-vip.com/transcoder/", ".tv-vip.info/c/transcoder/") + "?tt=" + str(data['tt']) + \ + url = item.url.replace(".tv-vip.com/transcoder/", ".tv-vip.in/c/transcoder/") + "?tt=" + str(data['tt']) + \ "&mm=" + data['mm'] + "&bb=" + data['bb'] + url += "|User-Agent=Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Mobile Safari/537.36" itemlist.append(item.clone(action="play", server="directo", url=url, folder=False)) return itemlist From 1cb13c09b0b5806f691eb2ccb2e4ca987c503b30 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Tue, 3 Jul 2018 10:13:51 -0500 Subject: [PATCH 20/37] help: fix mediaserver --- plugin.video.alfa/channels/help.py | 80 +++++++++++++++--------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/plugin.video.alfa/channels/help.py b/plugin.video.alfa/channels/help.py index 2454c9c6..6bd24cb3 100644 --- a/plugin.video.alfa/channels/help.py +++ b/plugin.video.alfa/channels/help.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import os -import xbmc from core.item import Item from platformcode import config, logger, platformtools @@ -41,50 +40,50 @@ def mainlist(item): logger.info() itemlist = [] + itemlist.append(Item(channel=item.channel, action="", title="FAQ:", + thumbnail=get_thumb("help.png"), + folder=False)) if config.is_xbmc(): - itemlist.append(Item(channel=item.channel, action="", title="FAQ:", - thumbnail=get_thumb("help.png"), - folder=False)) itemlist.append(Item(channel=item.channel, action="faq", title=" - ¿Cómo reportar un error?", thumbnail=get_thumb("help.png"), folder=False, extra="report_error")) - itemlist.append(Item(channel=item.channel, action="faq", - title=" - ¿Se pueden activar/desactivar los canales?", - thumbnail=get_thumb("help.png"), - folder=False, extra="onoff_canales")) - itemlist.append(Item(channel=item.channel, action="faq", - title=" - ¿Es posible la sincronización automática con Trakt?", - thumbnail=get_thumb("help.png"), - folder=False, extra="trakt_sync")) - itemlist.append(Item(channel=item.channel, action="faq", - title=" - ¿Es posible mostrar todos los resultados juntos en el buscador global?", - thumbnail=get_thumb("help.png"), - folder=False, extra="buscador_juntos")) - itemlist.append(Item(channel=item.channel, action="faq", - title=" - Los enlaces tardan en aparecer.", - thumbnail=get_thumb("help.png"), - folder=False, extra="tiempo_enlaces")) - itemlist.append(Item(channel=item.channel, action="faq", - title=" - La búsqueda de contenido no se hace correctamente.", - thumbnail=get_thumb("help.png"), - folder=False, extra="prob_busquedacont")) - itemlist.append(Item(channel=item.channel, action="faq", - title=" - Algún canal no funciona correctamente.", - thumbnail=get_thumb("help.png"), - folder=False, extra="canal_fallo")) - itemlist.append(Item(channel=item.channel, action="faq", - title=" - Los enlaces Torrent no funcionan.", - thumbnail=get_thumb("help.png"), - folder=False, extra="prob_torrent")) - itemlist.append(Item(channel=item.channel, action="faq", - title=" - No se actualiza correctamente la videoteca.", - thumbnail=get_thumb("help.png"), - folder=True, extra="prob_bib")) - itemlist.append(Item(channel=item.channel, action="faq", - title=" - Enlaces de interés", - thumbnail=get_thumb("help.png"), - folder=False, extra="")) + itemlist.append(Item(channel=item.channel, action="faq", + title=" - ¿Se pueden activar/desactivar los canales?", + thumbnail=get_thumb("help.png"), + folder=False, extra="onoff_canales")) + itemlist.append(Item(channel=item.channel, action="faq", + title=" - ¿Es posible la sincronización automática con Trakt?", + thumbnail=get_thumb("help.png"), + folder=False, extra="trakt_sync")) + itemlist.append(Item(channel=item.channel, action="faq", + title=" - ¿Es posible mostrar todos los resultados juntos en el buscador global?", + thumbnail=get_thumb("help.png"), + folder=False, extra="buscador_juntos")) + itemlist.append(Item(channel=item.channel, action="faq", + title=" - Los enlaces tardan en aparecer.", + thumbnail=get_thumb("help.png"), + folder=False, extra="tiempo_enlaces")) + itemlist.append(Item(channel=item.channel, action="faq", + title=" - La búsqueda de contenido no se hace correctamente.", + thumbnail=get_thumb("help.png"), + folder=False, extra="prob_busquedacont")) + itemlist.append(Item(channel=item.channel, action="faq", + title=" - Algún canal no funciona correctamente.", + thumbnail=get_thumb("help.png"), + folder=False, extra="canal_fallo")) + itemlist.append(Item(channel=item.channel, action="faq", + title=" - Los enlaces Torrent no funcionan.", + thumbnail=get_thumb("help.png"), + folder=False, extra="prob_torrent")) + itemlist.append(Item(channel=item.channel, action="faq", + title=" - No se actualiza correctamente la videoteca.", + thumbnail=get_thumb("help.png"), + folder=True, extra="prob_bib")) + itemlist.append(Item(channel=item.channel, action="faq", + title=" - Enlaces de interés", + thumbnail=get_thumb("help.png"), + folder=False, extra="")) return itemlist @@ -192,6 +191,7 @@ def faq(item): search.settings("") elif item.extra == "report_error": + import xbmc if config.get_platform(True)['num_version'] < 14: log_name = "xbmc.log" else: From b2df8be1667ad652ea7098a7cf516ec0e7ea356c Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 3 Jul 2018 19:13:45 +0200 Subject: [PATCH 21/37] Small Fix --- mediaserver/platformcode/config.py | 20 +------------------- mediaserver/resources/settings.xml | 2 +- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/mediaserver/platformcode/config.py b/mediaserver/platformcode/config.py index 4589f1dd..655eafdb 100644 --- a/mediaserver/platformcode/config.py +++ b/mediaserver/platformcode/config.py @@ -310,23 +310,6 @@ def verify_directories_created(): logger.debug("Creating %s: %s" % (path, saved_path)) filetools.mkdir(saved_path) - config_paths = [["folder_movies", "CINE"], - ["folder_tvshows", "SERIES"]] - - for path, default in config_paths: - saved_path = get_setting(path) - - if not saved_path: - saved_path = default - set_setting(path, saved_path) - - content_path = filetools.join(get_videolibrary_path(), saved_path) - if not filetools.exists(content_path): - logger.debug("Creating %s: %s" % (path, content_path)) - - # si se crea el directorio - filetools.mkdir(content_path) - def get_local_ip(): import socket @@ -386,8 +369,7 @@ configfilepath = os.path.join(get_data_path(), "settings.xml") if not os.path.exists(get_data_path()): os.mkdir(get_data_path()) load_settings() -TRANSLATION_FILE_PATH = os.path.join(get_runtime_path(), "resources", "language", settings_dic["mediacenter_language"], "strings.po") - +TRANSLATION_FILE_PATH = os.path.join(get_runtime_path(), "resources", "language", settings_dic["mediaserver_language"], "strings.po") # modo adulto: # sistema actual 0: Nunca, 1:Siempre, 2:Solo hasta que se reinicie sesión diff --git a/mediaserver/resources/settings.xml b/mediaserver/resources/settings.xml index 8a7e6746..8e01cccf 100644 --- a/mediaserver/resources/settings.xml +++ b/mediaserver/resources/settings.xml @@ -7,7 +7,7 @@ - + From c9dc403e2ce499fb805f242caae7f8b780f1b7f8 Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 3 Jul 2018 20:45:00 +0200 Subject: [PATCH 22/37] Fix missing part --- mediaserver/platformcode/config.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/mediaserver/platformcode/config.py b/mediaserver/platformcode/config.py index 655eafdb..a37a0c41 100644 --- a/mediaserver/platformcode/config.py +++ b/mediaserver/platformcode/config.py @@ -310,6 +310,23 @@ def verify_directories_created(): logger.debug("Creating %s: %s" % (path, saved_path)) filetools.mkdir(saved_path) + config_paths = [["folder_movies", "CINE"], + ["folder_tvshows", "SERIES"]] + + for path, default in config_paths: + saved_path = get_setting(path) + + if not saved_path: + saved_path = default + set_setting(path, saved_path) + + content_path = filetools.join(get_videolibrary_path(), saved_path) + if not filetools.exists(content_path): + logger.debug("Creating %s: %s" % (path, content_path)) + + # si se crea el directorio + filetools.mkdir(content_path) + def get_local_ip(): import socket From 0efdf788eb762ce915d5a7c9414cb0df19283d2a Mon Sep 17 00:00:00 2001 From: pipcat Date: Tue, 3 Jul 2018 20:59:10 +0200 Subject: [PATCH 23/37] Timeout general configurable --- plugin.video.alfa/core/httptools.py | 3 ++- plugin.video.alfa/resources/settings.xml | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugin.video.alfa/core/httptools.py b/plugin.video.alfa/core/httptools.py index 350bcf04..eee42e57 100755 --- a/plugin.video.alfa/core/httptools.py +++ b/plugin.video.alfa/core/httptools.py @@ -32,7 +32,8 @@ default_headers["Accept-Charset"] = "UTF-8" default_headers["Accept-Encoding"] = "gzip" # Tiempo máximo de espera para downloadpage, si no se especifica nada -HTTPTOOLS_DEFAULT_DOWNLOAD_TIMEOUT = None +HTTPTOOLS_DEFAULT_DOWNLOAD_TIMEOUT = config.get_setting('httptools_timeout', default=15) +if HTTPTOOLS_DEFAULT_DOWNLOAD_TIMEOUT == 0: HTTPTOOLS_DEFAULT_DOWNLOAD_TIMEOUT = None def get_url_headers(url): diff --git a/plugin.video.alfa/resources/settings.xml b/plugin.video.alfa/resources/settings.xml index ab3aa14a..58052e5e 100644 --- a/plugin.video.alfa/resources/settings.xml +++ b/plugin.video.alfa/resources/settings.xml @@ -117,6 +117,9 @@ - + + + + From fa5cb4baa1867f2c67b00e0f108ed0d7f54be68b Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 26 Jun 2018 23:06:41 +0200 Subject: [PATCH 24/37] Revert "Fix Localized Strings in JSON Files (Mediaserver)" This reverts commit 7f2d99238ce6364036383ea6a74c3d2bcea34087. --- mediaserver/platformcode/controllers/html.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/mediaserver/platformcode/controllers/html.py b/mediaserver/platformcode/controllers/html.py index 6268f13f..573171a1 100644 --- a/mediaserver/platformcode/controllers/html.py +++ b/mediaserver/platformcode/controllers/html.py @@ -696,17 +696,15 @@ class platform(Platformtools): c["value"] = dict_values[c["id"]] # Translation - string_id = re.findall(r'\$ADDON\[[^\d]+(\d+)]', c['label'], flags=re.DOTALL) - if c['label'].startswith('$') and len(string_id) > 0: - c['label'] = str(config.get_localized_string(string_id[0])) + if c['label'].startswith('@') and unicode(c['label'][1:]).isnumeric(): + c['label'] = str(config.get_localized_string(c['label'][1:])) if c["label"].endswith(":"): c["label"] = c["label"][:-1] if c['type'] == 'list': lvalues = [] for li in c['lvalues']: - string_id = re.findall(r'\$ADDON\[[^\d]+(\d+)]', li, flags=re.DOTALL) - if li.startswith('$') and len(string_id) > 0: - lvalues.append(str(config.get_localized_string(string_id[0]))) + if li.startswith('@') and unicode(li[1:]).isnumeric(): + lvalues.append(str(config.get_localized_string(li[1:]))) else: lvalues.append(li) c['lvalues'] = lvalues From 1a76c7cd7973f54b624df621f613df017aa44e3d Mon Sep 17 00:00:00 2001 From: Kingbox <37674310+lopezvg@users.noreply.github.com> Date: Wed, 4 Jul 2018 14:32:29 +0200 Subject: [PATCH 25/37] Newpct1: nuevo canal virtual con Alta Disponibilidad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Este nuevo canal virtual sustituye a los clones de Newpct1 actuales. Añade funciones de Alta Disponibilidad, cambiando automáticamente a otra web clone si está inaccesible la web en uso. --- plugin.video.alfa/channels/newpct1.json | 565 +++++++ plugin.video.alfa/channels/newpct1.py | 1610 ++++++++++++++++++++ plugin.video.alfa/channels/videolibrary.py | 12 +- plugin.video.alfa/lib/generictools.py | 208 ++- plugin.video.alfa/videolibrary_service.py | 12 +- 5 files changed, 2342 insertions(+), 65 deletions(-) create mode 100644 plugin.video.alfa/channels/newpct1.json create mode 100644 plugin.video.alfa/channels/newpct1.py diff --git a/plugin.video.alfa/channels/newpct1.json b/plugin.video.alfa/channels/newpct1.json new file mode 100644 index 00000000..a121e330 --- /dev/null +++ b/plugin.video.alfa/channels/newpct1.json @@ -0,0 +1,565 @@ +{ + "id": "newpct1", + "name": "Newpct1", + "active": true, + "adult": false, + "language": ["*"], + "thumbnail": "newpct1.png", + "banner": "newpct1.png", + "categories": [ + "movie", + "tvshow", + "anime", + "torrent", + "latino", + "documentary", + "vos", + "direct" + ], + "settings": [ + { + "id": "include_in_global_search", + "type": "bool", + "label": "Incluir en busqueda global", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "modo_grafico", + "type": "bool", + "label": "Buscar información extra (TMDB)", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "clonenewpct1_channel_default", + "type": "list", + "label": "Clone de NewPct1 por defecto", + "default": 0, + "enabled": true, + "visible": true, + "lvalues": [ + "Torrentrapid", + "Torrentlocura", + "Tumejortorrent", + "Tvsinpagar", + "Descargas2020", + "Mispelisyseries" + ] + }, + { + "id": "clonenewpct1_channels_list", + "type": "text", + "label": "Lista de clones de NewPct1 y orden de uso", + "default": "('1', 'torrentrapid', 'http://torrentrapid.com/', 'movie, tvshow, season, episode', ''), ('1', 'torrentlocura', 'http://torrentlocura.com/', 'movie, tvshow, season, episode', ''), ('1', 'tumejortorrent', 'http://tumejortorrent.com/', 'movie, tvshow, season, episode', ''), ('1', 'tvsinpagar', 'http://www.tvsinpagar.com/', 'tvshow, season, episode', ''), ('1', 'descargas2020', 'http://descargas2020.com/', 'movie, tvshow, season, episode', ''), ('1', 'mispelisyseries', 'http://mispelisyseries.com/', 'movie', 'search')", + "enabled": true, + "visible": false + }, + { + "id": "seleccionar_ult_temporadda_activa", + "type": "bool", + "label": "Seleccionar para Videoteca si estará activa solo la última Temporada", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "clonenewpct1_ver_enlaces_veronline", + "type": "list", + "label": "Mostrar enlaces Ver Online", + "default": 1, + "enabled": true, + "visible": true, + "lvalues": [ + "No", + "Todos", + "1", + "5", + "10", + "20" + ] + }, + { + "id": "clonenewpct1_verificar_enlaces_veronline", + "type": "list", + "label": "Verificar enlaces Ver Online", + "default": 1, + "enabled": true, + "visible": "!eq(-1,'No')", + "lvalues": [ + "No", + "Todos", + "1", + "5", + "10", + "20" + ] + }, + { + "id": "clonenewpct1_verificar_enlaces_veronline_validos", + "type": "bool", + "label": "¿Contar sólo enlaces 'verificados' en Ver Online?", + "default": true, + "enabled": true, + "visible": "!eq(-1,'No') + !eq(-2,'No')" + }, + { + "id": "clonenewpct1_excluir1_enlaces_veronline", + "type": "list", + "label": "Excluir Servidores para Ver Online", + "default": 9, + "max_excl": 5, + "enabled": true, + "visible": "!eq(-3,'No')", + "lvalues": [ + "No", + "Bankupload", + "Clipwatching", + "Flashx", + "Katfile", + "Mega", + "Mexashare", + "Movshare", + "Mowvideo", + "Openload", + "Powvideo", + "Rapidgator", + "Streamango", + "Streamcloud", + "Streame", + "Streaminto", + "Streamplay", + "Thevideo", + "Turbobit", + "Uploadedto", + "Uptobox", + "Userscloud", + "Vidabc", + "Vidspot" + ] + }, + { + "id": "clonenewpct1_excluir2_enlaces_veronline", + "type": "list", + "label": "Excluir Servidores para Ver Online", + "default": 12, + "enabled": true, + "visible": "!eq(-1,'No')", + "lvalues": [ + "No", + "Bankupload", + "Clipwatching", + "Flashx", + "Katfile", + "Mega", + "Mexashare", + "Movshare", + "Mowvideo", + "Openload", + "Powvideo", + "Rapidgator", + "Streamango", + "Streamcloud", + "Streame", + "Streaminto", + "Streamplay", + "Thevideo", + "Turbobit", + "Uploadedto", + "Uptobox", + "Userscloud", + "Vidabc", + "Vidspot" + ] + }, + { + "id": "clonenewpct1_excluir3_enlaces_veronline", + "type": "list", + "label": "Excluir Servidores para Ver Online", + "default": 20, + "enabled": true, + "visible": "!eq(-1,'No')", + "lvalues": [ + "No", + "Bankupload", + "Clipwatching", + "Flashx", + "Katfile", + "Mega", + "Mexashare", + "Movshare", + "Mowvideo", + "Openload", + "Powvideo", + "Rapidgator", + "Streamango", + "Streamcloud", + "Streame", + "Streaminto", + "Streamplay", + "Thevideo", + "Turbobit", + "Uploadedto", + "Uptobox", + "Userscloud", + "Vidabc", + "Vidspot" + ] + }, + { + "id": "clonenewpct1_excluir4_enlaces_veronline", + "type": "list", + "label": "Excluir Servidores para Ver Online", + "default": 0, + "enabled": true, + "visible": "!eq(-1,'No')", + "lvalues": [ + "No", + "Bankupload", + "Clipwatching", + "Flashx", + "Katfile", + "Mega", + "Mexashare", + "Movshare", + "Mowvideo", + "Openload", + "Powvideo", + "Rapidgator", + "Streamango", + "Streamcloud", + "Streame", + "Streaminto", + "Streamplay", + "Thevideo", + "Turbobit", + "Uploadedto", + "Uptobox", + "Userscloud", + "Vidabc", + "Vidspot" + ] + }, + { + "id": "clonenewpct1_excluir5_enlaces_veronline", + "type": "list", + "label": "Excluir Servidores para Ver Online", + "default": 0, + "enabled": true, + "visible": "!eq(-1,'No')", + "lvalues": [ + "No", + "Bankupload", + "Clipwatching", + "Flashx", + "Katfile", + "Mega", + "Mexashare", + "Movshare", + "Mowvideo", + "Openload", + "Powvideo", + "Rapidgator", + "Streamango", + "Streamcloud", + "Streame", + "Streaminto", + "Streamplay", + "Thevideo", + "Turbobit", + "Uploadedto", + "Uptobox", + "Userscloud", + "Vidabc", + "Vidspot" + ] + }, + { + "id": "clonenewpct1_ver_enlaces_descargas", + "type": "list", + "label": "Mostrar enlaces Descargas", + "default": 0, + "enabled": true, + "visible": true, + "lvalues": [ + "No", + "Todos", + "1", + "5", + "10", + "20", + "30", + "50", + "100" + ] + }, + { + "id": "clonenewpct1_verificar_enlaces_descargas", + "type": "list", + "label": "Verificar enlaces Descargas", + "default": 1, + "enabled": true, + "visible": "!eq(-1,'No')", + "lvalues": [ + "No", + "Todos", + "1", + "5", + "10", + "20", + "30", + "50", + "100" + ] + }, + { + "id": "clonenewpct1_verificar_enlaces_descargas_validos", + "type": "bool", + "label": "¿Contar sólo enlaces 'verificados' en Descargar?", + "default": true, + "enabled": true, + "visible": "!eq(-1,'No') + !eq(-2,'No')" + }, + { + "id": "clonenewpct1_excluir1_enlaces_descargas", + "type": "list", + "label": "Excluir Servidores para Ver Descargas", + "default": 0, + "enabled": true, + "visible": "!eq(-3,'No')", + "lvalues": [ + "No", + "Bankupload", + "Clipwatching", + "Flashx", + "Katfile", + "Mega", + "Mexashare", + "Movshare", + "Mowvideo", + "Openload", + "Powvideo", + "Rapidgator", + "Streamango", + "Streamcloud", + "Streame", + "Streaminto", + "Streamplay", + "Thevideo", + "Turbobit", + "Uploadedto", + "Uptobox", + "Userscloud", + "Vidabc", + "Vidspot" + ] + }, + { + "id": "clonenewpct1_excluir2_enlaces_descargas", + "type": "list", + "label": "Excluir Servidores para Ver Descargas", + "default": 0, + "enabled": true, + "visible": "!eq(-1,'No')", + "lvalues": [ + "No", + "Bankupload", + "Clipwatching", + "Flashx", + "Katfile", + "Mega", + "Mexashare", + "Movshare", + "Mowvideo", + "Openload", + "Powvideo", + "Rapidgator", + "Streamango", + "Streamcloud", + "Streame", + "Streaminto", + "Streamplay", + "Thevideo", + "Turbobit", + "Uploadedto", + "Uptobox", + "Userscloud", + "Vidabc", + "Vidspot" + ] + }, + { + "id": "clonenewpct1_excluir3_enlaces_descargas", + "type": "list", + "label": "Excluir Servidores para Descargas", + "default": 0, + "enabled": true, + "visible": "!eq(-1,'No')", + "lvalues": [ + "No", + "Bankupload", + "Clipwatching", + "Flashx", + "Katfile", + "Mega", + "Mexashare", + "Movshare", + "Mowvideo", + "Openload", + "Powvideo", + "Rapidgator", + "Streamango", + "Streamcloud", + "Streame", + "Streaminto", + "Streamplay", + "Thevideo", + "Turbobit", + "Uploadedto", + "Uptobox", + "Userscloud", + "Vidabc", + "Vidspot" + ] + }, + { + "id": "clonenewpct1_excluir4_enlaces_descargas", + "type": "list", + "label": "Excluir Servidores para Descargas", + "default": 0, + "enabled": true, + "visible": "!eq(-1,'No')", + "lvalues": [ + "No", + "Bankupload", + "Clipwatching", + "Flashx", + "Katfile", + "Mega", + "Mexashare", + "Movshare", + "Mowvideo", + "Openload", + "Powvideo", + "Rapidgator", + "Streamango", + "Streamcloud", + "Streame", + "Streaminto", + "Streamplay", + "Thevideo", + "Turbobit", + "Uploadedto", + "Uptobox", + "Userscloud", + "Vidabc", + "Vidspot" + ] + }, + { + "id": "clonenewpct1_excluir5_enlaces_descargas", + "type": "list", + "label": "Excluir Servidores para Descargas", + "default": 0, + "enabled": true, + "visible": "!eq(-1,'No')", + "lvalues": [ + "No", + "Bankupload", + "Clipwatching", + "Flashx", + "Katfile", + "Mega", + "Mexashare", + "Movshare", + "Mowvideo", + "Openload", + "Powvideo", + "Rapidgator", + "Streamango", + "Streamcloud", + "Streame", + "Streaminto", + "Streamplay", + "Thevideo", + "Turbobit", + "Uploadedto", + "Uptobox", + "Userscloud", + "Vidabc", + "Vidspot" + ] + }, + { + "id": "include_in_newest_peliculas", + "type": "bool", + "label": "Incluir en Novedades - Peliculas", + "default": true, + "enabled": true, + "visible": false + }, + { + "id": "include_in_newest_series", + "type": "bool", + "label": "Incluir en Novedades - Episodios de series", + "default": true, + "enabled": true, + "visible": false + }, + { + "id": "include_in_newest_anime", + "type": "bool", + "label": "Incluir en Novedades - Anime", + "default": true, + "enabled": true, + "visible": false + }, + { + "id": "include_in_newest_documentales", + "type": "bool", + "label": "Incluir en Novedades - Documentales", + "default": true, + "enabled": true, + "visible": false + }, + { + "id": "include_in_newest_latino", + "type": "bool", + "label": "Incluir en Novedades - Documentales", + "default": true, + "enabled": true, + "visible": false + }, + { + "id": "include_in_newest_4k", + "type": "bool", + "label": "Incluir en Novedades - 4K", + "default": true, + "enabled": true, + "visible": false + }, + { + "id": "clonenewpct1_timeout_downloadpage", + "type": "list", + "label": "Timeout (segs.) en descarga de páginas o verificación de servidores", + "default": 5, + "enabled": true, + "visible": true, + "lvalues": [ + "None", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10" + ] + } + ] +} \ No newline at end of file diff --git a/plugin.video.alfa/channels/newpct1.py b/plugin.video.alfa/channels/newpct1.py new file mode 100644 index 00000000..8edb752c --- /dev/null +++ b/plugin.video.alfa/channels/newpct1.py @@ -0,0 +1,1610 @@ +# -*- coding: utf-8 -*- + +import re +import sys +import urllib +import urlparse +import datetime +import ast + +from channelselector import get_thumb +from core import httptools +from core import scrapertools +from core import servertools +from core.item import Item +from platformcode import config, logger +from core import tmdb +from lib import generictools + +channel_py = 'newpct1' + +#Código para permitir usar un único canal para todas las webs clones de NewPct1 +clone_list = config.get_setting('clonenewpct1_channels_list', channel_py) #Carga lista de clones +clone_list = ast.literal_eval(clone_list) #la convierte en array +host_index = 0 +host_index = config.get_setting('clonenewpct1_channel_default', channel_py) #Clone por defecto +i = 0 +for active_clone, channel_clone, host_clone, contentType_clone, info_clone in clone_list: + if i == host_index: + channel_clone_name = channel_clone #Nombre del Canal elegido + host = host_clone #URL del Canal elegido + break + i += 1 +item = Item() +if item.channel != channel_py: + item.channel = channel_py + +#Carga de opciones del canal +__modo_grafico__ = config.get_setting('modo_grafico', channel_py) #TMDB? +modo_ultima_temp = config.get_setting('seleccionar_ult_temporadda_activa', channel_py) #Actualización sólo últ. Temporada? +timeout = config.get_setting('clonenewpct1_timeout_downloadpage', channel_py) #Timeout downloadpage +if timeout == 0: timeout = None + + +def mainlist(item): + logger.info() + + itemlist = [] + + if not item.channel_host: + item.channel_host = host + if item.category.lower() == channel_py: + item.category = channel_clone_name.capitalize() + + thumb_pelis = get_thumb("channels_movie.png") + thumb_pelis_hd = get_thumb("channels_movie_hd.png") + thumb_series = get_thumb("channels_tvshow.png") + thumb_series_hd = get_thumb("channels_tvshow_hd.png") + thumb_series_az = get_thumb("channels_tvshow_az.png") + thumb_docus = get_thumb("channels_documentary.png") + thumb_buscar = get_thumb("search.png") + thumb_settings = get_thumb("setting_0.png") + + itemlist.append(Item(channel=item.channel, action="submenu", title="Películas", url=item.channel_host, + extra="peliculas", thumbnail=thumb_pelis, category=item.category)) + + itemlist.append(Item(channel=item.channel, action="submenu", title="Series", url=item.channel_host, extra="series", + thumbnail=thumb_series, category=item.category)) + + itemlist.append(Item(channel=item.channel, action="submenu", title="Documentales", url=item.channel_host, extra="varios", + thumbnail=thumb_docus, category=item.category)) + itemlist.append( + Item(channel=item.channel, action="search", title="Buscar", url=item.channel_host + "buscar", thumbnail=thumb_buscar, category=item.category)) + + itemlist.append( + Item(channel=item.channel, action="", title="[COLOR yellow]Configuración de Servidores:[/COLOR]", url="", thumbnail=thumb_settings, category=item.category)) + itemlist.append( + Item(channel=item.channel, action="settingCanal", title="Servidores para Ver Online y Descargas", url="", thumbnail=thumb_settings, category=item.category)) + + return itemlist + + +def settingCanal(item): + from platformcode import platformtools + return platformtools.show_channel_settings() + + +def submenu(item): + logger.info() + itemlist = [] + + data = '' + try: + data = re.sub(r"\n|\r|\t|\s{2}|()", "", httptools.downloadpage(item.url, timeout=timeout).data) + except: + pass + + patron = '
  • <\/i>.*Inicio<\/a><\/li>(.+)<\/ul>\s?<\/nav>' + #Verificamos si se ha cargado una página, y si además tiene la estructura correcta + if not data or not scrapertools.find_single_match(data, patron): + logger.error("ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url + data) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + elif item.channel_alt: #Si ha habido fail-over, lo comento + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) + + if item.url_alt: del item.url_alt + del item.channel_alt + + data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") + data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com + if "pelisyseries.com" in item.channel_host and item.extra == "varios": #compatibilidad con mispelisy.series.com + data = '
  • Documentales
  • ' + else: + data = scrapertools.get_match(data, patron) #Seleccionamos el trozo que nos interesa + if not data: + logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + + patron = '
  • ([^>]+)<\/a><\/li>' + matches = re.compile(patron, re.DOTALL).findall(data) + + if not matches: + logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + + for scrapedurl, scrapedtitle in matches: + title = scrapedtitle.strip() + + #Preguntamos por las entradas que no corresponden al "extra" + if item.extra in scrapedtitle.lower() or (item.extra == "peliculas" and ("cine" in scrapedurl or "anime" in scrapedurl)) or (item.extra == "varios" and ("documentales" in scrapedurl or "varios" in scrapedurl)): + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) + itemlist.append(item.clone(action="alfabeto", title=title + " [A-Z]", url=scrapedurl)) + + if item.extra == "peliculas": + itemlist.append(item.clone(action="listado", title="Películas 4K", url=item.channel_host + "peliculas-hd/4kultrahd/")) + itemlist.append(item.clone(action="alfabeto", title="Películas 4K" + " [A-Z]", url=item.channel_host + "peliculas-hd/4kultrahd/")) + + return itemlist + + +def alfabeto(item): + logger.info() + itemlist = [] + + data = '' + data = re.sub(r"\n|\r|\t|\s{2}|()", "", httptools.downloadpage(item.url, timeout=timeout).data) + data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") + + patron = '
      (.*?)
    ' + if not data or not scrapertools.find_single_match(data, patron): + logger.error("ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL: " + item.url + data) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + elif item.channel_alt: #Si ha habido fail-over, lo comento + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) + + if item.url_alt: del item.url_alt + del item.channel_alt + + data = scrapertools.get_match(data, patron) + + patron = ']+>([^>]+)' + + matches = re.compile(patron, re.DOTALL).findall(data) + if not matches: + logger.error("ERROR 02: ALFABETO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: ALFABETO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + + for scrapedurl, scrapedtitle in matches: + title = scrapedtitle.upper() + + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) + + return itemlist + + +def listado(item): + logger.info() + itemlist = [] + clase = "pelilist" # etiqueta para localizar zona de listado de contenidos + url_next_page ='' # Controlde paginación + cnt_tot = 30 # Poner el num. máximo de items por página + + if item.totalItems: + del item.totalItems + + data = '' + try: + data = re.sub(r"\n|\r|\t|\s{2}|()", "", httptools.downloadpage(item.url, timeout=timeout).data) + except: + pass + + patron = '
      (.*?)
    ' #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, patron) and not '

    ( 0 ) Resultados encontrados ' in data): + logger.error("ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + item.url + " / DATA: " + data) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + + #Establecemos los valores básicos en función del tipo de contenido + if item.extra == "peliculas": + item.action = "findvideos" + item.contentType = "movie" + pag = True #Sí hay paginación + elif item.extra == "series" and not "/miniseries" in item.url: + item.action = "episodios" + item.contentType = "tvshow" + pag = True + elif item.extra == "varios" or "/miniseries" in item.url: + item.action = "findvideos" + item.contentType = "movie" + pag = True + + #Selecciona el tramo de la página con el listado de contenidos + patron = '
      (.*?)
    ' + if data: + fichas = scrapertools.get_match(data, patron) + if not fichas and not '

    ( 0 ) Resultados encontrados ' in data: #error + logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + elif '

    ( 0 ) Resultados encontrados ' in data: #no hay vídeos + return itemlist + else: + return itemlist + page_extra = clase + + #Scrapea los datos de cada vídeo. Título alternativo se mantiene, aunque no se usa de momento + patron = ' cnt_pag + cnt_tot: + url_next_page = item.url + matches = matches[cnt_pag:cnt_pag+cnt_tot] + next_page = '' + if matches_cnt <= cnt_pag + (cnt_tot * 2): + if pag: + next_page = 'b' + modo = 'continue' + else: + matches = matches[cnt_pag:cnt_pag+cnt_tot] + next_page = 'a' + patron_next_page = 'Next<\/a>' + matches_next_page = re.compile(patron_next_page, re.DOTALL).findall(data) + modo = 'continue' + if len(matches_next_page) > 0: + url_next_page = urlparse.urljoin(item.url, matches_next_page[0]) + modo = 'next' + + # Avanzamos el contador de líneas en una página + if item.next_page: + del item.next_page + if modo == 'next': + cnt_pag = 0 + else: + cnt_pag += cnt_tot + + #Tratamos todos los contenidos, creardo una variable local de Item + for scrapedurl, scrapedtitle, scrapedthumbnail, title_alt, calidad in matches: + item_local = item.clone() + if item_local.tipo: + del item_local.tipo + if item_local.totalItems: + del item_local.totalItems + if item_local.post_num: + del item_local.post_num + if item_local.category: + del item_local.category + + item_local.title = '' + item_local.context = "['buscar_trailer']" + + # Limpiamos títulos, Sacamos datos de calidad, audio y lenguaje + title = re.sub('\r\n', '', scrapedtitle).decode('iso-8859-1').encode('utf8').strip() + title_alt = re.sub('\r\n', '', title_alt).decode('iso-8859-1').encode('utf8').strip() + title = title.replace("á", "a").replace("é", "e").replace("í", "i").replace("ó", "o").replace("ú", "u").replace("ü", "u").replace("�", "ñ").replace("ñ", "ñ").replace(".", " ") + title_alt = title_alt.replace("á", "a").replace("é", "e").replace("í", "i").replace("ó", "o").replace("ú", "u").replace("ü", "u").replace("�", "ñ").replace("ñ", "ñ") + + item_local.quality = calidad + title_subs = [] + + #Determinamos y marcamos idiomas distintos del castellano + item_local.language = [] + if "[vos" in title.lower() or "v.o.s" in title.lower() or "vo" in title.lower() or ".com/pelicula/" in scrapedurl or ".com/series-vo" in scrapedurl or "-vo/" in scrapedurl or "vos" in calidad.lower() or "vose" in calidad.lower() or "v.o.s" in calidad.lower() or "sub" in calidad.lower() or ".com/peliculas-vo" in item.url: + item_local.language += ["VOS"] + title = title.replace(" [Subs. integrados]", "").replace(" [subs. Integrados]", "").replace(" [VOSE", "").replace(" [VOS", "").replace(" (V.O.S.E)", "").replace(" VO", "").replace("Subtitulos", "") + if "latino" in title.lower() or "argentina" in title.lower() or "-latino/" in scrapedurl or "latino" in calidad.lower() or "argentina" in calidad.lower(): + item_local.language += ["LAT"] + + #Guardamos info de 3D en calidad y limpiamos + if "3d" in title.lower(): + if not "3d" in item_local.quality.lower(): + item_local.quality = item_local.quality + " 3D" + calidad3D = scrapertools.find_single_match(title, r'\s(3[d|D]\s\w+)') + if calidad3D: + item_local.quality = item_local.quality.replace("3D", calidad3D) + title = re.sub(r'\s3[d|D]\s\w+', '', title) + title = re.sub(r'\s3[d|D]', '', title) + title_alt = re.sub(r'\s3[d|D]\s\w+', '', title_alt) + title_alt = re.sub(r'\s3[d|D]', '', title_alt) + if "imax" in title.lower(): + item_local.quality = item_local.quality + " IMAX" + title = title.replace(" IMAX", "").replace(" imax", "") + title_alt = title_alt.replace(" IMAX", "").replace(" imax", "") + if "2d" in title.lower(): + title = title.replace("(2D)", "").replace("(2d)", "").replace("2D", "").replace("2d", "") + title_subs += ["[2D]"] + + #Extraemos info adicional del título y la guardamos para después de TMDB + if "temp" in title.lower() or "cap" in title.lower(): #Eliminamos Temporada, solo nos interesa la serie completa + title = re.sub(r' - [t|T]emp\w+ \d+ Comp\w+\d+[x|X]\d+', ' Completa', title) + title = re.sub(r' - [t|T]emp\w+ \d+x\d+', '', title) + title = re.sub(r' - [t|T]emp\w+ \d+', '', title) + title = re.sub(r' - [t|T]emp\w+.*?\d+', '', title) + title = re.sub(r' [t|T]emp.*?\d+x\d+', '', title) + title = re.sub(r' [t|T]emp.*?\d+', '', title) + title = re.sub(r' [c|C]ap.*?\d+', '', title) + if "audio" in title.lower(): #Reservamos info de audio para después de TMDB + title_subs += ['[%s]' % scrapertools.find_single_match(title, r'(\[[a|A]udio.*?\])')] + title = re.sub(r'\[[a|A]udio.*?\]', '', title) + if "[dual" in title.lower() or "multileng" in title.lower() or "multileng" in item_local.quality.lower() or (("espa" in title.lower() or "spani" in title.lower()) and "VOS" in item_local.language): + item_local.language[0:0] = ["DUAL"] + title = re.sub(r'\[[D|d]ual.*?\]', '', title) + title = re.sub(r'\[[M|m]ultileng.*?\]', '', title) + item_local.quality = re.sub(r'\[[M|m]ultileng.*?\]', '', item_local.quality) + if "duolog" in title.lower(): + title_subs += ["[Saga]"] + title = title.replace(" Duologia", "").replace(" duologia", "").replace(" Duolog", "").replace(" duolog", "") + if "trilog" in title.lower(): + title_subs += ["[Saga]"] + title = title.replace(" Trilogia", "").replace(" trilogia", "").replace(" Trilog", "").replace(" trilog", "") + if "extendida" in title.lower(): + title_subs += ["[V. Extendida]"] + title = title.replace(" Version Extendida", "").replace(" (Version Extendida)", "").replace(" V. Extendida", "").replace(" VExtendida", "").replace(" V Extendida", "") + if "saga" in title.lower(): + title = title.replace(" Saga Completa", "").replace(" saga sompleta", "").replace(" Saga", "").replace(" saga", "") + title_subs += ["[Saga]"] + if "colecc" in title.lower() or "completa" in title.lower(): + title = title.replace(" Coleccion", "").replace(" coleccion", "").replace(" Colecci", "").replace(" colecci", "").replace(" Completa", "").replace(" completa", "").replace(" COMPLETA", "") + if scrapertools.find_single_match(title, r'(- [m|M].*?serie ?\w+)'): + title = re.sub(r'- [m|M].*?serie ?\w+', '', title) + title_subs += ["[Miniserie]"] + + #Limpiamos restos en título + title = title.replace("Castellano", "").replace("castellano", "").replace("inglés", "").replace("ingles", "").replace("Inglés", "").replace("Ingles", "").replace("Ingl", "").replace("Engl", "").replace("Calidad", "").replace("de la Serie", "") + title_alt = title_alt.replace("Castellano", "").replace("castellano", "").replace("inglés", "").replace("ingles", "").replace("Inglés", "").replace("Ingles", "").replace("Ingl", "").replace("Engl", "").replace("Calidad", "").replace("de la Serie", "") + + #Limpiamos cabeceras y colas del título + title = re.sub(r'Descargar\s\w+\-\w+', '', title) + title = re.sub(r'\(COMPLE.*?\)', '', title) + title = re.sub(r'\(\d{4}\)$', '', title) + title = re.sub(r'\d{4}$', '', title) + title = re.sub(r' \d+x\d+', '', title) + title = re.sub(r' x\d+', '', title) + + title = title.replace("Ver online ", "").replace("Descarga Serie HD ", "").replace("Descargar Serie HD ", "").replace("Descarga Serie ", "").replace("Descargar Serie ", "").replace("Ver en linea ", "").replace("Ver en linea", "").replace("HD ", "").replace("(Proper)", "").replace("RatDVD", "").replace("DVDRiP", "").replace("DVDRIP", "").replace("DVDRip", "").replace("DVDR", "").replace("DVD9", "").replace("DVD", "").replace("DVBRIP", "").replace("DVB", "").replace("LINE", "").replace("- ES ", "").replace("ES ", "").replace("COMPLETA", "").replace("(", "-").replace(")", "-").replace(".", " ").strip() + + title = title.replace("Descargar torrent ", "").replace("Descarga Gratis ", "").replace("Descargar Estreno ", "").replace("Descargar Estrenos ", "").replace("Pelicula en latino ", "").replace("Descargar Pelicula ", "").replace("Descargar Peliculas ", "").replace("Descargar peliculas ", "").replace("Descargar Todas ", "").replace("Descargar Otras ", "").replace("Descargar ", "").replace("Descarga ", "").replace("Bajar ", "").replace("HDRIP ", "").replace("HDRiP ", "").replace("HDRip ", "").replace("RIP ", "").replace("Rip", "").replace("RiP", "").replace("XviD", "").replace("AC3 5.1", "").replace("AC3", "").replace("1080p ", "").replace("720p ", "").replace("DVD-Screener ", "").replace("TS-Screener ", "").replace("Screener ", "").replace("BdRemux ", "").replace("BR ", "").replace("4KULTRA", "").replace("FULLBluRay", "").replace("FullBluRay", "").replace("BluRay", "").replace("Bonus Disc", "").replace("de Cine ", "").replace("TeleCine ", "").replace("latino", "").replace("Latino", "").replace("argentina", "").replace("Argentina", "").strip() + + if title.endswith("torrent gratis"): title = title[:-15] + if title.endswith("gratis"): title = title[:-7] + if title.endswith("torrent"): title = title[:-8] + if title.endswith("en HD"): title = title[:-6] + if title.endswith(" -"): title = title[:-2] + if "en espa" in title: title = title[:-11] + + item_local.quality = item_local.quality.replace("gratis ", "") + if "HDR" in title: + title = title.replace(" HDR", "") + if not "HDR" in item_local.quality: + item_local.quality += " HDR" + + title = title.strip() + title_alt = title_alt.strip() + item_local.quality = item_local.quality.strip() + + if not title: #Usamos solo el title_alt en caso de que no exista el título original + title = title_alt + if not title: + title = "SIN TITULO" + + #Limpieza final del título y guardado en las variables según su tipo de contenido + title = scrapertools.remove_htmltags(title) + item_local.title = title + if item_local.contentType == "movie": + item_local.contentTitle = title + else: + item_local.contentSerieName = title + + #Guardamos el resto de variables del vídeo + item_local.url = scrapedurl + item_local.thumbnail = scrapedthumbnail + item_local.contentThumbnail = scrapedthumbnail + + #Guardamos el año que puede venir en la url, por si luego no hay resultados desde TMDB + year = '' + if item_local.contentType == "movie": + year = scrapertools.find_single_match(scrapedurl, r'(\d{4})') + if year >= "1900" and year <= "2040" and year != "2020": + title_subs += [year] + item_local.infoLabels['year'] = '-' + + #Guarda la variable temporal que almacena la info adicional del título a ser restaurada después de TMDB + item_local.title_subs = title_subs + + #Agrega el item local a la lista itemlist + itemlist.append(item_local.clone()) + + #Pasamos a TMDB la lista completa Itemlist + tmdb.set_infoLabels(itemlist, __modo_grafico__) + + #Llamamos al método para el maquillaje de los títulos obtenidos desde TMDB + item, itemlist = generictools.post_tmdb_listado(item, itemlist) + + if len(itemlist) == 0: + itemlist.append(Item(channel=item.channel, action="mainlist", title="No se ha podido cargar el listado")) + else: + if url_next_page: + itemlist.append( + Item(channel=item.channel, action="listado", title="[COLOR gold][B]Pagina siguiente >> [/B][/COLOR]" + str(post_num) + " de " + str(total_pag), url=url_next_page, next_page=next_page, cnt_pag=cnt_pag, post_num=post_num, pag=pag, modo=modo, extra=item.extra)) + + #logger.debug(url_next_page + " / " + next_page + " / " + str(matches_cnt) + " / " + str(cnt_pag)+ " / " + str(total_pag) + " / " + str(pag) + " / " + modo + " / " + item.extra) + + return itemlist + +def listado_busqueda(item): + logger.info() + + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + if item.category and item.category != "newest": + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() + + itemlist = [] + cnt_tot = 40 # Poner el num. máximo de items por página. Dejamos que la web lo controle + cnt_title = 0 # Contador de líneas insertadas en Itemlist + cnt_pag = 0 # Contador de líneas leídas de Matches + timeout_search = 5 # Timeout un poco más largo para las búsquedas + if timeout > 5: + timeout_search = timeout # Timeout un poco más largo para las búsquedas + data = '' + + if item.cnt_pag: + cnt_pag = item.cnt_pag # Se guarda en la lista de páginas anteriores en Item + del item.cnt_pag + if item.totalItems: + del item.totalItems + if item.text_bold: + del item.text_bold + if item.text_color: + del item.text_color + + #Sistema de paginado para evitar páginas vacías o semi-vacías en casos de búsquedas con series con muchos episodios + title_lista = [] # Guarda la lista de series que ya están en Itemlist, para no duplicar lineas + if item.title_lista: # Si viene de una pasada anterior, la lista ya estará guardada + title_lista = item.title_lista # Se usa la lista de páginas anteriores en Item + title_lista_alt = [] + for url in title_lista: + title_lista_alt += [url] #hacemos una copia no vinculada de title_lista + matches = [] + cnt_next = 0 + total_pag = 1 + post_num = 1 + + #Máximo num. de líneas permitidas por TMDB. Máx de 5 páginas por Itemlist para no degradar el rendimiento + while cnt_title <= cnt_tot and cnt_next < 5: + + try: + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post, timeout=timeout_search).data) + except: + pass + + cnt_next += 1 + pattern = '
      (.*?)
    ' % item.pattern #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, pattern) and not '

    ( 0 ) Resultados encontrados ' in data): + logger.error("ERROR 01: LISTADO_BUSQUEDA: La Web no responde o ha cambiado de URL: " + item.url + item.post + " / DATA: " + data) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, pattern) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + elif item.channel_alt: #Si ha habido fail-over, lo comento + host = host.replace(item.channel_alt, item.channel) + + #Obtiene la dirección de la próxima página, si la hay + try: + post_actual = item.post #Guardamos el post actual por si hay overflow de Itemlist y hay que hechar marcha atrás + get, post, total_pag = scrapertools.find_single_match(data, '' - if "pelisyseries.com" in host_alt and item.extra == "varios": #compatibilidad con mispelisy.series.com - data = ' Documentales' + data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") + data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com + if "pelisyseries.com" in item.channel_host and item.extra == "varios": #compatibilidad con mispelisy.series.com + data = '
  • Documentales
  • ' else: - if data: - data = scrapertools.get_match(data, patron) - if not data: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - else: - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + data = scrapertools.get_match(data, patron) #Seleccionamos el trozo que nos interesa + if not data: + logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - patron = '<.*?href="([^"]+)".*?>([^>]+)' + patron = '
  • ([^>]+)<\/a><\/li>' matches = re.compile(patron, re.DOTALL).findall(data) + if not matches: logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.strip() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title=title + " [A-Z]", url=url, extra=item.extra)) + #Preguntamos por las entradas que no corresponden al "extra" + if item.extra in scrapedtitle.lower() or (item.extra == "peliculas" and ("cine" in scrapedurl or "anime" in scrapedurl)) or (item.extra == "varios" and ("documentales" in scrapedurl or "varios" in scrapedurl)): + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) + itemlist.append(item.clone(action="alfabeto", title=title + " [A-Z]", url=scrapedurl)) if item.extra == "peliculas": - itemlist.append(Item(channel=item.channel, action="listado", title="Películas 4K", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title="Películas 4K" + " [A-Z]", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) + itemlist.append(item.clone(action="listado", title="Películas 4K", url=item.channel_host + "peliculas-hd/4kultrahd/")) + itemlist.append(item.clone(action="alfabeto", title="Películas 4K" + " [A-Z]", url=item.channel_host + "peliculas-hd/4kultrahd/")) return itemlist @@ -155,28 +160,41 @@ def alfabeto(item): logger.info() itemlist = [] - data = re.sub(r"\n|\r|\t|\s{2}|()", "", httptools.downloadpage(item.url).data) + data = '' + data = re.sub(r"\n|\r|\t|\s{2}|()", "", httptools.downloadpage(item.url, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") patron = '
      (.*?)
    ' - if data: - data = scrapertools.get_match(data, patron) - else: - return itemlist + if not data or not scrapertools.find_single_match(data, patron): + logger.error("ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL: " + item.url + data) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + elif item.channel_alt: #Si ha habido fail-over, lo comento + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) + + if item.url_alt: del item.url_alt + del item.channel_alt + + data = scrapertools.get_match(data, patron) patron = ']+>([^>]+)' matches = re.compile(patron, re.DOTALL).findall(data) if not matches: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + logger.error("ERROR 02: ALFABETO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: ALFABETO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.upper() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) return itemlist @@ -191,11 +209,21 @@ def listado(item): if item.totalItems: del item.totalItems + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|()", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|()", "", httptools.downloadpage(item.url, timeout=timeout).data) except: + pass + + patron = '
      (.*?)
    ' #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, patron) and not '

    ( 0 ) Resultados encontrados ' in data): logger.error("ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + item.url + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Establecemos los valores básicos en función del tipo de contenido @@ -218,7 +246,7 @@ def listado(item): fichas = scrapertools.get_match(data, patron) if not fichas and not '

    ( 0 ) Resultados encontrados ' in data: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif '

    ( 0 ) Resultados encontrados ' in data: #no hay vídeos return itemlist @@ -235,7 +263,7 @@ def listado(item): matches = re.compile(patron, re.DOTALL).findall(fichas) if not matches: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + fichas) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("MATCHES: " + str(len(matches))) @@ -460,13 +488,21 @@ def listado(item): def listado_busqueda(item): logger.info() - - host = 'http://%s/' % scrapertools.find_single_match(item.url, '(\w+\.com)\/') + + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + if item.category and item.category != "newest": + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] cnt_tot = 40 # Poner el num. máximo de items por página. Dejamos que la web lo controle cnt_title = 0 # Contador de líneas insertadas en Itemlist cnt_pag = 0 # Contador de líneas leídas de Matches + timeout_search = 5 # Timeout un poco más largo para las búsquedas + if timeout > 5: + timeout_search = timeout # Timeout un poco más largo para las búsquedas + data = '' if item.cnt_pag: cnt_pag = item.cnt_pag # Se guarda en la lista de páginas anteriores en Item @@ -493,21 +529,21 @@ def listado_busqueda(item): #Máximo num. de líneas permitidas por TMDB. Máx de 5 páginas por Itemlist para no degradar el rendimiento while cnt_title <= cnt_tot and cnt_next < 5: - pattern = '
      (.*?)
    ' % item.pattern #seleccionamos el bloque que nos interesa try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post, timeout=timeout_search).data) except: pass - cnt_next += 1 - if not data or not scrapertools.find_single_match(data, pattern): + cnt_next += 1 + pattern = '
      (.*?)
    ' % item.pattern #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, pattern) and not '

    ( 0 ) Resultados encontrados ' in data): logger.error("ERROR 01: LISTADO_BUSQUEDA: La Web no responde o ha cambiado de URL: " + item.url + item.post + " / DATA: " + data) #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú item, data = generictools.fail_over_newpct1(item, pattern) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif item.channel_alt: #Si ha habido fail-over, lo comento host = host.replace(item.channel_alt, item.channel) @@ -531,7 +567,6 @@ def listado_busqueda(item): pattern = '
      (.*?)
    ' % item.pattern #seleccionamos el bloque que nos interesa data_alt = data data = scrapertools.get_match(data, pattern) - #pattern = ']*>(?P.*?)?<\/h2>' pattern = '<li[^>]*><a href="(?P<scrapedurl>[^"]+).*?' #url pattern += 'title="(?P<scrapedtitle>[^"]+).*?' #título pattern += '<img.*?src="(?P<scrapedthumbnail>[^"]+)?".*?' #thumb @@ -541,7 +576,8 @@ def listado_busqueda(item): matches_alt = re.compile(pattern, re.DOTALL).findall(data) if not matches_alt and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data_alt: #error logger.error("ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data_alt) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + item, itemlist = generictools.post_tmdb_listado(item, itemlist) #Pintamos los datos de fail-over, si los hay return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Ahora se hace una simulación para saber cuantas líneas podemos albergar en este Itemlist. @@ -830,14 +866,14 @@ def listado_busqueda(item): url_tvshow = host + calidad_mps + real_title_mps + "/" #... otras no. A probar... #Leemos la página, a ver si es una página de episodios - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" #Patrón de lista de episodios if not scrapertools.find_single_match(data_serie, pattern) and serieid: #no es válida la página, #intentarlo con la otra url - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") @@ -876,9 +912,10 @@ def findvideos(item): from core import channeltools logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -987,8 +1024,9 @@ def findvideos(item): excluir_enlaces_descargas = [] #Lista vacía de servidores excluidos en Descargar # Descarga la página + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass @@ -1001,7 +1039,7 @@ def findvideos(item): item, data = generictools.fail_over_newpct1(item, patron) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") @@ -1029,7 +1067,7 @@ def findvideos(item): item_local.url = scrapertools.find_single_match(data, patron) if not item_local.url: #error logger.error("ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos item_local.url = item_local.url.replace(" ", "%20") #sustituimos espacios por %20, por si acaso #logger.debug("Patron: " + patron + " url: " + item_local.url) @@ -1054,6 +1092,8 @@ def findvideos(item): #logger.debug(item_local) # VER vídeos, descargar vídeos un link, o múltiples links + data = scrapertools.find_single_match(data, '<div id="tab1" class="tab_content"(.*?<\/ul>(?:<div.*?>)?<\/div><\/div><\/div>)') #Seleccionar el bloque para evitar duplicados + host_dom = host.replace("https://", "").replace("http://", "").replace("www.", "") data = data.replace("http://tumejorserie.com/descargar/url_encript.php?link=", "(") data = re.sub(r'javascript:;" onClick="popup\("http:\/\/(?:www.)?' + host_dom + '\w{1,9}\/library\/include\/ajax\/get_modallinks.php\?links=', "", data) @@ -1066,7 +1106,7 @@ def findvideos(item): enlaces_ver = re.compile(patron, re.DOTALL).findall(data) enlaces_descargar = enlaces_ver #logger.debug(enlaces_ver) - + #Recorre todos los links de VER, si está permitido cnt_enl_ver = 1 cnt_enl_verif = 1 @@ -1100,7 +1140,7 @@ def findvideos(item): if verificar_enlaces_veronline != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_veronline or verificar_enlaces_veronline == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para cada link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_veronline_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1190,7 +1230,7 @@ def findvideos(item): if verificar_enlaces_descargas != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_descargas or verificar_enlaces_descargas == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para primer link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_descargas_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1232,9 +1272,10 @@ def findvideos(item): def episodios(item): logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -1255,7 +1296,7 @@ def episodios(item): data = '' try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, timeout=timeout).data) patron = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern data_alt = '' if data: data_alt = scrapertools.get_match(data, patron) @@ -1276,7 +1317,7 @@ def episodios(item): if not data: #No se ha encontrado ningún canal activo para este vídeo itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #Busca y pre-carga todas las páginas de episodios que componen las serie, para obtener la url de cada página @@ -1312,7 +1353,7 @@ def episodios(item): break try: if not data: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") data = data.replace("chapters", "buscar-list") #Compatibilidad con mispelisy.series.com pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern @@ -1321,7 +1362,7 @@ def episodios(item): raise except: logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / " + str(list_pages) + " / DATA: " + str(data)) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if "pelisyseries.com" in item.url: @@ -1331,7 +1372,7 @@ def episodios(item): matches = re.compile(pattern, re.DOTALL).findall(data) if not matches: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("patron: " + pattern) @@ -1399,7 +1440,7 @@ def episodios(item): match = [m.groupdict() for m in r.finditer(info)][0] if not match: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + info) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if match['season'] is None: match['season'] = season #Si no se encuentran valores, pero poner lo básico @@ -1449,8 +1490,6 @@ def episodios(item): if item_local.active: del item_local.active - if item_local.category: - del item_local.category if item_local.infoLabels['title']: del item_local.infoLabels['title'] item_local.context = "['buscar_trailer']" @@ -1467,6 +1506,8 @@ def episodios(item): del item_local.update_last if item_local.update_next: del item_local.update_next + if item_local.channel_host: + del item_local.channel_host itemlist.append(item_local.clone()) @@ -1501,9 +1542,6 @@ def actualizar_titulos(item): def search(item, texto): logger.info("search:" + texto) # texto = texto.replace(" ", "+") - - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() try: item.post = "q=%s" % texto diff --git a/plugin.video.alfa/channels/mispelisyseries.py b/plugin.video.alfa/channels/mispelisyseries.py index 0d207a6f..8811b706 100644 --- a/plugin.video.alfa/channels/mispelisyseries.py +++ b/plugin.video.alfa/channels/mispelisyseries.py @@ -12,40 +12,53 @@ from core import httptools from core import scrapertools from core import servertools from core.item import Item -from platformcode import config, logger +from platformcode import config, logger, platformtools from core import tmdb from lib import generictools -host = 'http://mispelisyseries.com/' +channel_py = 'newpct1' #Código para permitir usar un único canal para todas las webs clones de NewPct1 -clone_list = config.get_setting('clonenewpct1_channels_list', "torrentrapid") #Carga lista de clones -clone_list = ast.literal_eval(clone_list) #la convierte a lista de tuplas +clone_list = config.get_setting('clonenewpct1_channels_list', channel_py) #Carga lista de clones +clone_list = ast.literal_eval(clone_list) #la convierte en array host_index = 0 -host_index = config.get_setting('clonenewpct1_channel_default', "torrentrapid") #Clone por defecto +host_index = config.get_setting('clonenewpct1_channel_default', channel_py) #Clone por defecto i = 0 for active_clone, channel_clone, host_clone, contentType_clone, info_clone in clone_list: if i == host_index: - #channel_clone_name = channel_clone #ACTIVAR CUANDO SE PASE A NEWPCT1 - #host = 'http://%s/' % host_clone #ACTIVAR CUANDO SE PASE A NEWPCT1 - i += 1 + channel_clone_name = channel_clone #Nombre del Canal elegido + host = host_clone #URL del Canal elegido + break + i += 1 +item = Item() +item.channel_host = host +if item.channel != channel_py: + item.channel = channel_py +item.category = channel_clone_name.capitalize() #Carga de opciones del canal -item = Item() -if not item.channel: - item.channel = scrapertools.find_single_match(host, r'(\w+)\.com\/') -channel_clone_name = scrapertools.find_single_match(host, r'(\w+)\.com\/') #QUITAR CUANDO SE PASE A NEWPCT1 -__modo_grafico__ = config.get_setting('modo_grafico', item.channel) -modo_ultima_temp = config.get_setting('seleccionar_ult_temporadda_activa', item.channel) +__modo_grafico__ = config.get_setting('modo_grafico', channel_py) #TMDB? +modo_ultima_temp = config.get_setting('seleccionar_ult_temporadda_activa', channel_py) #Actualización sólo últ. Temporada? +timeout = config.get_setting('clonenewpct1_timeout_downloadpage', channel_py) #Timeout downloadpage +if timeout == 0: timeout = None + +platformtools.dialog_ok("NewPct1, ¡¡¡he vuelto como canal VIRTUAL!!!", "Hemos centralizado la gestión de los clones de NewPct1 en el canal virtual NewPct1. Los clones desaparecerán en breve.", "Para más información lee el tutorial: https://alfa-addon.com /threads/newpct1-implantando-alta-disponibilidad.1200/") + +#Vayamos a la siguiente acción en el canal Newpct1 +from platformcode import launcher +channel_clone_name = "mispelisyseries" #Nombre del Canal elegido +host = "http://mispelisyseries.com/" +item.category = channel_clone_name.capitalize() +item.action = "mainlist" +item.channel_host = host +launcher.run(item) def mainlist(item): logger.info() + if item.channel != channel_py: + return - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() - itemlist = [] thumb_pelis = get_thumb("channels_movie.png") @@ -58,20 +71,20 @@ def mainlist(item): thumb_settings = get_thumb("setting_0.png") itemlist.append(Item(channel=item.channel, action="submenu", title="Películas", url=host, - extra="peliculas", thumbnail=thumb_pelis )) + extra="peliculas", thumbnail=thumb_pelis, category=item.category)) itemlist.append(Item(channel=item.channel, action="submenu", title="Series", url=host, extra="series", - thumbnail=thumb_series)) + thumbnail=thumb_series, category=item.category)) itemlist.append(Item(channel=item.channel, action="submenu", title="Documentales", url=host, extra="varios", - thumbnail=thumb_docus)) + thumbnail=thumb_docus, category=item.category)) itemlist.append( - Item(channel=item.channel, action="search", title="Buscar", url=host + "buscar", thumbnail=thumb_buscar)) + Item(channel=item.channel, action="search", title="Buscar", url=host + "buscar", thumbnail=thumb_buscar, category=item.category)) itemlist.append( - Item(channel=item.channel, action="", title="[COLOR yellow]Configuración de Servidores:[/COLOR]", url="", thumbnail=thumb_settings)) + Item(channel=item.channel, action="", title="[COLOR yellow]Configuración de Servidores:[/COLOR]", url="", thumbnail=thumb_settings, category=item.category)) itemlist.append( - Item(channel=item.channel, action="settingCanal", title="Servidores para Ver Online y Descargas", url="", thumbnail=thumb_settings)) + Item(channel=item.channel, action="settingCanal", title="Servidores para Ver Online y Descargas", url="", thumbnail=thumb_settings, category=item.category)) return itemlist @@ -85,68 +98,60 @@ def submenu(item): logger.info() itemlist = [] + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass - host_alt = host - host_dom = host.replace("https://", "").replace("http://", "").replace("www.", "") - patron = '<li><a href="http://(?:www.)?' + host_dom + item.extra + '/">.*?<ul.*?>(.*?)</ul>' + patron = '<li><a\s?class="[^"]+"\s?href="http:[^"]+"><i\s?class=.*><\/i>.*Inicio<\/a><\/li>(.+)<\/ul>\s?<\/nav>' #Verificamos si se ha cargado una página, y si además tiene la estructura correcta if not data or not scrapertools.find_single_match(data, patron): - logger.error("ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url) + logger.error("ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url + data) #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú item, data = generictools.fail_over_newpct1(item, patron) if not data: #Si no ha logrado encontrar nada, salimos - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif item.channel_alt: #Si ha habido fail-over, lo comento - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR] [ALT ] en uso')) - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] caído')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) - host_alt = host.replace(item.channel_alt, item.channel) - del item.channel_alt if item.url_alt: del item.url_alt + del item.channel_alt - #data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") - #data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com - - host_dom = host_alt.replace("https://", "").replace("http://", "").replace("www.", "") - patron = '<li><a href="http://(?:www.)?' + host_dom + item.extra + '/">.*?<ul.*?>(.*?)</ul>' - if "pelisyseries.com" in host_alt and item.extra == "varios": #compatibilidad con mispelisy.series.com - data = '<a href="' + host_alt + 'varios/" title="Documentales"><i class="icon-rocket"></i> Documentales</a>' + data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") + data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com + if "pelisyseries.com" in item.channel_host and item.extra == "varios": #compatibilidad con mispelisy.series.com + data = '<li><a href="' + item.channel_host + 'varios/" title="Documentales">Documentales</a></li>' else: - if data: - data = scrapertools.get_match(data, patron) - if not data: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - else: - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + data = scrapertools.get_match(data, patron) #Seleccionamos el trozo que nos interesa + if not data: + logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - patron = '<.*?href="([^"]+)".*?>([^>]+)</a>' + patron = '<li><a.*?href="([^"]+)"\s?.itle="[^"]+"\s?>([^>]+)<\/a><\/li>' matches = re.compile(patron, re.DOTALL).findall(data) + if not matches: logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.strip() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title=title + " [A-Z]", url=url, extra=item.extra)) + #Preguntamos por las entradas que no corresponden al "extra" + if item.extra in scrapedtitle.lower() or (item.extra == "peliculas" and ("cine" in scrapedurl or "anime" in scrapedurl)) or (item.extra == "varios" and ("documentales" in scrapedurl or "varios" in scrapedurl)): + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) + itemlist.append(item.clone(action="alfabeto", title=title + " [A-Z]", url=scrapedurl)) if item.extra == "peliculas": - itemlist.append(Item(channel=item.channel, action="listado", title="Películas 4K", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title="Películas 4K" + " [A-Z]", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) + itemlist.append(item.clone(action="listado", title="Películas 4K", url=item.channel_host + "peliculas-hd/4kultrahd/")) + itemlist.append(item.clone(action="alfabeto", title="Películas 4K" + " [A-Z]", url=item.channel_host + "peliculas-hd/4kultrahd/")) return itemlist @@ -155,28 +160,41 @@ def alfabeto(item): logger.info() itemlist = [] - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = '' + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") patron = '<ul class="alfabeto">(.*?)</ul>' - if data: - data = scrapertools.get_match(data, patron) - else: - return itemlist + if not data or not scrapertools.find_single_match(data, patron): + logger.error("ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL: " + item.url + data) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + elif item.channel_alt: #Si ha habido fail-over, lo comento + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) + + if item.url_alt: del item.url_alt + del item.channel_alt + + data = scrapertools.get_match(data, patron) patron = '<a href="([^"]+)"[^>]+>([^>]+)</a>' matches = re.compile(patron, re.DOTALL).findall(data) if not matches: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + logger.error("ERROR 02: ALFABETO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: ALFABETO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.upper() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) return itemlist @@ -191,11 +209,21 @@ def listado(item): if item.totalItems: del item.totalItems + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: + pass + + patron = '<ul class="' + clase + '">(.*?)</ul>' #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, patron) and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data): logger.error("ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + item.url + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Establecemos los valores básicos en función del tipo de contenido @@ -218,7 +246,7 @@ def listado(item): fichas = scrapertools.get_match(data, patron) if not fichas and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif '<h3><strong>( 0 ) Resultados encontrados </strong>' in data: #no hay vídeos return itemlist @@ -235,7 +263,7 @@ def listado(item): matches = re.compile(patron, re.DOTALL).findall(fichas) if not matches: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + fichas) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("MATCHES: " + str(len(matches))) @@ -460,13 +488,21 @@ def listado(item): def listado_busqueda(item): logger.info() - - host = 'http://%s/' % scrapertools.find_single_match(item.url, '(\w+\.com)\/') + + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + if item.category and item.category != "newest": + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] cnt_tot = 40 # Poner el num. máximo de items por página. Dejamos que la web lo controle cnt_title = 0 # Contador de líneas insertadas en Itemlist cnt_pag = 0 # Contador de líneas leídas de Matches + timeout_search = 5 # Timeout un poco más largo para las búsquedas + if timeout > 5: + timeout_search = timeout # Timeout un poco más largo para las búsquedas + data = '' if item.cnt_pag: cnt_pag = item.cnt_pag # Se guarda en la lista de páginas anteriores en Item @@ -493,21 +529,21 @@ def listado_busqueda(item): #Máximo num. de líneas permitidas por TMDB. Máx de 5 páginas por Itemlist para no degradar el rendimiento while cnt_title <= cnt_tot and cnt_next < 5: - pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post, timeout=timeout_search).data) except: pass - cnt_next += 1 - if not data or not scrapertools.find_single_match(data, pattern): + cnt_next += 1 + pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, pattern) and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data): logger.error("ERROR 01: LISTADO_BUSQUEDA: La Web no responde o ha cambiado de URL: " + item.url + item.post + " / DATA: " + data) #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú item, data = generictools.fail_over_newpct1(item, pattern) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif item.channel_alt: #Si ha habido fail-over, lo comento host = host.replace(item.channel_alt, item.channel) @@ -531,7 +567,6 @@ def listado_busqueda(item): pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa data_alt = data data = scrapertools.get_match(data, pattern) - #pattern = '<li[^>]*><a href="(?P<url>[^"]+).*?<img.*?src="(?P<thumb>[^"]+)?".*?<h2.*?>(?P<title>.*?)?<\/h2>' pattern = '<li[^>]*><a href="(?P<scrapedurl>[^"]+).*?' #url pattern += 'title="(?P<scrapedtitle>[^"]+).*?' #título pattern += '<img.*?src="(?P<scrapedthumbnail>[^"]+)?".*?' #thumb @@ -541,7 +576,8 @@ def listado_busqueda(item): matches_alt = re.compile(pattern, re.DOTALL).findall(data) if not matches_alt and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data_alt: #error logger.error("ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data_alt) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + item, itemlist = generictools.post_tmdb_listado(item, itemlist) #Pintamos los datos de fail-over, si los hay return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Ahora se hace una simulación para saber cuantas líneas podemos albergar en este Itemlist. @@ -830,14 +866,14 @@ def listado_busqueda(item): url_tvshow = host + calidad_mps + real_title_mps + "/" #... otras no. A probar... #Leemos la página, a ver si es una página de episodios - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" #Patrón de lista de episodios if not scrapertools.find_single_match(data_serie, pattern) and serieid: #no es válida la página, #intentarlo con la otra url - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") @@ -876,9 +912,10 @@ def findvideos(item): from core import channeltools logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -987,8 +1024,9 @@ def findvideos(item): excluir_enlaces_descargas = [] #Lista vacía de servidores excluidos en Descargar # Descarga la página + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass @@ -1001,7 +1039,7 @@ def findvideos(item): item, data = generictools.fail_over_newpct1(item, patron) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") @@ -1029,7 +1067,7 @@ def findvideos(item): item_local.url = scrapertools.find_single_match(data, patron) if not item_local.url: #error logger.error("ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos item_local.url = item_local.url.replace(" ", "%20") #sustituimos espacios por %20, por si acaso #logger.debug("Patron: " + patron + " url: " + item_local.url) @@ -1054,6 +1092,8 @@ def findvideos(item): #logger.debug(item_local) # VER vídeos, descargar vídeos un link, o múltiples links + data = scrapertools.find_single_match(data, '<div id="tab1" class="tab_content"(.*?<\/ul>(?:<div.*?>)?<\/div><\/div><\/div>)') #Seleccionar el bloque para evitar duplicados + host_dom = host.replace("https://", "").replace("http://", "").replace("www.", "") data = data.replace("http://tumejorserie.com/descargar/url_encript.php?link=", "(") data = re.sub(r'javascript:;" onClick="popup\("http:\/\/(?:www.)?' + host_dom + '\w{1,9}\/library\/include\/ajax\/get_modallinks.php\?links=', "", data) @@ -1066,7 +1106,7 @@ def findvideos(item): enlaces_ver = re.compile(patron, re.DOTALL).findall(data) enlaces_descargar = enlaces_ver #logger.debug(enlaces_ver) - + #Recorre todos los links de VER, si está permitido cnt_enl_ver = 1 cnt_enl_verif = 1 @@ -1100,7 +1140,7 @@ def findvideos(item): if verificar_enlaces_veronline != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_veronline or verificar_enlaces_veronline == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para cada link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_veronline_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1190,7 +1230,7 @@ def findvideos(item): if verificar_enlaces_descargas != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_descargas or verificar_enlaces_descargas == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para primer link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_descargas_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1232,9 +1272,10 @@ def findvideos(item): def episodios(item): logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -1255,7 +1296,7 @@ def episodios(item): data = '' try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, timeout=timeout).data) patron = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern data_alt = '' if data: data_alt = scrapertools.get_match(data, patron) @@ -1276,7 +1317,7 @@ def episodios(item): if not data: #No se ha encontrado ningún canal activo para este vídeo itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #Busca y pre-carga todas las páginas de episodios que componen las serie, para obtener la url de cada página @@ -1312,7 +1353,7 @@ def episodios(item): break try: if not data: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") data = data.replace("chapters", "buscar-list") #Compatibilidad con mispelisy.series.com pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern @@ -1321,7 +1362,7 @@ def episodios(item): raise except: logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / " + str(list_pages) + " / DATA: " + str(data)) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if "pelisyseries.com" in item.url: @@ -1331,7 +1372,7 @@ def episodios(item): matches = re.compile(pattern, re.DOTALL).findall(data) if not matches: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("patron: " + pattern) @@ -1399,7 +1440,7 @@ def episodios(item): match = [m.groupdict() for m in r.finditer(info)][0] if not match: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + info) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if match['season'] is None: match['season'] = season #Si no se encuentran valores, pero poner lo básico @@ -1449,8 +1490,6 @@ def episodios(item): if item_local.active: del item_local.active - if item_local.category: - del item_local.category if item_local.infoLabels['title']: del item_local.infoLabels['title'] item_local.context = "['buscar_trailer']" @@ -1467,6 +1506,8 @@ def episodios(item): del item_local.update_last if item_local.update_next: del item_local.update_next + if item_local.channel_host: + del item_local.channel_host itemlist.append(item_local.clone()) @@ -1501,9 +1542,6 @@ def actualizar_titulos(item): def search(item, texto): logger.info("search:" + texto) # texto = texto.replace(" ", "+") - - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() try: item.post = "q=%s" % texto diff --git a/plugin.video.alfa/channels/torrentlocura.py b/plugin.video.alfa/channels/torrentlocura.py index 5bfd66a9..04d3c7c7 100755 --- a/plugin.video.alfa/channels/torrentlocura.py +++ b/plugin.video.alfa/channels/torrentlocura.py @@ -12,40 +12,53 @@ from core import httptools from core import scrapertools from core import servertools from core.item import Item -from platformcode import config, logger +from platformcode import config, logger, platformtools from core import tmdb from lib import generictools -host = 'http://torrentlocura.com/' +channel_py = 'newpct1' #Código para permitir usar un único canal para todas las webs clones de NewPct1 -clone_list = config.get_setting('clonenewpct1_channels_list', "torrentrapid") #Carga lista de clones -clone_list = ast.literal_eval(clone_list) #la convierte a lista de tuplas +clone_list = config.get_setting('clonenewpct1_channels_list', channel_py) #Carga lista de clones +clone_list = ast.literal_eval(clone_list) #la convierte en array host_index = 0 -host_index = config.get_setting('clonenewpct1_channel_default', "torrentrapid") #Clone por defecto +host_index = config.get_setting('clonenewpct1_channel_default', channel_py) #Clone por defecto i = 0 for active_clone, channel_clone, host_clone, contentType_clone, info_clone in clone_list: if i == host_index: - #channel_clone_name = channel_clone #ACTIVAR CUANDO SE PASE A NEWPCT1 - #host = 'http://%s/' % host_clone #ACTIVAR CUANDO SE PASE A NEWPCT1 - i += 1 + channel_clone_name = channel_clone #Nombre del Canal elegido + host = host_clone #URL del Canal elegido + break + i += 1 +item = Item() +item.channel_host = host +if item.channel != channel_py: + item.channel = channel_py +item.category = channel_clone_name.capitalize() #Carga de opciones del canal -item = Item() -if not item.channel: - item.channel = scrapertools.find_single_match(host, r'(\w+)\.com\/') -channel_clone_name = scrapertools.find_single_match(host, r'(\w+)\.com\/') #QUITAR CUANDO SE PASE A NEWPCT1 -__modo_grafico__ = config.get_setting('modo_grafico', item.channel) -modo_ultima_temp = config.get_setting('seleccionar_ult_temporadda_activa', item.channel) +__modo_grafico__ = config.get_setting('modo_grafico', channel_py) #TMDB? +modo_ultima_temp = config.get_setting('seleccionar_ult_temporadda_activa', channel_py) #Actualización sólo últ. Temporada? +timeout = config.get_setting('clonenewpct1_timeout_downloadpage', channel_py) #Timeout downloadpage +if timeout == 0: timeout = None + +platformtools.dialog_ok("NewPct1, ¡¡¡he vuelto como canal VIRTUAL!!!", "Hemos centralizado la gestión de los clones de NewPct1 en el canal virtual NewPct1. Los clones desaparecerán en breve.", "Para más información lee el tutorial: https://alfa-addon.com /threads/newpct1-implantando-alta-disponibilidad.1200/") + +#Vayamos a la siguiente acción en el canal Newpct1 +from platformcode import launcher +channel_clone_name = "torrentlocura" #Nombre del Canal elegido +host = "http://torrentlocura.com/" +item.category = channel_clone_name.capitalize() +item.action = "mainlist" +item.channel_host = host +launcher.run(item) def mainlist(item): logger.info() + if item.channel != channel_py: + return - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() - itemlist = [] thumb_pelis = get_thumb("channels_movie.png") @@ -58,20 +71,20 @@ def mainlist(item): thumb_settings = get_thumb("setting_0.png") itemlist.append(Item(channel=item.channel, action="submenu", title="Películas", url=host, - extra="peliculas", thumbnail=thumb_pelis )) + extra="peliculas", thumbnail=thumb_pelis, category=item.category)) itemlist.append(Item(channel=item.channel, action="submenu", title="Series", url=host, extra="series", - thumbnail=thumb_series)) + thumbnail=thumb_series, category=item.category)) itemlist.append(Item(channel=item.channel, action="submenu", title="Documentales", url=host, extra="varios", - thumbnail=thumb_docus)) + thumbnail=thumb_docus, category=item.category)) itemlist.append( - Item(channel=item.channel, action="search", title="Buscar", url=host + "buscar", thumbnail=thumb_buscar)) + Item(channel=item.channel, action="search", title="Buscar", url=host + "buscar", thumbnail=thumb_buscar, category=item.category)) itemlist.append( - Item(channel=item.channel, action="", title="[COLOR yellow]Configuración de Servidores:[/COLOR]", url="", thumbnail=thumb_settings)) + Item(channel=item.channel, action="", title="[COLOR yellow]Configuración de Servidores:[/COLOR]", url="", thumbnail=thumb_settings, category=item.category)) itemlist.append( - Item(channel=item.channel, action="settingCanal", title="Servidores para Ver Online y Descargas", url="", thumbnail=thumb_settings)) + Item(channel=item.channel, action="settingCanal", title="Servidores para Ver Online y Descargas", url="", thumbnail=thumb_settings, category=item.category)) return itemlist @@ -85,68 +98,60 @@ def submenu(item): logger.info() itemlist = [] + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass - host_alt = host - host_dom = host.replace("https://", "").replace("http://", "").replace("www.", "") - patron = '<li><a href="http://(?:www.)?' + host_dom + item.extra + '/">.*?<ul.*?>(.*?)</ul>' + patron = '<li><a\s?class="[^"]+"\s?href="http:[^"]+"><i\s?class=.*><\/i>.*Inicio<\/a><\/li>(.+)<\/ul>\s?<\/nav>' #Verificamos si se ha cargado una página, y si además tiene la estructura correcta if not data or not scrapertools.find_single_match(data, patron): - logger.error("ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url) + logger.error("ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url + data) #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú item, data = generictools.fail_over_newpct1(item, patron) if not data: #Si no ha logrado encontrar nada, salimos - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif item.channel_alt: #Si ha habido fail-over, lo comento - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR] [ALT ] en uso')) - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] caído')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) - host_alt = host.replace(item.channel_alt, item.channel) - del item.channel_alt if item.url_alt: del item.url_alt + del item.channel_alt - #data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") - #data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com - - host_dom = host_alt.replace("https://", "").replace("http://", "").replace("www.", "") - patron = '<li><a href="http://(?:www.)?' + host_dom + item.extra + '/">.*?<ul.*?>(.*?)</ul>' - if "pelisyseries.com" in host_alt and item.extra == "varios": #compatibilidad con mispelisy.series.com - data = '<a href="' + host_alt + 'varios/" title="Documentales"><i class="icon-rocket"></i> Documentales</a>' + data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") + data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com + if "pelisyseries.com" in item.channel_host and item.extra == "varios": #compatibilidad con mispelisy.series.com + data = '<li><a href="' + item.channel_host + 'varios/" title="Documentales">Documentales</a></li>' else: - if data: - data = scrapertools.get_match(data, patron) - if not data: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - else: - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + data = scrapertools.get_match(data, patron) #Seleccionamos el trozo que nos interesa + if not data: + logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - patron = '<.*?href="([^"]+)".*?>([^>]+)</a>' + patron = '<li><a.*?href="([^"]+)"\s?.itle="[^"]+"\s?>([^>]+)<\/a><\/li>' matches = re.compile(patron, re.DOTALL).findall(data) + if not matches: logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.strip() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title=title + " [A-Z]", url=url, extra=item.extra)) + #Preguntamos por las entradas que no corresponden al "extra" + if item.extra in scrapedtitle.lower() or (item.extra == "peliculas" and ("cine" in scrapedurl or "anime" in scrapedurl)) or (item.extra == "varios" and ("documentales" in scrapedurl or "varios" in scrapedurl)): + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) + itemlist.append(item.clone(action="alfabeto", title=title + " [A-Z]", url=scrapedurl)) if item.extra == "peliculas": - itemlist.append(Item(channel=item.channel, action="listado", title="Películas 4K", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title="Películas 4K" + " [A-Z]", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) + itemlist.append(item.clone(action="listado", title="Películas 4K", url=item.channel_host + "peliculas-hd/4kultrahd/")) + itemlist.append(item.clone(action="alfabeto", title="Películas 4K" + " [A-Z]", url=item.channel_host + "peliculas-hd/4kultrahd/")) return itemlist @@ -155,28 +160,41 @@ def alfabeto(item): logger.info() itemlist = [] - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = '' + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") patron = '<ul class="alfabeto">(.*?)</ul>' - if data: - data = scrapertools.get_match(data, patron) - else: - return itemlist + if not data or not scrapertools.find_single_match(data, patron): + logger.error("ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL: " + item.url + data) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + elif item.channel_alt: #Si ha habido fail-over, lo comento + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) + + if item.url_alt: del item.url_alt + del item.channel_alt + + data = scrapertools.get_match(data, patron) patron = '<a href="([^"]+)"[^>]+>([^>]+)</a>' matches = re.compile(patron, re.DOTALL).findall(data) if not matches: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + logger.error("ERROR 02: ALFABETO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: ALFABETO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.upper() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) return itemlist @@ -191,11 +209,21 @@ def listado(item): if item.totalItems: del item.totalItems + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: + pass + + patron = '<ul class="' + clase + '">(.*?)</ul>' #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, patron) and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data): logger.error("ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + item.url + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Establecemos los valores básicos en función del tipo de contenido @@ -218,7 +246,7 @@ def listado(item): fichas = scrapertools.get_match(data, patron) if not fichas and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif '<h3><strong>( 0 ) Resultados encontrados </strong>' in data: #no hay vídeos return itemlist @@ -235,7 +263,7 @@ def listado(item): matches = re.compile(patron, re.DOTALL).findall(fichas) if not matches: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + fichas) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("MATCHES: " + str(len(matches))) @@ -460,13 +488,21 @@ def listado(item): def listado_busqueda(item): logger.info() - - host = 'http://%s/' % scrapertools.find_single_match(item.url, '(\w+\.com)\/') + + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + if item.category and item.category != "newest": + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] cnt_tot = 40 # Poner el num. máximo de items por página. Dejamos que la web lo controle cnt_title = 0 # Contador de líneas insertadas en Itemlist cnt_pag = 0 # Contador de líneas leídas de Matches + timeout_search = 5 # Timeout un poco más largo para las búsquedas + if timeout > 5: + timeout_search = timeout # Timeout un poco más largo para las búsquedas + data = '' if item.cnt_pag: cnt_pag = item.cnt_pag # Se guarda en la lista de páginas anteriores en Item @@ -493,21 +529,21 @@ def listado_busqueda(item): #Máximo num. de líneas permitidas por TMDB. Máx de 5 páginas por Itemlist para no degradar el rendimiento while cnt_title <= cnt_tot and cnt_next < 5: - pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post, timeout=timeout_search).data) except: pass - cnt_next += 1 - if not data or not scrapertools.find_single_match(data, pattern): + cnt_next += 1 + pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, pattern) and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data): logger.error("ERROR 01: LISTADO_BUSQUEDA: La Web no responde o ha cambiado de URL: " + item.url + item.post + " / DATA: " + data) #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú item, data = generictools.fail_over_newpct1(item, pattern) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif item.channel_alt: #Si ha habido fail-over, lo comento host = host.replace(item.channel_alt, item.channel) @@ -531,7 +567,6 @@ def listado_busqueda(item): pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa data_alt = data data = scrapertools.get_match(data, pattern) - #pattern = '<li[^>]*><a href="(?P<url>[^"]+).*?<img.*?src="(?P<thumb>[^"]+)?".*?<h2.*?>(?P<title>.*?)?<\/h2>' pattern = '<li[^>]*><a href="(?P<scrapedurl>[^"]+).*?' #url pattern += 'title="(?P<scrapedtitle>[^"]+).*?' #título pattern += '<img.*?src="(?P<scrapedthumbnail>[^"]+)?".*?' #thumb @@ -541,7 +576,8 @@ def listado_busqueda(item): matches_alt = re.compile(pattern, re.DOTALL).findall(data) if not matches_alt and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data_alt: #error logger.error("ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data_alt) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + item, itemlist = generictools.post_tmdb_listado(item, itemlist) #Pintamos los datos de fail-over, si los hay return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Ahora se hace una simulación para saber cuantas líneas podemos albergar en este Itemlist. @@ -830,14 +866,14 @@ def listado_busqueda(item): url_tvshow = host + calidad_mps + real_title_mps + "/" #... otras no. A probar... #Leemos la página, a ver si es una página de episodios - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" #Patrón de lista de episodios if not scrapertools.find_single_match(data_serie, pattern) and serieid: #no es válida la página, #intentarlo con la otra url - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") @@ -876,9 +912,10 @@ def findvideos(item): from core import channeltools logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -987,8 +1024,9 @@ def findvideos(item): excluir_enlaces_descargas = [] #Lista vacía de servidores excluidos en Descargar # Descarga la página + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass @@ -1001,7 +1039,7 @@ def findvideos(item): item, data = generictools.fail_over_newpct1(item, patron) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") @@ -1029,7 +1067,7 @@ def findvideos(item): item_local.url = scrapertools.find_single_match(data, patron) if not item_local.url: #error logger.error("ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos item_local.url = item_local.url.replace(" ", "%20") #sustituimos espacios por %20, por si acaso #logger.debug("Patron: " + patron + " url: " + item_local.url) @@ -1054,6 +1092,8 @@ def findvideos(item): #logger.debug(item_local) # VER vídeos, descargar vídeos un link, o múltiples links + data = scrapertools.find_single_match(data, '<div id="tab1" class="tab_content"(.*?<\/ul>(?:<div.*?>)?<\/div><\/div><\/div>)') #Seleccionar el bloque para evitar duplicados + host_dom = host.replace("https://", "").replace("http://", "").replace("www.", "") data = data.replace("http://tumejorserie.com/descargar/url_encript.php?link=", "(") data = re.sub(r'javascript:;" onClick="popup\("http:\/\/(?:www.)?' + host_dom + '\w{1,9}\/library\/include\/ajax\/get_modallinks.php\?links=', "", data) @@ -1066,7 +1106,7 @@ def findvideos(item): enlaces_ver = re.compile(patron, re.DOTALL).findall(data) enlaces_descargar = enlaces_ver #logger.debug(enlaces_ver) - + #Recorre todos los links de VER, si está permitido cnt_enl_ver = 1 cnt_enl_verif = 1 @@ -1100,7 +1140,7 @@ def findvideos(item): if verificar_enlaces_veronline != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_veronline or verificar_enlaces_veronline == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para cada link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_veronline_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1190,7 +1230,7 @@ def findvideos(item): if verificar_enlaces_descargas != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_descargas or verificar_enlaces_descargas == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para primer link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_descargas_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1232,9 +1272,10 @@ def findvideos(item): def episodios(item): logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -1255,7 +1296,7 @@ def episodios(item): data = '' try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, timeout=timeout).data) patron = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern data_alt = '' if data: data_alt = scrapertools.get_match(data, patron) @@ -1276,7 +1317,7 @@ def episodios(item): if not data: #No se ha encontrado ningún canal activo para este vídeo itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #Busca y pre-carga todas las páginas de episodios que componen las serie, para obtener la url de cada página @@ -1312,7 +1353,7 @@ def episodios(item): break try: if not data: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") data = data.replace("chapters", "buscar-list") #Compatibilidad con mispelisy.series.com pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern @@ -1321,7 +1362,7 @@ def episodios(item): raise except: logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / " + str(list_pages) + " / DATA: " + str(data)) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if "pelisyseries.com" in item.url: @@ -1331,7 +1372,7 @@ def episodios(item): matches = re.compile(pattern, re.DOTALL).findall(data) if not matches: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("patron: " + pattern) @@ -1399,7 +1440,7 @@ def episodios(item): match = [m.groupdict() for m in r.finditer(info)][0] if not match: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + info) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if match['season'] is None: match['season'] = season #Si no se encuentran valores, pero poner lo básico @@ -1449,8 +1490,6 @@ def episodios(item): if item_local.active: del item_local.active - if item_local.category: - del item_local.category if item_local.infoLabels['title']: del item_local.infoLabels['title'] item_local.context = "['buscar_trailer']" @@ -1467,6 +1506,8 @@ def episodios(item): del item_local.update_last if item_local.update_next: del item_local.update_next + if item_local.channel_host: + del item_local.channel_host itemlist.append(item_local.clone()) @@ -1501,9 +1542,6 @@ def actualizar_titulos(item): def search(item, texto): logger.info("search:" + texto) # texto = texto.replace(" ", "+") - - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() try: item.post = "q=%s" % texto diff --git a/plugin.video.alfa/channels/torrentrapid.json b/plugin.video.alfa/channels/torrentrapid.json index f9106274..323d6468 100644 --- a/plugin.video.alfa/channels/torrentrapid.json +++ b/plugin.video.alfa/channels/torrentrapid.json @@ -53,7 +53,7 @@ "id": "clonenewpct1_channels_list", "type": "text", "label": "Lista de clones de NewPct1 y orden de uso", - "default": "('1', 'torrentrapid', 'torrentrapid.com', 'movie, tvshow, season, episode', ''), ('1', 'torrentlocura', 'torrentlocura.com', 'movie, tvshow, season, episode', ''), ('1', 'tumejortorrent', 'tumejortorrent.com', 'movie, tvshow, season, episode', ''), ('1', 'tvsinpagar', 'www.tvsinpagar.com', 'tvshow, season, episode', ''), ('1', 'descargas2020', 'descargas2020.com', 'movie, tvshow, season, episode', ''), ('1', 'mispelisyseries', 'mispelisyseries.com', 'movie, tvshow, season, episode', '')", + "default": "('1', 'torrentrapid', 'http://torrentrapid.com/', 'movie, tvshow, season, episode', ''), ('1', 'torrentlocura', 'http://torrentlocura.com/', 'movie, tvshow, season, episode', ''), ('1', 'tumejortorrent', 'http://tumejortorrent.com/', 'movie, tvshow, season, episode', ''), ('1', 'tvsinpagar', 'http://www.tvsinpagar.com/', 'tvshow, season, episode', ''), ('1', 'descargas2020', 'http://descargas2020.com/', 'movie, tvshow, season, episode', ''), ('1', 'mispelisyseries', 'http://mispelisyseries.com/', 'movie', 'search')", "enabled": true, "visible": false }, @@ -539,6 +539,27 @@ "default": true, "enabled": true, "visible": false + }, + { + "id": "clonenewpct1_timeout_downloadpage", + "type": "list", + "label": "Timeout (segs.) en descarga de páginas o verificación de servidores", + "default": 5, + "enabled": true, + "visible": true, + "lvalues": [ + "None", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10" + ] } ] } \ No newline at end of file diff --git a/plugin.video.alfa/channels/torrentrapid.py b/plugin.video.alfa/channels/torrentrapid.py index 292d7faa..ac2d77c4 100644 --- a/plugin.video.alfa/channels/torrentrapid.py +++ b/plugin.video.alfa/channels/torrentrapid.py @@ -12,40 +12,53 @@ from core import httptools from core import scrapertools from core import servertools from core.item import Item -from platformcode import config, logger +from platformcode import config, logger, platformtools from core import tmdb from lib import generictools -host = 'http://torrentrapid.com/' +channel_py = 'newpct1' #Código para permitir usar un único canal para todas las webs clones de NewPct1 -clone_list = config.get_setting('clonenewpct1_channels_list', "torrentrapid") #Carga lista de clones -clone_list = ast.literal_eval(clone_list) #la convierte a lista de tuplas +clone_list = config.get_setting('clonenewpct1_channels_list', channel_py) #Carga lista de clones +clone_list = ast.literal_eval(clone_list) #la convierte en array host_index = 0 -host_index = config.get_setting('clonenewpct1_channel_default', "torrentrapid") #Clone por defecto +host_index = config.get_setting('clonenewpct1_channel_default', channel_py) #Clone por defecto i = 0 for active_clone, channel_clone, host_clone, contentType_clone, info_clone in clone_list: if i == host_index: - #channel_clone_name = channel_clone #ACTIVAR CUANDO SE PASE A NEWPCT1 - #host = 'http://%s/' % host_clone #ACTIVAR CUANDO SE PASE A NEWPCT1 - i += 1 + channel_clone_name = channel_clone #Nombre del Canal elegido + host = host_clone #URL del Canal elegido + break + i += 1 +item = Item() +item.channel_host = host +if item.channel != channel_py: + item.channel = channel_py +item.category = channel_clone_name.capitalize() #Carga de opciones del canal -item = Item() -if not item.channel: - item.channel = scrapertools.find_single_match(host, r'(\w+)\.com\/') -channel_clone_name = scrapertools.find_single_match(host, r'(\w+)\.com\/') #QUITAR CUANDO SE PASE A NEWPCT1 -__modo_grafico__ = config.get_setting('modo_grafico', item.channel) -modo_ultima_temp = config.get_setting('seleccionar_ult_temporadda_activa', item.channel) +__modo_grafico__ = config.get_setting('modo_grafico', channel_py) #TMDB? +modo_ultima_temp = config.get_setting('seleccionar_ult_temporadda_activa', channel_py) #Actualización sólo últ. Temporada? +timeout = config.get_setting('clonenewpct1_timeout_downloadpage', channel_py) #Timeout downloadpage +if timeout == 0: timeout = None + +platformtools.dialog_ok("NewPct1, ¡¡¡he vuelto como canal VIRTUAL!!!", "Hemos centralizado la gestión de los clones de NewPct1 en el canal virtual NewPct1. Los clones desaparecerán en breve.", "Para más información lee el tutorial: https://alfa-addon.com /threads/newpct1-implantando-alta-disponibilidad.1200/") + +#Vayamos a la siguiente acción en el canal Newpct1 +from platformcode import launcher +channel_clone_name = "torrentrapid" #Nombre del Canal elegido +host = "http://torrentrapid.com/" +item.category = channel_clone_name.capitalize() +item.action = "mainlist" +item.channel_host = host +launcher.run(item) def mainlist(item): logger.info() + if item.channel != channel_py: + return - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() - itemlist = [] thumb_pelis = get_thumb("channels_movie.png") @@ -58,20 +71,20 @@ def mainlist(item): thumb_settings = get_thumb("setting_0.png") itemlist.append(Item(channel=item.channel, action="submenu", title="Películas", url=host, - extra="peliculas", thumbnail=thumb_pelis )) + extra="peliculas", thumbnail=thumb_pelis, category=item.category)) itemlist.append(Item(channel=item.channel, action="submenu", title="Series", url=host, extra="series", - thumbnail=thumb_series)) + thumbnail=thumb_series, category=item.category)) itemlist.append(Item(channel=item.channel, action="submenu", title="Documentales", url=host, extra="varios", - thumbnail=thumb_docus)) + thumbnail=thumb_docus, category=item.category)) itemlist.append( - Item(channel=item.channel, action="search", title="Buscar", url=host + "buscar", thumbnail=thumb_buscar)) + Item(channel=item.channel, action="search", title="Buscar", url=host + "buscar", thumbnail=thumb_buscar, category=item.category)) itemlist.append( - Item(channel=item.channel, action="", title="[COLOR yellow]Configuración de Servidores:[/COLOR]", url="", thumbnail=thumb_settings)) + Item(channel=item.channel, action="", title="[COLOR yellow]Configuración de Servidores:[/COLOR]", url="", thumbnail=thumb_settings, category=item.category)) itemlist.append( - Item(channel=item.channel, action="settingCanal", title="Servidores para Ver Online y Descargas", url="", thumbnail=thumb_settings)) + Item(channel=item.channel, action="settingCanal", title="Servidores para Ver Online y Descargas", url="", thumbnail=thumb_settings, category=item.category)) return itemlist @@ -85,68 +98,60 @@ def submenu(item): logger.info() itemlist = [] + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass - host_alt = host - host_dom = host.replace("https://", "").replace("http://", "").replace("www.", "") - patron = '<li><a href="http://(?:www.)?' + host_dom + item.extra + '/">.*?<ul.*?>(.*?)</ul>' + patron = '<li><a\s?class="[^"]+"\s?href="http:[^"]+"><i\s?class=.*><\/i>.*Inicio<\/a><\/li>(.+)<\/ul>\s?<\/nav>' #Verificamos si se ha cargado una página, y si además tiene la estructura correcta if not data or not scrapertools.find_single_match(data, patron): - logger.error("ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url) + logger.error("ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url + data) #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú item, data = generictools.fail_over_newpct1(item, patron) if not data: #Si no ha logrado encontrar nada, salimos - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif item.channel_alt: #Si ha habido fail-over, lo comento - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR] [ALT ] en uso')) - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] caído')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) - host_alt = host.replace(item.channel_alt, item.channel) - del item.channel_alt if item.url_alt: del item.url_alt + del item.channel_alt - #data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") - #data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com - - host_dom = host_alt.replace("https://", "").replace("http://", "").replace("www.", "") - patron = '<li><a href="http://(?:www.)?' + host_dom + item.extra + '/">.*?<ul.*?>(.*?)</ul>' - if "pelisyseries.com" in host_alt and item.extra == "varios": #compatibilidad con mispelisy.series.com - data = '<a href="' + host_alt + 'varios/" title="Documentales"><i class="icon-rocket"></i> Documentales</a>' + data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") + data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com + if "pelisyseries.com" in item.channel_host and item.extra == "varios": #compatibilidad con mispelisy.series.com + data = '<li><a href="' + item.channel_host + 'varios/" title="Documentales">Documentales</a></li>' else: - if data: - data = scrapertools.get_match(data, patron) - if not data: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - else: - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + data = scrapertools.get_match(data, patron) #Seleccionamos el trozo que nos interesa + if not data: + logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - patron = '<.*?href="([^"]+)".*?>([^>]+)</a>' + patron = '<li><a.*?href="([^"]+)"\s?.itle="[^"]+"\s?>([^>]+)<\/a><\/li>' matches = re.compile(patron, re.DOTALL).findall(data) + if not matches: logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.strip() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title=title + " [A-Z]", url=url, extra=item.extra)) + #Preguntamos por las entradas que no corresponden al "extra" + if item.extra in scrapedtitle.lower() or (item.extra == "peliculas" and ("cine" in scrapedurl or "anime" in scrapedurl)) or (item.extra == "varios" and ("documentales" in scrapedurl or "varios" in scrapedurl)): + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) + itemlist.append(item.clone(action="alfabeto", title=title + " [A-Z]", url=scrapedurl)) if item.extra == "peliculas": - itemlist.append(Item(channel=item.channel, action="listado", title="Películas 4K", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title="Películas 4K" + " [A-Z]", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) + itemlist.append(item.clone(action="listado", title="Películas 4K", url=item.channel_host + "peliculas-hd/4kultrahd/")) + itemlist.append(item.clone(action="alfabeto", title="Películas 4K" + " [A-Z]", url=item.channel_host + "peliculas-hd/4kultrahd/")) return itemlist @@ -155,28 +160,41 @@ def alfabeto(item): logger.info() itemlist = [] - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = '' + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") patron = '<ul class="alfabeto">(.*?)</ul>' - if data: - data = scrapertools.get_match(data, patron) - else: - return itemlist + if not data or not scrapertools.find_single_match(data, patron): + logger.error("ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL: " + item.url + data) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + elif item.channel_alt: #Si ha habido fail-over, lo comento + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) + + if item.url_alt: del item.url_alt + del item.channel_alt + + data = scrapertools.get_match(data, patron) patron = '<a href="([^"]+)"[^>]+>([^>]+)</a>' matches = re.compile(patron, re.DOTALL).findall(data) if not matches: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + logger.error("ERROR 02: ALFABETO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: ALFABETO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.upper() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) return itemlist @@ -191,11 +209,21 @@ def listado(item): if item.totalItems: del item.totalItems + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: + pass + + patron = '<ul class="' + clase + '">(.*?)</ul>' #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, patron) and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data): logger.error("ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + item.url + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Establecemos los valores básicos en función del tipo de contenido @@ -218,7 +246,7 @@ def listado(item): fichas = scrapertools.get_match(data, patron) if not fichas and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif '<h3><strong>( 0 ) Resultados encontrados </strong>' in data: #no hay vídeos return itemlist @@ -235,7 +263,7 @@ def listado(item): matches = re.compile(patron, re.DOTALL).findall(fichas) if not matches: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + fichas) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("MATCHES: " + str(len(matches))) @@ -460,13 +488,21 @@ def listado(item): def listado_busqueda(item): logger.info() - - host = 'http://%s/' % scrapertools.find_single_match(item.url, '(\w+\.com)\/') + + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + if item.category and item.category != "newest": + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] cnt_tot = 40 # Poner el num. máximo de items por página. Dejamos que la web lo controle cnt_title = 0 # Contador de líneas insertadas en Itemlist cnt_pag = 0 # Contador de líneas leídas de Matches + timeout_search = 5 # Timeout un poco más largo para las búsquedas + if timeout > 5: + timeout_search = timeout # Timeout un poco más largo para las búsquedas + data = '' if item.cnt_pag: cnt_pag = item.cnt_pag # Se guarda en la lista de páginas anteriores en Item @@ -493,21 +529,21 @@ def listado_busqueda(item): #Máximo num. de líneas permitidas por TMDB. Máx de 5 páginas por Itemlist para no degradar el rendimiento while cnt_title <= cnt_tot and cnt_next < 5: - pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post, timeout=timeout_search).data) except: pass - cnt_next += 1 - if not data or not scrapertools.find_single_match(data, pattern): + cnt_next += 1 + pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, pattern) and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data): logger.error("ERROR 01: LISTADO_BUSQUEDA: La Web no responde o ha cambiado de URL: " + item.url + item.post + " / DATA: " + data) #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú item, data = generictools.fail_over_newpct1(item, pattern) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif item.channel_alt: #Si ha habido fail-over, lo comento host = host.replace(item.channel_alt, item.channel) @@ -531,7 +567,6 @@ def listado_busqueda(item): pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa data_alt = data data = scrapertools.get_match(data, pattern) - #pattern = '<li[^>]*><a href="(?P<url>[^"]+).*?<img.*?src="(?P<thumb>[^"]+)?".*?<h2.*?>(?P<title>.*?)?<\/h2>' pattern = '<li[^>]*><a href="(?P<scrapedurl>[^"]+).*?' #url pattern += 'title="(?P<scrapedtitle>[^"]+).*?' #título pattern += '<img.*?src="(?P<scrapedthumbnail>[^"]+)?".*?' #thumb @@ -541,7 +576,8 @@ def listado_busqueda(item): matches_alt = re.compile(pattern, re.DOTALL).findall(data) if not matches_alt and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data_alt: #error logger.error("ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data_alt) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + item, itemlist = generictools.post_tmdb_listado(item, itemlist) #Pintamos los datos de fail-over, si los hay return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Ahora se hace una simulación para saber cuantas líneas podemos albergar en este Itemlist. @@ -830,14 +866,14 @@ def listado_busqueda(item): url_tvshow = host + calidad_mps + real_title_mps + "/" #... otras no. A probar... #Leemos la página, a ver si es una página de episodios - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" #Patrón de lista de episodios if not scrapertools.find_single_match(data_serie, pattern) and serieid: #no es válida la página, #intentarlo con la otra url - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") @@ -876,9 +912,10 @@ def findvideos(item): from core import channeltools logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -987,8 +1024,9 @@ def findvideos(item): excluir_enlaces_descargas = [] #Lista vacía de servidores excluidos en Descargar # Descarga la página + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass @@ -1001,7 +1039,7 @@ def findvideos(item): item, data = generictools.fail_over_newpct1(item, patron) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") @@ -1029,7 +1067,7 @@ def findvideos(item): item_local.url = scrapertools.find_single_match(data, patron) if not item_local.url: #error logger.error("ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos item_local.url = item_local.url.replace(" ", "%20") #sustituimos espacios por %20, por si acaso #logger.debug("Patron: " + patron + " url: " + item_local.url) @@ -1054,6 +1092,8 @@ def findvideos(item): #logger.debug(item_local) # VER vídeos, descargar vídeos un link, o múltiples links + data = scrapertools.find_single_match(data, '<div id="tab1" class="tab_content"(.*?<\/ul>(?:<div.*?>)?<\/div><\/div><\/div>)') #Seleccionar el bloque para evitar duplicados + host_dom = host.replace("https://", "").replace("http://", "").replace("www.", "") data = data.replace("http://tumejorserie.com/descargar/url_encript.php?link=", "(") data = re.sub(r'javascript:;" onClick="popup\("http:\/\/(?:www.)?' + host_dom + '\w{1,9}\/library\/include\/ajax\/get_modallinks.php\?links=', "", data) @@ -1066,7 +1106,7 @@ def findvideos(item): enlaces_ver = re.compile(patron, re.DOTALL).findall(data) enlaces_descargar = enlaces_ver #logger.debug(enlaces_ver) - + #Recorre todos los links de VER, si está permitido cnt_enl_ver = 1 cnt_enl_verif = 1 @@ -1100,7 +1140,7 @@ def findvideos(item): if verificar_enlaces_veronline != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_veronline or verificar_enlaces_veronline == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para cada link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_veronline_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1190,7 +1230,7 @@ def findvideos(item): if verificar_enlaces_descargas != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_descargas or verificar_enlaces_descargas == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para primer link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_descargas_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1232,9 +1272,10 @@ def findvideos(item): def episodios(item): logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -1255,7 +1296,7 @@ def episodios(item): data = '' try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, timeout=timeout).data) patron = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern data_alt = '' if data: data_alt = scrapertools.get_match(data, patron) @@ -1276,7 +1317,7 @@ def episodios(item): if not data: #No se ha encontrado ningún canal activo para este vídeo itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #Busca y pre-carga todas las páginas de episodios que componen las serie, para obtener la url de cada página @@ -1312,7 +1353,7 @@ def episodios(item): break try: if not data: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") data = data.replace("chapters", "buscar-list") #Compatibilidad con mispelisy.series.com pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern @@ -1321,7 +1362,7 @@ def episodios(item): raise except: logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / " + str(list_pages) + " / DATA: " + str(data)) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if "pelisyseries.com" in item.url: @@ -1331,7 +1372,7 @@ def episodios(item): matches = re.compile(pattern, re.DOTALL).findall(data) if not matches: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("patron: " + pattern) @@ -1399,7 +1440,7 @@ def episodios(item): match = [m.groupdict() for m in r.finditer(info)][0] if not match: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + info) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if match['season'] is None: match['season'] = season #Si no se encuentran valores, pero poner lo básico @@ -1449,8 +1490,6 @@ def episodios(item): if item_local.active: del item_local.active - if item_local.category: - del item_local.category if item_local.infoLabels['title']: del item_local.infoLabels['title'] item_local.context = "['buscar_trailer']" @@ -1467,6 +1506,8 @@ def episodios(item): del item_local.update_last if item_local.update_next: del item_local.update_next + if item_local.channel_host: + del item_local.channel_host itemlist.append(item_local.clone()) @@ -1501,9 +1542,6 @@ def actualizar_titulos(item): def search(item, texto): logger.info("search:" + texto) # texto = texto.replace(" ", "+") - - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() try: item.post = "q=%s" % texto diff --git a/plugin.video.alfa/channels/tumejortorrent.py b/plugin.video.alfa/channels/tumejortorrent.py index 105b8cda..a49c07bc 100644 --- a/plugin.video.alfa/channels/tumejortorrent.py +++ b/plugin.video.alfa/channels/tumejortorrent.py @@ -12,40 +12,53 @@ from core import httptools from core import scrapertools from core import servertools from core.item import Item -from platformcode import config, logger +from platformcode import config, logger, platformtools from core import tmdb from lib import generictools -host = 'http://tumejortorrent.com/' +channel_py = 'newpct1' #Código para permitir usar un único canal para todas las webs clones de NewPct1 -clone_list = config.get_setting('clonenewpct1_channels_list', "torrentrapid") #Carga lista de clones -clone_list = ast.literal_eval(clone_list) #la convierte a lista de tuplas +clone_list = config.get_setting('clonenewpct1_channels_list', channel_py) #Carga lista de clones +clone_list = ast.literal_eval(clone_list) #la convierte en array host_index = 0 -host_index = config.get_setting('clonenewpct1_channel_default', "torrentrapid") #Clone por defecto +host_index = config.get_setting('clonenewpct1_channel_default', channel_py) #Clone por defecto i = 0 for active_clone, channel_clone, host_clone, contentType_clone, info_clone in clone_list: if i == host_index: - #channel_clone_name = channel_clone #ACTIVAR CUANDO SE PASE A NEWPCT1 - #host = 'http://%s/' % host_clone #ACTIVAR CUANDO SE PASE A NEWPCT1 - i += 1 + channel_clone_name = channel_clone #Nombre del Canal elegido + host = host_clone #URL del Canal elegido + break + i += 1 +item = Item() +item.channel_host = host +if item.channel != channel_py: + item.channel = channel_py +item.category = channel_clone_name.capitalize() #Carga de opciones del canal -item = Item() -if not item.channel: - item.channel = scrapertools.find_single_match(host, r'(\w+)\.com\/') -channel_clone_name = scrapertools.find_single_match(host, r'(\w+)\.com\/') #QUITAR CUANDO SE PASE A NEWPCT1 -__modo_grafico__ = config.get_setting('modo_grafico', item.channel) -modo_ultima_temp = config.get_setting('seleccionar_ult_temporadda_activa', item.channel) +__modo_grafico__ = config.get_setting('modo_grafico', channel_py) #TMDB? +modo_ultima_temp = config.get_setting('seleccionar_ult_temporadda_activa', channel_py) #Actualización sólo últ. Temporada? +timeout = config.get_setting('clonenewpct1_timeout_downloadpage', channel_py) #Timeout downloadpage +if timeout == 0: timeout = None + +platformtools.dialog_ok("NewPct1, ¡¡¡he vuelto como canal VIRTUAL!!!", "Hemos centralizado la gestión de los clones de NewPct1 en el canal virtual NewPct1. Los clones desaparecerán en breve.", "Para más información lee el tutorial: https://alfa-addon.com /threads/newpct1-implantando-alta-disponibilidad.1200/") + +#Vayamos a la siguiente acción en el canal Newpct1 +from platformcode import launcher +channel_clone_name = "tumejortorrent" #Nombre del Canal elegido +host = "http://tumejortorrent.com/" +item.category = channel_clone_name.capitalize() +item.action = "mainlist" +item.channel_host = host +launcher.run(item) def mainlist(item): logger.info() + if item.channel != channel_py: + return - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() - itemlist = [] thumb_pelis = get_thumb("channels_movie.png") @@ -58,20 +71,20 @@ def mainlist(item): thumb_settings = get_thumb("setting_0.png") itemlist.append(Item(channel=item.channel, action="submenu", title="Películas", url=host, - extra="peliculas", thumbnail=thumb_pelis )) + extra="peliculas", thumbnail=thumb_pelis, category=item.category)) itemlist.append(Item(channel=item.channel, action="submenu", title="Series", url=host, extra="series", - thumbnail=thumb_series)) + thumbnail=thumb_series, category=item.category)) itemlist.append(Item(channel=item.channel, action="submenu", title="Documentales", url=host, extra="varios", - thumbnail=thumb_docus)) + thumbnail=thumb_docus, category=item.category)) itemlist.append( - Item(channel=item.channel, action="search", title="Buscar", url=host + "buscar", thumbnail=thumb_buscar)) + Item(channel=item.channel, action="search", title="Buscar", url=host + "buscar", thumbnail=thumb_buscar, category=item.category)) itemlist.append( - Item(channel=item.channel, action="", title="[COLOR yellow]Configuración de Servidores:[/COLOR]", url="", thumbnail=thumb_settings)) + Item(channel=item.channel, action="", title="[COLOR yellow]Configuración de Servidores:[/COLOR]", url="", thumbnail=thumb_settings, category=item.category)) itemlist.append( - Item(channel=item.channel, action="settingCanal", title="Servidores para Ver Online y Descargas", url="", thumbnail=thumb_settings)) + Item(channel=item.channel, action="settingCanal", title="Servidores para Ver Online y Descargas", url="", thumbnail=thumb_settings, category=item.category)) return itemlist @@ -85,68 +98,60 @@ def submenu(item): logger.info() itemlist = [] + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass - host_alt = host - host_dom = host.replace("https://", "").replace("http://", "").replace("www.", "") - patron = '<li><a href="http://(?:www.)?' + host_dom + item.extra + '/">.*?<ul.*?>(.*?)</ul>' + patron = '<li><a\s?class="[^"]+"\s?href="http:[^"]+"><i\s?class=.*><\/i>.*Inicio<\/a><\/li>(.+)<\/ul>\s?<\/nav>' #Verificamos si se ha cargado una página, y si además tiene la estructura correcta if not data or not scrapertools.find_single_match(data, patron): - logger.error("ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url) + logger.error("ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url + data) #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú item, data = generictools.fail_over_newpct1(item, patron) if not data: #Si no ha logrado encontrar nada, salimos - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif item.channel_alt: #Si ha habido fail-over, lo comento - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR] [ALT ] en uso')) - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] caído')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) - host_alt = host.replace(item.channel_alt, item.channel) - del item.channel_alt if item.url_alt: del item.url_alt + del item.channel_alt - #data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") - #data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com - - host_dom = host_alt.replace("https://", "").replace("http://", "").replace("www.", "") - patron = '<li><a href="http://(?:www.)?' + host_dom + item.extra + '/">.*?<ul.*?>(.*?)</ul>' - if "pelisyseries.com" in host_alt and item.extra == "varios": #compatibilidad con mispelisy.series.com - data = '<a href="' + host_alt + 'varios/" title="Documentales"><i class="icon-rocket"></i> Documentales</a>' + data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") + data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com + if "pelisyseries.com" in item.channel_host and item.extra == "varios": #compatibilidad con mispelisy.series.com + data = '<li><a href="' + item.channel_host + 'varios/" title="Documentales">Documentales</a></li>' else: - if data: - data = scrapertools.get_match(data, patron) - if not data: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - else: - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + data = scrapertools.get_match(data, patron) #Seleccionamos el trozo que nos interesa + if not data: + logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - patron = '<.*?href="([^"]+)".*?>([^>]+)</a>' + patron = '<li><a.*?href="([^"]+)"\s?.itle="[^"]+"\s?>([^>]+)<\/a><\/li>' matches = re.compile(patron, re.DOTALL).findall(data) + if not matches: logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.strip() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title=title + " [A-Z]", url=url, extra=item.extra)) + #Preguntamos por las entradas que no corresponden al "extra" + if item.extra in scrapedtitle.lower() or (item.extra == "peliculas" and ("cine" in scrapedurl or "anime" in scrapedurl)) or (item.extra == "varios" and ("documentales" in scrapedurl or "varios" in scrapedurl)): + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) + itemlist.append(item.clone(action="alfabeto", title=title + " [A-Z]", url=scrapedurl)) if item.extra == "peliculas": - itemlist.append(Item(channel=item.channel, action="listado", title="Películas 4K", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title="Películas 4K" + " [A-Z]", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) + itemlist.append(item.clone(action="listado", title="Películas 4K", url=item.channel_host + "peliculas-hd/4kultrahd/")) + itemlist.append(item.clone(action="alfabeto", title="Películas 4K" + " [A-Z]", url=item.channel_host + "peliculas-hd/4kultrahd/")) return itemlist @@ -155,28 +160,41 @@ def alfabeto(item): logger.info() itemlist = [] - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = '' + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") patron = '<ul class="alfabeto">(.*?)</ul>' - if data: - data = scrapertools.get_match(data, patron) - else: - return itemlist + if not data or not scrapertools.find_single_match(data, patron): + logger.error("ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL: " + item.url + data) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + elif item.channel_alt: #Si ha habido fail-over, lo comento + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) + + if item.url_alt: del item.url_alt + del item.channel_alt + + data = scrapertools.get_match(data, patron) patron = '<a href="([^"]+)"[^>]+>([^>]+)</a>' matches = re.compile(patron, re.DOTALL).findall(data) if not matches: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + logger.error("ERROR 02: ALFABETO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: ALFABETO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.upper() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) return itemlist @@ -191,11 +209,21 @@ def listado(item): if item.totalItems: del item.totalItems + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: + pass + + patron = '<ul class="' + clase + '">(.*?)</ul>' #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, patron) and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data): logger.error("ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + item.url + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Establecemos los valores básicos en función del tipo de contenido @@ -218,7 +246,7 @@ def listado(item): fichas = scrapertools.get_match(data, patron) if not fichas and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif '<h3><strong>( 0 ) Resultados encontrados </strong>' in data: #no hay vídeos return itemlist @@ -235,7 +263,7 @@ def listado(item): matches = re.compile(patron, re.DOTALL).findall(fichas) if not matches: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + fichas) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("MATCHES: " + str(len(matches))) @@ -460,13 +488,21 @@ def listado(item): def listado_busqueda(item): logger.info() - - host = 'http://%s/' % scrapertools.find_single_match(item.url, '(\w+\.com)\/') + + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + if item.category and item.category != "newest": + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] cnt_tot = 40 # Poner el num. máximo de items por página. Dejamos que la web lo controle cnt_title = 0 # Contador de líneas insertadas en Itemlist cnt_pag = 0 # Contador de líneas leídas de Matches + timeout_search = 5 # Timeout un poco más largo para las búsquedas + if timeout > 5: + timeout_search = timeout # Timeout un poco más largo para las búsquedas + data = '' if item.cnt_pag: cnt_pag = item.cnt_pag # Se guarda en la lista de páginas anteriores en Item @@ -493,21 +529,21 @@ def listado_busqueda(item): #Máximo num. de líneas permitidas por TMDB. Máx de 5 páginas por Itemlist para no degradar el rendimiento while cnt_title <= cnt_tot and cnt_next < 5: - pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post, timeout=timeout_search).data) except: pass - cnt_next += 1 - if not data or not scrapertools.find_single_match(data, pattern): + cnt_next += 1 + pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, pattern) and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data): logger.error("ERROR 01: LISTADO_BUSQUEDA: La Web no responde o ha cambiado de URL: " + item.url + item.post + " / DATA: " + data) #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú item, data = generictools.fail_over_newpct1(item, pattern) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif item.channel_alt: #Si ha habido fail-over, lo comento host = host.replace(item.channel_alt, item.channel) @@ -531,7 +567,6 @@ def listado_busqueda(item): pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa data_alt = data data = scrapertools.get_match(data, pattern) - #pattern = '<li[^>]*><a href="(?P<url>[^"]+).*?<img.*?src="(?P<thumb>[^"]+)?".*?<h2.*?>(?P<title>.*?)?<\/h2>' pattern = '<li[^>]*><a href="(?P<scrapedurl>[^"]+).*?' #url pattern += 'title="(?P<scrapedtitle>[^"]+).*?' #título pattern += '<img.*?src="(?P<scrapedthumbnail>[^"]+)?".*?' #thumb @@ -541,7 +576,8 @@ def listado_busqueda(item): matches_alt = re.compile(pattern, re.DOTALL).findall(data) if not matches_alt and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data_alt: #error logger.error("ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data_alt) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + item, itemlist = generictools.post_tmdb_listado(item, itemlist) #Pintamos los datos de fail-over, si los hay return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Ahora se hace una simulación para saber cuantas líneas podemos albergar en este Itemlist. @@ -830,14 +866,14 @@ def listado_busqueda(item): url_tvshow = host + calidad_mps + real_title_mps + "/" #... otras no. A probar... #Leemos la página, a ver si es una página de episodios - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" #Patrón de lista de episodios if not scrapertools.find_single_match(data_serie, pattern) and serieid: #no es válida la página, #intentarlo con la otra url - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") @@ -876,9 +912,10 @@ def findvideos(item): from core import channeltools logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -987,8 +1024,9 @@ def findvideos(item): excluir_enlaces_descargas = [] #Lista vacía de servidores excluidos en Descargar # Descarga la página + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass @@ -1001,7 +1039,7 @@ def findvideos(item): item, data = generictools.fail_over_newpct1(item, patron) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") @@ -1029,7 +1067,7 @@ def findvideos(item): item_local.url = scrapertools.find_single_match(data, patron) if not item_local.url: #error logger.error("ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos item_local.url = item_local.url.replace(" ", "%20") #sustituimos espacios por %20, por si acaso #logger.debug("Patron: " + patron + " url: " + item_local.url) @@ -1054,6 +1092,8 @@ def findvideos(item): #logger.debug(item_local) # VER vídeos, descargar vídeos un link, o múltiples links + data = scrapertools.find_single_match(data, '<div id="tab1" class="tab_content"(.*?<\/ul>(?:<div.*?>)?<\/div><\/div><\/div>)') #Seleccionar el bloque para evitar duplicados + host_dom = host.replace("https://", "").replace("http://", "").replace("www.", "") data = data.replace("http://tumejorserie.com/descargar/url_encript.php?link=", "(") data = re.sub(r'javascript:;" onClick="popup\("http:\/\/(?:www.)?' + host_dom + '\w{1,9}\/library\/include\/ajax\/get_modallinks.php\?links=', "", data) @@ -1066,7 +1106,7 @@ def findvideos(item): enlaces_ver = re.compile(patron, re.DOTALL).findall(data) enlaces_descargar = enlaces_ver #logger.debug(enlaces_ver) - + #Recorre todos los links de VER, si está permitido cnt_enl_ver = 1 cnt_enl_verif = 1 @@ -1100,7 +1140,7 @@ def findvideos(item): if verificar_enlaces_veronline != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_veronline or verificar_enlaces_veronline == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para cada link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_veronline_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1190,7 +1230,7 @@ def findvideos(item): if verificar_enlaces_descargas != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_descargas or verificar_enlaces_descargas == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para primer link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_descargas_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1232,9 +1272,10 @@ def findvideos(item): def episodios(item): logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -1255,7 +1296,7 @@ def episodios(item): data = '' try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, timeout=timeout).data) patron = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern data_alt = '' if data: data_alt = scrapertools.get_match(data, patron) @@ -1276,7 +1317,7 @@ def episodios(item): if not data: #No se ha encontrado ningún canal activo para este vídeo itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #Busca y pre-carga todas las páginas de episodios que componen las serie, para obtener la url de cada página @@ -1312,7 +1353,7 @@ def episodios(item): break try: if not data: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") data = data.replace("chapters", "buscar-list") #Compatibilidad con mispelisy.series.com pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern @@ -1321,7 +1362,7 @@ def episodios(item): raise except: logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / " + str(list_pages) + " / DATA: " + str(data)) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if "pelisyseries.com" in item.url: @@ -1331,7 +1372,7 @@ def episodios(item): matches = re.compile(pattern, re.DOTALL).findall(data) if not matches: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("patron: " + pattern) @@ -1399,7 +1440,7 @@ def episodios(item): match = [m.groupdict() for m in r.finditer(info)][0] if not match: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + info) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if match['season'] is None: match['season'] = season #Si no se encuentran valores, pero poner lo básico @@ -1449,8 +1490,6 @@ def episodios(item): if item_local.active: del item_local.active - if item_local.category: - del item_local.category if item_local.infoLabels['title']: del item_local.infoLabels['title'] item_local.context = "['buscar_trailer']" @@ -1467,6 +1506,8 @@ def episodios(item): del item_local.update_last if item_local.update_next: del item_local.update_next + if item_local.channel_host: + del item_local.channel_host itemlist.append(item_local.clone()) @@ -1501,9 +1542,6 @@ def actualizar_titulos(item): def search(item, texto): logger.info("search:" + texto) # texto = texto.replace(" ", "+") - - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() try: item.post = "q=%s" % texto diff --git a/plugin.video.alfa/channels/tvsinpagar.py b/plugin.video.alfa/channels/tvsinpagar.py index 8a0ef203..60f73eb5 100644 --- a/plugin.video.alfa/channels/tvsinpagar.py +++ b/plugin.video.alfa/channels/tvsinpagar.py @@ -12,40 +12,53 @@ from core import httptools from core import scrapertools from core import servertools from core.item import Item -from platformcode import config, logger +from platformcode import config, logger, platformtools from core import tmdb from lib import generictools -host = 'http://www.tvsinpagar.com/' +channel_py = 'newpct1' #Código para permitir usar un único canal para todas las webs clones de NewPct1 -clone_list = config.get_setting('clonenewpct1_channels_list', "torrentrapid") #Carga lista de clones -clone_list = ast.literal_eval(clone_list) #la convierte a lista de tuplas +clone_list = config.get_setting('clonenewpct1_channels_list', channel_py) #Carga lista de clones +clone_list = ast.literal_eval(clone_list) #la convierte en array host_index = 0 -host_index = config.get_setting('clonenewpct1_channel_default', "torrentrapid") #Clone por defecto +host_index = config.get_setting('clonenewpct1_channel_default', channel_py) #Clone por defecto i = 0 for active_clone, channel_clone, host_clone, contentType_clone, info_clone in clone_list: if i == host_index: - #channel_clone_name = channel_clone #ACTIVAR CUANDO SE PASE A NEWPCT1 - #host = 'http://%s/' % host_clone #ACTIVAR CUANDO SE PASE A NEWPCT1 - i += 1 + channel_clone_name = channel_clone #Nombre del Canal elegido + host = host_clone #URL del Canal elegido + break + i += 1 +item = Item() +item.channel_host = host +if item.channel != channel_py: + item.channel = channel_py +item.category = channel_clone_name.capitalize() #Carga de opciones del canal -item = Item() -if not item.channel: - item.channel = scrapertools.find_single_match(host, r'(\w+)\.com\/') -channel_clone_name = scrapertools.find_single_match(host, r'(\w+)\.com\/') #QUITAR CUANDO SE PASE A NEWPCT1 -__modo_grafico__ = config.get_setting('modo_grafico', item.channel) -modo_ultima_temp = config.get_setting('seleccionar_ult_temporadda_activa', item.channel) +__modo_grafico__ = config.get_setting('modo_grafico', channel_py) #TMDB? +modo_ultima_temp = config.get_setting('seleccionar_ult_temporadda_activa', channel_py) #Actualización sólo últ. Temporada? +timeout = config.get_setting('clonenewpct1_timeout_downloadpage', channel_py) #Timeout downloadpage +if timeout == 0: timeout = None + +platformtools.dialog_ok("NewPct1, ¡¡¡he vuelto como canal VIRTUAL!!!", "Hemos centralizado la gestión de los clones de NewPct1 en el canal virtual NewPct1. Los clones desaparecerán en breve.", "Para más información lee el tutorial: https://alfa-addon.com /threads/newpct1-implantando-alta-disponibilidad.1200/") + +#Vayamos a la siguiente acción en el canal Newpct1 +from platformcode import launcher +channel_clone_name = "tvsinpagar" #Nombre del Canal elegido +host = "http://www.tvsinpagar.com/" +item.category = channel_clone_name.capitalize() +item.action = "mainlist" +item.channel_host = host +launcher.run(item) def mainlist(item): logger.info() + if item.channel != channel_py: + return - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() - itemlist = [] thumb_pelis = get_thumb("channels_movie.png") @@ -58,20 +71,20 @@ def mainlist(item): thumb_settings = get_thumb("setting_0.png") itemlist.append(Item(channel=item.channel, action="submenu", title="Películas", url=host, - extra="peliculas", thumbnail=thumb_pelis )) + extra="peliculas", thumbnail=thumb_pelis, category=item.category)) itemlist.append(Item(channel=item.channel, action="submenu", title="Series", url=host, extra="series", - thumbnail=thumb_series)) + thumbnail=thumb_series, category=item.category)) itemlist.append(Item(channel=item.channel, action="submenu", title="Documentales", url=host, extra="varios", - thumbnail=thumb_docus)) + thumbnail=thumb_docus, category=item.category)) itemlist.append( - Item(channel=item.channel, action="search", title="Buscar", url=host + "buscar", thumbnail=thumb_buscar)) + Item(channel=item.channel, action="search", title="Buscar", url=host + "buscar", thumbnail=thumb_buscar, category=item.category)) itemlist.append( - Item(channel=item.channel, action="", title="[COLOR yellow]Configuración de Servidores:[/COLOR]", url="", thumbnail=thumb_settings)) + Item(channel=item.channel, action="", title="[COLOR yellow]Configuración de Servidores:[/COLOR]", url="", thumbnail=thumb_settings, category=item.category)) itemlist.append( - Item(channel=item.channel, action="settingCanal", title="Servidores para Ver Online y Descargas", url="", thumbnail=thumb_settings)) + Item(channel=item.channel, action="settingCanal", title="Servidores para Ver Online y Descargas", url="", thumbnail=thumb_settings, category=item.category)) return itemlist @@ -85,68 +98,60 @@ def submenu(item): logger.info() itemlist = [] + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass - host_alt = host - host_dom = host.replace("https://", "").replace("http://", "").replace("www.", "") - patron = '<li><a href="http://(?:www.)?' + host_dom + item.extra + '/">.*?<ul.*?>(.*?)</ul>' + patron = '<li><a\s?class="[^"]+"\s?href="http:[^"]+"><i\s?class=.*><\/i>.*Inicio<\/a><\/li>(.+)<\/ul>\s?<\/nav>' #Verificamos si se ha cargado una página, y si además tiene la estructura correcta if not data or not scrapertools.find_single_match(data, patron): - logger.error("ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url) + logger.error("ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL: " + item.url + data) #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú item, data = generictools.fail_over_newpct1(item, patron) if not data: #Si no ha logrado encontrar nada, salimos - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: SUBMENU: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif item.channel_alt: #Si ha habido fail-over, lo comento - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR] [ALT ] en uso')) - itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] caído')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) - host_alt = host.replace(item.channel_alt, item.channel) - del item.channel_alt if item.url_alt: del item.url_alt + del item.channel_alt - #data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") - #data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com - - host_dom = host_alt.replace("https://", "").replace("http://", "").replace("www.", "") - patron = '<li><a href="http://(?:www.)?' + host_dom + item.extra + '/">.*?<ul.*?>(.*?)</ul>' - if "pelisyseries.com" in host_alt and item.extra == "varios": #compatibilidad con mispelisy.series.com - data = '<a href="' + host_alt + 'varios/" title="Documentales"><i class="icon-rocket"></i> Documentales</a>' + data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") + data = data.replace("'", '"').replace('/series"', '/series/"') #Compatibilidad con mispelisy.series.com + if "pelisyseries.com" in item.channel_host and item.extra == "varios": #compatibilidad con mispelisy.series.com + data = '<li><a href="' + item.channel_host + 'varios/" title="Documentales">Documentales</a></li>' else: - if data: - data = scrapertools.get_match(data, patron) - if not data: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - else: - return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + data = scrapertools.get_match(data, patron) #Seleccionamos el trozo que nos interesa + if not data: + logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos - patron = '<.*?href="([^"]+)".*?>([^>]+)</a>' + patron = '<li><a.*?href="([^"]+)"\s?.itle="[^"]+"\s?>([^>]+)<\/a><\/li>' matches = re.compile(patron, re.DOTALL).findall(data) + if not matches: logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.strip() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title=title + " [A-Z]", url=url, extra=item.extra)) + #Preguntamos por las entradas que no corresponden al "extra" + if item.extra in scrapedtitle.lower() or (item.extra == "peliculas" and ("cine" in scrapedurl or "anime" in scrapedurl)) or (item.extra == "varios" and ("documentales" in scrapedurl or "varios" in scrapedurl)): + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) + itemlist.append(item.clone(action="alfabeto", title=title + " [A-Z]", url=scrapedurl)) if item.extra == "peliculas": - itemlist.append(Item(channel=item.channel, action="listado", title="Películas 4K", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) - itemlist.append( - Item(channel=item.channel, action="alfabeto", title="Películas 4K" + " [A-Z]", url=host_alt + "peliculas-hd/4kultrahd/", extra=item.extra)) + itemlist.append(item.clone(action="listado", title="Películas 4K", url=item.channel_host + "peliculas-hd/4kultrahd/")) + itemlist.append(item.clone(action="alfabeto", title="Películas 4K" + " [A-Z]", url=item.channel_host + "peliculas-hd/4kultrahd/")) return itemlist @@ -155,28 +160,41 @@ def alfabeto(item): logger.info() itemlist = [] - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = '' + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") patron = '<ul class="alfabeto">(.*?)</ul>' - if data: - data = scrapertools.get_match(data, patron) - else: - return itemlist + if not data or not scrapertools.find_single_match(data, patron): + logger.error("ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL: " + item.url + data) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: ALFABETO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos + elif item.channel_alt: #Si ha habido fail-over, lo comento + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.category + '[/COLOR] [ALT ] en uso')) + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel_alt.capitalize() + '[/COLOR] inaccesible')) + + if item.url_alt: del item.url_alt + del item.channel_alt + + data = scrapertools.get_match(data, patron) patron = '<a href="([^"]+)"[^>]+>([^>]+)</a>' matches = re.compile(patron, re.DOTALL).findall(data) if not matches: - logger.error("ERROR 02: SUBMENU: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: SUBMENU: Ha cambiado la estructura de la Web. Reportar el error con el log')) + logger.error("ERROR 02: ALFABETO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: ALFABETO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos for scrapedurl, scrapedtitle in matches: title = scrapedtitle.upper() - url = scrapedurl - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, extra=item.extra)) + itemlist.append(item.clone(action="listado", title=title, url=scrapedurl)) return itemlist @@ -191,11 +209,21 @@ def listado(item): if item.totalItems: del item.totalItems + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: + pass + + patron = '<ul class="' + clase + '">(.*?)</ul>' #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, patron) and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data): logger.error("ERROR 01: LISTADO: La Web no responde o ha cambiado de URL: " + item.url + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú + item, data = generictools.fail_over_newpct1(item, patron) + + if not data: #Si no ha logrado encontrar nada, salimos + itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO: La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Establecemos los valores básicos en función del tipo de contenido @@ -218,7 +246,7 @@ def listado(item): fichas = scrapertools.get_match(data, patron) if not fichas and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif '<h3><strong>( 0 ) Resultados encontrados </strong>' in data: #no hay vídeos return itemlist @@ -235,7 +263,7 @@ def listado(item): matches = re.compile(patron, re.DOTALL).findall(fichas) if not matches: #error logger.error("ERROR 02: LISTADO: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + fichas) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("MATCHES: " + str(len(matches))) @@ -460,13 +488,21 @@ def listado(item): def listado_busqueda(item): logger.info() - - host = 'http://%s/' % scrapertools.find_single_match(item.url, '(\w+\.com)\/') + + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + if item.category and item.category != "newest": + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] cnt_tot = 40 # Poner el num. máximo de items por página. Dejamos que la web lo controle cnt_title = 0 # Contador de líneas insertadas en Itemlist cnt_pag = 0 # Contador de líneas leídas de Matches + timeout_search = 5 # Timeout un poco más largo para las búsquedas + if timeout > 5: + timeout_search = timeout # Timeout un poco más largo para las búsquedas + data = '' if item.cnt_pag: cnt_pag = item.cnt_pag # Se guarda en la lista de páginas anteriores en Item @@ -493,21 +529,21 @@ def listado_busqueda(item): #Máximo num. de líneas permitidas por TMDB. Máx de 5 páginas por Itemlist para no degradar el rendimiento while cnt_title <= cnt_tot and cnt_next < 5: - pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, post=item.post, timeout=timeout_search).data) except: pass - cnt_next += 1 - if not data or not scrapertools.find_single_match(data, pattern): + cnt_next += 1 + pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa + if not data or (not scrapertools.find_single_match(data, pattern) and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data): logger.error("ERROR 01: LISTADO_BUSQUEDA: La Web no responde o ha cambiado de URL: " + item.url + item.post + " / DATA: " + data) #Si no hay datos consistentes, llamamos al método de fail_over para que encuentre un canal que esté activo y pueda gestionar el submenú item, data = generictools.fail_over_newpct1(item, pattern) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: LISTADO_BUSQUEDA:. La Web no responde o ha cambiado de URL. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos elif item.channel_alt: #Si ha habido fail-over, lo comento host = host.replace(item.channel_alt, item.channel) @@ -531,7 +567,6 @@ def listado_busqueda(item): pattern = '<ul class="%s">(.*?)</ul>' % item.pattern #seleccionamos el bloque que nos interesa data_alt = data data = scrapertools.get_match(data, pattern) - #pattern = '<li[^>]*><a href="(?P<url>[^"]+).*?<img.*?src="(?P<thumb>[^"]+)?".*?<h2.*?>(?P<title>.*?)?<\/h2>' pattern = '<li[^>]*><a href="(?P<scrapedurl>[^"]+).*?' #url pattern += 'title="(?P<scrapedtitle>[^"]+).*?' #título pattern += '<img.*?src="(?P<scrapedthumbnail>[^"]+)?".*?' #thumb @@ -541,7 +576,8 @@ def listado_busqueda(item): matches_alt = re.compile(pattern, re.DOTALL).findall(data) if not matches_alt and not '<h3><strong>( 0 ) Resultados encontrados </strong>' in data_alt: #error logger.error("ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data_alt) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) + item, itemlist = generictools.post_tmdb_listado(item, itemlist) #Pintamos los datos de fail-over, si los hay return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #Ahora se hace una simulación para saber cuantas líneas podemos albergar en este Itemlist. @@ -830,14 +866,14 @@ def listado_busqueda(item): url_tvshow = host + calidad_mps + real_title_mps + "/" #... otras no. A probar... #Leemos la página, a ver si es una página de episodios - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_id, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" #Patrón de lista de episodios if not scrapertools.find_single_match(data_serie, pattern) and serieid: #no es válida la página, #intentarlo con la otra url - data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow).data) + data_serie = data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(url_tvshow, timeout=timeout).data) data_serie = unicode(data_serie, "iso-8859-1", errors="replace").encode("utf-8") data_serie = data_serie.replace("chapters", "buscar-list") @@ -876,9 +912,10 @@ def findvideos(item): from core import channeltools logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -987,8 +1024,9 @@ def findvideos(item): excluir_enlaces_descargas = [] #Lista vacía de servidores excluidos en Descargar # Descarga la página + data = '' try: - data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url, timeout=timeout).data) except: pass @@ -1001,7 +1039,7 @@ def findvideos(item): item, data = generictools.fail_over_newpct1(item, patron) if not data: #Si no ha logrado encontrar nada, salimos itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: FINDVIDEOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") @@ -1029,7 +1067,7 @@ def findvideos(item): item_local.url = scrapertools.find_single_match(data, patron) if not item_local.url: #error logger.error("ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: FINDVIDEOS: El archivo Torrent no existe o ha cambiado la estructura de la Web. Verificar en la Web y reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos item_local.url = item_local.url.replace(" ", "%20") #sustituimos espacios por %20, por si acaso #logger.debug("Patron: " + patron + " url: " + item_local.url) @@ -1054,6 +1092,8 @@ def findvideos(item): #logger.debug(item_local) # VER vídeos, descargar vídeos un link, o múltiples links + data = scrapertools.find_single_match(data, '<div id="tab1" class="tab_content"(.*?<\/ul>(?:<div.*?>)?<\/div><\/div><\/div>)') #Seleccionar el bloque para evitar duplicados + host_dom = host.replace("https://", "").replace("http://", "").replace("www.", "") data = data.replace("http://tumejorserie.com/descargar/url_encript.php?link=", "(") data = re.sub(r'javascript:;" onClick="popup\("http:\/\/(?:www.)?' + host_dom + '\w{1,9}\/library\/include\/ajax\/get_modallinks.php\?links=', "", data) @@ -1066,7 +1106,7 @@ def findvideos(item): enlaces_ver = re.compile(patron, re.DOTALL).findall(data) enlaces_descargar = enlaces_ver #logger.debug(enlaces_ver) - + #Recorre todos los links de VER, si está permitido cnt_enl_ver = 1 cnt_enl_verif = 1 @@ -1100,7 +1140,7 @@ def findvideos(item): if verificar_enlaces_veronline != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_veronline or verificar_enlaces_veronline == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para cada link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_veronline_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1190,7 +1230,7 @@ def findvideos(item): if verificar_enlaces_descargas != 0: #Se quiere verificar si el link está activo? if cnt_enl_verif <= verificar_enlaces_descargas or verificar_enlaces_descargas == -1: #contador? #Llama a la subfunción de check_list_links(itemlist) para primer link de servidor - item_local.alive = servertools.check_video_link(enlace, servidor) #activo el link ? + item_local.alive = servertools.check_video_link(enlace, servidor, timeout=timeout) #activo el link ? if verificar_enlaces_descargas_validos: #Los links tienen que ser válidos para contarlos? if item_local.alive == "Ok": #Sí cnt_enl_verif += 1 #Movemos los contadores @@ -1232,9 +1272,10 @@ def findvideos(item): def episodios(item): logger.info() - #Renombramos el canal al nombre de clone elegido - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() + #Renombramos el canal al nombre de clone elegido. Actualizados URL + host = scrapertools.find_single_match(item.url, '(http.?\:\/\/(?:www.)?\w+\.\w+\/)') + #item.channel = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/') + item.category = scrapertools.find_single_match(item.url, 'http.?\:\/\/(?:www.)?(\w+)\.\w+\/').capitalize() itemlist = [] @@ -1255,7 +1296,7 @@ def episodios(item): data = '' try: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(item.url, timeout=timeout).data) patron = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern data_alt = '' if data: data_alt = scrapertools.get_match(data, patron) @@ -1276,7 +1317,7 @@ def episodios(item): if not data: #No se ha encontrado ningún canal activo para este vídeo itemlist.append(item.clone(action='', title="[COLOR yellow]" + item.channel.capitalize() + '[/COLOR]: Ningún canal NewPct1 activo')) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 01: EPISODIOS:. La Web no responde o la URL es erronea. Si la Web está activa, reportar el error con el log')) return itemlist #Busca y pre-carga todas las páginas de episodios que componen las serie, para obtener la url de cada página @@ -1312,7 +1353,7 @@ def episodios(item): break try: if not data: - data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page).data) + data = re.sub(r"\n|\r|\t|\s{2,}", "", httptools.downloadpage(page, timeout=timeout).data) data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8") data = data.replace("chapters", "buscar-list") #Compatibilidad con mispelisy.series.com pattern = '<ul class="%s">(.*?)</ul>' % "buscar-list" # item.pattern @@ -1321,7 +1362,7 @@ def episodios(item): raise except: logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / " + str(list_pages) + " / DATA: " + str(data)) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if "pelisyseries.com" in item.url: @@ -1331,7 +1372,7 @@ def episodios(item): matches = re.compile(pattern, re.DOTALL).findall(data) if not matches: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + data) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos #logger.debug("patron: " + pattern) @@ -1399,7 +1440,7 @@ def episodios(item): match = [m.groupdict() for m in r.finditer(info)][0] if not match: #error logger.error("ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web " + " / PATRON: " + pattern + " / DATA: " + info) - itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) + itemlist.append(item.clone(action='', title=item.category + ': ERROR 02: EPISODIOS: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos if match['season'] is None: match['season'] = season #Si no se encuentran valores, pero poner lo básico @@ -1449,8 +1490,6 @@ def episodios(item): if item_local.active: del item_local.active - if item_local.category: - del item_local.category if item_local.infoLabels['title']: del item_local.infoLabels['title'] item_local.context = "['buscar_trailer']" @@ -1467,6 +1506,8 @@ def episodios(item): del item_local.update_last if item_local.update_next: del item_local.update_next + if item_local.channel_host: + del item_local.channel_host itemlist.append(item_local.clone()) @@ -1501,9 +1542,6 @@ def actualizar_titulos(item): def search(item, texto): logger.info("search:" + texto) # texto = texto.replace(" ", "+") - - item.channel = channel_clone_name - if item.category: item.category = channel_clone_name.capitalize() try: item.post = "q=%s" % texto From dcc4b3d1d40c3e0df473bc29e284401b50c29c99 Mon Sep 17 00:00:00 2001 From: Kingbox <37674310+lopezvg@users.noreply.github.com> Date: Wed, 4 Jul 2018 14:41:27 +0200 Subject: [PATCH 27/37] GranTorrent y MejorTorrent: mejoras internas --- plugin.video.alfa/channels/grantorrent.py | 2 ++ plugin.video.alfa/channels/mejortorrent.py | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/plugin.video.alfa/channels/grantorrent.py b/plugin.video.alfa/channels/grantorrent.py index e4e4de76..597ad7b4 100644 --- a/plugin.video.alfa/channels/grantorrent.py +++ b/plugin.video.alfa/channels/grantorrent.py @@ -680,6 +680,8 @@ def episodios(item): del item_local.update_last if item_local.update_next: del item_local.update_next + if item_local.channel_host: + del item_local.channel_host #Verificamos el idioma por si encontramos algo if not item_local.language: diff --git a/plugin.video.alfa/channels/mejortorrent.py b/plugin.video.alfa/channels/mejortorrent.py index 50c29870..6f270d65 100755 --- a/plugin.video.alfa/channels/mejortorrent.py +++ b/plugin.video.alfa/channels/mejortorrent.py @@ -828,6 +828,21 @@ def episodios(item): item_local.action = "findvideos" item_local.contentType = "episode" item_local.extra = "episodios" + if item_local.library_playcounts: + del item_local.library_playcounts + if item_local.library_urls: + del item_local.library_urls + if item_local.path: + del item_local.path + if item_local.update_last: + del item_local.update_last + if item_local.update_next: + del item_local.update_next + if item_local.channel_host: + del item_local.channel_host + + item_local.title = '' + item_local.context = "['buscar_trailer']" item_local.url = urlparse.urljoin(host, scrapedurl) From 05f18490e5e7e7d08d270cdac298be415a30b8b5 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Wed, 4 Jul 2018 08:57:24 -0500 Subject: [PATCH 28/37] mp4upload: fix --- plugin.video.alfa/servers/mp4upload.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin.video.alfa/servers/mp4upload.py b/plugin.video.alfa/servers/mp4upload.py index 2efbcf56..83134cb1 100644 --- a/plugin.video.alfa/servers/mp4upload.py +++ b/plugin.video.alfa/servers/mp4upload.py @@ -18,6 +18,8 @@ def get_video_url(page_url, premium=False, user="", password="", video_password= data = data.replace("\\'", "'") media_url = scrapertools.find_single_match(data, '{type:"video/mp4",src:"([^"]+)"}') + if not media_url: + media_url = scrapertools.find_single_match(data, '"file":"([^"]+)') logger.info("media_url=" + media_url) video_urls = list() From 8f406aee767d38324f752efb2e959dd3962b02c2 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Wed, 4 Jul 2018 09:08:39 -0500 Subject: [PATCH 29/37] animeflv: fix --- plugin.video.alfa/channels/animeflv.py | 166 +++---------------------- 1 file changed, 19 insertions(+), 147 deletions(-) diff --git a/plugin.video.alfa/channels/animeflv.py b/plugin.video.alfa/channels/animeflv.py index 84b4fd07..14787bcc 100644 --- a/plugin.video.alfa/channels/animeflv.py +++ b/plugin.video.alfa/channels/animeflv.py @@ -1,9 +1,7 @@ # -*- coding: utf-8 -*- import re -import time import urlparse -import urllib from channels import renumbertools from core import httptools @@ -18,13 +16,10 @@ HOST = "https://animeflv.net/" def mainlist(item): logger.info() - itemlist = list() - itemlist.append(Item(channel=item.channel, action="novedades_episodios", title="Últimos episodios", url=HOST)) itemlist.append(Item(channel=item.channel, action="novedades_anime", title="Últimos animes", url=HOST)) itemlist.append(Item(channel=item.channel, action="listado", title="Animes", url=HOST + "browse?order=title")) - itemlist.append(Item(channel=item.channel, title="Buscar por:")) itemlist.append(Item(channel=item.channel, action="search", title=" Título")) itemlist.append(Item(channel=item.channel, action="search_section", title=" Género", url=HOST + "browse", @@ -35,9 +30,7 @@ def mainlist(item): extra="year")) itemlist.append(Item(channel=item.channel, action="search_section", title=" Estado", url=HOST + "browse", extra="status")) - itemlist = renumbertools.show_option(item.channel, itemlist) - return itemlist @@ -48,36 +41,29 @@ def search(item, texto): texto = texto.replace(" ", "+") post = "value=%s" % texto data = httptools.downloadpage(item.url, post=post).data - try: dict_data = jsontools.load(data) - for e in dict_data: if e["id"] != e["last_id"]: _id = e["last_id"] else: _id = e["id"] - url = "%sanime/%s/%s" % (HOST, _id, e["slug"]) title = e["title"] thumbnail = "%suploads/animes/covers/%s.jpg" % (HOST, e["id"]) new_item = item.clone(action="episodios", title=title, url=url, thumbnail=thumbnail) - if e["type"] != "movie": new_item.show = title new_item.context = renumbertools.context(item) else: new_item.contentType = "movie" new_item.contentTitle = title - itemlist.append(new_item) - except: import sys for line in sys.exc_info(): logger.error("%s" % line) return [] - return itemlist @@ -88,39 +74,30 @@ def search_section(item): data = re.sub(r"\n|\r|\t|\s{2}|-\s", "", data) patron = 'id="%s_select"[^>]+>(.*?)</select>' % item.extra data = scrapertools.find_single_match(data, patron) - matches = re.compile('<option value="([^"]+)">(.*?)</option>', re.DOTALL).findall(data) - for _id, title in matches: url = "%s?%s=%s&order=title" % (item.url, item.extra, _id) itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url, context=renumbertools.context(item))) - return itemlist def newest(categoria): itemlist = [] - if categoria == 'anime': itemlist = novedades_episodios(Item(url=HOST)) - return itemlist def novedades_episodios(item): logger.info() - data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t|\s{2}|-\s", "", data) data = scrapertools.find_single_match(data, '<h2>Últimos episodios</h2>.+?<ul class="ListEpisodios[^>]+>(.*?)</ul>') - matches = re.compile('<a href="([^"]+)"[^>]+>.+?<img src="([^"]+)".+?"Capi">(.*?)</span>' '<strong class="Title">(.*?)</strong>', re.DOTALL).findall(data) itemlist = [] - for url, thumbnail, str_episode, show in matches: - try: episode = int(str_episode.replace("Episodio ", "")) except ValueError: @@ -135,28 +112,21 @@ def novedades_episodios(item): new_item = Item(channel=item.channel, action="findvideos", title=title, url=url, show=show, thumbnail=thumbnail, fulltitle=title) - itemlist.append(new_item) - return itemlist def novedades_anime(item): logger.info() - data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t|\s{2}|-\s", "", data) data = scrapertools.find_single_match(data, '<ul class="ListAnimes[^>]+>(.*?)</ul>') - matches = re.compile('href="([^"]+)".+?<img src="([^"]+)".+?<span class=.+?>(.*?)</span>.+?<h3.+?>(.*?)</h3>.+?' '(?:</p><p>(.*?)</p>.+?)?</article></li>', re.DOTALL).findall(data) itemlist = [] - for url, thumbnail, _type, title, plot in matches: - url = urlparse.urljoin(HOST, url) thumbnail = urlparse.urljoin(HOST, thumbnail) - new_item = Item(channel=item.channel, action="episodios", title=title, url=url, thumbnail=thumbnail, fulltitle=title, plot=plot) if _type != "Película": @@ -165,173 +135,75 @@ def novedades_anime(item): else: new_item.contentType = "movie" new_item.contentTitle = title - itemlist.append(new_item) - return itemlist def listado(item): logger.info() - data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t|\s{2}|-\s", "", data) url_pagination = scrapertools.find_single_match(data, '<li class="active">.*?</li><li><a href="([^"]+)">') - data = scrapertools.find_multiple_matches(data, '<ul class="ListAnimes[^>]+>(.*?)</ul>') data = "".join(data) - matches = re.compile('<a href="([^"]+)">.+?<img src="([^"]+)".+?<span class=.+?>(.*?)</span>.+?<h3.*?>(.*?)</h3>' '.*?</p><p>(.*?)</p>', re.DOTALL).findall(data) - itemlist = [] - for url, thumbnail, _type, title, plot in matches: - url = urlparse.urljoin(HOST, url) thumbnail = urlparse.urljoin(HOST, thumbnail) - new_item = Item(channel=item.channel, action="episodios", title=title, url=url, thumbnail=thumbnail, fulltitle=title, plot=plot) - if _type == "Anime": new_item.show = title new_item.context = renumbertools.context(item) else: new_item.contentType = "movie" new_item.contentTitle = title - itemlist.append(new_item) - if url_pagination: url = urlparse.urljoin(HOST, url_pagination) title = ">> Pagina Siguiente" - itemlist.append(Item(channel=item.channel, action="listado", title=title, url=url)) - return itemlist def episodios(item): logger.info() itemlist = [] - data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t|\s{2}|-\s", "", data) - - # fix para renumbertools - item.show = scrapertools.find_single_match(data, '<h1 class="Title">(.*?)</h1>') - - if item.plot == "": - item.plot = scrapertools.find_single_match(data, 'Description[^>]+><p>(.*?)</p>') - - matches = re.compile('href="([^"]+)"><figure><img class="[^"]+" data-original="([^"]+)".+?</h3>' - '\s*<p>(.*?)</p>', re.DOTALL).findall(data) - - if matches: - for url, thumb, title in matches: - title = title.strip() - url = urlparse.urljoin(item.url, url) - # thumbnail = item.thumbnail - - try: - episode = int(scrapertools.find_single_match(title, "^.+?\s(\d+)$")) - except ValueError: - season = 1 - episode = 1 - else: - season, episode = renumbertools.numbered_for_tratk(item.channel, item.show, 1, episode) - - title = "%sx%s : %s" % (season, str(episode).zfill(2), item.title) - - itemlist.append(item.clone(action="findvideos", title=title, url=url, thumbnail=thumb, fulltitle=title, - fanart=item.thumbnail, contentType="episode")) - else: - # no hay thumbnail - matches = re.compile('<a href="(/ver/[^"]+)"[^>]+>(.*?)<', re.DOTALL).findall(data) - - for url, title in matches: - title = title.strip() - url = urlparse.urljoin(item.url, url) - thumb = item.thumbnail - - try: - episode = int(scrapertools.find_single_match(title, "^.+?\s(\d+)$")) - except ValueError: - season = 1 - episode = 1 - else: - season, episode = renumbertools.numbered_for_tratk(item.channel, item.show, 1, episode) - - title = "%sx%s : %s" % (season, str(episode).zfill(2), item.title) - - itemlist.append(item.clone(action="findvideos", title=title, url=url, thumbnail=thumb, fulltitle=title, - fanart=item.thumbnail, contentType="episode")) - + info = eval(scrapertools.find_single_match(data, 'anime_info = (.*?);')) + episodes = eval(scrapertools.find_single_match(data, 'var episodes = (.*?);')) + for episode in episodes: + url = '%s/ver/%s/%s-%s' % (HOST, episode[1], info[2], episode[0]) + title = '1x%s Episodio %s' % (episode[0], episode[0]) + itemlist.append(item.clone(title=title, url=url, action='findvideos', show=info[1])) + itemlist = itemlist[::-1] if config.get_videolibrary_support() and len(itemlist) > 0: itemlist.append(Item(channel=item.channel, title="Añadir esta serie a la videoteca", action="add_serie_to_library", extra="episodios")) - return itemlist def findvideos(item): logger.info() - itemlist = [] - data = re.sub(r"\n|\r|\t|\s{2}|-\s", "", httptools.downloadpage(item.url).data) - list_videos = scrapertools.find_multiple_matches(data, 'video\[\d\]\s=\s\'<iframe.+?src="([^"]+)"') - download_list = scrapertools.find_multiple_matches(data, 'href="http://ouo.io/s/y0d65LCP\?s=([^"]+)"') - for i in download_list: - list_videos.append(urllib.unquote_plus(i)) - aux_url = [] - cldup = False - for e in list_videos: - url_api = "https://s3.animeflv.com/check.php?server=%s&v=%s" - # izanagi, yourupload, hyperion - if e.startswith("https://s3.animeflv.com/embed"): - server, v = scrapertools.find_single_match(e, 'server=([^&]+)&v=(.*?)$') - data = httptools.downloadpage(url_api % (server, v)).data.replace("\\", "") - - if '{"error": "Por favor intenta de nuevo en unos segundos", "sleep": 3}' in data: - time.sleep(3) - data = httptools.downloadpage(url_api % (server, v)).data.replace("\\", "") - - if server != "hyperion": - url = scrapertools.find_single_match(data, '"file":"([^"]+)"') - if url: - itemlist.append(item.clone(title="Enlace encontrado en %s" % server, url=url, action="play")) - - else: - # pattern = '"direct":"([^"]+)"' - # url = scrapertools.find_single_match(data, pattern) - # itemlist.append(item.clone(title="Enlace encontrado en %s" % server, url=url, action="play")) - - pattern = '"label":([^,]+),"type":"video/mp4","file":"([^"]+)"' - matches = scrapertools.find_multiple_matches(data, pattern) - - video_urls = [] - for label, url in matches: - video_urls.append([label, "mp4", url]) - if video_urls: - video_urls.sort(key=lambda u: int(u[0])) - itemlist.append(item.clone(title="Enlace encontrado en %s" % server, action="play", - video_urls=video_urls)) - + download_list = scrapertools.find_multiple_matches(data, 'video\[\d+\] = \'<iframe .*?src="(.*?)"') + for url in download_list: + data = httptools.downloadpage(url).data + if 'izanagi' in url: + new_url = url.replace('embed', 'check') + new_data = httptools.downloadpage(new_url).data + url = scrapertools.find_single_match(new_data, '"file":"(.*?)"') else: - if e.startswith("https://cldup.com") and not cldup: - itemlist.append(item.clone(title="Enlace encontrado en Cldup", action="play", url=e)) - cldup = True - aux_url.append(e) - - itemlist.extend(servertools.find_video_items(data=",".join(aux_url))) - for videoitem in itemlist: - videoitem.fulltitle = item.fulltitle - videoitem.channel = item.channel - videoitem.thumbnail = item.thumbnail - + url = scrapertools.find_single_match(data, 'var redir = "(.*?)"') + if url != '': + url = url.replace("\\","") + itemlist.append(item.clone(title='%s', url=url, action='play')) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server) return itemlist From 97ff5124bba4842f55ed04e04b17ac11776116d6 Mon Sep 17 00:00:00 2001 From: pipcat <pip@pipcat.com> Date: Wed, 4 Jul 2018 16:40:46 +0200 Subject: [PATCH 30/37] Quitado texto de debug --- plugin.video.alfa/channels/animeyt.py | 4 ---- plugin.video.alfa/channels/pelispedia.py | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/plugin.video.alfa/channels/animeyt.py b/plugin.video.alfa/channels/animeyt.py index 85925a62..40e78e1a 100644 --- a/plugin.video.alfa/channels/animeyt.py +++ b/plugin.video.alfa/channels/animeyt.py @@ -32,10 +32,6 @@ def mainlist(item): itemlist = renumbertools.show_option(item.channel, itemlist) - # ~ prova = 'EIpStovt0/tFerZM4pviHBzddH308TWRR41XnHv9N4tUNih6r+GjCDa/cV1uVUQXEmZd1Hsu2ABzESzBMGiK6XUdRgYZYHImmrIWcn3tfYPCuSWBc2UgwxUtR+WOsov6YiGM5AdgJGFunoN' - # ~ aux = gktools.decode_rijndael(prova, preIV = 'b3512f4972d314da9', key='3e1a854e7d5835ab99d99a29afec8bbb') - # ~ itemlist.append(Item(channel=item.channel, title=aux, action="novedades", url=HOST)) - return itemlist diff --git a/plugin.video.alfa/channels/pelispedia.py b/plugin.video.alfa/channels/pelispedia.py index 98cafb6d..4c7b65b8 100644 --- a/plugin.video.alfa/channels/pelispedia.py +++ b/plugin.video.alfa/channels/pelispedia.py @@ -556,7 +556,7 @@ def play(item): url = item.url.replace('/embed/', '/stream/') + '/' + token # 3- Descargar página - data = gktools.get_data_with_cookie(url, item.url, ck) + data = gktools.get_data_with_cookie(url, ck, item.url) # 4- Extraer enlaces url = scrapertools.find_single_match(data, '<meta (?:name|property)="og:url" content="([^"]+)"') From 72a69458a971a75a95e2f277016651fcb90e1b0f Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Wed, 4 Jul 2018 10:04:16 -0500 Subject: [PATCH 31/37] tvvip: fix videoteca --- plugin.video.alfa/channels/tvvip.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/plugin.video.alfa/channels/tvvip.py b/plugin.video.alfa/channels/tvvip.py index 4b47bd66..b23f092d 100644 --- a/plugin.video.alfa/channels/tvvip.py +++ b/plugin.video.alfa/channels/tvvip.py @@ -3,7 +3,6 @@ import os import re import sys -import unicodedata import urllib import time @@ -15,10 +14,10 @@ from core import servertools from core import tmdb from core.item import Item from platformcode import config, logger -from platformcode import platformtools host = "http://tv-vip.com" + def mainlist(item): logger.info() item.viewmode = "movie" @@ -511,13 +510,13 @@ def series_library(item): # Funcion unicamente para añadir/actualizar series a la libreria lista_episodios = [] show = item.show.strip() - data_serie = anti_cloudflare(item.url, host=host, headers=headers) + data_serie = httptools.downloadpage(item.url).data data_serie = jsontools.load(data_serie) # Para series que en la web se listan divididas por temporadas if data_serie["sortedPlaylistChilds"]: for season_name in data_serie["sortedPlaylistChilds"]: url_season = host + "/json/playlist/%s/index.json" % season_name['id'] - data = anti_cloudflare(url_season, host=host, headers=headers) + data = httptools.downloadpage(url_season).data data = jsontools.load(data) if data["sortedRepoChilds"]: for child in data["sortedRepoChilds"]: @@ -623,7 +622,7 @@ def listas(item): logger.info() # Para añadir listas a la videoteca en carpeta CINE itemlist = [] - data = anti_cloudflare(item.url, host=host, headers=headers) + data = httptools.downloadpage(item.url).data data = jsontools.load(data) head = header_string + get_cookie_value() for child in data["sortedRepoChilds"]: From fd81998d3b6f755a508a79fd5502d0fa3e0d096a Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Wed, 4 Jul 2018 10:05:03 -0500 Subject: [PATCH 32/37] descargasmix: desactivado, web no funciona --- plugin.video.alfa/channels/descargasmix.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin.video.alfa/channels/descargasmix.json b/plugin.video.alfa/channels/descargasmix.json index 1955280c..a7635136 100644 --- a/plugin.video.alfa/channels/descargasmix.json +++ b/plugin.video.alfa/channels/descargasmix.json @@ -2,7 +2,7 @@ "id": "descargasmix", "name": "DescargasMIX", "language": ["cast", "lat"], - "active": true, + "active": false, "adult": false, "thumbnail": "descargasmix.png", "banner": "descargasmix.png", @@ -77,4 +77,4 @@ "visible": true } ] -} \ No newline at end of file +} From f82e9120a1ddbb9d0ee9586b9436663d34cd8dd2 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Wed, 4 Jul 2018 10:06:18 -0500 Subject: [PATCH 33/37] guaridavalencianista: contenido no es para Alfa --- plugin.video.alfa/channels/guaridavalencianista.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin.video.alfa/channels/guaridavalencianista.json b/plugin.video.alfa/channels/guaridavalencianista.json index e712f441..30e2e9d2 100755 --- a/plugin.video.alfa/channels/guaridavalencianista.json +++ b/plugin.video.alfa/channels/guaridavalencianista.json @@ -1,7 +1,7 @@ { "id": "guaridavalencianista", "name": "La Guarida valencianista", - "active": true, + "active": false, "adult": false, "language": ["cast"], "thumbnail": "guaridavalencianista.png", @@ -9,4 +9,4 @@ "categories": [ "documentary" ] -} \ No newline at end of file +} From d1c2778dd137726ad68d37eb8cb13ef4aa7652cf Mon Sep 17 00:00:00 2001 From: Kingbox <37674310+lopezvg@users.noreply.github.com> Date: Wed, 4 Jul 2018 18:25:16 +0200 Subject: [PATCH 34/37] MejorTorrent: mejora interna --- plugin.video.alfa/channels/mejortorrent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.video.alfa/channels/mejortorrent.py b/plugin.video.alfa/channels/mejortorrent.py index 6f270d65..8fc53494 100755 --- a/plugin.video.alfa/channels/mejortorrent.py +++ b/plugin.video.alfa/channels/mejortorrent.py @@ -495,7 +495,7 @@ def listado_busqueda(item): matches += re.compile(patron, re.DOTALL).findall(data) matches_cnt = len(matches) - if not matches and not 'Se han encontrado <b>0</b> resultados.' in data: #error + if not matches and not 'Se han encontrado <b>0</b> resultados.' and not "href='/juego-descargar-torrent" in data: #error logger.error("ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web " + " / PATRON: " + patron + " / DATA: " + data) itemlist.append(item.clone(action='', title=item.channel.capitalize() + ': ERROR 02: LISTADO_BUSQUEDA: Ha cambiado la estructura de la Web. Reportar el error con el log')) return itemlist #si no hay más datos, algo no funciona, pintamos lo que tenemos From edb8b2a149485a99e2c8a6206eebb3a2576eca7c Mon Sep 17 00:00:00 2001 From: pipcat <pip@pipcat.com> Date: Wed, 4 Jul 2018 19:32:59 +0200 Subject: [PATCH 35/37] Correccion en buscador --- plugin.video.alfa/channels/peliculasdk.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin.video.alfa/channels/peliculasdk.py b/plugin.video.alfa/channels/peliculasdk.py index dd5fcb50..689123b5 100644 --- a/plugin.video.alfa/channels/peliculasdk.py +++ b/plugin.video.alfa/channels/peliculasdk.py @@ -124,8 +124,8 @@ def buscador(item): titulo = '%s [%s][%s]' % (scrapedtitle, ','.join([a[:3] for a in audios]), calidad) - # Parece que las pelis de adultos se mezclan en la búsqueda y lo único que las diferencia es que no tienen Calidad - if calidades or __adult_mode__ != 0: + # Parece que las pelis de adultos se mezclan en la búsqueda y lo único que las diferencia es que no tienen Calidad y Audios + if (calidad and audios) or __adult_mode__ != 0: itemlist.append(Item(channel=item.channel, action="findvideos", url=scrapedurl, title=titulo, contentTitle=scrapedtitle, From 023aae84959a56bacc91c482d2af6aedf9938467 Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Wed, 4 Jul 2018 12:42:15 -0500 Subject: [PATCH 36/37] areadocumental: fix --- plugin.video.alfa/channels/areadocumental.py | 61 +++++++++++++++----- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/plugin.video.alfa/channels/areadocumental.py b/plugin.video.alfa/channels/areadocumental.py index b360e078..f43600d2 100644 --- a/plugin.video.alfa/channels/areadocumental.py +++ b/plugin.video.alfa/channels/areadocumental.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import urllib +import re from core import httptools from core import scrapertools @@ -25,7 +26,7 @@ def mainlist(item): itemlist.append(item.clone(title="Novedades", action="entradas", url= host + "/resultados-reciente.php?buscar=&genero=", fanart="http://i.imgur.com/Q7fsFI6.png")) - itemlist.append(item.clone(title="Destacados", action="entradas", + itemlist.append(item.clone(title="Destacados", action="destacados", url= host + "/resultados-destacados.php?buscar=&genero=", fanart="http://i.imgur.com/Q7fsFI6.png")) itemlist.append(item.clone(title="Categorías", action="cat", url= host + "/index.php", @@ -37,6 +38,12 @@ def mainlist(item): return itemlist +def get_source(url): + logger.info() + data = httptools.downloadpage(url).data + data = re.sub(r'\n|\r|\t| |<br>|\s{2,}|"|\(|\)', "", data) + return data + def configuracion(item): from platformcode import platformtools @@ -95,22 +102,19 @@ def indice(item): def cat(item): logger.info() itemlist = [] - data = httptools.downloadpage(item.url).data - bloque = scrapertools.find_single_match(data, '<ul class="menu">(.*?)</nav>') - matches = scrapertools.find_multiple_matches(bloque, "<li>.*?<a href='([^']+)'.*?>(.*?)</a>") - for scrapedurl, scrapedtitle in matches: - scrapedurl = host + "/" + scrapedurl - if not "span" in scrapedtitle: - scrapedtitle = "[COLOR gold] **" + scrapedtitle + "**[/COLOR]" - itemlist.append(item.clone(action="entradas", title=scrapedtitle, url=scrapedurl)) - else: - scrapedtitle = scrapertools.htmlclean(scrapedtitle) - itemlist.append(item.clone(action="entradas", title=scrapedtitle, url=scrapedurl)) + data = get_source(item.url) + bloques = scrapertools.find_multiple_matches(data, '</li><li class=dropdown>.*?</ul>') + for bloque in bloques: + matches = scrapertools.find_multiple_matches(bloque, "<li><a href=(.*?)>(.*?)<") + for scrapedurl, scrapedtitle in matches: + scrapedurl = host + "/" + scrapedurl + if not "TODO" in scrapedtitle: + itemlist.append(item.clone(action="entradas", title=scrapedtitle, url=scrapedurl)) return itemlist -def entradas(item): +def destacados(item): logger.info() itemlist = [] item.text_color = color2 @@ -161,6 +165,37 @@ def entradas(item): return itemlist + +def entradas(item): + logger.info() + itemlist = [] + item.text_color = color2 + + data = get_source(item.url) + + patron = 'class=imagen.*?href=(.*?)><img.*?src=(.*?) alt=.*?title=(.*?)/>.*?</h2>(\d{4}) (.*?)<.*?space>(.*?)<' + matches = scrapertools.find_multiple_matches(data, patron) + for scrapedurl, scrapedthumbnail, scrapedtitle, year, genero, scrapedplot in matches: + infolab = {'plot': scrapedplot, 'genre': genero} + scrapedurl = host + "/" + scrapedurl + scrapedthumbnail = host +'/'+ scrapedthumbnail + title = scrapedtitle + if not year.isspace() and year != "": + infolab['year'] = int(year) + + itemlist.append(item.clone(action="findvideos", title=title, fulltitle=title, + url=scrapedurl, thumbnail=scrapedthumbnail, infoLabels=infolab, contentTitle = + title)) + + next_page = scrapertools.find_single_match(data, '<a class=last>.*?</a></li><li><a href=(.*?)>.*?</a>') + next_page = scrapertools.htmlclean(next_page) + if next_page: + itemlist.append(item.clone(action="entradas", title=">> Página Siguiente", url=host + next_page, + text_color=color3)) + + return itemlist + + def findvideos(item): logger.info() itemlist = [] From 96ffc3d7bb64ed39329ceda7a16605c71b56a7cf Mon Sep 17 00:00:00 2001 From: Intel1 <25161862+Intel11@users.noreply.github.com> Date: Wed, 4 Jul 2018 14:05:04 -0500 Subject: [PATCH 37/37] cuenvana3: nuevo server --- plugin.video.alfa/channels/cuevana3.json | 69 ++++++++ plugin.video.alfa/channels/cuevana3.py | 200 +++++++++++++++++++++++ 2 files changed, 269 insertions(+) create mode 100644 plugin.video.alfa/channels/cuevana3.json create mode 100644 plugin.video.alfa/channels/cuevana3.py diff --git a/plugin.video.alfa/channels/cuevana3.json b/plugin.video.alfa/channels/cuevana3.json new file mode 100644 index 00000000..9734b502 --- /dev/null +++ b/plugin.video.alfa/channels/cuevana3.json @@ -0,0 +1,69 @@ +{ + "id": "cuevana3", + "name": "Cuevana 3", + "active": true, + "adult": false, + "language": ["lat", "cast"], + "thumbnail": "http://www.cuevana3.com/wp-content/uploads/2017/08/logo-v10.png", + "banner": "", + "version": 1, + "categories": [ + "movies" + ], + "settings": [ + { + "id": "include_in_global_search", + "type": "bool", + "label": "Incluir en busqueda global", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "filter_languages", + "type": "list", + "label": "Mostrar enlaces en idioma...", + "default": 0, + "enabled": true, + "visible": true, + "lvalues": [ + "No filtrar", + "LAT", + "CAST", + "VOSE" + ] + }, + { + "id": "include_in_newest_peliculas", + "type": "bool", + "label": "Incluir en Novedades - Peliculas", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "include_in_newest_infantiles", + "type": "bool", + "label": "Incluir en Novedades - Infantiles", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "include_in_newest_terror", + "type": "bool", + "label": "Incluir en Novedades - Terror", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "include_in_newest_documentales", + "type": "bool", + "label": "Incluir en Novedades - Documentales", + "default": true, + "enabled": true, + "visible": true + } + ] +} diff --git a/plugin.video.alfa/channels/cuevana3.py b/plugin.video.alfa/channels/cuevana3.py new file mode 100644 index 00000000..8265426b --- /dev/null +++ b/plugin.video.alfa/channels/cuevana3.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +# -*- Channel Cuevana 3 -*- +# -*- Created for Alfa-addon -*- +# -*- By the Alfa Develop Group -*- + +import re +import urllib +from channelselector import get_thumb +from core import httptools +from core import scrapertools +from core import servertools +from core import tmdb +from core.item import Item +from platformcode import config, logger +from channels import autoplay +from channels import filtertools + + +host = 'http://www.cuevana3.com/' + +IDIOMAS = {'Latino': 'LAT', 'Español': 'CAST', 'Subtitulado':'VOSE'} +list_language = IDIOMAS.values() +list_quality = [] +list_servers = ['fastplay', 'rapidvideo', 'streamplay', 'flashx', 'streamito', 'streamango', 'vidoza'] + + +def mainlist(item): + logger.info() + + autoplay.init(item.channel, list_servers, list_quality) + + itemlist = list() + itemlist.append(item.clone(title="Ultimas", action="list_all", url=host, thumbnail=get_thumb('last', auto=True))) + itemlist.append(item.clone(title="Generos", action="section", section='genre', + thumbnail=get_thumb('genres', auto=True))) + itemlist.append(item.clone(title="Castellano", action="list_all", url= host+'?s=Español', + thumbnail=get_thumb('audio', auto=True))) + itemlist.append(item.clone(title="Latino", action="list_all", url=host + '?s=Latino', + thumbnail=get_thumb('audio', auto=True))) + itemlist.append(item.clone(title="VOSE", action="list_all", url=host + '?s=Subtitulado', + thumbnail=get_thumb('audio', auto=True))) + itemlist.append(item.clone(title="Alfabetico", action="section", section='alpha', + thumbnail=get_thumb('alphabet', auto=True))) + itemlist.append(item.clone(title="Buscar", action="search", url=host+'?s=', + thumbnail=get_thumb('search', auto=True))) + + autoplay.show_option(item.channel, itemlist) + + return itemlist + + +def get_source(url): + logger.info() + data = httptools.downloadpage(url).data + data = re.sub(r'"|\n|\r|\t| |<br>|\s{2,}', "", data) + return data + + +def list_all(item): + logger.info() + itemlist = [] + + try: + data = get_source(item.url) + if item.section == 'alpha': + patron = '<span class=Num>\d+.*?<a href=(.*?) class.*?' + patron += 'src=(.*?) class.*?<strong>(.*?)</strong>.*?<td>(\d{4})</td>' + else: + patron = '<article id=post-.*?<a href=(.*?)>.*?src=(.*?) alt=.*?' + patron += '<h2 class=Title>(.*?)<\/h2>.*?<span class=Year>(.*?)<\/span>' + data = get_source(item.url) + matches = re.compile(patron, re.DOTALL).findall(data) + + for scrapedurl, scrapedthumbnail, scrapedtitle, year in matches: + + url = scrapedurl + if "|" in scrapedtitle: + scrapedtitle= scrapedtitle.split("|") + contentTitle = scrapedtitle[0].strip() + else: + contentTitle = scrapedtitle + + contentTitle = re.sub('\(.*?\)','', contentTitle) + + title = '%s [%s]'%(contentTitle, year) + thumbnail = 'http:'+scrapedthumbnail + itemlist.append(item.clone(action='findvideos', + title=title, + url=url, + thumbnail=thumbnail, + contentTitle=contentTitle, + infoLabels={'year':year} + )) + tmdb.set_infoLabels_itemlist(itemlist, True) + + # Paginación + + url_next_page = scrapertools.find_single_match(data,'<a class=next.*?href=(.*?)>') + if url_next_page: + itemlist.append(item.clone(title="Siguiente >>", url=url_next_page, action='list_all', section=item.section)) + except: + pass + return itemlist + +def section(item): + logger.info() + itemlist = [] + + data = get_source(host) + + action = 'list_all' + if item.section == 'quality': + patron = 'menu-item-object-category.*?menu-item-\d+><a href=(.*?)>(.*?)<\/a>' + elif item.section == 'genre': + patron = 'category menu-item-\d+><a href=(http:.*?)>(.*?)</a>' + elif item.section == 'year': + patron = 'custom menu-item-15\d+><a href=(.*?\?s.*?)>(\d{4})<\/a><\/li>' + elif item.section == 'alpha': + patron = '<li><a href=(.*?letter.*?)>(.*?)</a>' + action = 'list_all' + matches = re.compile(patron, re.DOTALL).findall(data) + + for data_one, data_two in matches: + + url = data_one + title = data_two + if title != 'Ver más': + new_item = Item(channel=item.channel, title= title, url=url, action=action, section=item.section) + itemlist.append(new_item) + + return itemlist + + +def findvideos(item): + logger.info() + + itemlist = [] + data = get_source(item.url) + patron = 'domain=(.*?) class=.*?><span>.*?</span>.*?<span>\d+ - (.*?) - (.*?)</span>' + matches = re.compile(patron, re.DOTALL).findall(data) + for url, language, quality in matches: + if url != '' and 'youtube' not in url: + itemlist.append(item.clone(title='%s', url=url, language=IDIOMAS[language], quality=quality, action='play')) + + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % '%s [%s] [%s]'%(i.server.capitalize(), + i.language, i.quality)) + tmdb.set_infoLabels_itemlist(itemlist, True) + try: + itemlist.append(trailer) + except: + pass + + # Requerido para FilterTools + itemlist = filtertools.get_links(itemlist, item, list_language) + + # Requerido para AutoPlay + + autoplay.start(itemlist, item) + + if config.get_videolibrary_support() and len(itemlist) > 0 and item.extra != 'findvideos': + itemlist.append( + Item(channel=item.channel, title='[COLOR yellow]Añadir esta pelicula a la videoteca[/COLOR]', url=item.url, + action="add_pelicula_to_library", extra="findvideos", contentTitle=item.contentTitle)) + + + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "+") + item.url = item.url + texto + + if texto != '': + return list_all(item) + else: + return [] + + +def newest(categoria): + logger.info() + itemlist = [] + item = Item() + try: + if categoria == 'infantiles': + item.url = host+'/category/animacion' + elif categoria == 'terror': + item.url = host+'/category/terror' + elif categoria == 'documentales': + item.url = host+'/category/documental' + itemlist = list_all(item) + if itemlist[-1].title == 'Siguiente >>': + itemlist.pop() + except: + import sys + for line in sys.exc_info(): + logger.error("{0}".format(line)) + return [] + + return itemlist