From 5be3182b048ffe7b16a2fe8a51f3bd058a10942e Mon Sep 17 00:00:00 2001 From: jeblove <249972068@qq.com> Date: Wed, 6 Mar 2024 23:39:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E3=80=90=E8=AF=8A=E6=96=AD?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=B0=83=E6=95=B4=E3=80=91=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 11 +- plugins/diagparamadjust/__init__.py | 348 ++++++++++++++++++++++++++++ 2 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 plugins/diagparamadjust/__init__.py diff --git a/package.json b/package.json index 7da0d81..924377c 100644 --- a/package.json +++ b/package.json @@ -390,5 +390,14 @@ "icon": "Amule_A.png", "author": "jxxghp", "level": 1 - } + }, + "DiagParamAdjust": { + "name": "诊断参数调整", + "description": "Emby专用插件|暂时性解决emby字幕偏移问题,需要emby安装Diagnostics插件。", + "version": "1.0", + "icon": "Themeengine_A.png", + "author": "jeblove", + "level": 1 + }, + } diff --git a/plugins/diagparamadjust/__init__.py b/plugins/diagparamadjust/__init__.py new file mode 100644 index 0000000..02645d9 --- /dev/null +++ b/plugins/diagparamadjust/__init__.py @@ -0,0 +1,348 @@ +import json +from datetime import datetime, timedelta + +from app.modules.emby import Emby +from app.core.config import settings +from app.plugins import _PluginBase +from app.log import logger +from typing import List, Tuple, Dict, Any, Optional +import pytz + +from apscheduler.triggers.cron import CronTrigger +from apscheduler.schedulers.background import BackgroundScheduler + +class DiagParamAdjust(_PluginBase): + # 插件名称 + plugin_name = "诊断参数调整" + # 插件描述 + plugin_desc = "Emby专用插件|暂时性解决emby字幕偏移问题,需要emby安装Diagnostics插件。" + # 插件图标 + plugin_icon = "Themeengine_A.png" + # 插件版本 + plugin_version = "1.0" + # 插件作者 + plugin_author = "jeblove" + # 作者主页 + author_url = "https://github.com/jeblove" + # 插件配置项ID前缀 + plugin_config_prefix = "dpa_" + # 加载顺序 + plugin_order = 14 + # 可使用的用户级别 + auth_level = 1 + + # 私有属性 + _enabled: bool = False + _offset = True + _onlyonce = False + _base_url = None + _endpoint = None + _api_key = None + _search_text = None + _replace_text = None + _cron = None + # 请求接口 + _url = "[HOST]emby/EncodingDiagnostics/DiagnosticOptions?api_key=[APIKEY]" + # 定时器 + _scheduler: Optional[BackgroundScheduler] = None + + def init_plugin(self, config: dict = None): + # 停止现有任务 + self.stop_service() + + if config: + self._enabled = config.get("enabled") + self._offset = config.get('offset') + self._onlyonce = config.get("onlyonce") + self._search_text = config.get("search") + self._replace_text = config.get("replace") + self._cron = config.get("cron") + + if self._onlyonce: + self._scheduler = BackgroundScheduler(timezone=settings.TZ) + logger.info(f"诊断参数调整服务启动,立刻运行一次") + self._scheduler.add_job(func=self.run, trigger='date', + run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3), + name="诊断参数调整") + + # 关闭一次性开关 + self._onlyonce = False + self.update_config({ + "enabled": self._enabled, + "offset": self._offset, + "onlyonce": False, + "search": self._search_text, + "replace": self._replace_text, + "cron": self._cron + }) + + # 启动任务 + # self.run() + if self._scheduler.get_jobs(): + self._scheduler.print_jobs() + self._scheduler.start() + + 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_service(self) -> List[Dict[str, Any]]: + """ + 注册插件公共服务 + [{ + "id": "服务ID", + "name": "服务名称", + "trigger": "触发器:cron/interval/date/CronTrigger.from_crontab()", + "func": self.xxx, + "kwargs": {} # 定时器参数 + }] + """ + if self._enabled and self._cron: + return [{ + "id": "DiagParamAdjust", + "name": "诊断参数调整定时服务", + "trigger": CronTrigger.from_crontab(self._cron), + "func": self.run, + "kwargs": {} + }] + + 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': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'enabled', + 'label': '启用插件', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'offset', + 'label': '字幕偏移用途', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'onlyonce', + 'label': '立即运行一次', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'search', + 'label': '搜索文本' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'replace', + 'label': '替换文本' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'cron', + 'label': '检测执行周期', + 'placeholder': '*/5 * * * *' + } + } + ] + }, + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + }, + 'content': [ + { + 'component': 'VAlert', + 'props': { + 'type': 'info', + 'variant': 'tonal', + 'text': '暂时性解决emby字幕偏移问题,请在默认参数的基础上修改至适合。\n 此替换文本参数应用于emby-Diagnostics-Parameter Adjustment。\n 默认参数用于修改ffmpeg中字幕覆盖在视频上的位置。\n 方案来源于https://opve.cn/archives/983.html', + 'style': 'white-space: pre-line;' + } + } + ] + } + ] + } + ] + } + ],{ + "enabled": False, + "offset": True, + "onlyonce": False, + "search": "x=(W-w)/2:y=(H-h):repeatlast=0", + "replace": "x=W/4:y=h/4:repeatlast=0", + "cron": "*/5 * * * *" + } + + def detect(self): + ''' + 检测是否存在目标参数 + + :return True: 存在; False: 不存在 + ''' + logger.info('字幕偏移修正,检测目标参数') + replaceText = "" + try: + # req_url = "[HOST]emby/EncodingDiagnostics/DiagnosticOptions?api_key=[APIKEY]" + res = Emby().get_data(self._url) + result = res.json() + data = result['Object']['CommandLineOptions'] + replaceText = data['ReplaceText'] + except json.JSONDecodeError as j: + logger.error('服务停止,Emby请安装【Diagnostics】插件') + return None + except KeyError: + # 以装插件,未设置过该参数 + # logger.info('目标参数为空') + pass + + # 符合所有情况 + if 'repeatlast' in replaceText \ + and 'x=(W-w)/2:y=(H-h):repeatlast=0' in data['SearchText'] \ + and result['Object']['TranscodingOptions']['DisableHardwareSubtitleOverlay']==True: + return True + + return False + + def setOptions(self): + data = { + "CommandLineOptions": { + "SearchText": self._search_text, + "ReplaceText": self._replace_text + }, + "TranscodingOptions": { + "DisableHardwareSubtitleOverlay": True + } + } + data = json.dumps(data) + headers = { + 'Content-Type': 'application/octet-stream' + } + res = Emby().post_data(self._url, data, headers) + if res.status_code // 100 == 2: + logger.info('参数设置成功') + return True + else: + logger.error('参数设置失败 {}'.format(res.status_code)) + + def run(self): + # 字幕偏移修正,则带检测 + if self._offset: + state = self.detect() + if state: + logger.info('参数正常,无需修正') + return True + elif state==None: + return None + + self.setOptions() + + + def get_page(self) -> List[dict]: + pass + + def stop_service(self): + """ + 退出插件 + """ + try: + if self._scheduler: + self._scheduler.remove_all_jobs() + if self._scheduler.running: + self._scheduler.shutdown() + self._scheduler = None + except Exception as e: + logger.error("退出插件失败:%s" % str(e)) + +