diff --git a/app/modules/rtorrent/__init__.py b/app/modules/rtorrent/__init__.py index 61af67a9..e55f76f4 100644 --- a/app/modules/rtorrent/__init__.py +++ b/app/modules/rtorrent/__init__.py @@ -16,13 +16,13 @@ from app.utils.string import StringUtils class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): - def init_module(self) -> None: """ 初始化模块 """ - super().init_service(service_name=Rtorrent.__name__.lower(), - service_type=Rtorrent) + super().init_service( + service_name=Rtorrent.__name__.lower(), service_type=Rtorrent + ) @staticmethod def get_name() -> str: @@ -77,9 +77,16 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): logger.info(f"rTorrent下载器 {name} 连接断开,尝试重连 ...") server.reconnect() - def download(self, content: Union[Path, str, bytes], download_dir: Path, cookie: str, - episodes: Set[int] = None, category: Optional[str] = None, label: Optional[str] = None, - downloader: Optional[str] = None) -> Optional[Tuple[Optional[str], Optional[str], Optional[str], str]]: + def download( + self, + content: Union[Path, str, bytes], + download_dir: Path, + cookie: str, + episodes: Set[int] = None, + category: Optional[str] = None, + label: Optional[str] = None, + downloader: Optional[str] = None, + ) -> Optional[Tuple[Optional[str], Optional[str], Optional[str], str]]: """ 根据种子文件,选择并添加下载任务 :param content: 种子文件地址或者磁力链接或种子内容 @@ -102,7 +109,9 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): if content.exists(): torrent_content = content.read_bytes() else: - torrent_content = FileCache().get(content.as_posix(), region="torrents") + torrent_content = FileCache().get( + content.as_posix(), region="torrents" + ) else: torrent_content = content @@ -123,9 +132,12 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): # 读取种子的名称 torrent_from_file, content = __get_torrent_info() # 检查是否为磁力链接 - is_magnet = isinstance(content, str) and content.startswith("magnet:") or isinstance(content, - bytes) and content.startswith( - b"magnet:") + is_magnet = ( + isinstance(content, str) + and content.startswith("magnet:") + or isinstance(content, bytes) + and content.startswith(b"magnet:") + ) if not torrent_from_file and not is_magnet: return None, None, None, f"添加种子任务失败:无法读取种子文件" @@ -137,7 +149,7 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): # 生成随机Tag tag = StringUtils.generate_random_str(10) if label: - tags = label.split(',') + [tag] + tags = label.split(",") + [tag] elif settings.TORRENT_TAG: tags = [tag, settings.TORRENT_TAG] else: @@ -165,18 +177,41 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): try: for torrent in torrents: # 名称与大小相等则认为是同一个种子 - if torrent.get("name") == getattr(torrent_from_file, 'name', '') \ - and torrent.get("total_size") == getattr(torrent_from_file, 'total_size', 0): + if torrent.get("name") == getattr( + torrent_from_file, "name", "" + ) and torrent.get("total_size") == getattr( + torrent_from_file, "total_size", 0 + ): torrent_hash = torrent.get("hash") - torrent_tags = [str(t).strip() for t in torrent.get("tags", "").split(',') if t.strip()] - logger.warn(f"下载器中已存在该种子任务:{torrent_hash} - {torrent.get('name')}") + torrent_tags = [ + str(t).strip() + for t in torrent.get("tags", "").split(",") + if t.strip() + ] + logger.warn( + f"下载器中已存在该种子任务:{torrent_hash} - {torrent.get('name')}" + ) # 给种子打上标签 if "已整理" in torrent_tags: - server.remove_torrents_tag(ids=torrent_hash, tag=['已整理']) - if settings.TORRENT_TAG and settings.TORRENT_TAG not in torrent_tags: - logger.info(f"给种子 {torrent_hash} 打上标签:{settings.TORRENT_TAG}") - server.set_torrents_tag(ids=torrent_hash, tags=[settings.TORRENT_TAG]) - return downloader or self.get_default_config_name(), torrent_hash, torrent_layout, f"下载任务已存在" + server.remove_torrents_tag( + ids=torrent_hash, tag=["已整理"] + ) + if ( + settings.TORRENT_TAG + and settings.TORRENT_TAG not in torrent_tags + ): + logger.info( + f"给种子 {torrent_hash} 打上标签:{settings.TORRENT_TAG}" + ) + server.set_torrents_tag( + ids=torrent_hash, tags=[settings.TORRENT_TAG] + ) + return ( + downloader or self.get_default_config_name(), + torrent_hash, + torrent_layout, + f"下载任务已存在", + ) finally: torrents.clear() del torrents @@ -185,13 +220,23 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): # 获取种子Hash torrent_hash = server.get_torrent_id_by_tag(tags=tag) if not torrent_hash: - return None, None, None, f"下载任务添加成功,但获取rTorrent任务信息失败:{content}" + return ( + None, + None, + None, + f"下载任务添加成功,但获取rTorrent任务信息失败:{content}", + ) else: if is_paused: # 种子文件 torrent_files = server.get_files(torrent_hash) if not torrent_files: - return downloader or self.get_default_config_name(), torrent_hash, torrent_layout, "获取种子文件失败,下载任务可能在暂停状态" + return ( + downloader or self.get_default_config_name(), + torrent_hash, + torrent_layout, + "获取种子文件失败,下载任务可能在暂停状态", + ) # 不需要的文件ID file_ids = [] @@ -202,8 +247,9 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): file_id = torrent_file.get("id") file_name = torrent_file.get("name") meta_info = MetaInfo(file_name) - if not meta_info.episode_list \ - or not set(meta_info.episode_list).issubset(episodes): + if not meta_info.episode_list or not set( + meta_info.episode_list + ).issubset(episodes): file_ids.append(file_id) else: sucess_epidised.update(meta_info.episode_list) @@ -213,17 +259,31 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): sucess_epidised = list(sucess_epidised) if sucess_epidised and file_ids: # 设置不需要的文件优先级为0(不下载) - server.set_files(torrent_hash=torrent_hash, file_ids=file_ids, priority=0) + server.set_files( + torrent_hash=torrent_hash, file_ids=file_ids, priority=0 + ) # 开始任务 server.start_torrents(torrent_hash) - return downloader or self.get_default_config_name(), torrent_hash, torrent_layout, f"添加下载成功,已选择集数:{sucess_epidised}" + return ( + downloader or self.get_default_config_name(), + torrent_hash, + torrent_layout, + f"添加下载成功,已选择集数:{sucess_epidised}", + ) else: - return downloader or self.get_default_config_name(), torrent_hash, torrent_layout, "添加下载成功" + return ( + downloader or self.get_default_config_name(), + torrent_hash, + torrent_layout, + "添加下载成功", + ) - def list_torrents(self, status: TorrentStatus = None, - hashs: Union[list, str] = None, - downloader: Optional[str] = None - ) -> Optional[List[Union[TransferTorrent, DownloadingTorrent]]]: + def list_torrents( + self, + status: TorrentStatus = None, + hashs: Union[list, str] = None, + downloader: Optional[str] = None, + ) -> Optional[List[Union[TransferTorrent, DownloadingTorrent]]]: """ 获取下载器种子列表 :param status: 种子状态 @@ -243,31 +303,41 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): if hashs: # 按Hash获取 for name, server in servers.items(): - torrents, _ = server.get_torrents(ids=hashs, tags=settings.TORRENT_TAG) or [] + torrents, _ = ( + server.get_torrents(ids=hashs, tags=settings.TORRENT_TAG) or [] + ) try: for torrent in torrents: content_path = torrent.get("content_path") if content_path: torrent_path = Path(content_path) else: - torrent_path = Path(torrent.get('save_path')) / torrent.get('name') - ret_torrents.append(TransferTorrent( - downloader=name, - title=torrent.get('name'), - path=torrent_path, - hash=torrent.get('hash'), - size=torrent.get('total_size'), - tags=torrent.get('tags'), - progress=torrent.get('progress', 0), - state="paused" if torrent.get('state') == 0 else "downloading", - )) + torrent_path = Path(torrent.get("save_path")) / torrent.get( + "name" + ) + ret_torrents.append( + TransferTorrent( + downloader=name, + title=torrent.get("name"), + path=torrent_path, + hash=torrent.get("hash"), + size=torrent.get("total_size"), + tags=torrent.get("tags"), + progress=torrent.get("progress", 0), + state="paused" + if torrent.get("state") == 0 + else "downloading", + ) + ) finally: torrents.clear() del torrents elif status == TorrentStatus.TRANSFER: # 获取已完成且未整理的 for name, server in servers.items(): - torrents = server.get_completed_torrents(tags=settings.TORRENT_TAG) or [] + torrents = ( + server.get_completed_torrents(tags=settings.TORRENT_TAG) or [] + ) try: for torrent in torrents: tags = torrent.get("tags") or "" @@ -278,43 +348,56 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): if content_path: torrent_path = Path(content_path) else: - torrent_path = Path(torrent.get('save_path')) / torrent.get('name') - ret_torrents.append(TransferTorrent( - downloader=name, - title=torrent.get('name'), - path=torrent_path, - hash=torrent.get('hash'), - tags=torrent.get('tags') - )) + torrent_path = Path(torrent.get("save_path")) / torrent.get( + "name" + ) + ret_torrents.append( + TransferTorrent( + downloader=name, + title=torrent.get("name"), + path=torrent_path, + hash=torrent.get("hash"), + tags=torrent.get("tags"), + ) + ) finally: torrents.clear() del torrents elif status == TorrentStatus.DOWNLOADING: # 获取正在下载的任务 for name, server in servers.items(): - torrents = server.get_downloading_torrents(tags=settings.TORRENT_TAG) or [] + torrents = ( + server.get_downloading_torrents(tags=settings.TORRENT_TAG) or [] + ) try: for torrent in torrents: - meta = MetaInfo(torrent.get('name')) - dlspeed = torrent.get('dlspeed', 0) - upspeed = torrent.get('upspeed', 0) - total_size = torrent.get('total_size', 0) - completed = torrent.get('completed', 0) - ret_torrents.append(DownloadingTorrent( - downloader=name, - hash=torrent.get('hash'), - title=torrent.get('name'), - name=meta.name, - year=meta.year, - season_episode=meta.season_episode, - progress=torrent.get('progress', 0), - size=total_size, - state="paused" if torrent.get('state') == 0 else "downloading", - dlspeed=StringUtils.str_filesize(dlspeed), - upspeed=StringUtils.str_filesize(upspeed), - left_time=StringUtils.str_secends( - (total_size - completed) / dlspeed) if dlspeed > 0 else '' - )) + meta = MetaInfo(torrent.get("name")) + dlspeed = torrent.get("dlspeed", 0) + upspeed = torrent.get("upspeed", 0) + total_size = torrent.get("total_size", 0) + completed = torrent.get("completed", 0) + ret_torrents.append( + DownloadingTorrent( + downloader=name, + hash=torrent.get("hash"), + title=torrent.get("name"), + name=meta.name, + year=meta.year, + season_episode=meta.season_episode, + progress=torrent.get("progress", 0), + size=total_size, + state="paused" + if torrent.get("state") == 0 + else "downloading", + dlspeed=StringUtils.str_filesize(dlspeed), + upspeed=StringUtils.str_filesize(upspeed), + left_time=StringUtils.str_secends( + (total_size - completed) / dlspeed + ) + if dlspeed > 0 + else "", + ) + ) finally: torrents.clear() del torrents @@ -322,7 +405,9 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): return None return ret_torrents # noqa - def transfer_completed(self, hashs: Union[str, list], downloader: Optional[str] = None) -> None: + def transfer_completed( + self, hashs: Union[str, list], downloader: Optional[str] = None + ) -> None: """ 转移完成后的处理 :param hashs: 种子Hash @@ -335,15 +420,19 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): org_tags = server.get_torrent_tags(ids=hashs) # 种子打上已整理标签 if org_tags: - tags = org_tags + ['已整理'] + tags = org_tags + ["已整理"] else: - tags = ['已整理'] + tags = ["已整理"] # 直接设置完整标签(覆盖) server.set_torrents_tag(ids=hashs, tags=tags, overwrite=True) return None - def remove_torrents(self, hashs: Union[str, list], delete_file: Optional[bool] = True, - downloader: Optional[str] = None) -> Optional[bool]: + def remove_torrents( + self, + hashs: Union[str, list], + delete_file: Optional[bool] = True, + downloader: Optional[str] = None, + ) -> Optional[bool]: """ 删除下载器种子 :param hashs: 种子Hash @@ -356,8 +445,9 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): return None return server.delete_torrents(delete_file=delete_file, ids=hashs) - def start_torrents(self, hashs: Union[list, str], - downloader: Optional[str] = None) -> Optional[bool]: + def start_torrents( + self, hashs: Union[list, str], downloader: Optional[str] = None + ) -> Optional[bool]: """ 开始下载 :param hashs: 种子Hash @@ -369,7 +459,9 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): return None return server.start_torrents(ids=hashs) - def stop_torrents(self, hashs: Union[list, str], downloader: Optional[str] = None) -> Optional[bool]: + def stop_torrents( + self, hashs: Union[list, str], downloader: Optional[str] = None + ) -> Optional[bool]: """ 停止下载 :param hashs: 种子Hash @@ -381,7 +473,9 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): return None return server.stop_torrents(ids=hashs) - def torrent_files(self, tid: str, downloader: Optional[str] = None) -> Optional[List[Dict]]: + def torrent_files( + self, tid: str, downloader: Optional[str] = None + ) -> Optional[List[Dict]]: """ 获取种子文件列表 """ @@ -390,7 +484,9 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): return None return server.get_files(tid=tid) - def downloader_info(self, downloader: Optional[str] = None) -> Optional[List[schemas.DownloaderInfo]]: + def downloader_info( + self, downloader: Optional[str] = None + ) -> Optional[List[schemas.DownloaderInfo]]: """ 下载器信息 """ @@ -406,10 +502,12 @@ class RtorrentModule(_ModuleBase, _DownloaderBase[Rtorrent]): info = server.transfer_info() if not info: continue - ret_info.append(schemas.DownloaderInfo( - download_speed=info.get("dl_info_speed"), - upload_speed=info.get("up_info_speed"), - download_size=info.get("dl_info_data"), - upload_size=info.get("up_info_data") - )) + ret_info.append( + schemas.DownloaderInfo( + download_speed=info.get("dl_info_speed"), + upload_speed=info.get("up_info_speed"), + download_size=info.get("dl_info_data"), + upload_size=info.get("up_info_data"), + ) + ) return ret_info diff --git a/app/modules/rtorrent/rtorrent.py b/app/modules/rtorrent/rtorrent.py index 9767e1f4..6166c484 100644 --- a/app/modules/rtorrent/rtorrent.py +++ b/app/modules/rtorrent/rtorrent.py @@ -16,7 +16,9 @@ class SCGITransport(xmlrpc.client.Transport): def single_request(self, host, handler, request_body, verbose=False): # 建立socket连接 parsed = urlparse(f"scgi://{host}") - sock = socket.create_connection((parsed.hostname, parsed.port or 5000), timeout=60) + sock = socket.create_connection( + (parsed.hostname, parsed.port or 5000), timeout=60 + ) try: # 构造SCGI请求头 headers = ( @@ -42,7 +44,7 @@ class SCGITransport(xmlrpc.client.Transport): # 跳过HTTP响应头 header_end = response.find(b"\r\n\r\n") if header_end != -1: - response = response[header_end + 4:] + response = response[header_end + 4 :] # 解析XML-RPC响应 return self.parse_response(self._build_response(response)) @@ -70,9 +72,14 @@ class Rtorrent: rTorrent下载器 """ - def __init__(self, host: Optional[str] = None, port: Optional[int] = None, - username: Optional[str] = None, password: Optional[str] = None, - **kwargs): + def __init__( + self, + host: Optional[str] = None, + port: Optional[int] = None, + username: Optional[str] = None, + password: Optional[str] = None, + **kwargs, + ): self._proxy = None if host and port: self._host = f"{host}:{port}" @@ -97,10 +104,7 @@ class Rtorrent: # SCGI直连模式 parsed = urlparse(url) logger.info(f"正在通过SCGI连接 rTorrent:{url}") - proxy = xmlrpc.client.ServerProxy( - url, - transport=SCGITransport() - ) + proxy = xmlrpc.client.ServerProxy(url, transport=SCGITransport()) else: # HTTP模式 (通过nginx/ruTorrent代理) if not url.startswith("http"): @@ -112,14 +116,18 @@ class Rtorrent: if parsed.port: url += f":{parsed.port}" url += parsed.path or "/RPC2" - logger.info(f"正在通过HTTP连接 rTorrent:{url.split('@')[-1] if '@' in url else url}") + logger.info( + f"正在通过HTTP连接 rTorrent:{url.split('@')[-1] if '@' in url else url}" + ) proxy = xmlrpc.client.ServerProxy(url) # 测试连接 proxy.system.client_version() return proxy except Exception as err: - stack_trace = "".join(traceback.format_exception(None, err, err.__traceback__))[:2000] + stack_trace = "".join( + traceback.format_exception(None, err, err.__traceback__) + )[:2000] logger.error(f"rTorrent 连接出错:{str(err)}\n{stack_trace}") return None @@ -137,9 +145,12 @@ class Rtorrent: """ self._proxy = self.__login_rtorrent() - def get_torrents(self, ids: Optional[Union[str, list]] = None, - status: Optional[str] = None, - tags: Optional[Union[str, list]] = None) -> Tuple[List[Dict], bool]: + def get_torrents( + self, + ids: Optional[Union[str, list]] = None, + status: Optional[str] = None, + tags: Optional[Union[str, list]] = None, + ) -> Tuple[List[Dict], bool]: """ 获取种子列表 :return: 种子列表, 是否发生异常 @@ -175,10 +186,10 @@ class Rtorrent: "completed": r[3], "dlspeed": r[4], "upspeed": r[5], - "state": r[6], # 0=stopped, 1=started - "complete": r[7], # 0=incomplete, 1=complete + "state": r[6], # 0=stopped, 1=started + "complete": r[7], # 0=incomplete, 1=complete "save_path": r[8], - "tags": r[9], # d.custom1 用于标签 + "tags": r[9], # d.custom1 用于标签 "is_active": r[10], "is_open": r[11], "ratio": int(r[12]) / 1000.0 if r[12] else 0, @@ -186,7 +197,9 @@ class Rtorrent: } # 计算进度 if torrent["total_size"] > 0: - torrent["progress"] = torrent["completed"] / torrent["total_size"] * 100 + torrent["progress"] = ( + torrent["completed"] / torrent["total_size"] * 100 + ) else: torrent["progress"] = 0 @@ -201,7 +214,9 @@ class Rtorrent: # 标签过滤 if tags: - torrent_tags = [t.strip() for t in torrent["tags"].split(",") if t.strip()] + torrent_tags = [ + t.strip() for t in torrent["tags"].split(",") if t.strip() + ] if isinstance(tags, str): tags_list = [t.strip() for t in tags.split(",")] else: @@ -215,8 +230,9 @@ class Rtorrent: logger.error(f"获取种子列表出错:{str(err)}") return [], True - def get_completed_torrents(self, ids: Union[str, list] = None, - tags: Union[str, list] = None) -> Optional[List[Dict]]: + def get_completed_torrents( + self, ids: Union[str, list] = None, tags: Union[str, list] = None + ) -> Optional[List[Dict]]: """ 获取已完成的种子 """ @@ -227,8 +243,9 @@ class Rtorrent: return None return [t for t in torrents if t.get("complete") == 1] - def get_downloading_torrents(self, ids: Union[str, list] = None, - tags: Union[str, list] = None) -> Optional[List[Dict]]: + def get_downloading_torrents( + self, ids: Union[str, list] = None, tags: Union[str, list] = None + ) -> Optional[List[Dict]]: """ 获取正在下载的种子 """ @@ -239,13 +256,15 @@ class Rtorrent: return None return [t for t in torrents if t.get("complete") == 0] - def add_torrent(self, - content: Union[str, bytes], - is_paused: Optional[bool] = False, - download_dir: Optional[str] = None, - tags: Optional[List[str]] = None, - cookie: Optional[str] = None, - **kwargs) -> bool: + def add_torrent( + self, + content: Union[str, bytes], + is_paused: Optional[bool] = False, + download_dir: Optional[str] = None, + tags: Optional[List[str]] = None, + cookie: Optional[str] = None, + **kwargs, + ) -> bool: """ 添加种子 :param content: 种子内容(bytes)或磁力链接/URL(str) @@ -340,6 +359,7 @@ class Rtorrent: self._proxy.d.erase(tid) if base_path: import shutil + path = Path(base_path) if path.is_dir(): shutil.rmtree(str(path), ignore_errors=True) @@ -364,27 +384,34 @@ class Rtorrent: if not tid: return None try: - files = self._proxy.f.multicall(tid, "", - "f.path=", - "f.size_bytes=", - "f.priority=", - "f.completed_chunks=", - "f.size_chunks=") + files = self._proxy.f.multicall( + tid, + "", + "f.path=", + "f.size_bytes=", + "f.priority=", + "f.completed_chunks=", + "f.size_chunks=", + ) result = [] for idx, f in enumerate(files): - result.append({ - "id": idx, - "name": f[0], - "size": f[1], - "priority": f[2], - "progress": int(f[3]) / int(f[4]) * 100 if int(f[4]) > 0 else 0 - }) + result.append( + { + "id": idx, + "name": f[0], + "size": f[1], + "priority": f[2], + "progress": int(f[3]) / int(f[4]) * 100 if int(f[4]) > 0 else 0, + } + ) return result except Exception as err: logger.error(f"获取种子文件列表出错:{str(err)}") return None - def set_files(self, torrent_hash: str = None, file_ids: list = None, priority: int = 0) -> bool: + def set_files( + self, torrent_hash: str = None, file_ids: list = None, priority: int = 0 + ) -> bool: """ 设置下载文件的优先级,priority为0为不下载,priority为1为普通 """ @@ -402,7 +429,9 @@ class Rtorrent: logger.error(f"设置种子文件状态出错:{str(err)}") return False - def set_torrents_tag(self, ids: Union[str, list], tags: List[str], overwrite: bool = False) -> bool: + def set_torrents_tag( + self, ids: Union[str, list], tags: List[str], overwrite: bool = False + ) -> bool: """ 设置种子标签(使用d.custom1) :param ids: 种子Hash @@ -423,7 +452,11 @@ class Rtorrent: else: # 获取现有标签 existing = self._proxy.d.custom1(tid) - existing_tags = [t.strip() for t in existing.split(",") if t.strip()] if existing else [] + existing_tags = ( + [t.strip() for t in existing.split(",") if t.strip()] + if existing + else [] + ) # 合并标签 merged = list(set(existing_tags + tags)) self._proxy.d.custom1.set(tid, ",".join(merged)) @@ -447,7 +480,11 @@ class Rtorrent: tag = [tag] for tid in ids: existing = self._proxy.d.custom1(tid) - existing_tags = [t.strip() for t in existing.split(",") if t.strip()] if existing else [] + existing_tags = ( + [t.strip() for t in existing.split(",") if t.strip()] + if existing + else [] + ) new_tags = [t for t in existing_tags if t not in tag] self._proxy.d.custom1.set(tid, ",".join(new_tags)) return True @@ -463,17 +500,23 @@ class Rtorrent: return [] try: existing = self._proxy.d.custom1(ids) - return [t.strip() for t in existing.split(",") if t.strip()] if existing else [] + return ( + [t.strip() for t in existing.split(",") if t.strip()] + if existing + else [] + ) except Exception as err: logger.error(f"获取种子标签出错:{str(err)}") return [] - def get_torrent_id_by_tag(self, tags: Union[str, list], - status: Optional[str] = None) -> Optional[str]: + def get_torrent_id_by_tag( + self, tags: Union[str, list], status: Optional[str] = None + ) -> Optional[str]: """ 通过标签多次尝试获取刚添加的种子ID,并移除标签 """ import time + if isinstance(tags, str): tags = [tags] torrent_id = None