fix #96
This commit is contained in:
parent
51b30e8e63
commit
9c0c7e8497
@ -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
|
||||||
|
@ -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
|
|
||||||
|
@ -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:
|
||||||
# 解析中种子hash,TMDB ID
|
if arg_str:
|
||||||
torrent_hash, tmdbid = extract_hash_and_number(arg_str)
|
logger.info(f"开始转移下载器文件,参数:{arg_str}")
|
||||||
if not hash or not tmdbid:
|
# 解析中种子hash,TMDB 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):
|
||||||
"""
|
"""
|
||||||
|
@ -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]:
|
||||||
"""
|
"""
|
||||||
获取种子文件列表
|
获取种子文件列表
|
||||||
"""
|
"""
|
||||||
|
@ -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]:
|
||||||
"""
|
"""
|
||||||
获取种子文件清单
|
获取种子文件清单
|
||||||
"""
|
"""
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user