fix TorrentTransfer,通过下载器API补充Tracker
This commit is contained in:
@ -334,3 +334,15 @@ class Qbittorrent(metaclass=Singleton):
|
|||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"重新校验种子出错:{err}")
|
logger.error(f"重新校验种子出错:{err}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def add_trackers(self, ids: Union[str, list], trackers: list):
|
||||||
|
"""
|
||||||
|
添加tracker
|
||||||
|
"""
|
||||||
|
if not self.qbc:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
return self.qbc.torrents_add_trackers(torrent_hashes=ids, urls=trackers)
|
||||||
|
except Exception as err:
|
||||||
|
logger.error(f"添加tracker出错:{err}")
|
||||||
|
return False
|
||||||
|
@ -244,7 +244,6 @@ class Transmission(metaclass=Singleton):
|
|||||||
if not self.trc:
|
if not self.trc:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
session = self.trc.get_session()
|
|
||||||
download_limit_enabled = True if download_limit else False
|
download_limit_enabled = True if download_limit else False
|
||||||
upload_limit_enabled = True if upload_limit else False
|
upload_limit_enabled = True if upload_limit else False
|
||||||
self.trc.set_session(
|
self.trc.set_session(
|
||||||
@ -268,3 +267,15 @@ class Transmission(metaclass=Singleton):
|
|||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"重新校验种子出错:{err}")
|
logger.error(f"重新校验种子出错:{err}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def add_trackers(self, ids: Union[str, list], trackers: list):
|
||||||
|
"""
|
||||||
|
添加Tracker
|
||||||
|
"""
|
||||||
|
if not self.trc:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
return self.trc.change_torrent(ids=ids, tracker_list=[trackers])
|
||||||
|
except Exception as err:
|
||||||
|
logger.error(f"添加Tracker出错:{err}")
|
||||||
|
return False
|
||||||
|
@ -7,7 +7,6 @@ from typing import Any, List, Dict, Tuple, Optional
|
|||||||
import pytz
|
import pytz
|
||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
from apscheduler.triggers.cron import CronTrigger
|
from apscheduler.triggers.cron import CronTrigger
|
||||||
from torrentool.bencode import Bencode
|
|
||||||
from torrentool.torrent import Torrent
|
from torrentool.torrent import Torrent
|
||||||
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
@ -485,10 +484,12 @@ class TorrentTransfer(_PluginBase):
|
|||||||
开始移转做种
|
开始移转做种
|
||||||
"""
|
"""
|
||||||
logger.info("开始移转做种任务 ...")
|
logger.info("开始移转做种任务 ...")
|
||||||
|
|
||||||
# 源下载器
|
# 源下载器
|
||||||
downloader = self._fromdownloader
|
downloader = self._fromdownloader
|
||||||
# 目的下载器
|
# 目的下载器
|
||||||
todownloader = self._todownloader
|
todownloader = self._todownloader
|
||||||
|
|
||||||
# 获取下载器中已完成的种子
|
# 获取下载器中已完成的种子
|
||||||
downloader_obj = self.__get_downloader(downloader)
|
downloader_obj = self.__get_downloader(downloader)
|
||||||
torrents = downloader_obj.get_completed_torrents()
|
torrents = downloader_obj.get_completed_torrents()
|
||||||
@ -497,16 +498,19 @@ class TorrentTransfer(_PluginBase):
|
|||||||
else:
|
else:
|
||||||
logger.info(f"下载器 {downloader} 没有已完成种子")
|
logger.info(f"下载器 {downloader} 没有已完成种子")
|
||||||
return
|
return
|
||||||
|
|
||||||
# 过滤种子,记录保存目录
|
# 过滤种子,记录保存目录
|
||||||
hash_strs = []
|
trans_torrents = []
|
||||||
for torrent in torrents:
|
for torrent in torrents:
|
||||||
if self._event.is_set():
|
if self._event.is_set():
|
||||||
logger.info(f"移转服务停止")
|
logger.info(f"移转服务停止")
|
||||||
return
|
return
|
||||||
|
|
||||||
# 获取种子hash
|
# 获取种子hash
|
||||||
hash_str = self.__get_hash(torrent, downloader)
|
hash_str = self.__get_hash(torrent, downloader)
|
||||||
# 获取保存路径
|
# 获取保存路径
|
||||||
save_path = self.__get_save_path(torrent, downloader)
|
save_path = self.__get_save_path(torrent, downloader)
|
||||||
|
|
||||||
if self._nopaths and save_path:
|
if self._nopaths and save_path:
|
||||||
# 过滤不需要移转的路径
|
# 过滤不需要移转的路径
|
||||||
nopath_skip = False
|
nopath_skip = False
|
||||||
@ -517,6 +521,7 @@ class TorrentTransfer(_PluginBase):
|
|||||||
break
|
break
|
||||||
if nopath_skip:
|
if nopath_skip:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 获取种子标签
|
# 获取种子标签
|
||||||
torrent_labels = self.__get_label(torrent, downloader)
|
torrent_labels = self.__get_label(torrent, downloader)
|
||||||
if torrent_labels and self._nolabels:
|
if torrent_labels and self._nolabels:
|
||||||
@ -528,40 +533,52 @@ class TorrentTransfer(_PluginBase):
|
|||||||
break
|
break
|
||||||
if is_skip:
|
if is_skip:
|
||||||
continue
|
continue
|
||||||
hash_strs.append({
|
|
||||||
|
# 添加转移数据
|
||||||
|
trans_torrents.append({
|
||||||
"hash": hash_str,
|
"hash": hash_str,
|
||||||
"save_path": save_path
|
"save_path": save_path,
|
||||||
|
"torrent": torrent
|
||||||
})
|
})
|
||||||
|
|
||||||
# 开始转移任务
|
# 开始转移任务
|
||||||
if hash_strs:
|
if trans_torrents:
|
||||||
logger.info(f"需要移转的种子数:{len(hash_strs)}")
|
logger.info(f"需要移转的种子数:{len(trans_torrents)}")
|
||||||
# 记数
|
# 记数
|
||||||
total = len(hash_strs)
|
total = len(trans_torrents)
|
||||||
|
# 总成功数
|
||||||
success = 0
|
success = 0
|
||||||
|
# 总失败数
|
||||||
fail = 0
|
fail = 0
|
||||||
for hash_item in hash_strs:
|
|
||||||
|
for torrent_item in trans_torrents:
|
||||||
# 检查种子文件是否存在
|
# 检查种子文件是否存在
|
||||||
torrent_file = Path(self._fromtorrentpath) / f"{hash_item.get('hash')}.torrent"
|
torrent_file = Path(self._fromtorrentpath) / f"{torrent_item.get('hash')}.torrent"
|
||||||
if not torrent_file.exists():
|
if not torrent_file.exists():
|
||||||
logger.error(f"种子文件不存在:{torrent_file}")
|
logger.error(f"种子文件不存在:{torrent_file}")
|
||||||
fail += 1
|
# 失败计数
|
||||||
continue
|
|
||||||
# 查询hash值是否已经在目的下载器中
|
|
||||||
todownloader_obj = self.__get_downloader(todownloader)
|
|
||||||
torrent_info, _ = todownloader_obj.get_torrents(ids=[hash_item.get('hash')])
|
|
||||||
if torrent_info:
|
|
||||||
logger.info(f"{hash_item.get('hash')} 已在目的下载器中,跳过 ...")
|
|
||||||
continue
|
|
||||||
# 转换保存路径
|
|
||||||
download_dir = self.__convert_save_path(hash_item.get('save_path'),
|
|
||||||
self._frompath,
|
|
||||||
self._topath)
|
|
||||||
if not download_dir:
|
|
||||||
logger.error(f"转换保存路径失败:{hash_item.get('save_path')}")
|
|
||||||
fail += 1
|
fail += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 如果是QB检查是否有Tracker,没有的话补充解析
|
# 查询hash值是否已经在目的下载器中
|
||||||
|
todownloader_obj = self.__get_downloader(todownloader)
|
||||||
|
torrent_info, _ = todownloader_obj.get_torrents(ids=[torrent_item.get('hash')])
|
||||||
|
if torrent_info:
|
||||||
|
logger.info(f"{torrent_item.get('hash')} 已在目的下载器中,跳过 ...")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 转换保存路径
|
||||||
|
download_dir = self.__convert_save_path(torrent_item.get('save_path'),
|
||||||
|
self._frompath,
|
||||||
|
self._topath)
|
||||||
|
if not download_dir:
|
||||||
|
logger.error(f"转换保存路径失败:{torrent_item.get('save_path')}")
|
||||||
|
# 失败计数
|
||||||
|
fail += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 如果源下载器是QB检查是否有Tracker,没有的话额外获取
|
||||||
|
trackers = None
|
||||||
if downloader == "qbittorrent":
|
if downloader == "qbittorrent":
|
||||||
# 读取trackers
|
# 读取trackers
|
||||||
try:
|
try:
|
||||||
@ -569,38 +586,21 @@ class TorrentTransfer(_PluginBase):
|
|||||||
main_announce = torrent_main.announce_urls
|
main_announce = torrent_main.announce_urls
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"解析种子文件 {torrent_file} 失败:{err}")
|
logger.error(f"解析种子文件 {torrent_file} 失败:{err}")
|
||||||
|
# 失败计数
|
||||||
fail += 1
|
fail += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not main_announce:
|
if not main_announce:
|
||||||
logger.info(f"{hash_item.get('hash')} 未发现tracker信息,尝试补充tracker信息...")
|
logger.info(f"{torrent_item.get('hash')} 未发现tracker信息,尝试补充tracker ...")
|
||||||
# 读取fastresume文件
|
# 从源下载任务信息中获取Tracker
|
||||||
fastresume_file = Path(self._fromtorrentpath) / f"{hash_item.get('hash')}.fastresume"
|
torrent = torrent_item.get('torrent')
|
||||||
if not fastresume_file.exists():
|
# 源trackers
|
||||||
logger.error(f"fastresume文件不存在:{fastresume_file}")
|
trackers = [tracker.get("url") for tracker in torrent.trackers]
|
||||||
fail += 1
|
logger.info(f"获取到源tracker:{trackers}")
|
||||||
continue
|
|
||||||
# 尝试补充trackers
|
|
||||||
try:
|
|
||||||
# 解析fastresume文件
|
|
||||||
torrent_fastresume = Bencode.read_file(fastresume_file)
|
|
||||||
# 读取trackers
|
|
||||||
fastresume_trackers = torrent_fastresume.get("trackers")
|
|
||||||
if fastresume_trackers:
|
|
||||||
# 重新赋值
|
|
||||||
torrent_main.announce_urls = fastresume_trackers
|
|
||||||
# 替换种子文件路径
|
|
||||||
torrent_file = settings.TEMP_PATH / f"{hash_item.get('hash')}.torrent"
|
|
||||||
# 编码并保存到临时文件
|
|
||||||
torrent_main.to_file(torrent_file)
|
|
||||||
except Exception as err:
|
|
||||||
logger.error(f"解析fastresume文件 {fastresume_file} 失败:{err}")
|
|
||||||
fail += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 发送到另一个下载器中下载:默认暂停、传输下载路径、关闭自动管理模式
|
# 发送到另一个下载器中下载:默认暂停、传输下载路径、关闭自动管理模式
|
||||||
logger.info(f"添加转移做种任务:{torrent_file} ...")
|
logger.info(f"添加转移做种任务到下载器 {todownloader}:{torrent_file} ...")
|
||||||
download_id = self.__download(downloader=downloader,
|
download_id = self.__download(downloader=todownloader,
|
||||||
content=torrent_file.read_bytes(),
|
content=torrent_file.read_bytes(),
|
||||||
save_path=download_dir)
|
save_path=download_dir)
|
||||||
if not download_id:
|
if not download_id:
|
||||||
@ -609,22 +609,34 @@ class TorrentTransfer(_PluginBase):
|
|||||||
logger.error(f"添加下载任务失败:{torrent_file}")
|
logger.error(f"添加下载任务失败:{torrent_file}")
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
# 下载成功
|
||||||
|
logger.info(f"成功添加转移做种任务,种子文件:{torrent_file}")
|
||||||
|
|
||||||
|
# 补充Tracker
|
||||||
|
if trackers:
|
||||||
|
logger.info(f"开始补充 {download_id} 的tracker:{trackers}")
|
||||||
|
todownloader_obj.add_trackers(ids=[download_id], trackers=trackers)
|
||||||
|
|
||||||
|
# TR会自动校验,QB需要手动校验
|
||||||
|
if todownloader == "qbittorrent":
|
||||||
|
logger.info(f"qbittorrent 开始校验 {download_id} ...")
|
||||||
|
todownloader_obj.recheck_torrents(ids=[download_id])
|
||||||
|
|
||||||
# 追加校验任务
|
# 追加校验任务
|
||||||
logger.info(f"添加校验检查任务:{download_id} ...")
|
logger.info(f"添加校验检查任务:{download_id} ...")
|
||||||
if not self._recheck_torrents.get(todownloader):
|
if not self._recheck_torrents.get(todownloader):
|
||||||
self._recheck_torrents[todownloader] = []
|
self._recheck_torrents[todownloader] = []
|
||||||
self._recheck_torrents[todownloader].append(download_id)
|
self._recheck_torrents[todownloader].append(download_id)
|
||||||
# 下载成功
|
|
||||||
logger.info(f"成功添加转移做种任务,种子文件:{torrent_file}")
|
|
||||||
# TR会自动校验
|
|
||||||
if downloader == "qbittorrent":
|
|
||||||
todownloader_obj.recheck_torrents(ids=[download_id])
|
|
||||||
# 删除源种子,不能删除文件!
|
# 删除源种子,不能删除文件!
|
||||||
if self._deletesource:
|
if self._deletesource:
|
||||||
downloader_obj.delete_torrents(delete_file=False, ids=[hash_item.get('hash')])
|
logger.info(f"删除源下载器任务(不含文件):{torrent_item.get('hash')} ...")
|
||||||
|
downloader_obj.delete_torrents(delete_file=False, ids=[torrent_item.get('hash')])
|
||||||
|
|
||||||
|
# 成功计数
|
||||||
success += 1
|
success += 1
|
||||||
# 插入转种记录
|
# 插入转种记录
|
||||||
history_key = "%s-%s" % (self._fromdownloader, hash_item.get('hash'))
|
history_key = "%s-%s" % (self._fromdownloader, torrent_item.get('hash'))
|
||||||
self.save_data(key=history_key,
|
self.save_data(key=history_key,
|
||||||
value={
|
value={
|
||||||
"to_download": self._todownloader,
|
"to_download": self._todownloader,
|
||||||
@ -634,6 +646,7 @@ class TorrentTransfer(_PluginBase):
|
|||||||
# 触发校验任务
|
# 触发校验任务
|
||||||
if success > 0 and self._autostart:
|
if success > 0 and self._autostart:
|
||||||
self.check_recheck()
|
self.check_recheck()
|
||||||
|
|
||||||
# 发送通知
|
# 发送通知
|
||||||
if self._notify:
|
if self._notify:
|
||||||
self.post_message(
|
self.post_message(
|
||||||
@ -655,22 +668,33 @@ class TorrentTransfer(_PluginBase):
|
|||||||
return
|
return
|
||||||
if self._is_recheck_running:
|
if self._is_recheck_running:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 校验下载器
|
||||||
downloader = self._todownloader
|
downloader = self._todownloader
|
||||||
|
|
||||||
# 需要检查的种子
|
# 需要检查的种子
|
||||||
recheck_torrents = self._recheck_torrents.get(downloader, [])
|
recheck_torrents = self._recheck_torrents.get(downloader, [])
|
||||||
if not recheck_torrents:
|
if not recheck_torrents:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(f"开始检查下载器 {downloader} 的校验任务 ...")
|
logger.info(f"开始检查下载器 {downloader} 的校验任务 ...")
|
||||||
|
|
||||||
|
# 运行状态
|
||||||
self._is_recheck_running = True
|
self._is_recheck_running = True
|
||||||
|
|
||||||
|
# 获取任务
|
||||||
downloader_obj = self.__get_downloader(downloader)
|
downloader_obj = self.__get_downloader(downloader)
|
||||||
torrents, _ = downloader_obj.get_torrents(ids=recheck_torrents)
|
torrents, _ = downloader_obj.get_torrents(ids=recheck_torrents)
|
||||||
if torrents:
|
if torrents:
|
||||||
|
# 可做种的种子
|
||||||
can_seeding_torrents = []
|
can_seeding_torrents = []
|
||||||
for torrent in torrents:
|
for torrent in torrents:
|
||||||
# 获取种子hash
|
# 获取种子hash
|
||||||
hash_str = self.__get_hash(torrent, downloader)
|
hash_str = self.__get_hash(torrent, downloader)
|
||||||
|
# 判断是否可做种
|
||||||
if self.__can_seeding(torrent, downloader):
|
if self.__can_seeding(torrent, downloader):
|
||||||
can_seeding_torrents.append(hash_str)
|
can_seeding_torrents.append(hash_str)
|
||||||
|
|
||||||
if can_seeding_torrents:
|
if can_seeding_torrents:
|
||||||
logger.info(f"共 {len(can_seeding_torrents)} 个任务校验完成,开始做种 ...")
|
logger.info(f"共 {len(can_seeding_torrents)} 个任务校验完成,开始做种 ...")
|
||||||
# 开始做种
|
# 开始做种
|
||||||
@ -678,11 +702,13 @@ class TorrentTransfer(_PluginBase):
|
|||||||
# 去除已经处理过的种子
|
# 去除已经处理过的种子
|
||||||
self._recheck_torrents[downloader] = list(
|
self._recheck_torrents[downloader] = list(
|
||||||
set(recheck_torrents).difference(set(can_seeding_torrents)))
|
set(recheck_torrents).difference(set(can_seeding_torrents)))
|
||||||
|
|
||||||
elif torrents is None:
|
elif torrents is None:
|
||||||
logger.info(f"下载器 {downloader} 查询校验任务失败,将在下次继续查询 ...")
|
logger.info(f"下载器 {downloader} 查询校验任务失败,将在下次继续查询 ...")
|
||||||
else:
|
else:
|
||||||
logger.info(f"下载器 {downloader} 中没有需要检查的校验任务,清空待处理列表 ...")
|
logger.info(f"下载器 {downloader} 中没有需要检查的校验任务,清空待处理列表 ...")
|
||||||
self._recheck_torrents[downloader] = []
|
self._recheck_torrents[downloader] = []
|
||||||
|
|
||||||
self._is_recheck_running = False
|
self._is_recheck_running = False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
Reference in New Issue
Block a user