fix transfer

This commit is contained in:
jxxghp 2023-06-11 14:52:23 +08:00
parent f57e801236
commit 760f603076
9 changed files with 189 additions and 149 deletions

View File

@ -103,8 +103,8 @@ class ChainBase(AbstractSingleton, metaclass=Singleton):
episodes: Set[int] = None) -> Optional[Tuple[Optional[str], str]]: episodes: Set[int] = None) -> Optional[Tuple[Optional[str], str]]:
return self.run_module("download", torrent_path=torrent_path, cookie=cookie, episodes=episodes) return self.run_module("download", torrent_path=torrent_path, cookie=cookie, episodes=episodes)
def list_torrents(self, status: TorrentStatus) -> Optional[List[dict]]: def list_torrents(self, status: TorrentStatus = None, hashs: Union[list, str] = None) -> Optional[List[dict]]:
return self.run_module("list_torrents", status=status) return self.run_module("list_torrents", status=status, hashs=hashs)
def remove_torrents(self, hashs: Union[str, list]) -> bool: def remove_torrents(self, hashs: Union[str, list]) -> bool:
return self.run_module("remove_torrents", hashs=hashs) return self.run_module("remove_torrents", hashs=hashs)

View File

@ -1,14 +1,15 @@
import re
from typing import List, Optional from typing import List, Optional
from app.chain import ChainBase from app.chain import ChainBase
from app.core.metainfo import MetaInfo
from app.core.context import MediaInfo
from app.core.config import settings from app.core.config import settings
from app.core.context import MediaInfo
from app.core.meta import MetaBase from app.core.meta import MetaBase
from app.core.metainfo import MetaInfo
from app.log import logger from app.log import logger
from app.utils.string import StringUtils from app.utils.string import StringUtils
from app.utils.system import SystemUtils from app.utils.system import SystemUtils
from app.utils.types import TorrentStatus, MediaType from app.utils.types import TorrentStatus
class TransferChain(ChainBase): class TransferChain(ChainBase):
@ -16,16 +17,47 @@ class TransferChain(ChainBase):
文件转移处理链 文件转移处理链
""" """
def process(self) -> bool: def process(self, arg_str: str = None) -> bool:
""" """
获取下载器中的种子列表并执行转移 获取下载器中的种子列表并执行转移
""" """
def extract_hash_and_number(string: str):
"""
从字符串中提取种子hash和编号
"""
pattern = r'([a-fA-F0-9]{32}) (\d+)'
match = re.search(pattern, string)
if match:
hash_value = match.group(1)
number = match.group(2)
return hash_value, int(number)
else:
return None, None
if arg_str:
logger.info(f"开始转移下载器文件,参数:{arg_str}")
# 解析中种子hashTMDB ID
torrent_hash, tmdbid = extract_hash_and_number(arg_str)
if not hash or not tmdbid:
logger.error(f"参数错误,参数:{arg_str}")
return False
# 获取种子
torrents: Optional[List[dict]] = self.list_torrents(hashs=torrent_hash)
if not torrents:
logger.error(f"没有获取到种子,参数:{arg_str}")
return False
# 查询媒体信息
arg_mediainfo = self.recognize_media(meta=MetaInfo(torrents[0].get("title")), tmdbid=tmdbid)
else:
arg_mediainfo = None
logger.info("开始执行下载器文件转移 ...") logger.info("开始执行下载器文件转移 ...")
# 从下载器获取种子列表 # 从下载器获取种子列表
torrents: Optional[List[dict]] = self.list_torrents(status=TorrentStatus.TRANSFER) torrents: Optional[List[dict]] = self.list_torrents(status=TorrentStatus.TRANSFER)
if not torrents: if not torrents:
logger.info("没有获取到已完成的下载任务") logger.info("没有获取到已完成的下载任务")
return False return False
logger.info(f"获取到 {len(torrents)} 个已完成的下载任务") logger.info(f"获取到 {len(torrents)} 个已完成的下载任务")
# 识别 # 识别
for torrent in torrents: for torrent in torrents:
@ -35,11 +67,15 @@ class TransferChain(ChainBase):
logger.warn(f'未识别到元数据,标题:{torrent.get("title")}') logger.warn(f'未识别到元数据,标题:{torrent.get("title")}')
continue continue
# 识别媒体信息 # 识别媒体信息
if not arg_mediainfo:
mediainfo: MediaInfo = self.recognize_media(meta=meta) mediainfo: MediaInfo = self.recognize_media(meta=meta)
if not mediainfo: if not mediainfo:
logger.warn(f'未识别到媒体信息,标题:{torrent.get("title")}') logger.warn(f'未识别到媒体信息,标题:{torrent.get("title")}')
self.post_message(title=f"{torrent.get('title')} 未识别到媒体信息,无法入库!") self.post_message(title=f"{torrent.get('title')} 未识别到媒体信息,无法入库!\n"
f"回复:/transfer {torrent.get('hash')} [tmdbid] 手动识别转移。")
continue continue
else:
mediainfo = arg_mediainfo
logger.info(f"{torrent.get('title')} 识别为:{mediainfo.type.value} {mediainfo.get_title_string()}") logger.info(f"{torrent.get('title')} 识别为:{mediainfo.type.value} {mediainfo.get_title_string()}")
# 更新媒体图片 # 更新媒体图片
self.obtain_image(mediainfo=mediainfo) self.obtain_image(mediainfo=mediainfo)

