From 8068523d8806b83f96f52ec71724cc150e20023e Mon Sep 17 00:00:00 2001 From: jxxghp Date: Thu, 26 Jun 2025 20:52:17 +0800 Subject: [PATCH] fix downloader --- app/modules/qbittorrent/__init__.py | 170 +++++++++++---------- app/modules/qbittorrent/qbittorrent.py | 29 ++-- app/modules/transmission/__init__.py | 183 ++++++++++++----------- app/modules/transmission/transmission.py | 43 +++--- 4 files changed, 225 insertions(+), 200 deletions(-) diff --git a/app/modules/qbittorrent/__init__.py b/app/modules/qbittorrent/__init__.py index 24b2d504..85177f00 100644 --- a/app/modules/qbittorrent/__init__.py +++ b/app/modules/qbittorrent/__init__.py @@ -166,19 +166,22 @@ class QbittorrentModule(_ModuleBase, _DownloaderBase[Qbittorrent]): if error: return None, None, None, "无法连接qbittorrent下载器" if torrents: - for torrent in torrents: - # 名称与大小相等则认为是同一个种子 - if torrent.get("name") == torrent_name and torrent.get("total_size") == torrent_size: - torrent_hash = torrent.get("hash") - torrent_tags = [str(tag).strip() for tag in torrent.get("tags").split(',')] - 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"下载任务已存在" + try: + for torrent in torrents: + # 名称与大小相等则认为是同一个种子 + if torrent.get("name") == torrent_name and torrent.get("total_size") == torrent_size: + torrent_hash = torrent.get("hash") + torrent_tags = [str(tag).strip() for tag in torrent.get("tags").split(',')] + 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"下载任务已存在" + finally: + torrents.clear() return None, None, None, f"添加种子任务失败:{content}" else: # 获取种子Hash @@ -196,16 +199,18 @@ class QbittorrentModule(_ModuleBase, _DownloaderBase[Qbittorrent]): file_ids = [] # 需要的集清单 sucess_epidised = [] - - for torrent_file in torrent_files: - 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): - file_ids.append(file_id) - else: - sucess_epidised = list(set(sucess_epidised).union(set(meta_info.episode_list))) + try: + for torrent_file in torrent_files: + 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): + file_ids.append(file_id) + else: + sucess_epidised = list(set(sucess_epidised).union(set(meta_info.episode_list))) + finally: + torrent_files.clear() if sucess_epidised and file_ids: # 选择文件 server.set_files(torrent_hash=torrent_hash, file_ids=file_ids, priority=0) @@ -244,67 +249,76 @@ class QbittorrentModule(_ModuleBase, _DownloaderBase[Qbittorrent]): if hashs: # 按Hash获取 for name, server in servers.items(): - torrents, _ = server.get_torrents(ids=hashs, tags=settings.TORRENT_TAG) - for torrent in torrents or []: - 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') * 100, - state="paused" if torrent.get('state') in ("paused", "pausedDL") else "downloading", - )) + 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') * 100, + state="paused" if torrent.get('state') in ("paused", "pausedDL") else "downloading", + )) + finally: + torrents.clear() elif status == TorrentStatus.TRANSFER: # 获取已完成且未整理的 for name, server in servers.items(): - torrents = server.get_completed_torrents(tags=settings.TORRENT_TAG) - for torrent in torrents or []: - tags = torrent.get("tags") or [] - if "已整理" in tags: - continue - # 内容路径 - content_path = torrent.get("content_path") - if content_path: - torrent_path = Path(content_path) - else: - torrent_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') - )) + torrents = server.get_completed_torrents(tags=settings.TORRENT_TAG) or [] + try: + for torrent in torrents: + tags = torrent.get("tags") or [] + if "已整理" in tags: + continue + # 内容路径 + content_path = torrent.get("content_path") + if content_path: + torrent_path = Path(content_path) + else: + torrent_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() elif status == TorrentStatus.DOWNLOADING: # 获取正在下载的任务 for name, server in servers.items(): - torrents = server.get_downloading_torrents(tags=settings.TORRENT_TAG) - for torrent in torrents or []: - meta = MetaInfo(torrent.get('name')) - 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') * 100, - size=torrent.get('total_size'), - state="paused" if torrent.get('state') in ("paused", "pausedDL") else "downloading", - dlspeed=StringUtils.str_filesize(torrent.get('dlspeed')), - upspeed=StringUtils.str_filesize(torrent.get('upspeed')), - left_time=StringUtils.str_secends( - (torrent.get('total_size') - torrent.get('completed')) / torrent.get( - 'dlspeed')) if torrent.get( - 'dlspeed') > 0 else '' - )) + torrents = server.get_downloading_torrents(tags=settings.TORRENT_TAG) or [] + try: + for torrent in torrents: + meta = MetaInfo(torrent.get('name')) + 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') * 100, + size=torrent.get('total_size'), + state="paused" if torrent.get('state') in ("paused", "pausedDL") else "downloading", + dlspeed=StringUtils.str_filesize(torrent.get('dlspeed')), + upspeed=StringUtils.str_filesize(torrent.get('upspeed')), + left_time=StringUtils.str_secends( + (torrent.get('total_size') - torrent.get('completed')) / torrent.get( + 'dlspeed')) if torrent.get( + 'dlspeed') > 0 else '' + )) + finally: + torrents.clear() else: return None return ret_torrents # noqa diff --git a/app/modules/qbittorrent/qbittorrent.py b/app/modules/qbittorrent/qbittorrent.py index e05b9d1d..dd2a8e0c 100644 --- a/app/modules/qbittorrent/qbittorrent.py +++ b/app/modules/qbittorrent/qbittorrent.py @@ -12,16 +12,9 @@ from app.utils.string import StringUtils class Qbittorrent: - _host: Optional[str] = None - _port: int = None - _username: Optional[str] = None - _password: Optional[str] = None - _category: Optional[bool] = False - _sequentail: Optional[bool] = False - _force_resume: Optional[bool] = False - - qbc: Client = None - + """ + qbittorrent下载器 + """ def __init__(self, host: Optional[str] = None, port: int = None, username: Optional[str] = None, password: Optional[str] = None, category: Optional[bool] = False, sequentail: Optional[bool] = False, @@ -43,8 +36,7 @@ class Qbittorrent: self._sequentail = sequentail self._force_resume = force_resume self._first_last_piece = first_last_piece - if self._host and self._port: - self.qbc = self.__login_qbittorrent() + self.qbc = self.__login_qbittorrent() def is_inactive(self) -> bool: """ @@ -65,6 +57,8 @@ class Qbittorrent: 连接qbittorrent :return: qbittorrent对象 """ + if not self._host or not self._port: + return None try: # 登录 logger.info(f"正在连接 qbittorrent:{self._host}:{self._port}") @@ -104,10 +98,13 @@ class Qbittorrent: results = [] if not isinstance(tags, list): tags = [tags] - for torrent in torrents: - torrent_tags = [str(tag).strip() for tag in torrent.get("tags").split(',')] - if set(tags).issubset(set(torrent_tags)): - results.append(torrent) + try: + for torrent in torrents: + torrent_tags = [str(tag).strip() for tag in torrent.get("tags").split(',')] + if set(tags).issubset(set(torrent_tags)): + results.append(torrent) + finally: + torrents.clear() return results, False return torrents or [], False except Exception as err: diff --git a/app/modules/transmission/__init__.py b/app/modules/transmission/__init__.py index 2f4e2154..1ded1222 100644 --- a/app/modules/transmission/__init__.py +++ b/app/modules/transmission/__init__.py @@ -163,24 +163,27 @@ class TransmissionModule(_ModuleBase, _DownloaderBase[Transmission]): if error: return None, None, None, "无法连接transmission下载器" if torrents: - for torrent in torrents: - # 名称与大小相等则认为是同一个种子 - if torrent.name == torrent_name and torrent.total_size == torrent_size: - torrent_hash = torrent.hashString - logger.warn(f"下载器中已存在该种子任务:{torrent_hash} - {torrent.name}") - # 给种子打上标签 - if settings.TORRENT_TAG: - logger.info(f"给种子 {torrent_hash} 打上标签:{settings.TORRENT_TAG}") - # 种子标签 - labels = [str(tag).strip() - for tag in torrent.labels] if hasattr(torrent, "labels") else [] - if "已整理" in labels: - labels.remove("已整理") - server.set_torrent_tag(ids=torrent_hash, tags=labels) - if settings.TORRENT_TAG and settings.TORRENT_TAG not in labels: - labels.append(settings.TORRENT_TAG) - server.set_torrent_tag(ids=torrent_hash, tags=labels) - return downloader or self.get_default_config_name(), torrent_hash, torrent_layout, f"下载任务已存在" + try: + for torrent in torrents: + # 名称与大小相等则认为是同一个种子 + if torrent.name == torrent_name and torrent.total_size == torrent_size: + torrent_hash = torrent.hashString + logger.warn(f"下载器中已存在该种子任务:{torrent_hash} - {torrent.name}") + # 给种子打上标签 + if settings.TORRENT_TAG: + logger.info(f"给种子 {torrent_hash} 打上标签:{settings.TORRENT_TAG}") + # 种子标签 + labels = [str(tag).strip() + for tag in torrent.labels] if hasattr(torrent, "labels") else [] + if "已整理" in labels: + labels.remove("已整理") + server.set_torrent_tag(ids=torrent_hash, tags=labels) + if settings.TORRENT_TAG and settings.TORRENT_TAG not in labels: + labels.append(settings.TORRENT_TAG) + server.set_torrent_tag(ids=torrent_hash, tags=labels) + return downloader or self.get_default_config_name(), torrent_hash, torrent_layout, f"下载任务已存在" + finally: + torrents.clear() return None, None, None, f"添加种子任务失败:{content}" else: torrent_hash = torrent.hashString @@ -192,23 +195,26 @@ class TransmissionModule(_ModuleBase, _DownloaderBase[Transmission]): # 需要的文件信息 file_ids = [] unwanted_file_ids = [] - for torrent_file in torrent_files: - file_id = torrent_file.id - file_name = torrent_file.name - meta_info = MetaInfo(file_name) - if not meta_info.episode_list: - unwanted_file_ids.append(file_id) - continue - selected = set(meta_info.episode_list).issubset(set(episodes)) - if not selected: - unwanted_file_ids.append(file_id) - continue - file_ids.append(file_id) - # 选择文件 - server.set_files(torrent_hash, file_ids) - server.set_unwanted_files(torrent_hash, unwanted_file_ids) - # 开始任务 - server.start_torrents(torrent_hash) + try: + for torrent_file in torrent_files: + file_id = torrent_file.id + file_name = torrent_file.name + meta_info = MetaInfo(file_name) + if not meta_info.episode_list: + unwanted_file_ids.append(file_id) + continue + selected = set(meta_info.episode_list).issubset(set(episodes)) + if not selected: + unwanted_file_ids.append(file_id) + continue + file_ids.append(file_id) + # 选择文件 + server.set_files(torrent_hash, file_ids) + server.set_unwanted_files(torrent_hash, unwanted_file_ids) + # 开始任务 + server.start_torrents(torrent_hash) + finally: + torrent_files.clear() return downloader or self.get_default_config_name(), torrent_hash, torrent_layout, "添加下载任务成功" else: return downloader or self.get_default_config_name(), torrent_hash, torrent_layout, "添加下载任务成功" @@ -236,61 +242,70 @@ class TransmissionModule(_ModuleBase, _DownloaderBase[Transmission]): if hashs: # 按Hash获取 for name, server in servers.items(): - torrents, _ = server.get_torrents(ids=hashs, tags=settings.TORRENT_TAG) - for torrent in torrents or []: - ret_torrents.append(TransferTorrent( - downloader=name, - title=torrent.name, - path=Path(torrent.download_dir) / torrent.name, - hash=torrent.hashString, - size=torrent.total_size, - tags=",".join(torrent.labels or []) - )) + torrents, _ = server.get_torrents(ids=hashs, tags=settings.TORRENT_TAG) or [] + try: + for torrent in torrents: + ret_torrents.append(TransferTorrent( + downloader=name, + title=torrent.name, + path=Path(torrent.download_dir) / torrent.name, + hash=torrent.hashString, + size=torrent.total_size, + tags=",".join(torrent.labels or []) + )) + finally: + torrents.clear() elif status == TorrentStatus.TRANSFER: # 获取已完成且未整理的 for name, server in servers.items(): - torrents = server.get_completed_torrents(tags=settings.TORRENT_TAG) - for torrent in torrents or []: - # 含"已整理"tag的不处理 - if "已整理" in torrent.labels or []: - continue - # 下载路径 - path = torrent.download_dir - # 无法获取下载路径的不处理 - if not path: - logger.debug(f"未获取到 {torrent.name} 下载保存路径") - continue - ret_torrents.append(TransferTorrent( - downloader=name, - title=torrent.name, - path=Path(torrent.download_dir) / torrent.name, - hash=torrent.hashString, - tags=",".join(torrent.labels or []), - progress=torrent.progress, - state="paused" if torrent.status == "stopped" else "downloading", - )) + torrents = server.get_completed_torrents(tags=settings.TORRENT_TAG) or [] + try: + for torrent in torrents: + # 含"已整理"tag的不处理 + if "已整理" in torrent.labels or []: + continue + # 下载路径 + path = torrent.download_dir + # 无法获取下载路径的不处理 + if not path: + logger.debug(f"未获取到 {torrent.name} 下载保存路径") + continue + ret_torrents.append(TransferTorrent( + downloader=name, + title=torrent.name, + path=Path(torrent.download_dir) / torrent.name, + hash=torrent.hashString, + tags=",".join(torrent.labels or []), + progress=torrent.progress, + state="paused" if torrent.status == "stopped" else "downloading", + )) + finally: + torrents.clear() elif status == TorrentStatus.DOWNLOADING: # 获取正在下载的任务 for name, server in servers.items(): - torrents = server.get_downloading_torrents(tags=settings.TORRENT_TAG) - for torrent in torrents or []: - meta = MetaInfo(torrent.name) - dlspeed = torrent.rate_download if hasattr(torrent, "rate_download") else torrent.rateDownload - upspeed = torrent.rate_upload if hasattr(torrent, "rate_upload") else torrent.rateUpload - ret_torrents.append(DownloadingTorrent( - downloader=name, - hash=torrent.hashString, - title=torrent.name, - name=meta.name, - year=meta.year, - season_episode=meta.season_episode, - progress=torrent.progress, - size=torrent.total_size, - state="paused" if torrent.status == "stopped" else "downloading", - dlspeed=StringUtils.str_filesize(dlspeed), - upspeed=StringUtils.str_filesize(upspeed), - left_time=StringUtils.str_secends(torrent.left_until_done / dlspeed) if dlspeed > 0 else '' - )) + torrents = server.get_downloading_torrents(tags=settings.TORRENT_TAG) or [] + try: + for torrent in torrents: + meta = MetaInfo(torrent.name) + dlspeed = torrent.rate_download if hasattr(torrent, "rate_download") else torrent.rateDownload + upspeed = torrent.rate_upload if hasattr(torrent, "rate_upload") else torrent.rateUpload + ret_torrents.append(DownloadingTorrent( + downloader=name, + hash=torrent.hashString, + title=torrent.name, + name=meta.name, + year=meta.year, + season_episode=meta.season_episode, + progress=torrent.progress, + size=torrent.total_size, + state="paused" if torrent.status == "stopped" else "downloading", + dlspeed=StringUtils.str_filesize(dlspeed), + upspeed=StringUtils.str_filesize(upspeed), + left_time=StringUtils.str_secends(torrent.left_until_done / dlspeed) if dlspeed > 0 else '' + )) + finally: + torrents.clear() else: return None return ret_torrents # noqa diff --git a/app/modules/transmission/transmission.py b/app/modules/transmission/transmission.py index 6f6437f8..0ce9f8ef 100755 --- a/app/modules/transmission/transmission.py +++ b/app/modules/transmission/transmission.py @@ -1,4 +1,4 @@ -from typing import Optional, Union, Tuple, List, Literal +from typing import Optional, Union, Tuple, List import transmission_rpc from transmission_rpc import Client, Torrent, File @@ -9,14 +9,9 @@ from app.utils.url import UrlUtils class Transmission: - _protocol: Literal["http", "https"] = "http" - _host: Optional[str] = None - _port: Optional[int] = None - _username: Optional[str] = None - _password: Optional[str] = None - - trc: Optional[Client] = None - + """ + Transmission下载器 + """ # 参考transmission web,仅查询需要的参数,加速种子搜索 _trarg = ["id", "name", "status", "labels", "hashString", "totalSize", "percentDone", "addedDate", "trackerList", "trackerStats", @@ -43,18 +38,19 @@ class Transmission: return self._username = username self._password = password - if self._host and self._port: - self.trc = self.__login_transmission() + self.trc = self.__login_transmission() def __login_transmission(self) -> Optional[Client]: """ 连接transmission :return: transmission对象 """ + if not self._host or not self._port: + return None try: # 登录 logger.info(f"正在连接 transmission:{self._protocol}://{self._host}:{self._port}") - trt = transmission_rpc.Client(protocol=self._protocol, + trt = transmission_rpc.Client(protocol=self._protocol, # noqa host=self._host, port=self._port, username=self._username, @@ -97,16 +93,19 @@ class Transmission: if tags and not isinstance(tags, list): tags = [tags] ret_torrents = [] - for torrent in torrents: - # 状态过滤 - if status and torrent.status not in status: - continue - # 种子标签 - labels = [str(tag).strip() - for tag in torrent.labels] if hasattr(torrent, "labels") else [] - if tags and not set(tags).issubset(set(labels)): - continue - ret_torrents.append(torrent) + try: + for torrent in torrents: + # 状态过滤 + if status and torrent.status not in status: + continue + # 种子标签 + labels = [str(tag).strip() + for tag in torrent.labels] if hasattr(torrent, "labels") else [] + if tags and not set(tags).issubset(set(labels)): + continue + ret_torrents.append(torrent) + finally: + torrents.clear() return ret_torrents, False def get_completed_torrents(self, ids: Union[str, list] = None,