feat: enhance agent download task controls

This commit is contained in:
jxxghp
2026-06-15 13:51:35 +08:00
parent d2803bed1e
commit 6a635ac720
19 changed files with 1332 additions and 183 deletions
+89
View File
@@ -310,6 +310,8 @@ class TransmissionModule(_ModuleBase, _DownloaderBase[Transmission]):
torrent_data, "left_until_done", "leftUntilDone"
) or 0
torrent_path = __get_torrent_path(torrent_data)
ratio_limit = __get_torrent_attr(torrent_data, "seed_ratio_limit", "seedRatioLimit")
seeding_time_limit = __get_torrent_attr(torrent_data, "seed_idle_limit", "seedIdleLimit")
return DownloaderTorrent(
downloader=downloader_name,
hash=torrent_data.hashString,
@@ -318,12 +320,20 @@ class TransmissionModule(_ModuleBase, _DownloaderBase[Transmission]):
year=meta.year,
season_episode=meta.season_episode,
path=Path(self.normalize_return_path(torrent_path, downloader_name)),
save_path=self.normalize_return_path(
Path(torrent_data.download_dir), downloader_name
) if getattr(torrent_data, "download_dir", None) else None,
content_path=self.normalize_return_path(torrent_path, downloader_name),
progress=__get_torrent_progress(torrent_data),
size=__get_torrent_size(torrent_data),
state=self.__normalize_torrent_state(torrent_data.status),
dlspeed=StringUtils.str_filesize(dlspeed),
upspeed=StringUtils.str_filesize(upspeed),
tags=__get_torrent_labels(torrent_data),
download_limit=__get_torrent_attr(torrent_data, "download_limit", "downloadLimit"),
upload_limit=__get_torrent_attr(torrent_data, "upload_limit", "uploadLimit"),
ratio_limit=ratio_limit,
seeding_time_limit=seeding_time_limit,
left_time=StringUtils.str_secends(
left_until_done / dlspeed
) if dlspeed > 0 else ''
@@ -491,6 +501,85 @@ class TransmissionModule(_ModuleBase, _DownloaderBase[Transmission]):
org_tags = server.get_torrent_tags(ids=hashs)
return server.set_torrent_tag(ids=hashs, tags=tags, org_tags=org_tags)
def update_torrent(
self,
hash_string: str,
downloader: Optional[str] = None,
download_limit: Optional[float] = None,
upload_limit: Optional[float] = None,
tracker_list: Optional[list] = None,
save_path: Optional[str] = None,
category: Optional[str] = None,
ratio_limit: Optional[float] = None,
seeding_time_limit: Optional[int] = None,
) -> Optional[Dict[str, bool]]:
"""
修改下载任务属性。
:param hash_string: 种子Hash
:param downloader: 下载器
:param download_limit: 下载限速,单位 KB/s
:param upload_limit: 上传限速,单位 KB/s
:param tracker_list: Tracker URL列表
:param save_path: 保存目录
:param category: 分类,Transmission 不支持
:param ratio_limit: 分享率限制
:param seeding_time_limit: 做种时间限制,单位分钟
:return: 各项修改结果
"""
server: Transmission = self.get_instance(downloader)
if not server:
return None
results = {}
if any(
value is not None
for value in (download_limit, upload_limit, ratio_limit, seeding_time_limit)
):
change_result = server.change_torrent(
hash_string=hash_string,
download_limit=download_limit,
upload_limit=upload_limit,
ratio_limit=ratio_limit,
seeding_time_limit=seeding_time_limit,
)
results["limits"] = change_result
if save_path is not None:
results["save_path"] = server.set_torrent_location(
hash_string=hash_string,
location=self.normalize_path(Path(save_path), downloader),
)
if tracker_list is not None:
results["trackers"] = server.update_tracker(
hash_string=hash_string, tracker_list=tracker_list
)
if category is not None:
results["category"] = False
return results
def get_torrent_trackers(
self,
hash_string: str,
downloader: Optional[str] = None,
) -> Optional[Dict[str, List[str]]]:
"""
查询下载任务Tracker列表。
:param hash_string: 种子Hash
:param downloader: 下载器
:return: 下载器名称到Tracker列表的映射
"""
if downloader:
server: Transmission = self.get_instance(downloader)
if not server:
return None
servers = {downloader: server}
else:
servers: Dict[str, Transmission] = self.get_instances()
ret_trackers = {}
for name, server in servers.items():
trackers = server.get_trackers(hash_string)
if trackers is not None:
ret_trackers[name] = trackers
return ret_trackers
def start_torrents(self, hashs: Union[list, str],
downloader: Optional[str] = None) -> Optional[bool]:
"""
+62 -33
View File
@@ -402,45 +402,46 @@ class Transmission:
"""
if not hash_string:
return False
if upload_limit:
uploadLimited = True
uploadLimit = int(upload_limit)
else:
uploadLimited = False
uploadLimit = 0
if download_limit:
downloadLimited = True
downloadLimit = int(download_limit)
else:
downloadLimited = False
downloadLimit = 0
if ratio_limit:
seedRatioMode = 1
seedRatioLimit = round(float(ratio_limit), 2)
else:
seedRatioMode = 2
seedRatioLimit = 0
if seeding_time_limit:
seedIdleMode = 1
seedIdleLimit = int(seeding_time_limit)
else:
seedIdleMode = 2
seedIdleLimit = 0
change_kwargs = {"ids": hash_string}
if upload_limit is not None:
change_kwargs["uploadLimited"] = bool(upload_limit)
change_kwargs["uploadLimit"] = int(upload_limit)
if download_limit is not None:
change_kwargs["downloadLimited"] = bool(download_limit)
change_kwargs["downloadLimit"] = int(download_limit)
if ratio_limit is not None:
change_kwargs["seedRatioMode"] = 1 if ratio_limit else 2
change_kwargs["seedRatioLimit"] = round(float(ratio_limit), 2) if ratio_limit else 0
if seeding_time_limit is not None:
change_kwargs["seedIdleMode"] = 1 if seeding_time_limit else 2
change_kwargs["seedIdleLimit"] = int(seeding_time_limit) if seeding_time_limit else 0
try:
self.trc.change_torrent(ids=hash_string,
uploadLimited=uploadLimited,
uploadLimit=uploadLimit,
downloadLimited=downloadLimited,
downloadLimit=downloadLimit,
seedRatioMode=seedRatioMode,
seedRatioLimit=seedRatioLimit,
seedIdleMode=seedIdleMode,
seedIdleLimit=seedIdleLimit)
self.trc.change_torrent(**change_kwargs)
return True
except Exception as err:
logger.error(f"设置种子出错:{str(err)}")
return False
def set_torrent_location(self, hash_string: str, location: str) -> bool:
"""
修改种子保存目录。
:param hash_string: 种子Hash
:param location: 新保存目录
:return: 是否修改成功
"""
if not self.trc or not hash_string or not location:
return False
try:
move_torrent_data = getattr(self.trc, "move_torrent_data", None)
if callable(move_torrent_data):
move_torrent_data(ids=hash_string, location=location)
else:
self.trc.change_torrent(ids=hash_string, download_dir=location)
return True
except Exception as err:
logger.error(f"设置种子保存目录出错:{str(err)}")
return False
def update_tracker(self, hash_string: str, tracker_list: list = None) -> bool:
"""
tr4.0及以上弃用直接设置tracker 共用change方法
@@ -456,6 +457,34 @@ class Transmission:
logger.error(f"修改tracker出错:{str(err)}")
return False
def get_trackers(self, hash_string: str) -> Optional[List[str]]:
"""
获取种子Tracker列表。
:param hash_string: 种子Hash
:return: Tracker URL列表
"""
if not self.trc or not hash_string:
return None
try:
torrents = self.trc.get_torrents(ids=hash_string, arguments=self._trarg)
if not torrents:
return []
torrent = torrents[0]
tracker_list = getattr(torrent, "tracker_list", None) \
or getattr(torrent, "trackerList", None) \
or []
if tracker_list:
return list(tracker_list)
trackers = getattr(torrent, "trackers", None) or []
return [
tracker.get("announce")
for tracker in trackers
if isinstance(tracker, dict) and tracker.get("announce")
]
except Exception as err:
logger.error(f"获取tracker出错:{str(err)}")
return None
def get_session(self) -> Optional[Session]:
"""
获取Transmission当前的会话信息和配置设置