Merge pull request #894 from thsrite/main

This commit is contained in:
jxxghp 2023-10-17 17:04:04 +08:00 committed by GitHub
commit bd2ef934d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 403 additions and 4 deletions

View File

@ -65,6 +65,15 @@ class ChainBase(metaclass=ABCMeta):
del cache
gc.collect()
@staticmethod
def remove_cache(filename: str) -> None:
"""
删除本地缓存
"""
cache_path = settings.TEMP_PATH / filename
if cache_path.exists():
Path(cache_path).unlink()
def run_module(self, method: str, *args, **kwargs) -> Any:
"""
运行包含该方法的所有模块然后返回结果

View File

@ -1,7 +1,13 @@
import json
import os
import re
from typing import Union
from app.chain import ChainBase
from app.core.config import settings
from app.log import logger
from app.schemas import Notification, MessageChannel
from app.utils.http import RequestUtils
from app.utils.system import SystemUtils
@ -10,6 +16,9 @@ class SystemChain(ChainBase):
系统级处理链
"""
_restart_file = "__system_restart__"
_update_file = "__system_update__"
def remote_clear_cache(self, channel: MessageChannel, userid: Union[int, str]):
"""
清理系统缓存
@ -22,6 +31,131 @@ class SystemChain(ChainBase):
"""
重启系统
"""
if channel and userid:
self.post_message(Notification(channel=channel,
title=f"系统正在重启,请耐心等候!", userid=userid))
title="系统正在重启,请耐心等候!", userid=userid))
# 保存重启信息
self.save_cache({
"channel": channel.value,
"userid": userid
}, self._restart_file)
SystemUtils.restart()
def update(self, channel: MessageChannel = None, userid: Union[int, str] = None):
"""
重启系统
"""
if SystemUtils.is_windows():
logger.error("windows暂不支持")
return
if channel and userid:
self.post_message(Notification(channel=channel,
title="系统正在更新,请耐心等候!", userid=userid))
# 保存重启信息
self.save_cache({
"channel": channel.value,
"userid": userid
}, self._update_file)
# 重启系统
os.system("bash /usr/local/bin/mp_update")
if channel and userid:
self.post_message(Notification(channel=channel,
title="暂无新版本!", userid=userid))
self.remove_cache(self._update_file)
def version(self, channel: MessageChannel, userid: Union[int, str]):
"""
查看当前版本远程版本
"""
release_version = self.__get_release_version()
local_version = self.get_local_version()
if release_version == local_version:
title = f"当前版本:{local_version},已是最新版本"
else:
title = f"当前版本:{local_version},远程版本:{release_version}"
self.post_message(Notification(channel=channel,
title=title, userid=userid))
def restart_finish(self):
"""
如通过交互命令重启
重启完发送msg
"""
cache_file, action, channel, userid = None, None, None, None
# 重启消息
restart_channel = self.load_cache(self._restart_file)
if restart_channel:
cache_file = self._restart_file
action = "重启"
# 发送重启完成msg
if not isinstance(restart_channel, dict):
restart_channel = json.loads(restart_channel)
channel = next(
(channel for channel in MessageChannel.__members__.values() if
channel.value == restart_channel.get('channel')), None)
userid = restart_channel.get('userid')
# 更新消息
update_channel = self.load_cache(self._update_file)
if update_channel:
cache_file = self._update_file
action = "更新"
# 发送重启完成msg
if not isinstance(update_channel, dict):
update_channel = json.loads(update_channel)
channel = next(
(channel for channel in MessageChannel.__members__.values() if
channel.value == update_channel.get('channel')), None)
userid = update_channel.get('userid')
# 发送消息
if channel and userid:
# 版本号
release_version = self.__get_release_version()
local_version = self.get_local_version()
if release_version == local_version:
title = f"当前版本:{local_version}"
else:
title = f"当前版本:{local_version},远程版本:{release_version}"
self.post_message(Notification(channel=channel,
title=f"系统已{action}完成!{title}",
userid=userid))
self.remove_cache(cache_file)
@staticmethod
def __get_release_version():
"""
获取最新版本
"""
version_res = RequestUtils(proxies=settings.PROXY).get_res(
"https://api.github.com/repos/jxxghp/MoviePilot/releases/latest")
if version_res:
ver_json = version_res.json()
version = f"{ver_json['tag_name']}"
return version
else:
return None
@staticmethod
def get_local_version():
"""
查看当前版本
"""
version_file = settings.ROOT_PATH / "version.py"
if version_file.exists():
try:
with open(version_file, 'rb') as f:
version = f.read()
pattern = r"v(\d+\.\d+\.\d+)"
match = re.search(pattern, str(version))
if match:
version = match.group(1)
return f"v{version}"
else:
logger.warn("未找到版本号")
return None
except Exception as err:
logger.error(f"加载版本文件 {version_file} 出错:{err}")

View File

@ -142,6 +142,18 @@ class Command(metaclass=Singleton):
"description": "重启系统",
"category": "管理",
"data": {}
},
"/version": {
"func": SystemChain(self._db).version,
"description": "当前版本",
"category": "管理",
"data": {}
},
"/update": {
"func": SystemChain(self._db).update,
"description": "更新系统",
"category": "管理",
"data": {}
}
}
# 汇总插件命令
@ -163,6 +175,8 @@ class Command(metaclass=Singleton):
self._thread = Thread(target=self.__run)
# 启动事件处理线程
self._thread.start()
# 重启msg
SystemChain(self._db).restart_finish()
def __run(self):
"""

