fix transfer
This commit is contained in:
parent
f57e801236
commit
760f603076
@ -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)
|
||||||
|
@ -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}")
|
||||||
|
# 解析中种子hash,TMDB 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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
"""
|
"""
|
||||||
|
@ -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
|
||||||
|
@ -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'))
|
||||||
|
@ -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:
|
||||||
"""
|
"""
|
||||||
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user