View File

@ -40,12 +40,12 @@ class Command(metaclass=Singleton):
"description": "同步豆瓣想看", "description": "同步豆瓣想看",
"data": {} "data": {}
}, },
"/subscriberefresh": { "/subscribe_refresh": {
"func": SubscribeChain().refresh, "func": SubscribeChain().refresh,
"description": "刷新订阅", "description": "刷新订阅",
"data": {} "data": {}
}, },
"/subscribesearch": { "/subscribe_search": {
"func": SubscribeChain().search, "func": SubscribeChain().search,
"description": "搜索订阅", "description": "搜索订阅",
"data": { "data": {
@ -135,15 +135,20 @@ class Command(metaclass=Singleton):
""" """
return self._commands.get(cmd, {}) return self._commands.get(cmd, {})
def execute(self, cmd: str) -> None: def execute(self, cmd: str, data_str: str = "") -> None:
""" """
执行命令 执行命令
""" """
command = self.get(cmd) command = self.get(cmd)
if command: if command:
logger.info(f"开始执行:{command.get('description')} ...") logger.info(f"开始执行:{command.get('description')} ...")
data = command['data'] if command.get('data') else {} cmd_data = command['data'] if command.get('data') else {}
command['func'](**data) if cmd_data:
command['func'](**cmd_data)
elif data_str:
command['func'](data_str)
else:
command['func']()
@staticmethod @staticmethod
def send_plugin_event(etype: EventType, data: dict) -> None: def send_plugin_event(etype: EventType, data: dict) -> None:
@ -157,9 +162,12 @@ class Command(metaclass=Singleton):
""" """
注册命令执行事件 注册命令执行事件
event_data: { event_data: {
"cmd": "/xxx" "cmd": "/xxx args"
} }
""" """
cmd = event.event_data.get('cmd') event_str = event.event_data.get('cmd')
if event_str:
cmd = event_str.split()[0]
args = " ".join(event_str.split()[1:])
if self.get(cmd): if self.get(cmd):
self.execute(cmd) self.execute(cmd, args)

View File

@ -137,10 +137,11 @@ class _ModuleBase(metaclass=ABCMeta):
""" """
pass pass
def list_torrents(self, status: TorrentStatus) -> Optional[List[dict]]: def list_torrents(self, status: TorrentStatus = None, hashs: Union[list, str] = None) -> Optional[List[dict]]:
""" """
获取下载器种子列表 获取下载器种子列表
:param status: 种子状态 :param status: 种子状态
:param hashs: 种子Hash
:return: 下载器中符合状态的种子列表 :return: 下载器中符合状态的种子列表
""" """
pass pass

View File

@ -89,19 +89,53 @@ class QbittorrentModule(_ModuleBase):
:param hashs: 种子Hash :param hashs: 种子Hash
:return: 处理状态 :return: 处理状态
""" """
return self.qbittorrent.set_torrents_tag(ids=hashs, tag=['已整理']) return self.qbittorrent.set_torrents_tag(ids=hashs, tags=['已整理'])
def list_torrents(self, status: TorrentStatus) -> Optional[List[dict]]: def list_torrents(self, status: TorrentStatus = None, hashs: Union[list, str] = None) -> Optional[List[dict]]:
""" """
获取下载器种子列表 获取下载器种子列表
:param status: 种子状态 :param status: 种子状态
:param hashs: 种子Hash
:return: 下载器中符合状态的种子列表 :return: 下载器中符合状态的种子列表
""" """
if status == TorrentStatus.TRANSFER: ret_torrents = []
torrents = self.qbittorrent.get_transfer_torrents(tag=settings.TORRENT_TAG or None) if hashs:
# 按Hash获取
torrents, _ = self.qbittorrent.get_torrents(ids=hashs)
for torrent in torrents:
content_path = torrent.get("content_path")
if content_path:
torrent_path = Path(content_path)
else:
torrent_path = Path(settings.DOWNLOAD_PATH) / torrent.get('name')
ret_torrents.append({
'title': torrent.get('name'),
'path': torrent_path,
'hash': torrent.get('hash'),
'tags': torrent.get('tags')
})
elif status == TorrentStatus.TRANSFER:
# 获取已完成且未整理的
torrents = self.qbittorrent.get_completed_torrents(tags=settings.TORRENT_TAG)
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 = Path(settings.DOWNLOAD_PATH) / torrent.get('name')
ret_torrents.append({
'title': torrent.get('name'),
'path': torrent_path,
'hash': torrent.get('hash'),
'tags': torrent.get('tags')
})
else: else:
return None return None
return torrents return ret_torrents
def remove_torrents(self, hashs: Union[str, list]) -> bool: def remove_torrents(self, hashs: Union[str, list]) -> bool:
""" """

View File

@ -1,5 +1,4 @@
import time import time
from pathlib import Path
from typing import Optional, Union, Tuple, List from typing import Optional, Union, Tuple, List
import qbittorrentapi import qbittorrentapi
@ -52,7 +51,7 @@ class Qbittorrent(metaclass=Singleton):
def get_torrents(self, ids: Union[str, list] = None, def get_torrents(self, ids: Union[str, list] = None,
status: Union[str, list] = None, status: Union[str, list] = None,
tag: Union[str, list] = None) -> Tuple[List[TorrentDictionary], bool]: tags: Union[str, list] = None) -> Tuple[List[TorrentDictionary], bool]:
""" """
获取种子列表 获取种子列表
return: 种子列表, 是否发生异常 return: 种子列表, 是否发生异常
@ -62,17 +61,12 @@ class Qbittorrent(metaclass=Singleton):
try: try:
torrents = self.qbc.torrents_info(torrent_hashes=ids, torrents = self.qbc.torrents_info(torrent_hashes=ids,
status_filter=status) status_filter=status)
if tag: if tags:
results = [] results = []
if not isinstance(tag, list): if not isinstance(tags, list):
tag = [tag] tags = [tags]
for torrent in torrents: for torrent in torrents:
include_flag = True if set(tags).issubset(set(torrent.get("tags"))):
for t in tag:
if t and t not in torrent.get("tags"):
include_flag = False
break
if include_flag:
results.append(torrent) results.append(torrent)
return results, False return results, False
return torrents or [], False return torrents or [], False
@ -81,18 +75,18 @@ class Qbittorrent(metaclass=Singleton):
return [], True return [], True
def get_completed_torrents(self, ids: Union[str, list] = None, def get_completed_torrents(self, ids: Union[str, list] = None,
tag: Union[str, list] = None) -> Optional[List[TorrentDictionary]]: tags: Union[str, list] = None) -> Optional[List[TorrentDictionary]]:
""" """
获取已完成的种子 获取已完成的种子
return: 种子列表, 如发生异常则返回None return: 种子列表, 如发生异常则返回None
""" """
if not self.qbc: if not self.qbc:
return None return None
torrents, error = self.get_torrents(status=["completed"], ids=ids, tag=tag) torrents, error = self.get_torrents(status=["completed"], ids=ids, tags=tags)
return None if error else torrents or [] return None if error else torrents or []
def get_downloading_torrents(self, ids: Union[str, list] = None, def get_downloading_torrents(self, ids: Union[str, list] = None,
tag: Union[str, list] = None) -> Optional[List[TorrentDictionary]]: tags: Union[str, list] = None) -> Optional[List[TorrentDictionary]]:
""" """
获取正在下载的种子 获取正在下载的种子
return: 种子列表, 如发生异常则返回None return: 种子列表, 如发生异常则返回None
@ -101,7 +95,7 @@ class Qbittorrent(metaclass=Singleton):
return None return None
torrents, error = self.get_torrents(ids=ids, torrents, error = self.get_torrents(ids=ids,
status=["downloading"], status=["downloading"],
tag=tag) tags=tags)
return None if error else torrents or [] return None if error else torrents or []
def remove_torrents_tag(self, ids: Union[str, list], tag: Union[str, list]) -> bool: def remove_torrents_tag(self, ids: Union[str, list], tag: Union[str, list]) -> bool:
@ -117,7 +111,7 @@ class Qbittorrent(metaclass=Singleton):
logger.error(f"移除种子Tag出错{err}") logger.error(f"移除种子Tag出错{err}")
return False return False
def set_torrents_tag(self, ids: Union[str, list], tag: list): def set_torrents_tag(self, ids: Union[str, list], tags: list):
""" """
设置种子状态为已整理以及是否强制做种 设置种子状态为已整理以及是否强制做种
""" """
@ -125,7 +119,7 @@ class Qbittorrent(metaclass=Singleton):
return return
try: try:
# 打标签 # 打标签
self.qbc.torrents_add_tags(tags=tag, torrent_hashes=ids) self.qbc.torrents_add_tags(tags=tags, torrent_hashes=ids)
except Exception as err: except Exception as err:
logger.error(f"设置种子Tag出错{err}") logger.error(f"设置种子Tag出错{err}")
@ -138,40 +132,6 @@ class Qbittorrent(metaclass=Singleton):
except Exception as err: except Exception as err:
logger.error(f"设置强制作种出错:{err}") logger.error(f"设置强制作种出错:{err}")
def get_transfer_torrents(self, tag: Union[str, list] = None) -> Optional[List[dict]]:
"""
获取下载文件转移任务种子
"""
# 处理下载完成的任务
torrents = self.get_completed_torrents() or []
trans_tasks = []
for torrent in torrents:
torrent_tags = torrent.get("tags") or ""
# 含"已整理"tag的不处理
if "已整理" in torrent_tags:
continue
# 开启标签隔离,未包含指定标签的不处理
if tag and tag not in torrent_tags:
logger.debug(f"{torrent.get('name')} 未包含指定标签:{tag}")
continue
path = torrent.get("save_path")
# 无法获取下载路径的不处理
if not path:
logger.warn(f"未获取到 {torrent.get('name')} 下载保存路径")
continue
content_path = torrent.get("content_path")
if content_path:
torrent_path = Path(content_path)
else:
torrent_path = Path(settings.DOWNLOAD_PATH) / torrent.get('name')
trans_tasks.append({
'title': torrent.get('name'),
'path': torrent_path,
'hash': torrent.get('hash'),
'tags': torrent.get('tags')
})
return trans_tasks
def __get_last_add_torrentid_by_tag(self, tag: Union[str, list], def __get_last_add_torrentid_by_tag(self, tag: Union[str, list],
status: Union[str, list] = None) -> Optional[str]: status: Union[str, list] = None) -> Optional[str]:
""" """
@ -179,7 +139,7 @@ class Qbittorrent(metaclass=Singleton):
:return: 种子ID :return: 种子ID
""" """
try: try:
torrents, _ = self.get_torrents(status=status, tag=tag) torrents, _ = self.get_torrents(status=status, tags=tag)
except Exception as err: except Exception as err:
logger.error(f"获取种子列表出错:{err}") logger.error(f"获取种子列表出错:{err}")
return None return None

View File

@ -262,7 +262,7 @@ class TmdbHelper:
continue continue
index += 1 index += 1
if not movie.get("names"): if not movie.get("names"):
movie = self.get_info(MediaType.MOVIE, movie.get("id")) movie = self.get_info(mtype=MediaType.MOVIE, tmdbid=movie.get("id"))
if movie and self.__compare_names(name, movie.get("names")): if movie and self.__compare_names(name, movie.get("names")):
return movie return movie
if index > 5: if index > 5:
@ -319,7 +319,7 @@ class TmdbHelper:
continue continue
index += 1 index += 1
if not tv.get("names"): if not tv.get("names"):
tv = self.get_info(MediaType.TV, tv.get("id")) tv = self.get_info(mtype=MediaType.TV, tmdbid=tv.get("id"))
if self.__compare_names(name, tv.get("names")): if self.__compare_names(name, tv.get("names")):
return tv return tv
if index > 5: if index > 5:
@ -374,7 +374,7 @@ class TmdbHelper:
# 匹配别名、译名 # 匹配别名、译名
for tv in tvs[:5]: for tv in tvs[:5]:
if not tv.get("names"): if not tv.get("names"):
tv = self.get_info(MediaType.TV, tv.get("id")) tv = self.get_info(mtype=MediaType.TV, tmdbid=tv.get("id"))
if not self.__compare_names(name, tv.get("names")): if not self.__compare_names(name, tv.get("names")):
continue continue
if __season_match(tv_info=tv, _season_year=season_year): if __season_match(tv_info=tv, _season_year=season_year):
@ -452,12 +452,12 @@ class TmdbHelper:
for multi in multis[:5]: for multi in multis[:5]:
if multi.get("media_type") == "movie": if multi.get("media_type") == "movie":
if not multi.get("names"): if not multi.get("names"):
multi = self.get_info(MediaType.MOVIE, multi.get("id")) multi = self.get_info(mtype=MediaType.MOVIE, tmdbid=multi.get("id"))
if self.__compare_names(name, multi.get("names")): if self.__compare_names(name, multi.get("names")):
return multi return multi
elif multi.get("media_type") == "tv": elif multi.get("media_type") == "tv":
if not multi.get("names"): if not multi.get("names"):
multi = self.get_info(MediaType.TV, multi.get("id")) multi = self.get_info(mtype=MediaType.TV, tmdbid=multi.get("id"))
if self.__compare_names(name, multi.get("names")): if self.__compare_names(name, multi.get("names")):
return multi return multi
return {} return {}
@ -541,15 +541,24 @@ class TmdbHelper:
genre_ids.append(genre.get('id')) genre_ids.append(genre.get('id'))
return genre_ids return genre_ids
# 设置语言 # 查询TMDB详ngeq
if mtype == MediaType.MOVIE: if mtype == MediaType.MOVIE:
tmdb_info = self.__get_movie_detail(tmdbid) tmdb_info = self.__get_movie_detail(tmdbid)
if tmdb_info: if tmdb_info:
tmdb_info['media_type'] = MediaType.MOVIE tmdb_info['media_type'] = MediaType.MOVIE
elif mtype == MediaType.TV:
tmdb_info = self.__get_tv_detail(tmdbid)
if tmdb_info:
tmdb_info['media_type'] = MediaType.TV
else:
tmdb_info = self.__get_movie_detail(tmdbid)
if tmdb_info:
tmdb_info['media_type'] = MediaType.MOVIE
else: else:
tmdb_info = self.__get_tv_detail(tmdbid) tmdb_info = self.__get_tv_detail(tmdbid)
if tmdb_info: if tmdb_info:
tmdb_info['media_type'] = MediaType.TV tmdb_info['media_type'] = MediaType.TV
if tmdb_info: if tmdb_info:
# 转换genreid # 转换genreid
tmdb_info['genre_ids'] = __get_genre_ids(tmdb_info.get('genres')) tmdb_info['genre_ids'] = __get_genre_ids(tmdb_info.get('genres'))

View File

@ -3,13 +3,13 @@ from typing import Set, Tuple, Optional, Union, List
from app.core.config import settings from app.core.config import settings
from app.core.metainfo import MetaInfo from app.core.metainfo import MetaInfo
from app.log import logger
from app.modules import _ModuleBase from app.modules import _ModuleBase
from app.modules.transmission.transmission import Transmission from app.modules.transmission.transmission import Transmission
from app.utils.types import TorrentStatus from app.utils.types import TorrentStatus
class TransmissionModule(_ModuleBase): class TransmissionModule(_ModuleBase):
transmission: Transmission = None transmission: Transmission = None
def init_module(self) -> None: def init_module(self) -> None:
@ -77,19 +77,48 @@ class TransmissionModule(_ModuleBase):
:param hashs: 种子Hash :param hashs: 种子Hash
:return: 处理状态 :return: 处理状态
""" """
return self.transmission.set_torrent_tag(ids=hashs, tag=['已整理']) return self.transmission.set_torrent_tag(ids=hashs, tags=['已整理'])
def list_torrents(self, status: TorrentStatus) -> Optional[List[dict]]: def list_torrents(self, status: TorrentStatus = None, hashs: Union[list, str] = None) -> Optional[List[dict]]:
""" """
获取下载器种子列表 获取下载器种子列表
:param status: 种子状态 :param status: 种子状态
:param hashs: 种子Hash
:return: 下载器中符合状态的种子列表 :return: 下载器中符合状态的种子列表
""" """
if status == TorrentStatus.TRANSFER: ret_torrents = []
torrents = self.transmission.get_transfer_torrents(tag=settings.TORRENT_TAG or None) if hashs:
# 按Hash获取
torrents, _ = self.transmission.get_torrents(ids=hashs)
for torrent in torrents:
ret_torrents.append({
'title': torrent.name,
'path': Path(torrent.download_dir) / torrent.name,
'hash': torrent.hashString,
'tags': torrent.labels
})
elif status == TorrentStatus.TRANSFER:
# 获取已完成且未整理的
torrents = self.transmission.get_completed_torrents(tags=settings.TORRENT_TAG)
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({
'title': torrent.name,
'path': Path(path) / torrent.name,
'hash': torrent.hashString,
'tags': torrent.labels
})
else: else:
return None return None
return torrents return ret_torrents
def remove_torrents(self, hashs: Union[str, list]) -> bool: def remove_torrents(self, hashs: Union[str, list]) -> bool:
""" """

View File

@ -1,4 +1,3 @@
from pathlib import Path
from typing import Optional, Union, Tuple, List from typing import Optional, Union, Tuple, List
import transmission_rpc import transmission_rpc
@ -50,7 +49,7 @@ class Transmission(metaclass=Singleton):
return None return None
def get_torrents(self, ids: Union[str, list] = None, status: Union[str, list] = None, def get_torrents(self, ids: Union[str, list] = None, status: Union[str, list] = None,
tag: Union[str, list] = None) -> Tuple[List[Torrent], bool]: tags: Union[str, list] = None) -> Tuple[List[Torrent], bool]:
""" """
获取种子列表 获取种子列表
返回结果 种子列表, 是否有错误 返回结果 种子列表, 是否有错误
@ -64,25 +63,22 @@ class Transmission(metaclass=Singleton):
return [], True return [], True
if status and not isinstance(status, list): if status and not isinstance(status, list):
status = [status] status = [status]
if tag and not isinstance(tag, list): if tags and not isinstance(tags, list):
tag = [tag] tags = [tags]
ret_torrents = [] ret_torrents = []
for torrent in torrents: for torrent in torrents:
# 状态过滤
if status and torrent.status not in status: if status and torrent.status not in status:
continue continue
# 种子标签
labels = torrent.labels if hasattr(torrent, "labels") else [] labels = torrent.labels if hasattr(torrent, "labels") else []
include_flag = True if tags and not set(tags).issubset(set(labels)):
if tag: continue
for t in tag:
if t and t not in labels:
include_flag = False
break
if include_flag:
ret_torrents.append(torrent) ret_torrents.append(torrent)
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,
tag: Union[str, list] = None) -> Optional[List[Torrent]]: tags: Union[str, list] = None) -> Optional[List[Torrent]]:
""" """
获取已完成的种子列表 获取已完成的种子列表
return 种子列表, 发生错误时返回None return 种子列表, 发生错误时返回None
@ -90,14 +86,14 @@ class Transmission(metaclass=Singleton):
if not self.trc: if not self.trc:
return None return None
try: try:
torrents, error = self.get_torrents(status=["seeding", "seed_pending"], ids=ids, tag=tag) torrents, error = self.get_torrents(status=["seeding", "seed_pending"], ids=ids, tags=tags)
return None if error else torrents or [] return None if error else torrents or []
except Exception as err: except Exception as err:
logger.error(f"获取已完成的种子列表出错:{err}") logger.error(f"获取已完成的种子列表出错:{err}")
return None return None
def get_downloading_torrents(self, ids: Union[str, list] = None, def get_downloading_torrents(self, ids: Union[str, list] = None,
tag: Union[str, list] = None) -> Optional[List[Torrent]]: tags: Union[str, list] = None) -> Optional[List[Torrent]]:
""" """
获取正在下载的种子列表 获取正在下载的种子列表
return 种子列表, 发生错误时返回None return 种子列表, 发生错误时返回None
@ -107,58 +103,25 @@ class Transmission(metaclass=Singleton):
try: try:
torrents, error = self.get_torrents(ids=ids, torrents, error = self.get_torrents(ids=ids,
status=["downloading", "download_pending"], status=["downloading", "download_pending"],
tag=tag) tags=tags)
return None if error else torrents or [] return None if error else torrents or []
except Exception as err: except Exception as err:
logger.error(f"获取正在下载的种子列表出错:{err}") logger.error(f"获取正在下载的种子列表出错:{err}")
return None return None
def set_torrent_tag(self, ids: str, tag: list) -> bool: def set_torrent_tag(self, ids: str, tags: list) -> bool:
""" """
设置种子标签 设置种子标签
""" """
if not ids or not tag: if not ids or not tags:
return False return False
try: try:
self.trc.change_torrent(labels=tag, ids=ids) self.trc.change_torrent(labels=tags, ids=ids)
return True return True
except Exception as err: except Exception as err:
logger.error(f"设置种子标签出错:{err}") logger.error(f"设置种子标签出错:{err}")
return False return False
def get_transfer_torrents(self, tag: Union[str, list] = None) -> List[dict]:
"""
获取下载文件转移任务种子
"""
# 处理下载完成的任务
torrents = self.get_completed_torrents() or []
trans_tasks = []
for torrent in torrents:
# 3.0版本以下的Transmission没有labels
if not hasattr(torrent, "labels"):
logger.error(f"版本可能过低无labels属性请安装3.0以上版本!")
break
torrent_tags = torrent.labels or ""
# 含"已整理"tag的不处理
if "已整理" in torrent_tags:
continue
# 开启标签隔离,未包含指定标签的不处理
if tag and tag not in torrent_tags:
logger.debug(f"{torrent.name} 未包含指定标签:{tag}")
continue
path = torrent.download_dir
# 无法获取下载路径的不处理
if not path:
logger.debug(f"未获取到 {torrent.name} 下载保存路径")
continue
trans_tasks.append({
'title': torrent.name,
'path': Path(path) / torrent.name,
'hash': torrent.hashString,
'tags': torrent.labels
})
return trans_tasks
def add_torrent(self, content: Union[str, bytes], def add_torrent(self, content: Union[str, bytes],
is_paused: bool = False, is_paused: bool = False,
download_dir: str = None, download_dir: str = None,