View File

@ -211,7 +211,7 @@ class QbittorrentModule(_ModuleBase):
:param hashs: 种子Hash
:return: bool
"""
return self.qbittorrent.start_torrents(ids=hashs)
return self.qbittorrent.stop_torrents(ids=hashs)
def torrent_files(self, tid: str) -> Optional[TorrentFilesList]:
"""

View File

@ -404,6 +404,7 @@ class DirMonitor(_PluginBase):
)
if self._notify:
self.chain.post_message(Notification(
mtype=NotificationType.Manual,
title=f"{mediainfo.title_year}{file_meta.season_episode} 入库失败!",
text=f"原因:{transferinfo.message or '未知'}",
image=mediainfo.get_message_image()

View File

@ -30,7 +30,7 @@ class InvitesSignin(_PluginBase):
# 作者主页
author_url = "https://github.com/thsrite"
# 插件配置项ID前缀
plugin_config_prefix = "invitessignin"
plugin_config_prefix = "invitessignin_"
# 加载顺序
plugin_order = 24
# 可使用的用户级别

View File

@ -969,6 +969,13 @@ class MediaSyncDel(_PluginBase):
self.chain.stop_torrents(torrent_hash)
handle_cnt += 1
logger.info(f"暂停转种后下载任务:{download} - {download_id}")
# 删除转种后下载任务
if download == "transmission":
self.tr.stop_torrents(ids=download_id)
else:
self.qb.stop_torrents(ids=download_id)
handle_cnt += 1
else:
# 未转种de情况
if delete_flag:

View File

@ -0,0 +1,234 @@
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from app.chain.system import SystemChain
from app.core.config import settings
from app.plugins import _PluginBase
from typing import Any, List, Dict, Tuple, Optional
from app.log import logger
from app.schemas import NotificationType
from app.utils.http import RequestUtils
class MoviePilotUpdateNotify(_PluginBase):
# 插件名称
plugin_name = "MoviePilot更新推送"
# 插件描述
plugin_desc = "MoviePilot推送release更新通知、自动更新。"
# 插件图标
plugin_icon = "update.png"
# 主题色
plugin_color = "#4179F4"
# 插件版本
plugin_version = "1.0"
# 插件作者
plugin_author = "thsrite"
# 作者主页
author_url = "https://github.com/thsrite"
# 插件配置项ID前缀
plugin_config_prefix = "moviepilotupdatenotify_"
# 加载顺序
plugin_order = 25
# 可使用的用户级别
auth_level = 1
# 私有属性
_enabled = False
# 任务执行间隔
_cron = None
_update = False
_notify = False
# 定时器
_scheduler: Optional[BackgroundScheduler] = None
def init_plugin(self, config: dict = None):
# 停止现有任务
self.stop_service()
if config:
self._enabled = config.get("enabled")
self._cron = config.get("cron")
self._update = config.get("update")
self._notify = config.get("notify")
# 加载模块
if self._enabled:
# 定时服务
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
if self._cron:
try:
self._scheduler.add_job(func=self.__check_update,
trigger=CronTrigger.from_crontab(self._cron),
name="检查MoviePilot更新")
except Exception as err:
logger.error(f"定时任务配置错误:{err}")
# 启动任务
if self._scheduler.get_jobs():
self._scheduler.print_jobs()
self._scheduler.start()
def __check_update(self):
"""
检查MoviePilot更新
"""
release_version, description, update_time = self.__get_release_version()
if not release_version:
logger.error("最新版本获取失败,停止运行")
return
# 本地版本
local_version = SystemChain(self.db).get_local_version()
if release_version == local_version:
logger.info(f"当前版本:{local_version} 远程版本:{release_version} 停止运行")
return
# 推送更新消息
if self._notify:
self.post_message(
mtype=NotificationType.SiteMessage,
title="【MoviePilot更新通知】",
text=f"{release_version} \n"
f"\n"
f"{description} \n"
f"{update_time}")
# 自动更新
if self._update:
logger.info("开始执行自动更新…")
SystemChain(self.db).update()
@staticmethod
def __get_release_version():
"""
获取最新版本
"""
version_res = RequestUtils(proxies=settings.PROXY).get_res(
"https://api.github.com/repos/jxxghp/MoviePilot/releases/latest")
if version_res:
ver_json = version_res.json()
version = f"{ver_json['tag_name']}"
description = f"{ver_json['body']}"
update_time = f"{ver_json['published_at']}"
return version, description, update_time
else:
return None, None, None
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': 4
},
'content': [
{
'component': 'VSwitch',
'props': {
'model': 'enabled',
'label': '启用插件',
}
}
]
},
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 4
},
'content': [
{
'component': 'VSwitch',
'props': {
'model': 'update',
'label': '自动更新',
}
}
]
},
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 4
},
'content': [
{
'component': 'VSwitch',
'props': {
'model': 'notify',
'label': '发送通知',
}
}
]
}
]
},
{
'component': 'VRow',
'content': [
{
'component': 'VCol',
'props': {
'cols': 12,
},
'content': [
{
'component': 'VTextField',
'props': {
'model': 'cron',
'label': '检查周期',
'placeholder': '5位cron表达式'
}
}
]
},
]
}
]
}
], {
"enabled": False,
"update": False,
"notify": False,
"cron": "0 9 * * *"
}
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))