205 lines
6.8 KiB
Python
205 lines
6.8 KiB
Python
from pathlib import Path
|
||
from typing import Any, List, Dict, Tuple
|
||
|
||
from requests import RequestException
|
||
|
||
from app.chain.tmdb import TmdbChain
|
||
from app.core.event import eventmanager, Event
|
||
from app.helper.nfo import NfoReader
|
||
from app.log import logger
|
||
from app.plugins import _PluginBase
|
||
from app.schemas import TransferInfo, MediaInfo
|
||
from app.schemas.types import EventType, MediaType
|
||
from app.utils.common import retry
|
||
from app.utils.http import RequestUtils
|
||
|
||
|
||
class PersonMeta(_PluginBase):
|
||
# 插件名称
|
||
plugin_name = "演职人员刮削"
|
||
# 插件描述
|
||
plugin_desc = "刮削演职人员图片以及中文名称。"
|
||
# 插件图标
|
||
plugin_icon = "actor.png"
|
||
# 主题色
|
||
plugin_color = "#E66E72"
|
||
# 插件版本
|
||
plugin_version = "1.0"
|
||
# 插件作者
|
||
plugin_author = "jxxghp"
|
||
# 作者主页
|
||
author_url = "https://github.com/jxxghp"
|
||
# 插件配置项ID前缀
|
||
plugin_config_prefix = "personmeta_"
|
||
# 加载顺序
|
||
plugin_order = 24
|
||
# 可使用的用户级别
|
||
auth_level = 1
|
||
|
||
# 私有属性
|
||
tmdbchain = None
|
||
_enabled = False
|
||
_metadir = ""
|
||
|
||
def init_plugin(self, config: dict = None):
|
||
self.tmdbchain = TmdbChain(self.db)
|
||
if config:
|
||
self._enabled = config.get("enabled")
|
||
self._metadir = config.get("metadir")
|
||
|
||
def get_state(self) -> bool:
|
||
return self._enabled
|
||
|
||
@staticmethod
|
||
def get_command() -> List[Dict[str, Any]]:
|
||
pass
|
||
|
||
def get_api(self) -> List[Dict[str, Any]]:
|
||
pass
|
||
|
||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||
"""
|
||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||
"""
|
||
return [
|
||
{
|
||
'component': 'VForm',
|
||
'content': [
|
||
{
|
||
'component': 'VRow',
|
||
'content': [
|
||
{
|
||
'component': 'VCol',
|
||
'props': {
|
||
'cols': 12,
|
||
'md': 6
|
||
},
|
||
'content': [
|
||
{
|
||
'component': 'VSwitch',
|
||
'props': {
|
||
'model': 'enabled',
|
||
'label': '启用插件',
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
{
|
||
'component': 'VRow',
|
||
'content': [
|
||
{
|
||
'component': 'VCol',
|
||
'props': {
|
||
'cols': 12,
|
||
},
|
||
'content': [
|
||
{
|
||
'component': 'VTextField',
|
||
'props': {
|
||
'model': 'metadir',
|
||
'label': '人物元数据目录',
|
||
'placeholder': '/metadata/people'
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
], {
|
||
"enabled": False,
|
||
"metadir": ""
|
||
}
|
||
|
||
def get_page(self) -> List[dict]:
|
||
pass
|
||
|
||
@eventmanager.register(EventType.TransferComplete)
|
||
def scrap_rt(self, event: Event):
|
||
"""
|
||
根据事件实时刮削演员信息
|
||
"""
|
||
if not self._enabled:
|
||
return
|
||
# 下载人物头像
|
||
if not self._metadir:
|
||
logger.warning("人物元数据目录未配置,无法下载人物头像")
|
||
return
|
||
# 事件数据
|
||
mediainfo: MediaInfo = event.event_data.get("mediainfo")
|
||
transferinfo: TransferInfo = event.event_data.get("transferinfo")
|
||
if not mediainfo or not transferinfo:
|
||
return
|
||
# 文件路径
|
||
filepath = transferinfo.target_path
|
||
if not filepath:
|
||
return
|
||
# 电影
|
||
if mediainfo.type == MediaType.MOVIE:
|
||
# nfo文件
|
||
nfofile = filepath.with_name("movie.nfo")
|
||
if not nfofile.exists():
|
||
nfofile = filepath.parent / f"{filepath.stem}.nfo"
|
||
if not nfofile.exists():
|
||
logger.warning(f"电影nfo文件不存在:{nfofile}")
|
||
return
|
||
else:
|
||
# nfo文件
|
||
nfofile = filepath.parent.with_name("tvshow.nfo")
|
||
if not nfofile.exists():
|
||
logger.warning(f"剧集nfo文件不存在:{nfofile}")
|
||
return
|
||
# 读取nfo文件
|
||
nfo = NfoReader(nfofile)
|
||
# 读取演员信息
|
||
actors = nfo.get_elements("actor") or []
|
||
for actor in actors:
|
||
# 演员ID
|
||
actor_id = actor.find("id").text
|
||
if not actor_id:
|
||
continue
|
||
# 演员名称
|
||
actor_name = actor.find("name").text
|
||
# 查询演员详情
|
||
actor_info = self.tmdbchain.person_detail(actor_id)
|
||
if not actor_info:
|
||
continue
|
||
# 演员头像
|
||
actor_image = actor_info.get("profile_path")
|
||
if not actor_image:
|
||
continue
|
||
# 计算保存路径
|
||
image_path = Path(self._metadir) / f"{actor_name}-tmdb-{actor_id}{Path(actor_image).suffix}"
|
||
if image_path.exists():
|
||
continue
|
||
# 下载图片
|
||
self.download_image(f"https://image.tmdb.org/t/p/original{actor_image}", image_path)
|
||
|
||
@staticmethod
|
||
@retry(RequestException, logger=logger)
|
||
def download_image(image_url: str, path: Path):
|
||
"""
|
||
下载图片,保存到指定路径
|
||
"""
|
||
try:
|
||
logger.info(f"正在下载演职人员图片:{image_url} ...")
|
||
r = RequestUtils().get_res(url=image_url, raise_exception=True)
|
||
if r:
|
||
path.write_bytes(r.content)
|
||
logger.info(f"图片已保存:{path}")
|
||
else:
|
||
logger.info(f"图片下载失败,请检查网络连通性:{image_url}")
|
||
except RequestException as err:
|
||
raise err
|
||
except Exception as err:
|
||
logger.error(f"图片下载失败:{err}")
|
||
|
||
def stop_service(self):
|
||
"""
|
||
退出插件
|
||
"""
|
||
pass
|