fix typing

This commit is contained in:
jxxghp 2023-06-13 23:41:50 +08:00
parent c1a22518a2
commit c06122ff19
15 changed files with 186 additions and 132 deletions

View File

@ -10,6 +10,7 @@ from app.core.module import ModuleManager
from app.core.context import MediaInfo, TorrentInfo from app.core.context import MediaInfo, TorrentInfo
from app.core.meta import MetaBase from app.core.meta import MetaBase
from app.log import logger from app.log import logger
from app.schemas.context import TransferInfo, TransferTorrent, ExistMediaInfo
from app.utils.singleton import AbstractSingleton, Singleton from app.utils.singleton import AbstractSingleton, Singleton
from app.utils.types import TorrentStatus, MediaType from app.utils.types import TorrentStatus, MediaType
@ -106,22 +107,23 @@ class ChainBase(AbstractSingleton, metaclass=Singleton):
def download_added(self, context: Context, torrent_path: Path) -> None: def download_added(self, context: Context, torrent_path: Path) -> None:
return self.run_module("download_added", context=context, torrent_path=torrent_path) return self.run_module("download_added", context=context, torrent_path=torrent_path)
def list_torrents(self, status: TorrentStatus = None, hashs: Union[list, str] = None) -> Optional[List[dict]]: def list_torrents(self, status: TorrentStatus = None,
hashs: Union[list, str] = None) -> Optional[List[TransferTorrent]]:
return self.run_module("list_torrents", status=status, hashs=hashs) return self.run_module("list_torrents", status=status, hashs=hashs)
def transfer(self, path: str, mediainfo: MediaInfo) -> Optional[dict]: def transfer(self, path: Path, mediainfo: MediaInfo) -> Optional[TransferInfo]:
return self.run_module("transfer", path=path, mediainfo=mediainfo) return self.run_module("transfer", path=path, mediainfo=mediainfo)
def transfer_completed(self, hashs: Union[str, list], transinfo: dict) -> None: def transfer_completed(self, hashs: Union[str, list], transinfo: TransferInfo) -> None:
return self.run_module("transfer_completed", hashs=hashs, transinfo=transinfo) return self.run_module("transfer_completed", hashs=hashs, transinfo=transinfo)
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)
def media_exists(self, mediainfo: MediaInfo) -> Optional[dict]: def media_exists(self, mediainfo: MediaInfo) -> Optional[ExistMediaInfo]:
return self.run_module("media_exists", mediainfo=mediainfo) return self.run_module("media_exists", mediainfo=mediainfo)
def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: str) -> Optional[bool]: def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: Path) -> Optional[bool]:
return self.run_module("refresh_mediaserver", mediainfo=mediainfo, file_path=file_path) return self.run_module("refresh_mediaserver", mediainfo=mediainfo, file_path=file_path)
def post_message(self, title: str, text: str = None, def post_message(self, title: str, text: str = None,

View File

@ -8,6 +8,7 @@ from app.core.meta import MetaBase
from app.core.metainfo import MetaInfo from app.core.metainfo import MetaInfo
from app.helper.torrent import TorrentHelper from app.helper.torrent import TorrentHelper
from app.log import logger from app.log import logger
from app.schemas.context import ExistMediaInfo, NotExistMediaInfo
from app.utils.string import StringUtils from app.utils.string import StringUtils
from app.utils.types import MediaType from app.utils.types import MediaType
@ -57,7 +58,7 @@ class DownloadChain(ChainBase):
def batch_download(self, def batch_download(self,
contexts: List[Context], contexts: List[Context],
need_tvs: dict = None, need_tvs: Dict[int, List[NotExistMediaInfo]] = None,
userid: str = None) -> Tuple[List[Context], dict]: userid: str = None) -> Tuple[List[Context], dict]:
""" """
根据缺失数据自动种子列表中组合择优下载 根据缺失数据自动种子列表中组合择优下载
@ -155,7 +156,13 @@ class DownloadChain(ChainBase):
""" """
need = list(set(need).difference(set(current))) need = list(set(need).difference(set(current)))
if need: if need:
need_tvs[tmdbid][seq]["episodes"] = need not_exist = need_tvs[tmdbid][seq]
need_tvs[tmdbid][seq] = NotExistMediaInfo(
season=not_exist.season,
episodes=need,
total_episodes=not_exist.total_episodes,
start_episode=not_exist.start_episode
)
else: else:
need_tvs[tmdbid].pop(seq) need_tvs[tmdbid].pop(seq)
if not need_tvs.get(tmdbid) and need_tvs.get(tmdbid) is not None: if not need_tvs.get(tmdbid) and need_tvs.get(tmdbid) is not None:
@ -189,10 +196,10 @@ class DownloadChain(ChainBase):
for tv in need_tv: for tv in need_tv:
if not tv: if not tv:
continue continue
if not tv.get("episodes"): if not tv.episodes:
if not need_seasons.get(need_tmdbid): if not need_seasons.get(need_tmdbid):
need_seasons[need_tmdbid] = [] need_seasons[need_tmdbid] = []
need_seasons[need_tmdbid].append(tv.get("season") or 1) need_seasons[need_tmdbid].append(tv.season or 1)
# 查找整季包含的种子,只处理整季没集的种子或者是集数超过季的种子 # 查找整季包含的种子,只处理整季没集的种子或者是集数超过季的种子
for need_tmdbid, need_season in need_seasons.items(): for need_tmdbid, need_season in need_seasons.items():
for context in contexts: for context in contexts:
@ -236,10 +243,10 @@ class DownloadChain(ChainBase):
continue continue
index = 0 index = 0
for tv in need_tv: for tv in need_tv:
need_season = tv.get("season") or 1 need_season = tv.season or 1
need_episodes = tv.get("episodes") need_episodes = tv.episodes
total_episodes = tv.get("total_episodes") total_episodes = tv.total_episodes
start_episode = tv.get("start_episode") or 1 start_episode = tv.start_episode or 1
# 缺失整季的转化为缺失集进行比较 # 缺失整季的转化为缺失集进行比较
if not need_episodes: if not need_episodes:
need_episodes = list(range(start_episode, total_episodes + start_episode)) need_episodes = list(range(start_episode, total_episodes + start_episode))
@ -278,8 +285,8 @@ class DownloadChain(ChainBase):
continue continue
index = 0 index = 0
for tv in need_tv: for tv in need_tv:
need_season = tv.get("season") or 1 need_season = tv.season or 1
need_episodes = tv.get("episodes") need_episodes = tv.episodes
if not need_episodes: if not need_episodes:
continue continue
for context in contexts: for context in contexts:
@ -326,7 +333,9 @@ class DownloadChain(ChainBase):
return downloaded_list, need_tvs return downloaded_list, need_tvs
def get_no_exists_info(self, meta: MetaBase, def get_no_exists_info(self, meta: MetaBase,
mediainfo: MediaInfo, no_exists: dict = None) -> Tuple[bool, dict]: mediainfo: MediaInfo,
no_exists: Dict[int, List[NotExistMediaInfo]] = None
) -> Tuple[bool, Dict[int, List[NotExistMediaInfo]]]:
""" """
检查媒体库查询是否存在对于剧集同时返回不存在的季集信息 检查媒体库查询是否存在对于剧集同时返回不存在的季集信息
:param meta: 元数据 :param meta: 元数据
@ -347,26 +356,26 @@ class DownloadChain(ChainBase):
""" """
if not no_exists.get(mediainfo.tmdb_id): if not no_exists.get(mediainfo.tmdb_id):
no_exists[mediainfo.tmdb_id] = [ no_exists[mediainfo.tmdb_id] = [
{ NotExistMediaInfo(
"season": _season, season=_season,
"episodes": _episodes, episodes=_episodes,
"total_episodes": _total, total_episodes=_total,
"start_episode": _start start_episode=_start)
}
] ]
else: else:
no_exists[mediainfo.tmdb_id].append({ no_exists[mediainfo.tmdb_id].append(
"season": _season, NotExistMediaInfo(
"episodes": _episodes, season=_season,
"total_episodes": _total, episodes=_episodes,
"start_episode": _start total_episodes=_total,
}) start_episode=_start)
)
if not no_exists: if not no_exists:
no_exists = {} no_exists = {}
if mediainfo.type == MediaType.MOVIE: if mediainfo.type == MediaType.MOVIE:
# 电影 # 电影
exists_movies: Optional[dict] = self.media_exists(mediainfo) exists_movies: Optional[ExistMediaInfo] = self.media_exists(mediainfo)
if exists_movies: if exists_movies:
logger.info(f"媒体库中已存在电影:{mediainfo.get_title_string()}") logger.info(f"媒体库中已存在电影:{mediainfo.get_title_string()}")
return True, {} return True, {}
@ -384,7 +393,7 @@ class DownloadChain(ChainBase):
logger.error(f"媒体信息中没有季集信息:{mediainfo.get_title_string()}") logger.error(f"媒体信息中没有季集信息:{mediainfo.get_title_string()}")
return False, {} return False, {}
# 电视剧 # 电视剧
exists_tvs: Optional[dict] = self.media_exists(mediainfo) exists_tvs: Optional[ExistMediaInfo] = self.media_exists(mediainfo)
if not exists_tvs: if not exists_tvs:
# 所有剧集均缺失 # 所有剧集均缺失
for season, episodes in mediainfo.seasons.items(): for season, episodes in mediainfo.seasons.items():
@ -400,7 +409,7 @@ class DownloadChain(ChainBase):
if meta.begin_season \ if meta.begin_season \
and season not in meta.get_season_list(): and season not in meta.get_season_list():
continue continue
exist_seasons = exists_tvs.get("seasons") exist_seasons = exists_tvs.seasons
if exist_seasons.get(season): if exist_seasons.get(season):
# 取差集 # 取差集
episodes = list(set(episodes).difference(set(exist_seasons[season]))) episodes = list(set(episodes).difference(set(exist_seasons[season])))

View File

@ -7,6 +7,7 @@ from app.core.meta import MetaBase
from app.core.metainfo import MetaInfo from app.core.metainfo import MetaInfo
from app.helper.sites import SitesHelper from app.helper.sites import SitesHelper
from app.log import logger from app.log import logger
from app.schemas.context import NotExistMediaInfo
from app.utils.string import StringUtils from app.utils.string import StringUtils
from app.utils.types import MediaType from app.utils.types import MediaType
@ -22,7 +23,7 @@ class SearchChain(ChainBase):
def process(self, meta: MetaBase, mediainfo: MediaInfo, def process(self, meta: MetaBase, mediainfo: MediaInfo,
keyword: str = None, keyword: str = None,
no_exists: Dict[int, List[dict]] = None) -> Optional[List[Context]]: no_exists: Dict[int, List[NotExistMediaInfo]] = None) -> Optional[List[Context]]:
""" """
根据媒体信息执行搜索 根据媒体信息执行搜索
:param meta: 元数据 :param meta: 元数据

View File

@ -9,6 +9,7 @@ from app.core.config import settings
from app.db.subscribes import Subscribes from app.db.subscribes import Subscribes
from app.helper.sites import SitesHelper from app.helper.sites import SitesHelper
from app.log import logger from app.log import logger
from app.schemas.context import NotExistMediaInfo
from app.utils.string import StringUtils from app.utils.string import StringUtils
from app.utils.types import MediaType from app.utils.types import MediaType
@ -290,7 +291,7 @@ class SubscribeChain(ChainBase):
}) })
@staticmethod @staticmethod
def __get_subscribe_no_exits(no_exists: Dict[int, List[dict]], def __get_subscribe_no_exits(no_exists: Dict[int, List[NotExistMediaInfo]],
tmdb_id: int, tmdb_id: int,
begin_season: int, begin_season: int,
total_episode: int, total_episode: int,
@ -310,37 +311,37 @@ class SubscribeChain(ChainBase):
index = 0 index = 0
for no_exist in no_exists.get(tmdb_id): for no_exist in no_exists.get(tmdb_id):
# 替换原季值 # 替换原季值
if no_exist.get("season") == begin_season: if no_exist.season == begin_season:
# 原季集列表 # 原季集列表
episode_list = no_exist.get("episodes") episode_list = no_exist.episodes
# 原总集数 # 原总集数
total = no_exist.get("total_episodes") total = no_exist.total_episodes
if total_episode and start_episode: if total_episode and start_episode:
# 有开始集和总集数 # 有开始集和总集数
episodes = list(range(start_episode, total_episode + 1)) episodes = list(range(start_episode, total_episode + 1))
no_exists[tmdb_id][index] = { no_exists[tmdb_id][index] = NotExistMediaInfo(
"season": begin_season, season=begin_season,
"episodes": episodes, episodes=episodes,
"total_episodes": total_episode, total_episodes=total_episode,
"start_episode": start_episode start_episode=start_episode
} )
elif not start_episode: elif not start_episode:
# 有总集数没有开始集 # 有总集数没有开始集
episodes = list(range(min(episode_list or [1]), total_episode + 1)) episodes = list(range(min(episode_list or [1]), total_episode + 1))
no_exists[tmdb_id][index] = { no_exists[tmdb_id][index] = NotExistMediaInfo(
"season": begin_season, season=begin_season,
"episodes": episodes, episodes=episodes,
"total_episodes": total_episode, total_episodes=total_episode,
"start_episode": min(episode_list or [1]) start_episode=min(episode_list or [1])
} )
elif not total_episode: elif not total_episode:
# 有开始集没有总集数 # 有开始集没有总集数
episodes = list(range(start_episode, max(episode_list or [total]) + 1)) episodes = list(range(start_episode, max(episode_list or [total]) + 1))
no_exists[tmdb_id][index] = { no_exists[tmdb_id][index] = NotExistMediaInfo(
"season": begin_season, season=begin_season,
"episodes": episodes, episodes=episodes,
"total_episodes": max(episode_list or [total]), total_episodes=max(episode_list or [total]),
"start_episode": start_episode start_episode=start_episode
} )
index += 1 index += 1
return no_exists return no_exists

View File

@ -1,12 +1,13 @@
import re import re
from pathlib import Path
from typing import List, Optional from typing import List, Optional
from app.chain import ChainBase from app.chain import ChainBase
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
from app.core.metainfo import MetaInfo from app.core.metainfo import MetaInfo
from app.log import logger from app.log import logger
from app.schemas.context import TransferInfo, TransferTorrent
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 from app.utils.types import TorrentStatus
@ -43,16 +44,16 @@ class TransferChain(ChainBase):
logger.error(f"参数错误,参数:{arg_str}") logger.error(f"参数错误,参数:{arg_str}")
return False return False
# 获取种子 # 获取种子
torrents: Optional[List[dict]] = self.list_torrents(hashs=torrent_hash) torrents: Optional[List[TransferTorrent]] = self.list_torrents(hashs=torrent_hash)
if not torrents: if not torrents:
logger.error(f"没有获取到种子,参数:{arg_str}") logger.error(f"没有获取到种子,参数:{arg_str}")
return False return False
# 识别前预处理 # 识别前预处理
result: Optional[tuple] = self.prepare_recognize(title=torrents[0].get("title")) result: Optional[tuple] = self.prepare_recognize(title=torrents[0].title)
if result: if result:
title, subtitle = result title, subtitle = result
else: else:
title, subtitle = torrents[0].get("title"), None title, subtitle = torrents[0].title, None
# 识别 # 识别
meta = MetaInfo(title=title, subtitle=subtitle) meta = MetaInfo(title=title, subtitle=subtitle)
# 查询媒体信息 # 查询媒体信息
@ -61,7 +62,7 @@ class TransferChain(ChainBase):
arg_mediainfo = None arg_mediainfo = None
logger.info("开始执行下载器文件转移 ...") logger.info("开始执行下载器文件转移 ...")
# 从下载器获取种子列表 # 从下载器获取种子列表
torrents: Optional[List[dict]] = self.list_torrents(status=TorrentStatus.TRANSFER) torrents: Optional[List[TransferTorrent]] = self.list_torrents(status=TorrentStatus.TRANSFER)
if not torrents: if not torrents:
logger.info("没有获取到已完成的下载任务") logger.info("没有获取到已完成的下载任务")
return False return False
@ -70,11 +71,11 @@ class TransferChain(ChainBase):
# 识别 # 识别
for torrent in torrents: for torrent in torrents:
# 识别前预处理 # 识别前预处理
result: Optional[tuple] = self.prepare_recognize(title=torrent.get("title")) result: Optional[tuple] = self.prepare_recognize(title=torrent.title)
if result: if result:
title, subtitle = result title, subtitle = result
else: else:
title, subtitle = torrent.get("title"), None title, subtitle = torrent.title, None
# 识别元数据 # 识别元数据
meta: MetaBase = MetaInfo(title=title, subtitle=subtitle) meta: MetaBase = MetaInfo(title=title, subtitle=subtitle)
if not meta.get_name(): if not meta.get_name():
@ -84,45 +85,45 @@ class TransferChain(ChainBase):
# 识别媒体信息 # 识别媒体信息
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.title}')
self.post_message(title=f"{torrent.get('title')} 未识别到媒体信息,无法入库!\n" self.post_message(title=f"{torrent.title} 未识别到媒体信息,无法入库!\n"
f"回复:```\n/transfer {torrent.get('hash')} [tmdbid]\n``` 手动识别转移。") f"回复:```\n/transfer {torrent.hash} [tmdbid]\n``` 手动识别转移。")
continue continue
else: else:
mediainfo = arg_mediainfo mediainfo = arg_mediainfo
logger.info(f"{torrent.get('title')} 识别为:{mediainfo.type.value} {mediainfo.get_title_string()}") logger.info(f"{torrent.title} 识别为:{mediainfo.type.value} {mediainfo.get_title_string()}")
# 更新媒体图片 # 更新媒体图片
self.obtain_image(mediainfo=mediainfo) self.obtain_image(mediainfo=mediainfo)
# 转移 # 转移
transferinfo: dict = self.transfer(mediainfo=mediainfo, path=torrent.get("path")) transferinfo: TransferInfo = self.transfer(mediainfo=mediainfo, path=Path(torrent.path))
if not transferinfo or not transferinfo.get("target_path"): if not transferinfo or not transferinfo.target_path:
logger.warn(f"{torrent.get('title')} 入库失败") logger.warn(f"{torrent.title} 入库失败")
self.post_message( self.post_message(
title=f"{mediainfo.get_title_string()}{meta.get_season_episode_string()} 入库失败!", title=f"{mediainfo.get_title_string()}{meta.get_season_episode_string()} 入库失败!",
text=f"原因:{transferinfo.get('message') if transferinfo else '未知'}", text=f"原因:{transferinfo.message if transferinfo else '未知'}",
image=mediainfo.get_message_image() image=mediainfo.get_message_image()
), ),
continue continue
# 转移完成 # 转移完成
self.transfer_completed(hashs=torrent.get("hash"), transinfo=transferinfo) self.transfer_completed(hashs=torrent.hash, transinfo=transferinfo)
# 刮剥 # 刮剥
self.scrape_metadata(path=transferinfo.get('target_path'), mediainfo=mediainfo) self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo)
# 刷新媒体库 # 刷新媒体库
self.refresh_mediaserver(mediainfo=mediainfo, file_path=transferinfo.get('target_path')) self.refresh_mediaserver(mediainfo=mediainfo, file_path=transferinfo.target_path)
# 发送通知 # 发送通知
self.__send_transfer_message(meta=meta, mediainfo=mediainfo, transferinfo=transferinfo) self.__send_transfer_message(meta=meta, mediainfo=mediainfo, transferinfo=transferinfo)
logger.info("下载器文件转移执行完成") logger.info("下载器文件转移执行完成")
return True return True
def __send_transfer_message(self, meta: MetaBase, mediainfo: MediaInfo, transferinfo: dict): def __send_transfer_message(self, meta: MetaBase, mediainfo: MediaInfo, transferinfo: TransferInfo):
""" """
发送入库成功的消息 发送入库成功的消息
""" """
# 文件大小 # 文件大小
file_size = StringUtils.str_filesize( file_size = StringUtils.str_filesize(
SystemUtils.get_directory_size( SystemUtils.get_directory_size(
transferinfo.get('target_path') transferinfo.target_path
) )
) )
msg_title = f"{mediainfo.get_title_string()} 已入库" msg_title = f"{mediainfo.get_title_string()} 已入库"

