From f53ae6573dd64465487f3002e18cfa7e23714e3a Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 17 Nov 2024 15:34:28 +0800 Subject: [PATCH] add ChineseSubFinder V2 --- package.json | 3 +- package.v2.json | 12 ++ plugins.v2/chinesesubfinder/__init__.py | 255 ++++++++++++++++++++++++ 3 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 plugins.v2/chinesesubfinder/__init__.py diff --git a/package.json b/package.json index 1ea49fe..c81332d 100644 --- a/package.json +++ b/package.json @@ -112,8 +112,7 @@ "version": "1.1", "icon": "chinesesubfinder.png", "author": "jxxghp", - "level": 1, - "v2": true + "level": 1 }, "DoubanRank": { "name": "豆瓣榜单订阅", diff --git a/package.v2.json b/package.v2.json index 297417e..ac2dd47 100644 --- a/package.v2.json +++ b/package.v2.json @@ -227,5 +227,17 @@ "history": { "v2.1": "兼容MoviePilot V2" } + }, + "ChineseSubFinder": { + "name": "ChineseSubFinder", + "description": "整理入库时通知ChineseSubFinder下载字幕。", + "labels": "字幕", + "version": "2.0", + "icon": "chinesesubfinder.png", + "author": "jxxghp", + "level": 1, + "history": { + "v2.0": "兼容MoviePilot V2" + } } } \ No newline at end of file diff --git a/plugins.v2/chinesesubfinder/__init__.py b/plugins.v2/chinesesubfinder/__init__.py new file mode 100644 index 0000000..eb80ff7 --- /dev/null +++ b/plugins.v2/chinesesubfinder/__init__.py @@ -0,0 +1,255 @@ +from functools import lru_cache +from pathlib import Path +from typing import List, Tuple, Dict, Any + +from app.core.config import settings +from app.core.context import MediaInfo +from app.core.event import eventmanager, Event +from app.log import logger +from app.plugins import _PluginBase +from app.schemas import TransferInfo, FileItem +from app.schemas.types import EventType, MediaType +from app.utils.http import RequestUtils +from app.utils.system import SystemUtils + + +class ChineseSubFinder(_PluginBase): + # 插件名称 + plugin_name = "ChineseSubFinder" + # 插件描述 + plugin_desc = "整理入库时通知ChineseSubFinder下载字幕。" + # 插件图标 + plugin_icon = "chinesesubfinder.png" + # 插件版本 + plugin_version = "2.0" + # 插件作者 + plugin_author = "jxxghp" + # 作者主页 + author_url = "https://github.com/jxxghp" + # 插件配置项ID前缀 + plugin_config_prefix = "chinesesubfinder_" + # 加载顺序 + plugin_order = 5 + # 可使用的用户级别 + auth_level = 1 + + # 私有属性 + _save_tmp_path = None + _enabled = False + _host = None + _api_key = None + _remote_path = None + _local_path = None + + def init_plugin(self, config: dict = None): + self._save_tmp_path = settings.TEMP_PATH + if config: + self._enabled = config.get("enabled") + self._api_key = config.get("api_key") + self._host = config.get('host') + if self._host: + if not self._host.startswith('http'): + self._host = "http://" + self._host + if not self._host.endswith('/'): + self._host = self._host + "/" + self._local_path = config.get("local_path") + self._remote_path = config.get("remote_path") + + @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]]: + 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, + 'md': 6 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'host', + 'label': '服务器' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'api_key', + 'label': 'API密钥' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'local_path', + 'label': '本地路径' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'remote_path', + 'label': '远端路径' + } + } + ] + } + ] + } + ] + } + ], { + "enabled": False, + "host": "", + "api_key": "", + "local_path": "", + "remote_path": "" + } + + def get_state(self) -> bool: + return self._enabled + + def get_page(self) -> List[dict]: + pass + + def stop_service(self): + pass + + @eventmanager.register(EventType.TransferComplete) + def download(self, event: Event): + """ + 调用ChineseSubFinder下载字幕 + """ + if not self._enabled or not self._host or not self._api_key: + return + item = event.event_data + if not item: + return + # 请求地址 + req_url = "%sapi/v1/add-job" % self._host + + # 媒体信息 + item_media: MediaInfo = item.get("mediainfo") + # 转移信息 + item_transfer: TransferInfo = item.get("transferinfo") + # 类型 + item_type = item_media.type + # 目的路径 + item_dest: FileItem = item_transfer.target_diritem + # 是否蓝光原盘 + item_bluray = SystemUtils.is_bluray_dir(Path(item_dest.path)) + # 文件清单 + item_file_list = item_transfer.file_list_new + + if item_bluray: + # 蓝光原盘虚拟个文件 + item_file_list = ["%s.mp4" % Path(item_dest.path) / item_dest.name] + + for file_path in item_file_list: + # 路径替换 + if self._local_path and self._remote_path and file_path.startswith(self._local_path): + file_path = file_path.replace(self._local_path, self._remote_path).replace('\\', '/') + + # 调用CSF下载字幕 + self.__request_csf(req_url=req_url, + file_path=file_path, + item_type=0 if item_type == MediaType.MOVIE else 1, + item_bluray=item_bluray) + + @lru_cache(maxsize=128) + def __request_csf(self, req_url, file_path, item_type, item_bluray): + # 一个名称只建一个任务 + logger.info("通知ChineseSubFinder下载字幕: %s" % file_path) + params = { + "video_type": item_type, + "physical_video_file_full_path": file_path, + "task_priority_level": 3, + "media_server_inside_video_id": "", + "is_bluray": item_bluray + } + try: + res = RequestUtils(headers={ + "Authorization": "Bearer %s" % self._api_key + }).post(req_url, json=params) + if not res or res.status_code != 200: + logger.error("调用ChineseSubFinder API失败!") + else: + # 如果文件目录没有识别的nfo元数据, 此接口会返回控制符,推测是ChineseSubFinder的原因 + # emby refresh元数据时异步的 + if res.text: + job_id = res.json().get("job_id") + message = res.json().get("message") + if not job_id: + logger.warn("ChineseSubFinder下载字幕出错:%s" % message) + else: + logger.info("ChineseSubFinder任务添加成功:%s" % job_id) + elif res.status_code != 200: + logger.warn(f"ChineseSubFinder调用出错:{res.status_code} - {res.reason}") + except Exception as e: + logger.error("连接ChineseSubFinder出错:" + str(e))