fix downloader

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