View File

@ -6,6 +6,7 @@ from ruamel.yaml import CommentedMap
from app.core.context import MediaInfo, TorrentInfo, Context from app.core.context import MediaInfo, TorrentInfo, Context
from app.core.meta import MetaBase from app.core.meta import MetaBase
from app.schemas.context import TransferInfo, TransferTorrent, ExistMediaInfo
from app.utils.types import TorrentStatus, MediaType from app.utils.types import TorrentStatus, MediaType
@ -98,7 +99,7 @@ class _ModuleBase(metaclass=ABCMeta):
""" """
pass pass
def media_exists(self, mediainfo: MediaInfo) -> Optional[dict]: def media_exists(self, mediainfo: MediaInfo) -> Optional[ExistMediaInfo]:
""" """
判断媒体文件是否存在 判断媒体文件是否存在
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
@ -156,7 +157,7 @@ class _ModuleBase(metaclass=ABCMeta):
pass pass
def list_torrents(self, status: TorrentStatus = None, def list_torrents(self, status: TorrentStatus = None,
hashs: Union[list, str] = None) -> Optional[List[dict]]: hashs: Union[list, str] = None) -> Optional[List[TransferTorrent]]:
""" """
获取下载器种子列表 获取下载器种子列表
:param status: 种子状态 :param status: 种子状态
@ -165,7 +166,7 @@ class _ModuleBase(metaclass=ABCMeta):
""" """
pass pass
def transfer(self, path: str, mediainfo: MediaInfo) -> Optional[dict]: def transfer(self, path: Path, mediainfo: MediaInfo) -> Optional[TransferInfo]:
""" """
转移一个路径下的文件 转移一个路径下的文件
:param path: 文件路径 :param path: 文件路径
@ -174,7 +175,7 @@ class _ModuleBase(metaclass=ABCMeta):
""" """
pass pass
def transfer_completed(self, hashs: Union[str, list], transinfo: dict) -> None: def transfer_completed(self, hashs: Union[str, list], transinfo: TransferInfo) -> None:
""" """
转移完成后的处理 转移完成后的处理
:param hashs: 种子Hash :param hashs: 种子Hash
@ -191,7 +192,7 @@ class _ModuleBase(metaclass=ABCMeta):
""" """
pass pass
def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: str) -> Optional[bool]: def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: Path) -> Optional[bool]:
""" """
刷新媒体库 刷新媒体库
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息

View File

@ -1,10 +1,11 @@
import json from pathlib import Path
from typing import Optional, Tuple, Union, Any from typing import Optional, Tuple, Union, Any
from app.core.context import MediaInfo from app.core.context import MediaInfo
from app.log import logger from app.log import logger
from app.modules import _ModuleBase from app.modules import _ModuleBase
from app.modules.emby.emby import Emby from app.modules.emby.emby import Emby
from app.schemas.context import ExistMediaInfo
from app.utils.types import MediaType from app.utils.types import MediaType
@ -31,7 +32,7 @@ class EmbyModule(_ModuleBase):
""" """
return self.emby.get_webhook_message(form.get("data")) return self.emby.get_webhook_message(form.get("data"))
def media_exists(self, mediainfo: MediaInfo) -> Optional[dict]: def media_exists(self, mediainfo: MediaInfo) -> Optional[ExistMediaInfo]:
""" """
判断媒体文件是否存在 判断媒体文件是否存在
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
@ -44,7 +45,7 @@ class EmbyModule(_ModuleBase):
return None return None
else: else:
logger.info(f"媒体库中已存在:{movies}") logger.info(f"媒体库中已存在:{movies}")
return {"type": MediaType.MOVIE} return ExistMediaInfo(type=MediaType.MOVIE)
else: else:
tvs = self.emby.get_tv_episodes(title=mediainfo.title, tvs = self.emby.get_tv_episodes(title=mediainfo.title,
year=mediainfo.year, year=mediainfo.year,
@ -54,9 +55,9 @@ class EmbyModule(_ModuleBase):
return None return None
else: else:
logger.info(f"{mediainfo.get_title_string()} 媒体库中已存在:{tvs}") logger.info(f"{mediainfo.get_title_string()} 媒体库中已存在:{tvs}")
return {"type": MediaType.TV, "seasons": tvs} return ExistMediaInfo(type=MediaType.TV, seasons=tvs)
def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: str) -> Optional[bool]: def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: Path) -> Optional[bool]:
""" """
刷新媒体库 刷新媒体库
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息

View File

@ -11,6 +11,7 @@ from app.core.config import settings
from app.core.meta import MetaBase from app.core.meta import MetaBase
from app.log import logger from app.log import logger
from app.modules import _ModuleBase from app.modules import _ModuleBase
from app.schemas.context import TransferInfo
from app.utils.system import SystemUtils from app.utils.system import SystemUtils
from app.utils.types import MediaType from app.utils.types import MediaType
@ -28,7 +29,7 @@ class FileTransferModule(_ModuleBase):
def init_setting(self) -> Tuple[str, Union[str, bool]]: def init_setting(self) -> Tuple[str, Union[str, bool]]:
pass pass
def transfer(self, path: str, mediainfo: MediaInfo) -> Optional[dict]: def transfer(self, path: Path, mediainfo: MediaInfo) -> Optional[TransferInfo]:
""" """
文件转移 文件转移
:param path: 文件路径 :param path: 文件路径
@ -38,18 +39,14 @@ class FileTransferModule(_ModuleBase):
if not settings.LIBRARY_PATH: if not settings.LIBRARY_PATH:
logger.error("未设置媒体库目录,无法转移文件") logger.error("未设置媒体库目录,无法转移文件")
return None return None
target_path, msg = self.transfer_media(in_path=Path(path), target_path, msg = self.transfer_media(in_path=path,
meidainfo=mediainfo, meidainfo=mediainfo,
rmt_mode=settings.TRANSFER_TYPE, rmt_mode=settings.TRANSFER_TYPE,
target_dir=Path(settings.LIBRARY_PATH)) target_dir=Path(settings.LIBRARY_PATH))
if not path: if not path:
logger.error(msg) logger.error(msg)
return { return TransferInfo(path=path, target_path=target_path, message=msg)
"path": path,
"target_path": target_path,
"message": msg
}
@staticmethod @staticmethod
def __transfer_command(file_item: Path, target_file: Path, rmt_mode) -> int: def __transfer_command(file_item: Path, target_file: Path, rmt_mode) -> int:

View File

@ -1,10 +1,12 @@
import json import json
from pathlib import Path
from typing import Optional, Tuple, Union, Any from typing import Optional, Tuple, Union, Any
from app.core.context import MediaInfo from app.core.context import MediaInfo
from app.log import logger from app.log import logger
from app.modules import _ModuleBase from app.modules import _ModuleBase
from app.modules.jellyfin.jellyfin import Jellyfin from app.modules.jellyfin.jellyfin import Jellyfin
from app.schemas.context import ExistMediaInfo
from app.utils.types import MediaType from app.utils.types import MediaType
@ -30,7 +32,7 @@ class JellyfinModule(_ModuleBase):
""" """
return self.jellyfin.get_webhook_message(json.loads(body)) return self.jellyfin.get_webhook_message(json.loads(body))
def media_exists(self, mediainfo: MediaInfo) -> Optional[dict]: def media_exists(self, mediainfo: MediaInfo) -> Optional[ExistMediaInfo]:
""" """
判断媒体文件是否存在 判断媒体文件是否存在
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
@ -43,7 +45,7 @@ class JellyfinModule(_ModuleBase):
return None return None
else: else:
logger.info(f"媒体库中已存在:{movies}") logger.info(f"媒体库中已存在:{movies}")
return {"type": MediaType.MOVIE} return ExistMediaInfo(type=MediaType.MOVIE)
else: else:
tvs = self.jellyfin.get_tv_episodes(title=mediainfo.title, tvs = self.jellyfin.get_tv_episodes(title=mediainfo.title,
year=mediainfo.year, year=mediainfo.year,
@ -53,9 +55,9 @@ class JellyfinModule(_ModuleBase):
return None return None
else: else:
logger.info(f"{mediainfo.get_title_string()} 媒体库中已存在:{tvs}") logger.info(f"{mediainfo.get_title_string()} 媒体库中已存在:{tvs}")
return {"type": MediaType.TV, "seasons": tvs} return ExistMediaInfo(type=MediaType.TV, seasons=tvs)
def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: str) -> Optional[bool]: def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: Path) -> Optional[bool]:
""" """
刷新媒体库 刷新媒体库
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息

View File

@ -1,9 +1,11 @@
from pathlib import Path
from typing import Optional, Tuple, Union, Any from typing import Optional, Tuple, Union, Any
from app.core.context import MediaInfo from app.core.context import MediaInfo
from app.log import logger from app.log import logger
from app.modules import _ModuleBase from app.modules import _ModuleBase
from app.modules.plex.plex import Plex from app.modules.plex.plex import Plex
from app.schemas.context import ExistMediaInfo
from app.utils.types import MediaType from app.utils.types import MediaType
@ -30,7 +32,7 @@ class PlexModule(_ModuleBase):
""" """
return self.plex.get_webhook_message(form.get("payload")) return self.plex.get_webhook_message(form.get("payload"))
def media_exists(self, mediainfo: MediaInfo) -> Optional[dict]: def media_exists(self, mediainfo: MediaInfo) -> Optional[ExistMediaInfo]:
""" """
判断媒体文件是否存在 判断媒体文件是否存在
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
@ -43,7 +45,7 @@ class PlexModule(_ModuleBase):
return None return None
else: else:
logger.info(f"媒体库中已存在:{movies}") logger.info(f"媒体库中已存在:{movies}")
return {"type": MediaType.MOVIE} return ExistMediaInfo(type=MediaType.MOVIE)
else: else:
tvs = self.plex.get_tv_episodes(title=mediainfo.title, tvs = self.plex.get_tv_episodes(title=mediainfo.title,
year=mediainfo.year) year=mediainfo.year)
@ -52,9 +54,9 @@ class PlexModule(_ModuleBase):
return None return None
else: else:
logger.info(f"{mediainfo.get_title_string()} 媒体库中已存在:{tvs}") logger.info(f"{mediainfo.get_title_string()} 媒体库中已存在:{tvs}")
return {"type": MediaType.TV, "seasons": tvs} return ExistMediaInfo(type=MediaType.TV, seasons=tvs)
def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: str) -> Optional[bool]: def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: Path) -> Optional[bool]:
""" """
刷新媒体库 刷新媒体库
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息

View File

@ -6,6 +6,7 @@ from app.core.metainfo import MetaInfo
from app.log import logger from app.log import logger
from app.modules import _ModuleBase from app.modules import _ModuleBase
from app.modules.qbittorrent.qbittorrent import Qbittorrent from app.modules.qbittorrent.qbittorrent import Qbittorrent
from app.schemas.context import TransferInfo, TransferTorrent
from app.utils.string import StringUtils from app.utils.string import StringUtils
from app.utils.types import TorrentStatus from app.utils.types import TorrentStatus
@ -84,7 +85,8 @@ class QbittorrentModule(_ModuleBase):
else: else:
return torrent_hash, "添加下载成功" return torrent_hash, "添加下载成功"
def list_torrents(self, status: TorrentStatus = None, hashs: Union[list, str] = None) -> Optional[List[dict]]: def list_torrents(self, status: TorrentStatus = None,
hashs: Union[list, str] = None) -> Optional[List[TransferTorrent]]:
""" """
获取下载器种子列表 获取下载器种子列表
:param status: 种子状态 :param status: 种子状态
@ -101,12 +103,12 @@ class QbittorrentModule(_ModuleBase):
torrent_path = Path(content_path) torrent_path = Path(content_path)
else: else:
torrent_path = Path(settings.DOWNLOAD_PATH) / torrent.get('name') torrent_path = Path(settings.DOWNLOAD_PATH) / torrent.get('name')
ret_torrents.append({ ret_torrents.append(TransferTorrent(
'title': torrent.get('name'), title=torrent.get('name'),
'path': torrent_path, path=torrent_path,
'hash': torrent.get('hash'), hash=torrent.get('hash'),
'tags': torrent.get('tags') tags=torrent.get('tags')
}) ))
elif status == TorrentStatus.TRANSFER: elif status == TorrentStatus.TRANSFER:
# 获取已完成且未整理的 # 获取已完成且未整理的
torrents = self.qbittorrent.get_completed_torrents(tags=settings.TORRENT_TAG) torrents = self.qbittorrent.get_completed_torrents(tags=settings.TORRENT_TAG)
@ -120,17 +122,17 @@ class QbittorrentModule(_ModuleBase):
torrent_path = Path(content_path) torrent_path = Path(content_path)
else: else:
torrent_path = Path(settings.DOWNLOAD_PATH) / torrent.get('name') torrent_path = Path(settings.DOWNLOAD_PATH) / torrent.get('name')
ret_torrents.append({ ret_torrents.append(TransferTorrent(
'title': torrent.get('name'), title=torrent.get('name'),
'path': torrent_path, path=torrent_path,
'hash': torrent.get('hash'), hash=torrent.get('hash'),
'tags': torrent.get('tags') tags=torrent.get('tags')
}) ))
else: else:
return None return None
return ret_torrents return ret_torrents
def transfer_completed(self, hashs: Union[str, list], transinfo: dict) -> None: def transfer_completed(self, hashs: Union[str, list], transinfo: TransferInfo) -> None:
""" """
转移完成后的处理 转移完成后的处理
:param hashs: 种子Hash :param hashs: 种子Hash

