From d341e6cb040622ee68426a278a9e1912d7805321 Mon Sep 17 00:00:00 2001 From: sgpublic Date: Mon, 6 May 2024 19:07:26 +0800 Subject: [PATCH 1/2] feat: auto get token with xunlei 1.21.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #277,还能自动获取 device_id,这样迅雷在 1.21.1 就能开箱即用了无需其他配置 --- .../xunlei_download_provider/provider.py | 58 +++++++++++++++---- kubespider/utils/version_parser.py | 16 +++++ 2 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 kubespider/utils/version_parser.py diff --git a/kubespider/download_provider/xunlei_download_provider/provider.py b/kubespider/download_provider/xunlei_download_provider/provider.py index c166efec..339fd81a 100644 --- a/kubespider/download_provider/xunlei_download_provider/provider.py +++ b/kubespider/download_provider/xunlei_download_provider/provider.py @@ -1,6 +1,7 @@ # This code is quite ugly becase the logic in xunlei is disgusting. # encoding:utf-8 import logging +import re import time import json @@ -14,6 +15,8 @@ from download_provider import provider from api.values import Task +from kubespider.utils.version_parser import check_version_at_lest + class XunleiDownloadProvider(provider.DownloadProvider): def __init__(self, name: str, config_reader: AbsConfigReader) -> None: @@ -21,7 +24,8 @@ def __init__(self, name: str, config_reader: AbsConfigReader) -> None: self.provider_name = name self.provider_type = 'xunlei_download_provider' self.http_endpoint = '' - self.device_id = '' + self._device_id = None + self._token_str = None self.js_ctx = execjs.compile('') self.request_handler = get_request_controller(use_proxy=False) @@ -47,6 +51,15 @@ def send_torrent_task(self, task: Task) -> TypeError: file_info = self.list_files(token, magnet_url) return self.send_task(token, file_info, magnet_url, task.path) + def device_id(self): + if self._device_id is None: + info_watch = "/webman/3rdparty/pan-xunlei-com/index.cgi/device/info/watch" + token = self.get_pan_token() + req = self.request_handler.post(self.http_endpoint + info_watch, + headers={'pan-auth': token}, timeout=30) + self._device_id = json.loads(req.text).get("target") + return self._device_id + def send_magnet_task(self, task: Task) -> TypeError: logging.info('Start magnet download:%s', task.url) token = self.get_pan_token() @@ -70,11 +83,14 @@ def remove_tasks(self, tasks: list[Task]): def load_config(self) -> TypeError: cfg = self.config_reader.read() self.http_endpoint = cfg.get('http_endpoint', 'http://127.0.0.1:2345') - token_js_path = cfg.get('token_js_path', '/app/.config/dependencies/xunlei_download_provider/get_token.js') - with open(token_js_path, 'r', encoding='utf-8') as js_file: - js_text = js_file.read() - self.js_ctx = execjs.compile(js_text) - self.device_id = cfg.get('device_id', '') + try: + token_js_path = cfg.get('token_js_path', '/app/.config/dependencies/xunlei_download_provider/get_token.js') + with open(token_js_path, 'r', encoding='utf-8') as js_file: + js_text = js_file.read() + self.js_ctx = execjs.compile(js_text) + except Exception as err: + logging.error("Cannot read .config/dependencies/xunlei_download_provider/get_token.js: %s", err) + # self.device_id = cfg.get('device_id', '') def list_files(self, token: str, url: str) -> dict: try: @@ -101,9 +117,9 @@ def send_task(self, token: str, file_info: dict, url: str, path: str) -> TypeErr "name": file_info['list']['resources'][0]['name'], "file_name": file_info['list']['resources'][0]['name'], "file_size": str(file_size), - "space": "device_id#" + self.device_id, + "space": "device_id#" + self.device_id(), "params": { - "target": "device_id#" + self.device_id, + "target": "device_id#" + self.device_id(), "url": url, "total_file_count": str(file_info['list']['resources'][0]['file_count']), "sub_file_index": str(self.get_file_index(file_info)), @@ -139,7 +155,7 @@ def create_sub_path(self, token: str, dir_name: str, parent_id: str) -> TypeErro data = { "parent_id": parent_id, "name": dir_name, - "space": "device_id#" + self.device_id, + "space": "device_id#" + self.device_id(), "kind": "drive#folder" } rep = self.request_handler.post(self.http_endpoint + path, headers={'pan-auth': token}, timeout=30, @@ -161,7 +177,7 @@ def get_path_id(self, token: str, path: str) -> str: if len(dir_list) == cnt: return parent_id file_path = '/webman/3rdparty/pan-xunlei-com/index.cgi/drive/v1/files?space=device_id%23' + \ - self.device_id + '&limit=200&filters=%7B%22kind%22%3A%7B%22eq%22%3A%22drive%23folder%22%7D%7D&page_token=&' + \ + self.device_id() + '&limit=200&filters=%7B%22kind%22%3A%7B%22eq%22%3A%22drive%23folder%22%7D%7D&page_token=&' + \ 'pan_auth=' + token + '&device_space=&parent_id=' + parent_id rep = self.request_handler.get(self.http_endpoint + file_path, headers={'pan-auth': token}, timeout=30) if rep.status_code != 200: @@ -192,6 +208,15 @@ def get_path_id(self, token: str, path: str) -> str: logging.error("get path id error:%s", err) return "" + def get_server_version(self) -> str: + try: + rep = self.request_handler.get(self.http_endpoint + '/webman/3rdparty/pan-xunlei-com/index.cgi/launcher/status', + timeout=30) + return str(json.loads(rep.text).get('running_version')) + except Exception as err: + logging.error("get xunlei server version error:%s", err) + return "" + def get_file_index(self, file_info: dict) -> str: file_count = int(file_info['list']['resources'][0]['file_count']) if file_count == 1: @@ -199,6 +224,19 @@ def get_file_index(self, file_info: dict) -> str: return '0-' + str(file_count - 1) def get_pan_token(self) -> str: + server_version = self.get_server_version() + if check_version_at_lest(server_version, "1.21.1"): + if self._token_str is not None: + return self._token_str + resp = self.request_handler.get(self.http_endpoint + '/webman/3rdparty/pan-xunlei-com/index.cgi/', + timeout=30) + uiauth = r'function uiauth\(value\){ return "(.*)" }' + for script in re.findall(uiauth, resp.text): + self._token_str = script + return self._token_str + logging.error('Get xunlei token from html error') + return "" + xunlei_e = int(time.time()) xunlei_cn = int(time.time()) try: diff --git a/kubespider/utils/version_parser.py b/kubespider/utils/version_parser.py new file mode 100644 index 00000000..5fe37ceb --- /dev/null +++ b/kubespider/utils/version_parser.py @@ -0,0 +1,16 @@ +def check_version_at_lest(current_version: str, target_version: str) -> bool: + if current_version == target_version: + return True + current_version = parse_version(current_version) + target_version = parse_version(target_version) + index = 0 + while True: + if len(current_version) <= index or len(target_version) <= index: + return False + if current_version[index] > target_version[index]: + return True + index += 1 + + +def parse_version(version_name: str) -> list[int]: + return [int(x) for x in version_name.split('.')] From 87dce34157a013a66cbeb5d534baff730201e97e Mon Sep 17 00:00:00 2001 From: sgpublic Date: Wed, 8 May 2024 19:47:23 +0800 Subject: [PATCH 2/2] chore: fix import --- .../download_provider/xunlei_download_provider/provider.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kubespider/download_provider/xunlei_download_provider/provider.py b/kubespider/download_provider/xunlei_download_provider/provider.py index 339fd81a..c8ec6a77 100644 --- a/kubespider/download_provider/xunlei_download_provider/provider.py +++ b/kubespider/download_provider/xunlei_download_provider/provider.py @@ -12,11 +12,10 @@ from utils.config_reader import AbsConfigReader from utils.helper import get_request_controller +from utils.version_parser import check_version_at_lest from download_provider import provider from api.values import Task -from kubespider.utils.version_parser import check_version_at_lest - class XunleiDownloadProvider(provider.DownloadProvider): def __init__(self, name: str, config_reader: AbsConfigReader) -> None: