This commit is contained in:
jxxghp 2023-08-13 08:42:36 +08:00
parent 51b30e8e63
commit 9c0c7e8497
7 changed files with 149 additions and 153 deletions

View File

@ -2,11 +2,12 @@ import gc
import pickle import pickle
import traceback import traceback
from abc import ABCMeta from abc import ABCMeta
from msilib.schema import File
from pathlib import Path from pathlib import Path
from typing import Optional, Any, Tuple, List, Set, Union, Dict from typing import Optional, Any, Tuple, List, Set, Union, Dict
from qbittorrentapi import TorrentFilesList
from ruamel.yaml import CommentedMap from ruamel.yaml import CommentedMap
from transmission_rpc import File
from app.core.config import settings from app.core.config import settings
from app.core.context import Context from app.core.context import Context
@ -308,7 +309,7 @@ class ChainBase(metaclass=ABCMeta):
""" """
return self.run_module("stop_torrents", hashs=hashs) return self.run_module("stop_torrents", hashs=hashs)
def torrent_files(self, tid: str) -> Optional[List[File]]: def torrent_files(self, tid: str) -> Optional[Union[TorrentFilesList, List[File]]]:
""" """
根据种子文件选择并添加下载任务 根据种子文件选择并添加下载任务
:param tid: 种子Hash :param tid: 种子Hash

View File

@ -1,5 +1,4 @@
import re import re
from msilib.schema import File
from pathlib import Path from pathlib import Path
from typing import List, Optional, Tuple, Set, Dict, Union from typing import List, Optional, Tuple, Set, Dict, Union
@ -624,13 +623,3 @@ class DownloadChain(ChainBase):
删除下载任务 删除下载任务
""" """
return self.remove_torrents(hashs=[hash_str]) return self.remove_torrents(hashs=[hash_str])
def get_files(self, tid: str) -> Optional[List[File]]:
"""
获取种子文件清单
"""
try:
return self.torrent_files(tid=tid)
except Exception as err:
logger.error(f"获取种子文件列表出错:{err}")
return None

View File

@ -1,6 +1,7 @@
import json import json
import re import re
import shutil import shutil
import threading
from pathlib import Path from pathlib import Path
from typing import List, Optional, Union from typing import List, Optional, Union
@ -19,6 +20,8 @@ from app.schemas.types import TorrentStatus, EventType, MediaType, ProgressKey,
from app.utils.string import StringUtils from app.utils.string import StringUtils
from app.utils.system import SystemUtils from app.utils.system import SystemUtils
lock = threading.Lock()
class TransferChain(ChainBase): class TransferChain(ChainBase):
""" """
@ -52,105 +55,129 @@ class TransferChain(ChainBase):
else: else:
return None, None return None, None
if arg_str: # 全局锁,避免重复处理
logger.info(f"开始转移下载器文件,参数:{arg_str}") with lock:
# 解析中种子hashTMDB ID if arg_str:
torrent_hash, tmdbid = extract_hash_and_number(arg_str) logger.info(f"开始转移下载器文件,参数:{arg_str}")
if not hash or not tmdbid: # 解析中种子hashTMDB ID
logger.error(f"参数错误,参数:{arg_str}") torrent_hash, tmdbid = extract_hash_and_number(arg_str)
return False if not hash or not tmdbid:
# 获取种子 logger.error(f"参数错误,参数:{arg_str}")
torrents: Optional[List[TransferTorrent]] = self.list_torrents(hashs=torrent_hash) return False
if not torrents: # 获取种子
logger.error(f"没有获取到种子,参数:{arg_str}") torrents: Optional[List[TransferTorrent]] = self.list_torrents(hashs=torrent_hash)
return False if not torrents:
# 查询媒体信息 logger.error(f"没有获取到种子,参数:{arg_str}")
arg_mediainfo = self.recognize_media(tmdbid=tmdbid) return False
else: # 查询媒体信息
arg_mediainfo = None arg_mediainfo = self.recognize_media(tmdbid=tmdbid)
logger.info("开始执行下载器文件转移 ...") else:
# 从下载器获取种子列表 arg_mediainfo = None
torrents: Optional[List[TransferTorrent]] = self.list_torrents(status=TorrentStatus.TRANSFER) logger.info("开始执行下载器文件转移 ...")
if not torrents: # 从下载器获取种子列表
logger.info("没有获取到已完成的下载任务") torrents: Optional[List[TransferTorrent]] = self.list_torrents(status=TorrentStatus.TRANSFER)
return False if not torrents:
logger.info("没有获取到已完成的下载任务")
return False
logger.info(f"获取到 {len(torrents)} 个已完成的下载任务") logger.info(f"获取到 {len(torrents)} 个已完成的下载任务")
# 开始进度 # 开始进度
self.progress.start(ProgressKey.FileTransfer) self.progress.start(ProgressKey.FileTransfer)
# 总数 # 总数
total_num = len(torrents) total_num = len(torrents)
# 已处理数量 # 已处理数量
processed_num = 0 processed_num = 0
self.progress.update(value=0, self.progress.update(value=0,
text=f"开始转移下载任务文件,共 {total_num} 个任务 ...", text=f"开始转移下载任务文件,共 {total_num} 个任务 ...",
key=ProgressKey.FileTransfer)
for torrent in torrents:
# 更新进度
self.progress.update(value=processed_num / total_num * 100,
text=f"正在转移 {torrent.title} ...",
key=ProgressKey.FileTransfer) key=ProgressKey.FileTransfer)
# 识别元数据 for torrent in torrents:
meta: MetaBase = MetaInfo(title=torrent.title) # 更新进度
if not meta.name: self.progress.update(value=processed_num / total_num * 100,
logger.error(f'未识别到元数据,标题:{torrent.title}') text=f"正在转移 {torrent.title} ...",
continue key=ProgressKey.FileTransfer)
if not arg_mediainfo: # 识别元数据
# 查询下载记录识别情况 meta: MetaBase = MetaInfo(title=torrent.title)
downloadhis: DownloadHistory = self.downloadhis.get_by_hash(torrent.hash) if not meta.name:
if downloadhis: logger.error(f'未识别到元数据,标题:{torrent.title}')
# 类型 continue
mtype = MediaType(downloadhis.type) if not arg_mediainfo:
# 补充剧集信息 # 查询下载记录识别情况
if mtype == MediaType.TV \ downloadhis: DownloadHistory = self.downloadhis.get_by_hash(torrent.hash)
and ((not meta.season_list and downloadhis.seasons) if downloadhis:
or (not meta.episode_list and downloadhis.episodes)): # 类型
meta = MetaInfo(f"{torrent.title} {downloadhis.seasons} {downloadhis.episodes}") mtype = MediaType(downloadhis.type)
# 按TMDBID识别 # 补充剧集信息
mediainfo = self.recognize_media(mtype=mtype, if mtype == MediaType.TV \
tmdbid=downloadhis.tmdbid) and ((not meta.season_list and downloadhis.seasons)
or (not meta.episode_list and downloadhis.episodes)):
meta = MetaInfo(f"{torrent.title} {downloadhis.seasons} {downloadhis.episodes}")
# 按TMDBID识别
mediainfo = self.recognize_media(mtype=mtype,
tmdbid=downloadhis.tmdbid)
else:
# 使用标题识别媒体信息
mediainfo: MediaInfo = self.recognize_media(meta=meta)
if not mediainfo:
logger.warn(f'未识别到媒体信息,标题:{torrent.title}')
self.post_message(Notification(
channel=channel,
mtype=NotificationType.Manual,
title=f"{torrent.title} 未识别到媒体信息,无法入库!\n"
f"回复:```\n/transfer {torrent.hash} [tmdbid]\n``` 手动识别转移。",
userid=userid))
# 新增转移失败历史记录
self.transferhis.add(
src=str(torrent.path),
mode=settings.TRANSFER_TYPE,
seasons=meta.season,
episodes=meta.episode,
download_hash=torrent.hash,
status=0,
errmsg="未识别到媒体信息"
)
continue
else: else:
# 使用标题识别媒体信息 mediainfo = arg_mediainfo
mediainfo: MediaInfo = self.recognize_media(meta=meta) logger.info(f"{torrent.title} 识别为:{mediainfo.type.value} {mediainfo.title_year}")
if not mediainfo: # 更新媒体图片
logger.warn(f'未识别到媒体信息,标题:{torrent.title}') self.obtain_images(mediainfo=mediainfo)
# 转移
transferinfo: TransferInfo = self.transfer(mediainfo=mediainfo,
path=torrent.path,
transfer_type=settings.TRANSFER_TYPE)
if not transferinfo or not transferinfo.target_path:
# 转移失败
logger.warn(f"{torrent.title} 入库失败")
self.post_message(Notification( self.post_message(Notification(
channel=channel, channel=channel,
mtype=NotificationType.Manual, title=f"{mediainfo.title_year}{meta.season_episode} 入库失败!",
title=f"{torrent.title} 未识别到媒体信息,无法入库!\n" text=f"原因:{transferinfo.message if transferinfo else '未知'}",
f"回复:```\n/transfer {torrent.hash} [tmdbid]\n``` 手动识别转移。", image=mediainfo.get_message_image(),
userid=userid)) userid=userid
))
# 新增转移失败历史记录 # 新增转移失败历史记录
self.transferhis.add( self.transferhis.add(
src=str(torrent.path), src=str(torrent.path),
dest=str(transferinfo.target_path) if transferinfo else None,
mode=settings.TRANSFER_TYPE, mode=settings.TRANSFER_TYPE,
type=mediainfo.type.value,
category=mediainfo.category,
title=mediainfo.title,
year=mediainfo.year,
tmdbid=mediainfo.tmdb_id,
imdbid=mediainfo.imdb_id,
tvdbid=mediainfo.tvdb_id,
doubanid=mediainfo.douban_id,
seasons=meta.season, seasons=meta.season,
episodes=meta.episode, episodes=meta.episode,
image=mediainfo.get_poster_image(),
download_hash=torrent.hash, download_hash=torrent.hash,
status=0, status=0,
errmsg="未识别到媒体信息" errmsg=transferinfo.message if transferinfo else '未知错误',
files=json.dumps(transferinfo.file_list) if transferinfo else None
) )
continue continue
else: # 新增转移成功历史记录
mediainfo = arg_mediainfo
logger.info(f"{torrent.title} 识别为:{mediainfo.type.value} {mediainfo.title_year}")
# 更新媒体图片
self.obtain_images(mediainfo=mediainfo)
# 转移
transferinfo: TransferInfo = self.transfer(mediainfo=mediainfo,
path=torrent.path,
transfer_type=settings.TRANSFER_TYPE)
if not transferinfo or not transferinfo.target_path:
# 转移失败
logger.warn(f"{torrent.title} 入库失败")
self.post_message(Notification(
channel=channel,
title=f"{mediainfo.title_year}{meta.season_episode} 入库失败!",
text=f"原因:{transferinfo.message if transferinfo else '未知'}",
image=mediainfo.get_message_image(),
userid=userid
))
# 新增转移失败历史记录
self.transferhis.add( self.transferhis.add(
src=str(torrent.path), src=str(torrent.path),
dest=str(transferinfo.target_path) if transferinfo else None, dest=str(transferinfo.target_path) if transferinfo else None,
@ -167,55 +194,33 @@ class TransferChain(ChainBase):
episodes=meta.episode, episodes=meta.episode,
image=mediainfo.get_poster_image(), image=mediainfo.get_poster_image(),
download_hash=torrent.hash, download_hash=torrent.hash,
status=0, status=1,
errmsg=transferinfo.message if transferinfo else '未知错误', files=json.dumps(transferinfo.file_list)
files=json.dumps(transferinfo.file_list) if transferinfo else None
) )
continue # 转移完成
# 新增转移成功历史记录 self.transfer_completed(hashs=torrent.hash, transinfo=transferinfo)
self.transferhis.add( # 刮削元数据
src=str(torrent.path), self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo)
dest=str(transferinfo.target_path) if transferinfo else None, # 刷新媒体库
mode=settings.TRANSFER_TYPE, self.refresh_mediaserver(mediainfo=mediainfo, file_path=transferinfo.target_path)
type=mediainfo.type.value, # 发送通知
category=mediainfo.category, self.send_transfer_message(meta=meta, mediainfo=mediainfo, transferinfo=transferinfo)
title=mediainfo.title, # 广播事件
year=mediainfo.year, self.eventmanager.send_event(EventType.TransferComplete, {
tmdbid=mediainfo.tmdb_id, 'meta': meta,
imdbid=mediainfo.imdb_id, 'mediainfo': mediainfo,
tvdbid=mediainfo.tvdb_id, 'transferinfo': transferinfo
doubanid=mediainfo.douban_id, })
seasons=meta.season, # 计数
episodes=meta.episode, processed_num += 1
image=mediainfo.get_poster_image(), # 更新进度
download_hash=torrent.hash, self.progress.update(value=processed_num / total_num * 100,
status=1, text=f"{torrent.title} 转移完成",
files=json.dumps(transferinfo.file_list) key=ProgressKey.FileTransfer)
) # 结束进度
# 转移完成 self.progress.end(ProgressKey.FileTransfer)
self.transfer_completed(hashs=torrent.hash, transinfo=transferinfo) logger.info("下载器文件转移执行完成")
# 刮削元数据 return True
self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo)
# 刷新媒体库
self.refresh_mediaserver(mediainfo=mediainfo, file_path=transferinfo.target_path)
# 发送通知
self.send_transfer_message(meta=meta, mediainfo=mediainfo, transferinfo=transferinfo)
# 广播事件
self.eventmanager.send_event(EventType.TransferComplete, {
'meta': meta,
'mediainfo': mediainfo,
'transferinfo': transferinfo
})
# 计数
processed_num += 1
# 更新进度
self.progress.update(value=processed_num / total_num * 100,
text=f"{torrent.title} 转移完成",
key=ProgressKey.FileTransfer)
# 结束进度
self.progress.end(ProgressKey.FileTransfer)
logger.info("下载器文件转移执行完成")
return True
def send_transfer_message(self, meta: MetaBase, mediainfo: MediaInfo, transferinfo: TransferInfo): def send_transfer_message(self, meta: MetaBase, mediainfo: MediaInfo, transferinfo: TransferInfo):
""" """

View File

@ -1,7 +1,8 @@
from msilib.schema import File
from pathlib import Path from pathlib import Path
from typing import Set, Tuple, Optional, Union, List from typing import Set, Tuple, Optional, Union, List
from qbittorrentapi import TorrentFilesList
from app import schemas from app import schemas
from app.core.config import settings from app.core.config import settings
from app.core.metainfo import MetaInfo from app.core.metainfo import MetaInfo
@ -188,7 +189,7 @@ class QbittorrentModule(_ModuleBase):
""" """
return self.qbittorrent.start_torrents(ids=hashs) return self.qbittorrent.start_torrents(ids=hashs)
def torrent_files(self, tid: str) -> Optional[List[File]]: def torrent_files(self, tid: str) -> Optional[TorrentFilesList]:
""" """
获取种子文件列表 获取种子文件列表
""" """

View File

@ -1,9 +1,8 @@
import time import time
from msilib.schema import File
from typing import Optional, Union, Tuple, List from typing import Optional, Union, Tuple, List
import qbittorrentapi import qbittorrentapi
from qbittorrentapi import TorrentDictionary from qbittorrentapi import TorrentDictionary, TorrentFilesList
from qbittorrentapi.client import Client from qbittorrentapi.client import Client
from qbittorrentapi.transfer import TransferInfoDictionary from qbittorrentapi.transfer import TransferInfoDictionary
@ -266,7 +265,7 @@ class Qbittorrent(metaclass=Singleton):
logger.error(f"删除种子出错:{err}") logger.error(f"删除种子出错:{err}")
return False return False
def get_files(self, tid: str) -> Optional[List[File]]: def get_files(self, tid: str) -> Optional[TorrentFilesList]:
""" """
获取种子文件清单 获取种子文件清单
""" """

