feat 手动整理支持自动识别批量处理,增加进度显示
This commit is contained in:
parent
921783d6bb
commit
683ba4cfad
@ -5,11 +5,7 @@ from fastapi import APIRouter, Depends
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from app import schemas
|
from app import schemas
|
||||||
from app.chain.media import MediaChain
|
|
||||||
from app.chain.transfer import TransferChain
|
from app.chain.transfer import TransferChain
|
||||||
from app.core.config import settings
|
|
||||||
from app.core.context import MediaInfo
|
|
||||||
from app.core.metainfo import MetaInfo
|
|
||||||
from app.core.security import verify_token
|
from app.core.security import verify_token
|
||||||
from app.db import get_db
|
from app.db import get_db
|
||||||
from app.schemas import MediaType
|
from app.schemas import MediaType
|
||||||
@ -19,11 +15,11 @@ router = APIRouter()
|
|||||||
|
|
||||||
@router.post("/manual", summary="手动转移", response_model=schemas.Response)
|
@router.post("/manual", summary="手动转移", response_model=schemas.Response)
|
||||||
def manual_transfer(path: str,
|
def manual_transfer(path: str,
|
||||||
tmdbid: int,
|
|
||||||
type_name: str,
|
|
||||||
target: str = None,
|
target: str = None,
|
||||||
|
tmdbid: int = None,
|
||||||
|
type_name: str = None,
|
||||||
season: int = None,
|
season: int = None,
|
||||||
transfer_type: str = settings.TRANSFER_TYPE,
|
transfer_type: str = None,
|
||||||
episode_format: str = None,
|
episode_format: str = None,
|
||||||
episode_detail: str = None,
|
episode_detail: str = None,
|
||||||
episode_part: str = None,
|
episode_part: str = None,
|
||||||
@ -52,17 +48,8 @@ def manual_transfer(path: str,
|
|||||||
target = Path(target)
|
target = Path(target)
|
||||||
if not target.exists():
|
if not target.exists():
|
||||||
return schemas.Response(success=False, message=f"目标路径不存在")
|
return schemas.Response(success=False, message=f"目标路径不存在")
|
||||||
# 识别元数据
|
# 类型
|
||||||
meta = MetaInfo(in_path.stem)
|
mtype = MediaType(type_name) if type_name else None
|
||||||
mtype = MediaType(type_name)
|
|
||||||
# 整合数据
|
|
||||||
meta.type = mtype
|
|
||||||
if season:
|
|
||||||
meta.begin_season = season
|
|
||||||
# 识别媒体信息
|
|
||||||
mediainfo: MediaInfo = MediaChain(db).recognize_media(tmdbid=tmdbid, mtype=mtype)
|
|
||||||
if not mediainfo:
|
|
||||||
return schemas.Response(success=False, message=f"媒体信息识别失败,tmdbid: {tmdbid}")
|
|
||||||
# 自定义格式
|
# 自定义格式
|
||||||
epformat = None
|
epformat = None
|
||||||
if episode_offset or episode_part or episode_detail or episode_format:
|
if episode_offset or episode_part or episode_detail or episode_format:
|
||||||
@ -75,10 +62,11 @@ def manual_transfer(path: str,
|
|||||||
# 开始转移
|
# 开始转移
|
||||||
state, errormsg = TransferChain(db).manual_transfer(
|
state, errormsg = TransferChain(db).manual_transfer(
|
||||||
in_path=in_path,
|
in_path=in_path,
|
||||||
mediainfo=mediainfo,
|
|
||||||
transfer_type=transfer_type,
|
|
||||||
target=target,
|
target=target,
|
||||||
meta=meta,
|
tmdbid=tmdbid,
|
||||||
|
mtype=mtype,
|
||||||
|
season=season,
|
||||||
|
transfer_type=transfer_type,
|
||||||
epformat=epformat,
|
epformat=epformat,
|
||||||
min_filesize=min_filesize
|
min_filesize=min_filesize
|
||||||
)
|
)
|
||||||
|
@ -7,6 +7,7 @@ from typing import List, Optional, Tuple, Union
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from app.chain import ChainBase
|
from app.chain import ChainBase
|
||||||
|
from app.chain.media import MediaChain
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.core.context import MediaInfo
|
from app.core.context import MediaInfo
|
||||||
from app.core.meta import MetaBase
|
from app.core.meta import MetaBase
|
||||||
@ -35,6 +36,7 @@ class TransferChain(ChainBase):
|
|||||||
self.downloadhis = DownloadHistoryOper(self._db)
|
self.downloadhis = DownloadHistoryOper(self._db)
|
||||||
self.transferhis = TransferHistoryOper(self._db)
|
self.transferhis = TransferHistoryOper(self._db)
|
||||||
self.progress = ProgressHelper()
|
self.progress = ProgressHelper()
|
||||||
|
self.mediachain = MediaChain(self._db)
|
||||||
|
|
||||||
def process(self) -> bool:
|
def process(self) -> bool:
|
||||||
"""
|
"""
|
||||||
@ -51,21 +53,8 @@ class TransferChain(ChainBase):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
logger.info(f"获取到 {len(torrents)} 个已完成的下载任务")
|
logger.info(f"获取到 {len(torrents)} 个已完成的下载任务")
|
||||||
# 开始进度
|
|
||||||
self.progress.start(ProgressKey.FileTransfer)
|
|
||||||
# 总数
|
|
||||||
total_num = len(torrents)
|
|
||||||
# 已处理数量
|
|
||||||
processed_num = 0
|
|
||||||
self.progress.update(value=0,
|
|
||||||
text=f"开始转移下载任务文件,共 {total_num} 个任务 ...",
|
|
||||||
key=ProgressKey.FileTransfer)
|
|
||||||
|
|
||||||
for torrent in torrents:
|
for torrent in torrents:
|
||||||
# 更新进度
|
|
||||||
self.progress.update(value=processed_num / total_num * 100,
|
|
||||||
text=f"正在转移 {torrent.title} ...",
|
|
||||||
key=ProgressKey.FileTransfer)
|
|
||||||
# 识别元数据
|
# 识别元数据
|
||||||
meta: MetaBase = MetaInfo(title=torrent.title)
|
meta: MetaBase = MetaInfo(title=torrent.title)
|
||||||
if not meta.name:
|
if not meta.name:
|
||||||
@ -166,15 +155,7 @@ class TransferChain(ChainBase):
|
|||||||
|
|
||||||
# 转移完成
|
# 转移完成
|
||||||
self.transfer_completed(hashs=torrent.hash, transinfo=transferinfo)
|
self.transfer_completed(hashs=torrent.hash, transinfo=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("下载器文件转移执行完成")
|
logger.info("下载器文件转移执行完成")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -333,56 +314,190 @@ class TransferChain(ChainBase):
|
|||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
def manual_transfer(self, in_path: Path,
|
def manual_transfer(self, in_path: Path,
|
||||||
mediainfo: MediaInfo,
|
|
||||||
transfer_type: str = settings.TRANSFER_TYPE,
|
|
||||||
target: Path = None,
|
target: Path = None,
|
||||||
meta: MetaBase = None,
|
tmdbid: int = None,
|
||||||
|
mtype: MediaType = None,
|
||||||
|
season: int = None,
|
||||||
|
transfer_type: str = None,
|
||||||
epformat: EpisodeFormat = None,
|
epformat: EpisodeFormat = None,
|
||||||
min_filesize: int = 0) -> Tuple[bool, str]:
|
min_filesize: int = 0) -> Tuple[bool, str]:
|
||||||
"""
|
"""
|
||||||
手动转移
|
手动转移
|
||||||
:param in_path: 源文件路径
|
:param in_path: 源文件路径
|
||||||
:param mediainfo: 媒体信息
|
|
||||||
:param transfer_type: 转移类型
|
|
||||||
:param target: 目标路径
|
:param target: 目标路径
|
||||||
:param meta: 元数据
|
:param tmdbid: TMDB ID
|
||||||
|
:param mtype: 媒体类型
|
||||||
|
:param season: 季度
|
||||||
|
:param transfer_type: 转移类型
|
||||||
:param epformat: 剧集格式
|
:param epformat: 剧集格式
|
||||||
:param min_filesize: 最小文件大小(MB)
|
:param min_filesize: 最小文件大小(MB)
|
||||||
"""
|
"""
|
||||||
# 开始转移
|
logger.info(f"手动转移:{in_path} ...")
|
||||||
transferinfo: TransferInfo = self.transfer(
|
|
||||||
path=in_path,
|
|
||||||
mediainfo=mediainfo,
|
|
||||||
transfer_type=transfer_type,
|
|
||||||
target=target,
|
|
||||||
epformat=epformat,
|
|
||||||
min_filesize=min_filesize
|
|
||||||
)
|
|
||||||
if not transferinfo:
|
|
||||||
return False, "文件转移模块运行失败"
|
|
||||||
if not transferinfo.target_path:
|
|
||||||
return False, transferinfo.message
|
|
||||||
|
|
||||||
# 新增转移成功历史记录
|
# 默认转移类型
|
||||||
self.__insert_sucess_history(
|
if not transfer_type:
|
||||||
src_path=in_path,
|
transfer_type = settings.TRANSFER_TYPE
|
||||||
meta=meta,
|
|
||||||
mediainfo=mediainfo,
|
if tmdbid:
|
||||||
transferinfo=transferinfo
|
# 有输入TMDBID时单个识别
|
||||||
)
|
meta = MetaInfo(in_path.stem)
|
||||||
# 刮削元数据
|
# 整合数据
|
||||||
self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo)
|
if mtype:
|
||||||
# 刷新媒体库
|
meta.type = mtype
|
||||||
self.refresh_mediaserver(mediainfo=mediainfo, file_path=transferinfo.target_path)
|
if season:
|
||||||
# 发送通知
|
meta.begin_season = season
|
||||||
self.send_transfer_message(meta=meta, mediainfo=mediainfo, transferinfo=transferinfo)
|
# 识别媒体信息
|
||||||
# 广播事件
|
mediainfo: MediaInfo = self.mediachain.recognize_media(tmdbid=tmdbid, mtype=mtype)
|
||||||
self.eventmanager.send_event(EventType.TransferComplete, {
|
if not mediainfo:
|
||||||
'meta': meta,
|
return False, f"媒体信息识别失败,tmdbid: {tmdbid}, type: {mtype.value}"
|
||||||
'mediainfo': mediainfo,
|
# 开始进度
|
||||||
'transferinfo': transferinfo
|
self.progress.start(ProgressKey.FileTransfer)
|
||||||
})
|
self.progress.update(value=0,
|
||||||
return True, ""
|
text=f"开始转移 {in_path} ...",
|
||||||
|
key=ProgressKey.FileTransfer)
|
||||||
|
# 开始转移
|
||||||
|
transferinfo: TransferInfo = self.transfer(
|
||||||
|
path=in_path,
|
||||||
|
mediainfo=mediainfo,
|
||||||
|
transfer_type=transfer_type,
|
||||||
|
target=target,
|
||||||
|
epformat=epformat,
|
||||||
|
min_filesize=min_filesize
|
||||||
|
)
|
||||||
|
if not transferinfo:
|
||||||
|
return False, "文件转移模块运行失败"
|
||||||
|
if not transferinfo.target_path:
|
||||||
|
return False, transferinfo.message
|
||||||
|
|
||||||
|
# 新增转移成功历史记录
|
||||||
|
self.__insert_sucess_history(
|
||||||
|
src_path=in_path,
|
||||||
|
meta=meta,
|
||||||
|
mediainfo=mediainfo,
|
||||||
|
transferinfo=transferinfo
|
||||||
|
)
|
||||||
|
# 刮削元数据
|
||||||
|
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
|
||||||
|
})
|
||||||
|
self.progress.end(ProgressKey.FileTransfer)
|
||||||
|
logger.info(f"{in_path} 转移完成")
|
||||||
|
return True, ""
|
||||||
|
else:
|
||||||
|
# 错误信息
|
||||||
|
errmsgs = []
|
||||||
|
# 自动识别所有文件
|
||||||
|
transfer_files = SystemUtils.list_files(directory=in_path,
|
||||||
|
extensions=settings.RMT_MEDIAEXT,
|
||||||
|
min_filesize=min_filesize)
|
||||||
|
if not transfer_files:
|
||||||
|
return False, "没有找到可转移的文件"
|
||||||
|
# 开始进度
|
||||||
|
self.progress.start(ProgressKey.FileTransfer)
|
||||||
|
# 总数
|
||||||
|
total_num = len(transfer_files)
|
||||||
|
# 已处理数量
|
||||||
|
processed_num = 0
|
||||||
|
self.progress.update(value=0,
|
||||||
|
text=f"开始转移 {in_path},共 {total_num} 个文件 ...",
|
||||||
|
key=ProgressKey.FileTransfer)
|
||||||
|
for transfer_file in transfer_files:
|
||||||
|
# 更新进度
|
||||||
|
self.progress.update(value=processed_num / total_num * 100,
|
||||||
|
text=f"正在转移 {transfer_file.name} ...",
|
||||||
|
key=ProgressKey.FileTransfer)
|
||||||
|
# 上级目录元数据
|
||||||
|
meta = MetaInfo(title=transfer_file.parent.name)
|
||||||
|
# 文件元数据,不包含后缀
|
||||||
|
file_meta = MetaInfo(title=transfer_file.stem)
|
||||||
|
# 合并元数据
|
||||||
|
file_meta.merge(meta)
|
||||||
|
|
||||||
|
if not file_meta.name:
|
||||||
|
logger.error(f"{transfer_file} 无法识别有效信息")
|
||||||
|
errmsgs.append(f"{transfer_file.name} 无法识别有效信息")
|
||||||
|
# 更新进度
|
||||||
|
processed_num += 1
|
||||||
|
self.progress.update(value=processed_num / total_num * 100,
|
||||||
|
text=f"{transfer_file.name} 无法识别有效信息",
|
||||||
|
key=ProgressKey.FileTransfer)
|
||||||
|
continue
|
||||||
|
# 整合数据
|
||||||
|
if mtype:
|
||||||
|
file_meta.type = mtype
|
||||||
|
if season:
|
||||||
|
file_meta.begin_season = season
|
||||||
|
# 识别媒体信息
|
||||||
|
mediainfo: MediaInfo = self.mediachain.recognize_media(meta=file_meta)
|
||||||
|
if not mediainfo:
|
||||||
|
logger.error(f"{transfer_file} 媒体信息识别失败")
|
||||||
|
errmsgs.append(f"{transfer_file.name} 媒体信息识别失败")
|
||||||
|
# 更新进度
|
||||||
|
processed_num += 1
|
||||||
|
self.progress.update(value=processed_num / total_num * 100,
|
||||||
|
text=f"{transfer_file.name} 媒体信息识别失败!",
|
||||||
|
key=ProgressKey.FileTransfer)
|
||||||
|
continue
|
||||||
|
# 开始转移
|
||||||
|
transferinfo: TransferInfo = self.transfer(
|
||||||
|
path=in_path,
|
||||||
|
mediainfo=mediainfo,
|
||||||
|
transfer_type=transfer_type,
|
||||||
|
target=target,
|
||||||
|
meta=file_meta,
|
||||||
|
epformat=epformat,
|
||||||
|
min_filesize=min_filesize
|
||||||
|
)
|
||||||
|
if not transferinfo:
|
||||||
|
return False, "文件转移模块运行失败"
|
||||||
|
if not transferinfo.target_path:
|
||||||
|
logger.error(f"{transfer_file} 转移失败:{transferinfo.message}")
|
||||||
|
errmsgs.append(f"{transfer_file.name} 转移失败:{transferinfo.message}")
|
||||||
|
# 更新进度
|
||||||
|
processed_num += 1
|
||||||
|
self.progress.update(value=processed_num / total_num * 100,
|
||||||
|
text=f"{transfer_file.name} 转移失败:{transferinfo.message}",
|
||||||
|
key=ProgressKey.FileTransfer)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 新增转移成功历史记录
|
||||||
|
self.__insert_sucess_history(
|
||||||
|
src_path=transfer_file,
|
||||||
|
meta=file_meta,
|
||||||
|
mediainfo=mediainfo,
|
||||||
|
transferinfo=transferinfo
|
||||||
|
)
|
||||||
|
# 刮削元数据
|
||||||
|
self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo)
|
||||||
|
# 刷新媒体库
|
||||||
|
self.refresh_mediaserver(mediainfo=mediainfo, file_path=transferinfo.target_path)
|
||||||
|
# 发送通知
|
||||||
|
self.send_transfer_message(meta=file_meta, mediainfo=mediainfo, transferinfo=transferinfo)
|
||||||
|
# 广播事件
|
||||||
|
self.eventmanager.send_event(EventType.TransferComplete, {
|
||||||
|
'meta': file_meta,
|
||||||
|
'mediainfo': mediainfo,
|
||||||
|
'transferinfo': transferinfo
|
||||||
|
})
|
||||||
|
# 更新进度
|
||||||
|
processed_num += 1
|
||||||
|
self.progress.update(value=processed_num / total_num * 100,
|
||||||
|
text=f"{transfer_file.name} 转移完成",
|
||||||
|
key=ProgressKey.FileTransfer)
|
||||||
|
# 结束进度
|
||||||
|
logger.info(f"转移完成,共 {total_num} 个文件,成功 {total_num - len(errmsgs)} 个,失败 {len(errmsgs)} 个")
|
||||||
|
self.progress.end(ProgressKey.FileTransfer)
|
||||||
|
if errmsgs:
|
||||||
|
return False, "\n".join(errmsgs)
|
||||||
|
return True, ""
|
||||||
|
|
||||||
def __insert_sucess_history(self, src_path: Path, meta: MetaBase,
|
def __insert_sucess_history(self, src_path: Path, meta: MetaBase,
|
||||||
mediainfo: MediaInfo, transferinfo: TransferInfo,
|
mediainfo: MediaInfo, transferinfo: TransferInfo,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user