From 46c628a6717e106d2330837c5d49b4c3271e1e32 Mon Sep 17 00:00:00 2001 From: ljmeng Date: Thu, 28 Mar 2024 00:20:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=BB=A3=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E5=8A=A8=E6=80=81=E5=8A=A0=E8=BD=BD=E7=9A=84?= =?UTF-8?q?=E4=B8=8D=E7=A1=AE=E5=AE=9A=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- plugins/crossseed/__init__.py | 130 ++++++++++++++++++++++++- plugins/crossseed/cross_seed_helper.py | 128 ------------------------ 3 files changed, 126 insertions(+), 134 deletions(-) delete mode 100644 plugins/crossseed/cross_seed_helper.py diff --git a/package.json b/package.json index 87a080e..ea8c2f3 100644 --- a/package.json +++ b/package.json @@ -186,7 +186,7 @@ "CrossSeed": { "name": "青蛙辅种助手", "description": "参考ReseedPuppy和IYUU辅种插件实现自动辅种,支持站点:青蛙、AGSVPT、麒麟、UBits、聆音等。", - "version": "1.6", + "version": "1.6.1", "icon": "qingwa.png", "author": "233@qingwa", "level": 2 diff --git a/plugins/crossseed/__init__.py b/plugins/crossseed/__init__.py index 215af32..2a57166 100644 --- a/plugins/crossseed/__init__.py +++ b/plugins/crossseed/__init__.py @@ -1,11 +1,12 @@ -import math +import hashlib import os from datetime import datetime, timedelta from pathlib import Path from threading import Event -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Self, Tuple import pytz +import requests from app.core.config import settings from app.core.event import eventmanager from app.db.models import Site @@ -23,10 +24,129 @@ from app.utils.string import StringUtils from app.utils.timer import TimerUtils from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.triggers.cron import CronTrigger +from bencode import dumps, loads -from plugins.crossseed.cross_seed_helper import (CrossSeedHelper, CSSiteConfig, - TorInfo) +class CSSiteConfig(object): + """ + 站点辅种配置类 + """ + + def __init__(self, site_name: str, site_url: str, site_passkey: str) -> None: + self.name = site_name + self.url = site_url.removesuffix("/") + self.passkey = site_passkey + + def get_api_url(self): + if self.name == "憨憨": + return f"{self.url}/npapi/pieces-hash" + return f"{self.url}/api/pieces-hash" + + def get_torrent_url(self, torrent_id: str): + return f"{self.url}/download.php?id={torrent_id}&passkey={self.passkey}" + + +class TorInfo: + + def __init__( + self, + site_name: str = None, + torrent_path: str = None, + file_path: str = None, + info_hash: str = None, + pieces_hash: str = None, + torrent_id: str = None, + ) -> None: + self.site_name = site_name + self.torrent_path = torrent_path + self.file_path = file_path + self.info_hash = info_hash + self.pieces_hash = pieces_hash + self.torrent_id = torrent_id + self.torrent_announce = None + + @staticmethod + def local(torrent_path: str, info_hash: str, pieces_hash: str) -> Self: + + return TorInfo( + torrent_path=torrent_path, info_hash=info_hash, pieces_hash=pieces_hash + ) + + @staticmethod + def remote(site_name: str, pieces_hash: str, torrent_id: str) -> Self: + return TorInfo( + site_name=site_name, pieces_hash=pieces_hash, torrent_id=torrent_id + ) + + @staticmethod + def from_data(data: bytes) -> tuple[Self, str]: + try: + torrent = loads(data) + info = torrent["info"] + pieces = info["pieces"] + info_hash = hashlib.sha1(dumps(info)).hexdigest() + pieces_hash = hashlib.sha1(pieces).hexdigest() + local_tor = TorInfo(info_hash=info_hash, pieces_hash=pieces_hash) + #从种子中获取 announce, qb可能存在获取不到的情况,会存在于fastresume文件中 + if "announce" in torrent: + local_tor.torrent_announce = torrent["announce"] + return local_tor, None + except Exception as err: + return None, err + + def get_name_id_tag(self): + return f"{self.site_name}:{self.torrent_id}" + + def get_name_pieces_tag(self): + return f"{self.site_name}:{self.pieces_hash}" + +class CrossSeedHelper(object): + _version = "0.2.0" + + def get_local_torrent_info(self, torrent_path: Path | str) -> tuple[TorInfo, str]: + try: + torrent_data = None + if isinstance(torrent_path, Path): + torrent_data = torrent_path.read_bytes() + else: + with open(torrent_path, "rb") as f: + torrent_data = f.read() + local_tor, err = TorInfo.from_data(torrent_data) + if not local_tor: + return None, err + local_tor.torrent_path = str(torrent_path) + return local_tor, "" + except Exception as err: + return None, err + + def get_target_torrent( + self, site: CSSiteConfig, pieces_hash_set: list[str] + ) -> list[TorInfo]: + """ + 返回pieces_hash对应的种子信息,包括站点id,pieces_hash,种子id + """ + headers = { + "Content-Type": "application/json", + "Accept": "application/json", + "User-Agent": "CrossSeedHelper", + } + data = {"passkey": site.passkey, "pieces_hash": pieces_hash_set} + try: + response = requests.post( + site.get_api_url(), headers=headers, json=data, timeout=10 + ) + response.raise_for_status() + except requests.exceptions.RequestException as e: + return None, f"站点{site.name}请求失败:{e}" + rsp_body = response.json() + + remote_torrent_infos = [] + if isinstance(rsp_body["data"], dict): + for pieces_hash, torrent_id in rsp_body["data"].items(): + remote_torrent_infos.append( + TorInfo.remote(site.name, pieces_hash, torrent_id) + ) + return remote_torrent_infos, None class CrossSeed(_PluginBase): # 插件名称 @@ -36,7 +156,7 @@ class CrossSeed(_PluginBase): # 插件图标 plugin_icon = "qingwa.png" # 插件版本 - plugin_version = "1.6" + plugin_version = "1.6.1" # 插件作者 plugin_author = "233@qingwa" # 作者主页 diff --git a/plugins/crossseed/cross_seed_helper.py b/plugins/crossseed/cross_seed_helper.py deleted file mode 100644 index 08e5bd3..0000000 --- a/plugins/crossseed/cross_seed_helper.py +++ /dev/null @@ -1,128 +0,0 @@ -import hashlib -from pathlib import Path -from typing import Self - -import requests -from bencode import bdecode, bencode - - -class CSSiteConfig(object): - """ - 站点辅种配置类 - """ - - def __init__(self, site_name: str, site_url: str, site_passkey: str) -> None: - self.name = site_name - self.url = site_url.removesuffix("/") - self.passkey = site_passkey - - def get_api_url(self): - if self.name == "憨憨": - return f"{self.url}/npapi/pieces-hash" - return f"{self.url}/api/pieces-hash" - - def get_torrent_url(self, torrent_id: str): - return f"{self.url}/download.php?id={torrent_id}&passkey={self.passkey}" - - -class TorInfo: - - def __init__( - self, - site_name: str = None, - torrent_path: str = None, - file_path: str = None, - info_hash: str = None, - pieces_hash: str = None, - torrent_id: str = None, - ) -> None: - self.site_name = site_name - self.torrent_path = torrent_path - self.file_path = file_path - self.info_hash = info_hash - self.pieces_hash = pieces_hash - self.torrent_id = torrent_id - self.torrent_announce = None - - @staticmethod - def local(torrent_path: str, info_hash: str, pieces_hash: str) -> Self: - - return TorInfo( - torrent_path=torrent_path, info_hash=info_hash, pieces_hash=pieces_hash - ) - - @staticmethod - def remote(site_name: str, pieces_hash: str, torrent_id: str) -> Self: - return TorInfo( - site_name=site_name, pieces_hash=pieces_hash, torrent_id=torrent_id - ) - - @staticmethod - def from_data(data: bytes) -> tuple[Self, str]: - try: - torrent = bdecode(data) - info = torrent["info"] - pieces = info["pieces"] - info_hash = hashlib.sha1(bencode(info)).hexdigest() - pieces_hash = hashlib.sha1(pieces).hexdigest() - local_tor = TorInfo(info_hash=info_hash, pieces_hash=pieces_hash) - #从种子中获取 announce, qb可能存在获取不到的情况,会存在于fastresume文件中 - if "announce" in torrent: - local_tor.torrent_announce = torrent["announce"] - return local_tor, None - except Exception as err: - return None, err - - def get_name_id_tag(self): - return f"{self.site_name}:{self.torrent_id}" - - def get_name_pieces_tag(self): - return f"{self.site_name}:{self.pieces_hash}" - -class CrossSeedHelper(object): - _version = "0.2.0" - - def get_local_torrent_info(self, torrent_path: Path | str) -> tuple[TorInfo, str]: - try: - torrent_data = None - if isinstance(torrent_path, Path): - torrent_data = torrent_path.read_bytes() - else: - with open(torrent_path, "rb") as f: - torrent_data = f.read() - local_tor, err = TorInfo.from_data(torrent_data) - if not local_tor: - return None, err - local_tor.torrent_path = str(torrent_path) - return local_tor, "" - except Exception as err: - return None, err - - def get_target_torrent( - self, site: CSSiteConfig, pieces_hash_set: list[str] - ) -> list[TorInfo]: - """ - 返回pieces_hash对应的种子信息,包括站点id,pieces_hash,种子id - """ - headers = { - "Content-Type": "application/json", - "Accept": "application/json", - "User-Agent": "CrossSeedHelper", - } - data = {"passkey": site.passkey, "pieces_hash": pieces_hash_set} - try: - response = requests.post( - site.get_api_url(), headers=headers, json=data, timeout=10 - ) - response.raise_for_status() - except requests.exceptions.RequestException as e: - return None, f"站点{site.name}请求失败:{e}" - rsp_body = response.json() - - remote_torrent_infos = [] - if isinstance(rsp_body["data"], dict): - for pieces_hash, torrent_id in rsp_body["data"].items(): - remote_torrent_infos.append( - TorInfo.remote(site.name, pieces_hash, torrent_id) - ) - return remote_torrent_infos, None