View File

@ -1,7 +1,8 @@
from msilib.schema import File
from pathlib import Path from pathlib import Path
from typing import Set, Tuple, Optional, Union, List from typing import Set, Tuple, Optional, Union, List
from transmission_rpc import File
from app import schemas from app import schemas
from app.core.config import settings from app.core.config import settings
from app.core.metainfo import MetaInfo from app.core.metainfo import MetaInfo

View File

@ -715,7 +715,7 @@ class MediaSyncDel(_PluginBase):
logger.info(f"{history_key} 转种时未删除源下载任务,开始删除源下载任务…") logger.info(f"{history_key} 转种时未删除源下载任务,开始删除源下载任务…")
try: try:
dl_files = self.chain.get_files(tid=torrent_hash) dl_files = self.chain.torrent_files(tid=torrent_hash)
if not dl_files: if not dl_files:
logger.info(f"未获取到 {settings.DOWNLOADER} - {torrent_hash} 种子文件,种子已被删除") logger.info(f"未获取到 {settings.DOWNLOADER} - {torrent_hash} 种子文件,种子已被删除")
else: else:
@ -736,7 +736,7 @@ class MediaSyncDel(_PluginBase):
# 如果是False则说明种子文件没有完全被删除暂停种子暂不处理 # 如果是False则说明种子文件没有完全被删除暂停种子暂不处理
if delete_flag: if delete_flag:
try: try:
dl_files = self.chain.get_files(tid=download_id) dl_files = self.chain.torrent_files(tid=download_id)
if not dl_files: if not dl_files:
logger.info(f"未获取到 {download} - {download_id} 种子文件,种子已被删除") logger.info(f"未获取到 {download} - {download_id} 种子文件,种子已被删除")
else: else: