From 07fc210cee8ec65a8f05e3d1bfa6adf3b6282734 Mon Sep 17 00:00:00 2001 From: pipcat Date: Wed, 13 Jun 2018 16:23:36 +0200 Subject: [PATCH] correccion pelispedia y animeyt con nuevo gktools --- plugin.video.alfa/channels/animeyt.py | 38 +-- plugin.video.alfa/channels/pelispedia.py | 169 +------------ plugin.video.alfa/lib/gktools.py | 297 +++++++++++++++++++++++ 3 files changed, 323 insertions(+), 181 deletions(-) create mode 100644 plugin.video.alfa/lib/gktools.py diff --git a/plugin.video.alfa/channels/animeyt.py b/plugin.video.alfa/channels/animeyt.py index 449ccd9d..c8810dca 100644 --- a/plugin.video.alfa/channels/animeyt.py +++ b/plugin.video.alfa/channels/animeyt.py @@ -11,6 +11,8 @@ from core.item import Item from core import tmdb from platformcode import config,logger +import gktools + __modo_grafico__ = config.get_setting('modo_grafico', 'animeyt') HOST = "http://animeyt.tv/" @@ -138,7 +140,7 @@ def episodios(item): matches = scrapertools.find_multiple_matches(data, patron) for url, scrapedtitle, episode in matches: - + season = 1 episode = int(episode) season, episode = renumbertools.numbered_for_tratk(item.channel, scrapedtitle, season, episode) @@ -158,16 +160,20 @@ def findvideos(item): data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t| |
", "", data) - patron = 'Player\("(.*?)"' + # ~ patron = 'Player\("(.*?)"' + patron = 'iframe src="([^"]*)"' matches = scrapertools.find_multiple_matches(data, patron) for url in matches: - if "cldup" in url: - title = "Opcion Cldup" - if "chumi" in url: - title = "Opcion Chumi" - itemlist.append(item.clone(channel=item.channel, folder=False, title=title, action="play", url=url)) + 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: @@ -176,16 +182,18 @@ def findvideos(item): return itemlist -def player(item): +def play(item): logger.info() itemlist = [] + + if 'https://s2.animeyt.tv/rakuten.php?' in item.url: + itemlist = gktools.gk_play(item) - data = httptools.downloadpage(item.url, add_referer=True).data - data = re.sub(r"\n|\r|\t| |
", "", data) - - url = scrapertools.find_single_match(data, 'sources: \[{file:\'(.*?)\'') - - itemlist = servertools.find_video_items(data=data) - + # PENDIENTE ANALIZAR DEMÁS CASOS... + # ~ else: + # ~ headers = {'Referer': item.referer} + # ~ resp = httptools.downloadpage(item.url, headers=headers, cookies=False) + # ~ with open('animeyt-play-%s.html' % item.title, 'w') as f: f.write(resp.data); f.close() + return itemlist diff --git a/plugin.video.alfa/channels/pelispedia.py b/plugin.video.alfa/channels/pelispedia.py index 77ecaa34..ab21b721 100644 --- a/plugin.video.alfa/channels/pelispedia.py +++ b/plugin.video.alfa/channels/pelispedia.py @@ -16,6 +16,8 @@ from platformcode import config, logger from platformcode import platformtools from core import filetools +import gktools + __channel__ = "pelispedia" CHANNEL_HOST = "http://www.pelispedia.tv/" @@ -510,98 +512,12 @@ def findvideos(item): def play(item): logger.info("url=%s" % item.url) - itemlist = [] - if item.url.startswith("https://pelispedia.video/v.php"): + itemlist = gktools.gk_play(item) - headers = {'Referer': item.referer} - resp = httptools.downloadpage(item.url, headers=headers, cookies=False) - - for h in resp.headers: - ck = scrapertools.find_single_match(resp.headers[h], '__cfduid=([^;]*)') - if ck: - 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]) - - break - - - else: - itemlist = servertools.find_video_items(data=item.url) - for videoitem in itemlist: - videoitem.title = item.title - videoitem.channel = __channel__ - - logger.info("retorna itemlist: %s" % itemlist) return itemlist - # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def obtener_data(url, referer=''): @@ -665,82 +581,3 @@ def decodificar_cookie(data): g = eval(l1) return eval(l2).replace(";path=/;max-age=86400", "") - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -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 - block = None - hasher = hashlib.new(hash_algorithm) - while number_of_derived_words < target_key_size: - if block is not None: - hasher.update(block) - - hasher.update(passwd) - hasher.update(salt) - block = hasher.digest() - hasher = hashlib.new(hash_algorithm) - - for i in range(1, iterations): - hasher.update(block) - block = hasher.digest() - hasher = hashlib.new(hash_algorithm) - - derived_bytes += block[0: min(len(block), (target_key_size - number_of_derived_words) * 4)] - - number_of_derived_words += len(block)/4 - - return { - "key": derived_bytes[0: key_size * 4], - "iv": derived_bytes[key_size * 4:] - } - -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 - - kdf = evpKDF(password, salt) - - try: # Intentar con librería AES del sistema - from Crypto.Cipher import AES - cipherSpec = AES.new(kdf['key'], AES.MODE_CBC, iv) - except: # Si falla intentar con librería del addon - import jscrypto - cipherSpec = jscrypto.new(kdf['key'], jscrypto.MODE_CBC, iv) - ciphertext = cipherSpec.encrypt(paddedPlaintext) - - return json.dumps({'ct': base64.b64encode(ciphertext), 'iv': iv.encode("hex"), 's': salt.encode("hex")}, sort_keys=True, separators=(',', ':')) - -def generar_token(gsv, pwd): - txt = obtener_cripto(pwd, gsv) - - _0x382d28 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' - - valors = [0, 0, 0] - cicle = 0 - retorn = '' - for ch in txt: - valors[cicle] = ord(ch) - cicle += 1 - if cicle == 3: - primer = _0x382d28[valors[0] >> 0x2] - segon = _0x382d28[((valors[0] & 0x3) << 0x4) | (valors[1] >> 0x4)] - tercer = _0x382d28[((valors[1] & 0xf) << 0x2) | (valors[2] >> 0x6)] - quart = _0x382d28[valors[2] & 0x3f] - retorn += primer + segon + tercer + quart - - valors = [0, 0, 0] - cicle = 0 - - return retorn diff --git a/plugin.video.alfa/lib/gktools.py b/plugin.video.alfa/lib/gktools.py new file mode 100644 index 00000000..c71c0909 --- /dev/null +++ b/plugin.video.alfa/lib/gktools.py @@ -0,0 +1,297 @@ +# -*- coding: utf-8 -*- + +''' +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 + +A partir de aquí 2 opciones: + +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 + +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. + +''' + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import urlparse +from core import httptools +from core import scrapertools +# ~ from platformcode import logger + +def gk_play(item): + + 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 + + # 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]) + + + 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' + 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]) + + + return itemlist + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Correcciones en las urls finales obtenidas +# ------------------------------------------ +def corregir_url(url, referer): + url = url.replace('\/', '/') + if 'chomikuj.pl/' in url: url += "|Referer=%s" % referer + return url + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +# Generar un token válido a partir de un texto y una clave +# -------------------------------------------------------- + +# gsv: google-site-verification, obtenido de '> 0x2] + segon = _0x382d28[((valors[0] & 0x3) << 0x4) | (valors[1] >> 0x4)] + tercer = _0x382d28[((valors[1] & 0xf) << 0x2) | (valors[2] >> 0x6)] + quart = _0x382d28[valors[2] & 0x3f] + retorn += primer + segon + tercer + quart + + valors = [0, 0, 0] + cicle = 0 + + return retorn + + +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 + + kdf = evpKDF(password, salt) + + try: # Intentar con librería AES del sistema + from Crypto.Cipher import AES + cipherSpec = AES.new(kdf['key'], AES.MODE_CBC, iv) + except: # Si falla intentar con librería del addon + import jscrypto + cipherSpec = jscrypto.new(kdf['key'], jscrypto.MODE_CBC, iv) + ciphertext = cipherSpec.encrypt(paddedPlaintext) + + return json.dumps({'ct': base64.b64encode(ciphertext), 'iv': iv.encode("hex"), 's': salt.encode("hex")}, sort_keys=True, separators=(',', ':')) + + +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 + block = None + hasher = hashlib.new(hash_algorithm) + while number_of_derived_words < target_key_size: + if block is not None: + hasher.update(block) + + hasher.update(passwd) + hasher.update(salt) + block = hasher.digest() + hasher = hashlib.new(hash_algorithm) + + for i in range(1, iterations): + hasher.update(block) + block = hasher.digest() + hasher = hashlib.new(hash_algorithm) + + derived_bytes += block[0: min(len(block), (target_key_size - number_of_derived_words) * 4)] + + number_of_derived_words += len(block)/4 + + return { + "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]