From ff38e125ca3731b9619da5b1471b0019bed585fe Mon Sep 17 00:00:00 2001 From: Arjix <53124886+ArjixWasTaken@users.noreply.github.com> Date: Fri, 20 Aug 2021 18:58:51 +0300 Subject: [PATCH] Update kwik.py --- anime_downloader/extractors/kwik.py | 159 +++++++++++++++++++--------- 1 file changed, 108 insertions(+), 51 deletions(-) diff --git a/anime_downloader/extractors/kwik.py b/anime_downloader/extractors/kwik.py index 3cb93f9..dab6ca4 100644 --- a/anime_downloader/extractors/kwik.py +++ b/anime_downloader/extractors/kwik.py @@ -1,65 +1,122 @@ -import logging -from platform import node -import re -import subprocess +from base64 import b64decode import requests -import tempfile +import logging +import re from anime_downloader.extractors.base_extractor import BaseExtractor -from anime_downloader.sites.helpers.request import temp_dir from anime_downloader.sites import helpers -from anime_downloader import util -from anime_downloader.util import eval_in_node from subprocess import CalledProcessError +from anime_downloader import util logger = logging.getLogger(__name__) class Kwik(BaseExtractor): - '''Extracts video url from kwik pages, Kwik has some `security` - which allows to access kwik pages when only referred by something - and the kwik video stream when referred through the corresponding - kwik video page. - ''' + YTSM = re.compile(r"ysmm = '([^']+)") + + KWIK_PARAMS_RE = re.compile(r'\("(\w+)",\d+,"(\w+)",(\d+),(\d+),\d+\)') + KWIK_D_URL = re.compile(r'action="([^"]+)"') + KWIK_D_TOKEN = re.compile(r'value="([^"]+)"') + + CHARACTER_MAP = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" + + def get_string(self, content: str, s1: int, s2: int) -> str: + slice_2 = self.CHARACTER_MAP[0:s2] + + acc = 0 + for n, i in enumerate(content[::-1]): + acc += int(i if i.isdigit() else 0) * s1**n + + k = '' + while acc > 0: + k = slice_2[int(acc % s2)] + k + acc = (acc - (acc % s2)) / s2 + + return k or '0' + + def decrypt(self, full_string: str, key: str, v1: int, v2: int) -> str: + v1, v2 = int(v1), int(v2) + r, i = "", 0 + + while i < len(full_string): + s = "" + while (full_string[i] != key[v2]): + s += full_string[i] + i += 1 + j = 0 + while j < len(key): + s = s.replace(key[j], str(j)) + j += 1 + r += chr(int(self.get_string(s, v2, 10)) - v1) + i += 1 + return r + + def decode_adfly(self, coded_key: str) -> str: + r, j = '', '' + for n, l in enumerate(coded_key): + if not n % 2: + r += l + else: + j = l + j + + encoded_uri = list(r + j) + numbers = ((i, n) for i, n in enumerate(encoded_uri) if str.isdigit(n)) + for first, second in zip(numbers, numbers): + xor = int(first[1]) ^ int(second[1]) + if xor < 10: + encoded_uri[first[0]] = str(xor) + + return b64decode(("".join(encoded_uri)).encode("utf-8") + )[16:-16].decode('utf-8', errors='ignore') + + def bypass_adfly(self, adfly_url): + session = requests.session() + + response_code = 302 + while response_code != 200: + adfly_content = session.get( + session.get( + adfly_url, + allow_redirects=False).headers.get('location'), + allow_redirects=False) + response_code = adfly_content.status_code + return self.decode_adfly(self.YTSM.search(adfly_content.text).group(1)) + + def get_stream_url_from_kwik(self, adfly_url): + session = requests.session() + + f_content = requests.get( + self.bypass_adfly(adfly_url), + headers={ + 'referer': 'https://kwik.cx/' + } + ) + decrypted = self.decrypt( + * + self.KWIK_PARAMS_RE.search( + f_content.text + ).group( + 1, 2, + 3, 4 + ) + ) + + code = 419 + while code != 302: + content = session.post( + self.KWIK_D_URL.search(decrypted).group(1), + allow_redirects=False, + data={ + '_token': self.KWIK_D_TOKEN.search(decrypted).group(1)}, + headers={ + 'referer': str(f_content.url), + 'cookie': f_content.headers.get('set-cookie')}) + code = content.status_code + + return content.headers.get('location') def _get_data(self): - ld = logger.debug - # Kwik servers don't have direct link access you need to be referred - # from somewhere, I will just use the url itself. We then - # have to rebuild the url. Hopefully kwik doesn't block this too - - # Necessary - - headers = {"Referer": "https://kwik.cx/"} - - res = requests.get(self.url, headers=headers) - - evalText = helpers.soupify(res.text) - - scripts = evalText.select("script") - - for i in scripts: - rexd = re.compile("", "") - break - - tf = tempfile.mktemp(dir=temp_dir) - - with open(tf, 'w', encoding="utf-8") as f: - f.write(rexd) - nodeRes = str(subprocess.getoutput(f"node {tf}")) - - ld(nodeRes) - - stream_url = re.search( - r"source='([^;]*)';", nodeRes).group().replace("source='", "").replace("';", "") - - ld(stream_url) - return { - 'stream_url': stream_url, - 'referer': "https://kwik.cx/" + 'stream_url': self.get_stream_url_from_kwik(self.url), + 'referer': None }