View File

@ -6,6 +6,7 @@ from app.core.metainfo import MetaInfo
from app.log import logger 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.schemas.context import TransferInfo, TransferTorrent
from app.utils.types import TorrentStatus from app.utils.types import TorrentStatus
@ -71,7 +72,8 @@ class TransmissionModule(_ModuleBase):
else: else:
return torrent_hash, "添加下载任务成功" return torrent_hash, "添加下载任务成功"
def list_torrents(self, status: TorrentStatus = None, hashs: Union[list, str] = None) -> Optional[List[dict]]: def list_torrents(self, status: TorrentStatus = None,
hashs: Union[list, str] = None) -> Optional[List[TransferTorrent]]:
""" """
获取下载器种子列表 获取下载器种子列表
:param status: 种子状态 :param status: 种子状态
@ -83,12 +85,12 @@ class TransmissionModule(_ModuleBase):
# 按Hash获取 # 按Hash获取
torrents, _ = self.transmission.get_torrents(ids=hashs, tags=settings.TORRENT_TAG) torrents, _ = self.transmission.get_torrents(ids=hashs, tags=settings.TORRENT_TAG)
for torrent in torrents: for torrent in torrents:
ret_torrents.append({ ret_torrents.append(TransferTorrent(
'title': torrent.name, title=torrent.name,
'path': Path(torrent.download_dir) / torrent.name, path=Path(torrent.download_dir) / torrent.name,
'hash': torrent.hashString, hash=torrent.hashString,
'tags': torrent.labels tags=torrent.labels
}) ))
elif status == TorrentStatus.TRANSFER: elif status == TorrentStatus.TRANSFER:
# 获取已完成且未整理的 # 获取已完成且未整理的
torrents = self.transmission.get_completed_torrents(tags=settings.TORRENT_TAG) torrents = self.transmission.get_completed_torrents(tags=settings.TORRENT_TAG)
@ -102,17 +104,17 @@ class TransmissionModule(_ModuleBase):
if not path: if not path:
logger.debug(f"未获取到 {torrent.name} 下载保存路径") logger.debug(f"未获取到 {torrent.name} 下载保存路径")
continue continue
ret_torrents.append({ ret_torrents.append(TransferTorrent(
'title': torrent.name, title=torrent.name,
'path': Path(path) / torrent.name, path=Path(torrent.download_dir) / torrent.name,
'hash': torrent.hashString, hash=torrent.hashString,
'tags': torrent.labels tags=torrent.labels
}) ))
else: else:
return None return None
return ret_torrents return ret_torrents
def transfer_completed(self, hashs: Union[str, list], transinfo: dict) -> None: def transfer_completed(self, hashs: Union[str, list], transinfo: TransferInfo) -> None:
""" """
转移完成后的处理 转移完成后的处理
:param hashs: 种子Hash :param hashs: 种子Hash

View File

@ -1,7 +1,5 @@
from pathlib import Path
from typing import Tuple, Union from typing import Tuple, Union
from app.core.context import Context
from app.modules import _ModuleBase from app.modules import _ModuleBase

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import base64
import json import json
import re import re
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
@ -7,7 +6,6 @@ from typing import Optional
from urllib.parse import urljoin, urlsplit from urllib.parse import urljoin, urlsplit
import requests import requests
from lxml import etree
from requests import Session from requests import Session
from app.core.config import settings from app.core.config import settings

View File

@ -1,7 +1,10 @@
from typing import Optional from pathlib import Path
from typing import Optional, Dict
from pydantic import BaseModel from pydantic import BaseModel
from app.utils.types import MediaType
class MetaInfo(BaseModel): class MetaInfo(BaseModel):
# 是否处理的文件 # 是否处理的文件
@ -84,3 +87,37 @@ class Context(BaseModel):
meta_info: Optional[MetaInfo] meta_info: Optional[MetaInfo]
# 媒体信息 # 媒体信息
media_info: Optional[MediaInfo] media_info: Optional[MediaInfo]
class TransferTorrent(BaseModel):
title: Optional[str] = None
path: Optional[Path] = None
hash: Optional[str] = None
tags: Optional[str] = None
class TransferInfo(BaseModel):
# 转移⼁路径
path: Optional[Path] = None
# 转移后路径
target_path: Optional[Path] = None
# 错误信息
message: Optional[str] = None
class ExistMediaInfo(BaseModel):
# 类型 电影、电视剧
type: MediaType
# 季
seasons: Optional[Dict[int, list]] = None
class NotExistMediaInfo(BaseModel):
# 季
season: int
# 剧集列表
episodes: list = []
# 总集数
total_episodes: int = 0
# 开始集
start_episode: int = 0