diff --git a/app/api/endpoints/history.py b/app/api/endpoints/history.py index e102ade9..29a399b5 100644 --- a/app/api/endpoints/history.py +++ b/app/api/endpoints/history.py @@ -1,4 +1,3 @@ -import json from typing import List, Any from fastapi import APIRouter, Depends diff --git a/app/api/endpoints/login.py b/app/api/endpoints/login.py index 6d59e227..7d88f8fd 100644 --- a/app/api/endpoints/login.py +++ b/app/api/endpoints/login.py @@ -1,4 +1,3 @@ -import json from datetime import timedelta from typing import Any, List diff --git a/app/api/endpoints/message.py b/app/api/endpoints/message.py index 48121d3f..7af814d7 100644 --- a/app/api/endpoints/message.py +++ b/app/api/endpoints/message.py @@ -14,7 +14,7 @@ from app.db import get_db from app.db.models import User from app.db.models.message import Message from app.db.user_oper import get_current_active_superuser -from app.helper.serviceconfig import ServiceConfigHelper +from app.helper.service import ServiceConfigHelper from app.log import logger from app.modules.wechat.WXBizMsgCrypt3 import WXBizMsgCrypt from app.schemas.types import MessageChannel diff --git a/app/api/endpoints/transfer.py b/app/api/endpoints/transfer.py index f33c13fd..1530ebe9 100644 --- a/app/api/endpoints/transfer.py +++ b/app/api/endpoints/transfer.py @@ -1,4 +1,3 @@ -import json from pathlib import Path from typing import Any, Optional diff --git a/app/api/endpoints/webhook.py b/app/api/endpoints/webhook.py index a4299416..88856732 100644 --- a/app/api/endpoints/webhook.py +++ b/app/api/endpoints/webhook.py @@ -22,7 +22,7 @@ async def webhook_message(background_tasks: BackgroundTasks, _: str = Depends(verify_apitoken) ) -> Any: """ - Webhook响应,配置请求中需要添加参数:token=API_TOKEN&source=消息配置名 + Webhook响应,配置请求中需要添加参数:token=API_TOKEN&source=媒体服务器名 """ body = await request.body() form = await request.form() @@ -35,7 +35,7 @@ async def webhook_message(background_tasks: BackgroundTasks, def webhook_message(background_tasks: BackgroundTasks, request: Request, _: str = Depends(verify_apitoken)) -> Any: """ - Webhook响应,配置请求中需要添加参数:token=API_TOKEN&source=消息配置名 + Webhook响应,配置请求中需要添加参数:token=API_TOKEN&source=媒体服务器名 """ args = request.query_params background_tasks.add_task(start_webhook_chain, None, None, args) diff --git a/app/chain/__init__.py b/app/chain/__init__.py index 038d10b0..7c38a3c6 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -17,7 +17,7 @@ from app.core.module import ModuleManager from app.db.message_oper import MessageOper from app.db.user_oper import UserOper from app.helper.message import MessageHelper -from app.helper.serviceconfig import ServiceConfigHelper +from app.helper.service import ServiceConfigHelper from app.log import logger from app.schemas import TransferInfo, TransferTorrent, ExistMediaInfo, DownloadingTorrent, CommingMessage, Notification, \ WebhookEventInfo, TmdbEpisode, MediaPerson, FileItem @@ -101,7 +101,7 @@ class ChainBase(metaclass=ABCMeta): try: module_name = module.get_name() except Exception as err: - logger.error(f"获取模块名称出错:{str(err)}") + logger.debug(f"获取模块名称出错:{str(err)}") module_name = module_id try: func = getattr(module, method) diff --git a/app/chain/mediaserver.py b/app/chain/mediaserver.py index ebc4dd21..d4d549e2 100644 --- a/app/chain/mediaserver.py +++ b/app/chain/mediaserver.py @@ -1,11 +1,10 @@ -import json import threading from typing import List, Union, Optional, Generator from app import schemas from app.chain import ChainBase from app.db.mediaserver_oper import MediaServerOper -from app.helper.serviceconfig import ServiceConfigHelper +from app.helper.service import ServiceConfigHelper from app.log import logger lock = threading.Lock() diff --git a/app/chain/message.py b/app/chain/message.py index d0f63630..c072cad0 100644 --- a/app/chain/message.py +++ b/app/chain/message.py @@ -1,5 +1,4 @@ import copy -import json import re from typing import Any, Optional, Dict, Union diff --git a/app/chain/tmdb.py b/app/chain/tmdb.py index 13c05b1e..d57c7cf3 100644 --- a/app/chain/tmdb.py +++ b/app/chain/tmdb.py @@ -127,11 +127,11 @@ class TmdbChain(ChainBase, metaclass=Singleton): return None @cached(cache=TTLCache(maxsize=1, ttl=3600)) - def get_trending_wallpapers(self, num: int = 10) -> Optional[List[str]]: + def get_trending_wallpapers(self, num: int = 10) -> List[str]: """ 获取所有流行壁纸 """ infos = self.tmdb_trending() if infos: return [info.backdrop_path for info in infos if info and info.backdrop_path][:num] - return None + return [] diff --git a/app/core/module.py b/app/core/module.py index e16a6b33..ea3cd949 100644 --- a/app/core/module.py +++ b/app/core/module.py @@ -5,7 +5,7 @@ from app.core.config import settings from app.core.event import eventmanager from app.helper.module import ModuleHelper from app.log import logger -from app.schemas.types import EventType +from app.schemas.types import EventType, ModuleType from app.utils.object import ObjectUtils from app.utils.singleton import Singleton @@ -124,6 +124,17 @@ class ModuleManager(metaclass=Singleton): and ObjectUtils.check_method(getattr(module, method)): yield module + def get_running_type_modules(self, module_type: ModuleType) -> Generator: + """ + 获取指定类型的模块列表 + """ + if not self._running_modules: + return [] + for _, module in self._running_modules.items(): + if hasattr(module, 'get_type') \ + and module.get_type() == module_type: + yield module + def get_module(self, module_id: str) -> Any: """ 根据模块id获取模块 diff --git a/app/db/mediaserver_oper.py b/app/db/mediaserver_oper.py index 024d137e..47da9c58 100644 --- a/app/db/mediaserver_oper.py +++ b/app/db/mediaserver_oper.py @@ -1,4 +1,3 @@ -import json from typing import Optional from sqlalchemy.orm import Session diff --git a/app/db/plugindata_oper.py b/app/db/plugindata_oper.py index 18bae943..8a0fcdf3 100644 --- a/app/db/plugindata_oper.py +++ b/app/db/plugindata_oper.py @@ -1,9 +1,7 @@ -import json from typing import Any from app.db import DbOper from app.db.models.plugindata import PluginData -from app.utils.object import ObjectUtils class PluginDataOper(DbOper): diff --git a/app/db/site_oper.py b/app/db/site_oper.py index 754f5fe1..8a83acdd 100644 --- a/app/db/site_oper.py +++ b/app/db/site_oper.py @@ -1,4 +1,3 @@ -import json from datetime import datetime from typing import Tuple, List diff --git a/app/db/systemconfig_oper.py b/app/db/systemconfig_oper.py index 73324d13..9eaf05d1 100644 --- a/app/db/systemconfig_oper.py +++ b/app/db/systemconfig_oper.py @@ -1,10 +1,8 @@ -import json from typing import Any, Union from app.db import DbOper from app.db.models.systemconfig import SystemConfig from app.schemas.types import SystemConfigKey -from app.utils.object import ObjectUtils from app.utils.singleton import Singleton diff --git a/app/db/transferhistory_oper.py b/app/db/transferhistory_oper.py index 96083248..88b02fb2 100644 --- a/app/db/transferhistory_oper.py +++ b/app/db/transferhistory_oper.py @@ -1,4 +1,3 @@ -import json import time from typing import Any, List diff --git a/app/db/user_oper.py b/app/db/user_oper.py index c1a4c1d6..8037aa9a 100644 --- a/app/db/user_oper.py +++ b/app/db/user_oper.py @@ -1,4 +1,3 @@ -import json from typing import Optional from fastapi import Depends, HTTPException diff --git a/app/db/userconfig_oper.py b/app/db/userconfig_oper.py index fcd747ea..b263f71c 100644 --- a/app/db/userconfig_oper.py +++ b/app/db/userconfig_oper.py @@ -1,10 +1,8 @@ -import json from typing import Any, Union, Dict, Optional from app.db import DbOper from app.db.models.userconfig import UserConfig from app.schemas.types import UserConfigKey -from app.utils.object import ObjectUtils from app.utils.singleton import Singleton diff --git a/app/helper/downloader.py b/app/helper/downloader.py index 56fe7751..e0e449ba 100644 --- a/app/helper/downloader.py +++ b/app/helper/downloader.py @@ -1,8 +1,8 @@ from typing import Optional -from app.helper.servicebase import ServiceBaseHelper +from app.helper.service import ServiceBaseHelper from app.schemas import DownloaderConf, ServiceInfo -from app.schemas.types import SystemConfigKey +from app.schemas.types import SystemConfigKey, ModuleType class DownloaderHelper(ServiceBaseHelper[DownloaderConf]): @@ -14,29 +14,24 @@ class DownloaderHelper(ServiceBaseHelper[DownloaderConf]): super().__init__( config_key=SystemConfigKey.Downloaders, conf_type=DownloaderConf, - modules=["QbittorrentModule", "TransmissionModule"] + module_type=ModuleType.Downloader ) - def is_qbittorrent(self, service: Optional[ServiceInfo] = None, name: Optional[str] = None) -> bool: + def is_downloader( + self, + service_type: Optional[str] = None, + service: Optional[ServiceInfo] = None, + name: Optional[str] = None, + ) -> bool: """ - 判断指定的下载器是否为 qbittorrent 类型,需要传入 `service` 或 `name` 中的任一参数 - + 通用的下载器类型判断方法 + :param service_type: 下载器的类型名称(如 'qbittorrent', 'transmission') :param service: 要判断的服务信息 :param name: 服务的名称 - :return: 如果服务类型为 qbittorrent,返回 True;否则返回 False。 + :return: 如果服务类型或实例为指定类型,返回 True;否则返回 False """ - if not service: - service = self.get_service(name=name) - return service.type == "qbittorrent" if service else False + # 如果未提供 service 则通过 name 获取服务 + service = service or self.get_service(name=name) - def is_transmission(self, service: Optional[ServiceInfo] = None, name: Optional[str] = None) -> bool: - """ - 判断指定的下载器是否为 transmission 类型,需要传入 `service` 或 `name` 中的任一参数 - - :param service: 要判断的服务信息 - :param name: 服务的名称 - :return: 如果服务类型为 transmission,返回 True;否则返回 False。 - """ - if not service: - service = self.get_service(name=name) - return service.type == "transmission" if service else False + # 判断服务类型是否为指定类型 + return bool(service and service.type == service_type) diff --git a/app/helper/mediaserver.py b/app/helper/mediaserver.py index f1178282..ffeb97be 100644 --- a/app/helper/mediaserver.py +++ b/app/helper/mediaserver.py @@ -1,8 +1,8 @@ from typing import Optional -from app.helper.servicebase import ServiceBaseHelper +from app.helper.service import ServiceBaseHelper from app.schemas import MediaServerConf, ServiceInfo -from app.schemas.types import SystemConfigKey +from app.schemas.types import SystemConfigKey, ModuleType class MediaServerHelper(ServiceBaseHelper[MediaServerConf]): @@ -14,41 +14,24 @@ class MediaServerHelper(ServiceBaseHelper[MediaServerConf]): super().__init__( config_key=SystemConfigKey.MediaServers, conf_type=MediaServerConf, - modules=["PlexModule", "EmbyModule", "JellyfinModule"] + module_type=ModuleType.MediaServer ) - def is_plex(self, service: Optional[ServiceInfo] = None, name: Optional[str] = None) -> bool: + def is_media_server( + self, + service_type: Optional[str] = None, + service: Optional[ServiceInfo] = None, + name: Optional[str] = None, + ) -> bool: """ - 判断指定的媒体服务器是否为 Plex 类型,需要传入 `service` 或 `name` 中的任一参数 - + 通用的媒体服务器类型判断方法 + :param service_type: 媒体服务器的类型名称(如 'plex', 'emby', 'jellyfin') :param service: 要判断的服务信息 :param name: 服务的名称 - :return: 如果服务类型为 plex,返回 True;否则返回 False。 + :return: 如果服务类型或实例为指定类型,返回 True;否则返回 False """ - if not service: - service = self.get_service(name=name) - return service.type == "plex" if service else False + # 如果未提供 service 则通过 name 获取服务 + service = service or self.get_service(name=name) - def is_emby(self, service: Optional[ServiceInfo] = None, name: Optional[str] = None) -> bool: - """ - 判断指定的媒体服务器是否为 Emby 类型,需要传入 `service` 或 `name` 中的任一参数 - - :param service: 要判断的服务信息 - :param name: 服务的名称 - :return: 如果服务类型为 emby,返回 True;否则返回 False。 - """ - if not service: - service = self.get_service(name=name) - return service.type == "emby" if service else False - - def is_jellyfin(self, service: Optional[ServiceInfo] = None, name: Optional[str] = None) -> bool: - """ - 判断指定的媒体服务器是否为 Jellyfin 类型,需要传入 `service` 或 `name` 中的任一参数 - - :param service: 要判断的服务信息 - :param name: 服务的名称 - :return: 如果服务类型为 jellyfin,返回 True;否则返回 False。 - """ - if not service: - service = self.get_service(name=name) - return service.type == "jellyfin" if service else False + # 判断服务类型是否为指定类型 + return bool(service and service.type == service_type) diff --git a/app/helper/notification.py b/app/helper/notification.py index f0cd70f0..86ccb105 100644 --- a/app/helper/notification.py +++ b/app/helper/notification.py @@ -1,8 +1,8 @@ from typing import Optional -from app.helper.servicebase import ServiceBaseHelper +from app.helper.service import ServiceBaseHelper from app.schemas import NotificationConf, ServiceInfo -from app.schemas.types import SystemConfigKey +from app.schemas.types import SystemConfigKey, ModuleType class NotificationHelper(ServiceBaseHelper[NotificationConf]): @@ -14,84 +14,25 @@ class NotificationHelper(ServiceBaseHelper[NotificationConf]): super().__init__( config_key=SystemConfigKey.Notifications, conf_type=NotificationConf, - modules=[ - "WechatModule", - "WebPushModule", - "VoceChatModule", - "TelegramModule", - "SynologyChatModule", - "SlackModule" - ] + module_type=ModuleType.Notification ) - def is_wechat(self, service: Optional[ServiceInfo] = None, name: Optional[str] = None) -> bool: + def is_notification( + self, + service_type: Optional[str] = None, + service: Optional[ServiceInfo] = None, + name: Optional[str] = None, + ) -> bool: """ - 判断指定的消息通知服务是否为 Wechat 类型,需要传入 `service` 或 `name` 中的任一参数 + 通用的消息通知服务类型判断方法 + :param service_type: 消息通知服务的类型名称(如 'wechat', 'voicechat', 'telegram', 等) :param service: 要判断的服务信息 :param name: 服务的名称 - :return: 如果服务类型为 wechat,返回 True;否则返回 False。 + :return: 如果服务类型或实例为指定类型,返回 True;否则返回 False """ - if not service: - service = self.get_service(name=name) - return service.type == "wechat" if service else False + # 如果未提供 service 则通过 name 获取服务 + service = service or self.get_service(name=name) - def is_webpush(self, service: Optional[ServiceInfo] = None, name: Optional[str] = None) -> bool: - """ - 判断指定的消息通知服务是否为 WebPush 类型,需要传入 `service` 或 `name` 中的任一参数 - - :param service: 要判断的服务信息 - :param name: 服务的名称 - :return: 如果服务类型为 webpush,返回 True;否则返回 False。 - """ - if not service: - service = self.get_service(name=name) - return service.type == "webpush" if service else False - - def is_voicechat(self, service: Optional[ServiceInfo] = None, name: Optional[str] = None) -> bool: - """ - 判断指定的消息通知服务是否为 VoiceChat 类型,需要传入 `service` 或 `name` 中的任一参数 - - :param service: 要判断的服务信息 - :param name: 服务的名称 - :return: 如果服务类型为 voicechat,返回 True;否则返回 False。 - """ - if not service: - service = self.get_service(name=name) - return service.type == "voicechat" if service else False - - def is_telegram(self, service: Optional[ServiceInfo] = None, name: Optional[str] = None) -> bool: - """ - 判断指定的消息通知服务是否为 Telegram 类型,需要传入 `service` 或 `name` 中的任一参数 - - :param service: 要判断的服务信息 - :param name: 服务的名称 - :return: 如果服务类型为 telegram,返回 True;否则返回 False。 - """ - if not service: - service = self.get_service(name=name) - return service.type == "telegram" if service else False - - def is_synologychat(self, service: Optional[ServiceInfo] = None, name: Optional[str] = None) -> bool: - """ - 判断指定的消息通知服务是否为 SynologyChat 类型,需要传入 `service` 或 `name` 中的任一参数 - - :param service: 要判断的服务信息 - :param name: 服务的名称 - :return: 如果服务类型为 synologychat,返回 True;否则返回 False。 - """ - if not service: - service = self.get_service(name=name) - return service.type == "synologychat" if service else False - - def is_slack(self, service: Optional[ServiceInfo] = None, name: Optional[str] = None) -> bool: - """ - 判断指定的消息通知服务是否为 Slack 类型,需要传入 `service` 或 `name` 中的任一参数 - - :param service: 要判断的服务信息 - :param name: 服务的名称 - :return: 如果服务类型为 slack,返回 True;否则返回 False。 - """ - if not service: - service = self.get_service(name=name) - return service.type == "slack" if service else False + # 判断服务类型是否为指定类型 + return bool(service and service.type == service_type) diff --git a/app/helper/servicebase.py b/app/helper/service.py similarity index 55% rename from app/helper/servicebase.py rename to app/helper/service.py index 40b65dc1..57a1b357 100644 --- a/app/helper/servicebase.py +++ b/app/helper/service.py @@ -1,23 +1,83 @@ from typing import Dict, List, Optional, Type, TypeVar, Generic, Iterator from app.core.module import ModuleManager -from app.helper.serviceconfig import ServiceConfigHelper -from app.schemas import ServiceInfo -from app.schemas.types import SystemConfigKey +from app.db.systemconfig_oper import SystemConfigOper +from app.schemas import DownloaderConf, MediaServerConf, NotificationConf, NotificationSwitchConf, ServiceInfo +from app.schemas.types import NotificationType, SystemConfigKey, ModuleType TConf = TypeVar("TConf") +class ServiceConfigHelper: + """ + 配置帮助类,获取不同类型的服务配置 + """ + + @staticmethod + def get_configs(config_key: SystemConfigKey, conf_type: Type) -> List: + """ + 通用获取配置的方法,根据 config_key 获取相应的配置并返回指定类型的配置列表 + + :param config_key: 系统配置的 key + :param conf_type: 用于实例化配置对象的类类型 + :return: 配置对象列表 + """ + config_data = SystemConfigOper().get(config_key) + if not config_data: + return [] + # 直接使用 conf_type 来实例化配置对象 + return [conf_type(**conf) for conf in config_data] + + @staticmethod + def get_downloader_configs() -> List[DownloaderConf]: + """ + 获取下载器的配置 + """ + return ServiceConfigHelper.get_configs(SystemConfigKey.Downloaders, DownloaderConf) + + @staticmethod + def get_mediaserver_configs() -> List[MediaServerConf]: + """ + 获取媒体服务器的配置 + """ + return ServiceConfigHelper.get_configs(SystemConfigKey.MediaServers, MediaServerConf) + + @staticmethod + def get_notification_configs() -> List[NotificationConf]: + """ + 获取消息通知渠道的配置 + """ + return ServiceConfigHelper.get_configs(SystemConfigKey.Notifications, NotificationConf) + + @staticmethod + def get_notification_switches() -> List[NotificationSwitchConf]: + """ + 获取消息通知场景的开关 + """ + return ServiceConfigHelper.get_configs(SystemConfigKey.NotificationSwitchs, NotificationSwitchConf) + + @staticmethod + def get_notification_switch(mtype: NotificationType) -> Optional[str]: + """ + 获取指定类型的消息通知场景的开关 + """ + switchs = ServiceConfigHelper.get_notification_switches() + for switch in switchs: + if switch.type == mtype.value: + return switch.action + return None + + class ServiceBaseHelper(Generic[TConf]): """ 通用服务帮助类,抽象获取配置和服务实例的通用逻辑 """ - def __init__(self, config_key: SystemConfigKey, conf_type: Type[TConf], modules: List[str]): + def __init__(self, config_key: SystemConfigKey, conf_type: Type[TConf], module_type: ModuleType): self.modulemanager = ModuleManager() self.config_key = config_key self.conf_type = conf_type - self.modules = modules + self.module_type = module_type def get_configs(self, include_disabled: bool = False) -> Dict[str, TConf]: """ @@ -47,8 +107,8 @@ class ServiceBaseHelper(Generic[TConf]): 迭代所有模块的实例及其对应的配置,返回 ServiceInfo 实例 """ configs = self.get_configs() - for module_name in self.modules: - module = self.modulemanager.get_running_module(module_name) + modules = self.modulemanager.get_running_type_modules(self.module_type) + for module in modules: if not module: continue module_instances = module.get_instances() @@ -81,9 +141,10 @@ class ServiceBaseHelper(Generic[TConf]): return { service_info.name: service_info for service_info in self.iterate_module_instances() - if service_info.config and - (type_filter is None or service_info.type == type_filter) and - (name_filters_set is None or service_info.name in name_filters_set) + if service_info.config and ( + type_filter is None or service_info.type == type_filter + ) and ( + name_filters_set is None or service_info.name in name_filters_set) } def get_service(self, name: str, type_filter: Optional[str] = None) -> Optional[ServiceInfo]: diff --git a/app/helper/serviceconfig.py b/app/helper/serviceconfig.py deleted file mode 100644 index 6822d22e..00000000 --- a/app/helper/serviceconfig.py +++ /dev/null @@ -1,65 +0,0 @@ -from typing import List, Type, Optional - -from app.db.systemconfig_oper import SystemConfigOper -from app.schemas import DownloaderConf, MediaServerConf, NotificationConf, NotificationSwitchConf -from app.schemas.types import SystemConfigKey, NotificationType - - -class ServiceConfigHelper: - """ - 配置帮助类,获取不同类型的服务配置 - """ - - @staticmethod - def get_configs(config_key: SystemConfigKey, conf_type: Type) -> List: - """ - 通用获取配置的方法,根据 config_key 获取相应的配置并返回指定类型的配置列表 - - :param config_key: 系统配置的 key - :param conf_type: 用于实例化配置对象的类类型 - :return: 配置对象列表 - """ - config_data = SystemConfigOper().get(config_key) - if not config_data: - return [] - # 直接使用 conf_type 来实例化配置对象 - return [conf_type(**conf) for conf in config_data] - - @staticmethod - def get_downloader_configs() -> List[DownloaderConf]: - """ - 获取下载器的配置 - """ - return ServiceConfigHelper.get_configs(SystemConfigKey.Downloaders, DownloaderConf) - - @staticmethod - def get_mediaserver_configs() -> List[MediaServerConf]: - """ - 获取媒体服务器的配置 - """ - return ServiceConfigHelper.get_configs(SystemConfigKey.MediaServers, MediaServerConf) - - @staticmethod - def get_notification_configs() -> List[NotificationConf]: - """ - 获取消息通知渠道的配置 - """ - return ServiceConfigHelper.get_configs(SystemConfigKey.Notifications, NotificationConf) - - @staticmethod - def get_notification_switches() -> List[NotificationSwitchConf]: - """ - 获取消息通知场景的开关 - """ - return ServiceConfigHelper.get_configs(SystemConfigKey.NotificationSwitchs, NotificationSwitchConf) - - @staticmethod - def get_notification_switch(mtype: NotificationType) -> Optional[str]: - """ - 获取指定类型的消息通知场景的开关 - """ - switchs = ServiceConfigHelper.get_notification_switches() - for switch in switchs: - if switch.type == mtype.value: - return switch.action - return None diff --git a/app/modules/__init__.py b/app/modules/__init__.py index 13bfe58f..967fc529 100644 --- a/app/modules/__init__.py +++ b/app/modules/__init__.py @@ -1,8 +1,9 @@ from abc import abstractmethod, ABCMeta from typing import Generic, Tuple, Union, TypeVar, Type, Dict, Optional, Callable, Any -from app.helper.serviceconfig import ServiceConfigHelper +from app.helper.service import ServiceConfigHelper from app.schemas import Notification, MessageChannel, NotificationConf, MediaServerConf, DownloaderConf +from app.schemas.types import ModuleType class _ModuleBase(metaclass=ABCMeta): @@ -34,6 +35,14 @@ class _ModuleBase(metaclass=ABCMeta): """ pass + @staticmethod + @abstractmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + pass + @abstractmethod def stop(self) -> None: """ diff --git a/app/modules/bangumi/__init__.py b/app/modules/bangumi/__init__.py index ddd3cd51..7052ee2e 100644 --- a/app/modules/bangumi/__init__.py +++ b/app/modules/bangumi/__init__.py @@ -7,6 +7,7 @@ from app.core.meta import MetaBase from app.log import logger from app.modules import _ModuleBase from app.modules.bangumi.bangumi import BangumiApi +from app.schemas.types import ModuleType from app.utils.http import RequestUtils @@ -37,6 +38,13 @@ class BangumiModule(_ModuleBase): def get_name() -> str: return "Bangumi" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.MediaRecognize + def recognize_media(self, bangumiid: int = None, **kwargs) -> Optional[MediaInfo]: """ diff --git a/app/modules/douban/__init__.py b/app/modules/douban/__init__.py index 12a09e35..a6810f4c 100644 --- a/app/modules/douban/__init__.py +++ b/app/modules/douban/__init__.py @@ -14,7 +14,7 @@ from app.modules.douban.apiv2 import DoubanApi from app.modules.douban.douban_cache import DoubanCache from app.modules.douban.scraper import DoubanScraper from app.schemas import MediaPerson, APIRateLimitException -from app.schemas.types import MediaType +from app.schemas.types import MediaType, ModuleType from app.utils.common import retry from app.utils.http import RequestUtils from app.utils.limit import rate_limit_exponential @@ -51,6 +51,13 @@ class DoubanModule(_ModuleBase): def get_name() -> str: return "豆瓣" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.MediaRecognize + def recognize_media(self, meta: MetaBase = None, mtype: MediaType = None, doubanid: str = None, diff --git a/app/modules/emby/__init__.py b/app/modules/emby/__init__.py index c6cedabb..7d237f1c 100644 --- a/app/modules/emby/__init__.py +++ b/app/modules/emby/__init__.py @@ -5,7 +5,6 @@ from app.core.context import MediaInfo from app.log import logger from app.modules import _ModuleBase, _MediaServerBase from app.modules.emby.emby import Emby -from app.schemas import MediaServerConf from app.schemas.types import MediaType @@ -22,6 +21,10 @@ class EmbyModule(_ModuleBase, _MediaServerBase[Emby]): def get_name() -> str: return "Emby" + @staticmethod + def get_type() -> str: + return "mediaserver" + def stop(self): pass @@ -78,7 +81,10 @@ class EmbyModule(_ModuleBase, _MediaServerBase[Emby]): server: Emby = self.get_instance(source) if not server: return None - return server.get_webhook_message(form, args) + result = server.get_webhook_message(form, args) + if result: + result.server_name = source + return result for server in self.get_instances().values(): if server: diff --git a/app/modules/fanart/__init__.py b/app/modules/fanart/__init__.py index 6ccb0993..7088c14c 100644 --- a/app/modules/fanart/__init__.py +++ b/app/modules/fanart/__init__.py @@ -6,7 +6,7 @@ from app.core.context import MediaInfo, settings from app.log import logger from app.modules import _ModuleBase from app.utils.http import RequestUtils -from app.schemas.types import MediaType +from app.schemas.types import MediaType, ModuleType class FanartModule(_ModuleBase): @@ -335,6 +335,13 @@ class FanartModule(_ModuleBase): def get_name() -> str: return "Fanart" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Other + def obtain_images(self, mediainfo: MediaInfo) -> Optional[MediaInfo]: """ 获取图片 diff --git a/app/modules/filemanager/__init__.py b/app/modules/filemanager/__init__.py index 3a271a06..67073f09 100644 --- a/app/modules/filemanager/__init__.py +++ b/app/modules/filemanager/__init__.py @@ -17,7 +17,7 @@ from app.log import logger from app.modules import _ModuleBase from app.modules.filemanager.storages import StorageBase from app.schemas import TransferInfo, ExistMediaInfo, TmdbEpisode, TransferDirectoryConf, FileItem, StorageUsage -from app.schemas.types import MediaType +from app.schemas.types import MediaType, ModuleType from app.utils.system import SystemUtils lock = Lock() @@ -44,6 +44,13 @@ class FileManagerModule(_ModuleBase): def get_name() -> str: return "文件整理" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Other + def stop(self): pass diff --git a/app/modules/filter/__init__.py b/app/modules/filter/__init__.py index b1767afd..51ea2d11 100644 --- a/app/modules/filter/__init__.py +++ b/app/modules/filter/__init__.py @@ -7,6 +7,7 @@ from app.helper.rule import RuleHelper from app.log import logger from app.modules import _ModuleBase from app.modules.filter.RuleParser import RuleParser +from app.schemas.types import ModuleType from app.utils.string import StringUtils @@ -159,6 +160,13 @@ class FilterModule(_ModuleBase): def get_name() -> str: return "过滤器" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Other + def stop(self): pass diff --git a/app/modules/indexer/__init__.py b/app/modules/indexer/__init__.py index ad548ca3..4f1b441d 100644 --- a/app/modules/indexer/__init__.py +++ b/app/modules/indexer/__init__.py @@ -18,7 +18,7 @@ from app.modules.indexer.spider.tnode import TNodeSpider from app.modules.indexer.spider.torrentleech import TorrentLeech from app.modules.indexer.spider.yema import YemaSpider from app.schemas import SiteUserData -from app.schemas.types import MediaType +from app.schemas.types import MediaType, ModuleType from app.utils.string import StringUtils @@ -40,6 +40,13 @@ class IndexerModule(_ModuleBase): def get_name() -> str: return "站点索引" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Indexer + def stop(self): pass diff --git a/app/modules/jellyfin/__init__.py b/app/modules/jellyfin/__init__.py index a0107123..e59e45d7 100644 --- a/app/modules/jellyfin/__init__.py +++ b/app/modules/jellyfin/__init__.py @@ -5,8 +5,7 @@ from app.core.context import MediaInfo from app.log import logger from app.modules import _ModuleBase, _MediaServerBase from app.modules.jellyfin.jellyfin import Jellyfin -from app.schemas import MediaServerConf -from app.schemas.types import MediaType +from app.schemas.types import MediaType, ModuleType class JellyfinModule(_ModuleBase, _MediaServerBase[Jellyfin]): @@ -22,6 +21,13 @@ class JellyfinModule(_ModuleBase, _MediaServerBase[Jellyfin]): def get_name() -> str: return "Jellyfin" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.MediaServer + def init_setting(self) -> Tuple[str, Union[str, bool]]: pass @@ -78,7 +84,10 @@ class JellyfinModule(_ModuleBase, _MediaServerBase[Jellyfin]): server: Jellyfin = self.get_instance(source) if not server: return None - return server.get_webhook_message(body) + result = server.get_webhook_message(body) + if result: + result.server_name = source + return result for server in self.get_instances().values(): if server: diff --git a/app/modules/plex/__init__.py b/app/modules/plex/__init__.py index 25a8dca9..381de1a2 100644 --- a/app/modules/plex/__init__.py +++ b/app/modules/plex/__init__.py @@ -5,8 +5,7 @@ from app.core.context import MediaInfo from app.log import logger from app.modules import _ModuleBase, _MediaServerBase from app.modules.plex.plex import Plex -from app.schemas import MediaServerConf -from app.schemas.types import MediaType +from app.schemas.types import MediaType, ModuleType class PlexModule(_ModuleBase, _MediaServerBase[Plex]): @@ -22,6 +21,13 @@ class PlexModule(_ModuleBase, _MediaServerBase[Plex]): def get_name() -> str: return "Plex" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.MediaServer + def stop(self): pass @@ -64,7 +70,10 @@ class PlexModule(_ModuleBase, _MediaServerBase[Plex]): server: Plex = self.get_instance(source) if not server: return None - return server.get_webhook_message(form) + result = server.get_webhook_message(form) + if result: + result.server_name = source + return result for server in self.get_instances().values(): if server: diff --git a/app/modules/qbittorrent/__init__.py b/app/modules/qbittorrent/__init__.py index a706ef6c..bccac263 100644 --- a/app/modules/qbittorrent/__init__.py +++ b/app/modules/qbittorrent/__init__.py @@ -12,7 +12,7 @@ from app.log import logger from app.modules import _ModuleBase, _DownloaderBase from app.modules.qbittorrent.qbittorrent import Qbittorrent from app.schemas import TransferTorrent, DownloadingTorrent -from app.schemas.types import TorrentStatus +from app.schemas.types import TorrentStatus, ModuleType from app.utils.string import StringUtils from app.utils.system import SystemUtils @@ -30,6 +30,13 @@ class QbittorrentModule(_ModuleBase, _DownloaderBase[Qbittorrent]): def get_name() -> str: return "Qbittorrent" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Downloader + def stop(self): pass diff --git a/app/modules/qbittorrent/qbittorrent.py b/app/modules/qbittorrent/qbittorrent.py index 3d544a07..33e2e87e 100644 --- a/app/modules/qbittorrent/qbittorrent.py +++ b/app/modules/qbittorrent/qbittorrent.py @@ -82,9 +82,9 @@ class Qbittorrent: logger.error(f"qbittorrent 连接出错:{str(err)}") return None - def get_torrents(self, ids: Union[str, list] = None, - status: Union[str, list] = None, - tags: Union[str, list] = None) -> Tuple[List[TorrentDictionary], bool]: + def get_torrents(self, ids: Optional[Union[str, list]] = None, + status: Optional[str] = None, + tags: Optional[Union[str, list]] = None) -> Tuple[List[TorrentDictionary], bool]: """ 获取种子列表 return: 种子列表, 是否发生异常 @@ -117,7 +117,7 @@ class Qbittorrent: if not self.qbc: return None # completed会包含移动状态 改为获取seeding状态 包含活动上传, 正在做种, 及强制做种 - torrents, error = self.get_torrents(status=["seeding"], ids=ids, tags=tags) + torrents, error = self.get_torrents(status="seeding", ids=ids, tags=tags) return None if error else torrents or [] def get_downloading_torrents(self, ids: Union[str, list] = None, @@ -129,7 +129,7 @@ class Qbittorrent: if not self.qbc: return None torrents, error = self.get_torrents(ids=ids, - status=["downloading"], + status="downloading", tags=tags) return None if error else torrents or [] @@ -195,7 +195,7 @@ class Qbittorrent: logger.error(f"设置强制作种出错:{str(err)}") def __get_last_add_torrentid_by_tag(self, tags: Union[str, list], - status: Union[str, list] = None) -> Optional[str]: + status: Optional[str] = None) -> Optional[str]: """ 根据种子的下载链接获取下载中或暂停的钟子的ID :return: 种子ID @@ -211,7 +211,7 @@ class Qbittorrent: return None def get_torrent_id_by_tag(self, tags: Union[str, list], - status: Union[str, list] = None) -> Optional[str]: + status: Optional[str] = None) -> Optional[str]: """ 通过标签多次尝试获取刚添加的种子ID,并移除标签 """ diff --git a/app/modules/slack/__init__.py b/app/modules/slack/__init__.py index 34476f85..ce84f828 100644 --- a/app/modules/slack/__init__.py +++ b/app/modules/slack/__init__.py @@ -2,12 +2,12 @@ import json import re from typing import Optional, Union, List, Tuple, Any -from app.core.config import settings from app.core.context import MediaInfo, Context from app.log import logger from app.modules import _ModuleBase, _MessageBase from app.modules.slack.slack import Slack from app.schemas import MessageChannel, CommingMessage, Notification +from app.schemas.types import ModuleType class SlackModule(_ModuleBase, _MessageBase[Slack]): @@ -23,6 +23,13 @@ class SlackModule(_ModuleBase, _MessageBase[Slack]): def get_name() -> str: return "Slack" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Notification + def stop(self): """ 停止模块 diff --git a/app/modules/subtitle/__init__.py b/app/modules/subtitle/__init__.py index 8964c07b..961f5cfa 100644 --- a/app/modules/subtitle/__init__.py +++ b/app/modules/subtitle/__init__.py @@ -10,6 +10,7 @@ from app.core.context import Context from app.helper.torrent import TorrentHelper from app.log import logger from app.modules import _ModuleBase +from app.schemas.types import ModuleType from app.utils.http import RequestUtils from app.utils.string import StringUtils from app.utils.system import SystemUtils @@ -32,6 +33,13 @@ class SubtitleModule(_ModuleBase): def get_name() -> str: return "站点字幕" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Other + def init_setting(self) -> Tuple[str, Union[str, bool]]: pass diff --git a/app/modules/synologychat/__init__.py b/app/modules/synologychat/__init__.py index ba58653b..868268a7 100644 --- a/app/modules/synologychat/__init__.py +++ b/app/modules/synologychat/__init__.py @@ -5,6 +5,7 @@ from app.log import logger from app.modules import _ModuleBase, _MessageBase from app.modules.synologychat.synologychat import SynologyChat from app.schemas import MessageChannel, CommingMessage, Notification +from app.schemas.types import ModuleType class SynologyChatModule(_ModuleBase, _MessageBase[SynologyChat]): @@ -20,6 +21,13 @@ class SynologyChatModule(_ModuleBase, _MessageBase[SynologyChat]): def get_name() -> str: return "Synology Chat" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Notification + def stop(self): pass diff --git a/app/modules/telegram/__init__.py b/app/modules/telegram/__init__.py index ad19647c..a46d76ef 100644 --- a/app/modules/telegram/__init__.py +++ b/app/modules/telegram/__init__.py @@ -1,12 +1,12 @@ import json from typing import Optional, Union, List, Tuple, Any, Dict -from app.core.config import settings from app.core.context import MediaInfo, Context from app.log import logger from app.modules import _ModuleBase, _MessageBase from app.modules.telegram.telegram import Telegram from app.schemas import MessageChannel, CommingMessage, Notification +from app.schemas.types import ModuleType class TelegramModule(_ModuleBase, _MessageBase[Telegram]): @@ -22,6 +22,13 @@ class TelegramModule(_ModuleBase, _MessageBase[Telegram]): def get_name() -> str: return "Telegram" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Notification + def stop(self): """ 停止模块 diff --git a/app/modules/themoviedb/__init__.py b/app/modules/themoviedb/__init__.py index a7a1d24d..4d497353 100644 --- a/app/modules/themoviedb/__init__.py +++ b/app/modules/themoviedb/__init__.py @@ -13,7 +13,7 @@ from app.modules.themoviedb.scraper import TmdbScraper from app.modules.themoviedb.tmdb_cache import TmdbCache from app.modules.themoviedb.tmdbapi import TmdbApi from app.schemas import MediaPerson -from app.schemas.types import MediaType, MediaImageType +from app.schemas.types import MediaType, MediaImageType, ModuleType from app.utils.http import RequestUtils @@ -41,6 +41,13 @@ class TheMovieDbModule(_ModuleBase): def get_name() -> str: return "TheMovieDb" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.MediaRecognize + def stop(self): self.cache.save() self.tmdb.close() diff --git a/app/modules/themoviedb/tmdbapi.py b/app/modules/themoviedb/tmdbapi.py index 1fe129d3..02cf1651 100644 --- a/app/modules/themoviedb/tmdbapi.py +++ b/app/modules/themoviedb/tmdbapi.py @@ -770,7 +770,7 @@ class TmdbApi: logger.debug(f"{tmdbid} 查询结果:{tmdbinfo.get('title')}") return tmdbinfo or {} except Exception as e: - print(str(e)) + logger.error(str(e)) return None def __get_tv_detail(self, @@ -953,7 +953,7 @@ class TmdbApi: logger.debug(f"{tmdbid} 查询结果:{tmdbinfo.get('name')}") return tmdbinfo or {} except Exception as e: - print(str(e)) + logger.error(str(e)) return None def get_tv_season_detail(self, tmdbid: int, season: int): @@ -1027,7 +1027,7 @@ class TmdbApi: tmdbinfo = self.season.details(tv_id=tmdbid, season_num=season) return tmdbinfo or {} except Exception as e: - print(str(e)) + logger.error(str(e)) return {} def get_tv_episode_detail(self, tmdbid: int, season: int, episode: int) -> dict: @@ -1044,7 +1044,7 @@ class TmdbApi: tmdbinfo = self.episode.details(tv_id=tmdbid, season_num=season, episode_num=episode) return tmdbinfo or {} except Exception as e: - print(str(e)) + logger.error(str(e)) return {} def discover_movies(self, **kwargs) -> List[dict]: @@ -1064,7 +1064,7 @@ class TmdbApi: info['media_type'] = MediaType.MOVIE return tmdbinfo or [] except Exception as e: - print(str(e)) + logger.error(str(e)) return [] def discover_tvs(self, **kwargs) -> List[dict]: @@ -1084,7 +1084,7 @@ class TmdbApi: info['media_type'] = MediaType.TV return tmdbinfo or [] except Exception as e: - print(str(e)) + logger.error(str(e)) return [] def discover_trending(self, page: int = 1) -> List[dict]: @@ -1097,7 +1097,7 @@ class TmdbApi: logger.debug(f"正在获取流行趋势:page={page} ...") return self.trending.all_week(page=page) except Exception as e: - print(str(e)) + logger.error(str(e)) return [] def get_movie_images(self, tmdbid: int) -> dict: @@ -1110,7 +1110,7 @@ class TmdbApi: logger.debug(f"正在获取电影图片:{tmdbid}...") return self.movie.images(movie_id=tmdbid) or {} except Exception as e: - print(str(e)) + logger.error(str(e)) return {} def get_tv_images(self, tmdbid: int) -> dict: @@ -1123,7 +1123,7 @@ class TmdbApi: logger.debug(f"正在获取电视剧图片:{tmdbid}...") return self.tv.images(tv_id=tmdbid) or {} except Exception as e: - print(str(e)) + logger.error(str(e)) return {} def get_movie_similar(self, tmdbid: int) -> List[dict]: @@ -1136,7 +1136,7 @@ class TmdbApi: logger.debug(f"正在获取相似电影:{tmdbid}...") return self.movie.similar(movie_id=tmdbid) or [] except Exception as e: - print(str(e)) + logger.error(str(e)) return [] def get_tv_similar(self, tmdbid: int) -> List[dict]: @@ -1149,7 +1149,7 @@ class TmdbApi: logger.debug(f"正在获取相似电视剧:{tmdbid}...") return self.tv.similar(tv_id=tmdbid) or [] except Exception as e: - print(str(e)) + logger.error(str(e)) return [] def get_movie_recommend(self, tmdbid: int) -> List[dict]: @@ -1162,7 +1162,7 @@ class TmdbApi: logger.debug(f"正在获取推荐电影:{tmdbid}...") return self.movie.recommendations(movie_id=tmdbid) or [] except Exception as e: - print(str(e)) + logger.error(str(e)) return [] def get_tv_recommend(self, tmdbid: int) -> List[dict]: @@ -1175,7 +1175,7 @@ class TmdbApi: logger.debug(f"正在获取推荐电视剧:{tmdbid}...") return self.tv.recommendations(tv_id=tmdbid) or [] except Exception as e: - print(str(e)) + logger.error(str(e)) return [] def get_movie_credits(self, tmdbid: int, page: int = 1, count: int = 24) -> List[dict]: @@ -1192,7 +1192,7 @@ class TmdbApi: return cast[(page - 1) * count: page * count] return [] except Exception as e: - print(str(e)) + logger.error(str(e)) return [] def get_tv_credits(self, tmdbid: int, page: int = 1, count: int = 24) -> List[dict]: @@ -1209,7 +1209,7 @@ class TmdbApi: return cast[(page - 1) * count: page * count] return [] except Exception as e: - print(str(e)) + logger.error(str(e)) return [] def get_person_detail(self, person_id: int) -> dict: @@ -1242,7 +1242,7 @@ class TmdbApi: logger.debug(f"正在获取人物详情:{person_id}...") return self.person.details(person_id=person_id) or {} except Exception as e: - print(str(e)) + logger.error(str(e)) return {} def get_person_credits(self, person_id: int, page: int = 1, count: int = 24) -> List[dict]: @@ -1263,7 +1263,7 @@ class TmdbApi: return cast[(page - 1) * count: page * count] return [] except Exception as e: - print(str(e)) + logger.error(str(e)) return [] def clear_cache(self): @@ -1301,7 +1301,7 @@ class TmdbApi: episode_years[order] = str(first_date).split("-")[0] return episode_years except Exception as e: - print(str(e)) + logger.error(str(e)) return {} def close(self): diff --git a/app/modules/thetvdb/__init__.py b/app/modules/thetvdb/__init__.py index 36e22886..ee65f8c2 100644 --- a/app/modules/thetvdb/__init__.py +++ b/app/modules/thetvdb/__init__.py @@ -4,6 +4,7 @@ from app.core.config import settings from app.log import logger from app.modules import _ModuleBase from app.modules.thetvdb import tvdbapi +from app.schemas.types import ModuleType from app.utils.http import RequestUtils @@ -20,6 +21,13 @@ class TheTvDbModule(_ModuleBase): def get_name() -> str: return "TheTvDb" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.MediaRecognize + def stop(self): self.tvdb.close() diff --git a/app/modules/transmission/__init__.py b/app/modules/transmission/__init__.py index c13473ad..e54d18ad 100644 --- a/app/modules/transmission/__init__.py +++ b/app/modules/transmission/__init__.py @@ -12,7 +12,7 @@ from app.log import logger from app.modules import _ModuleBase, _DownloaderBase from app.modules.transmission.transmission import Transmission from app.schemas import TransferTorrent, DownloadingTorrent -from app.schemas.types import TorrentStatus +from app.schemas.types import TorrentStatus, ModuleType from app.utils.string import StringUtils from app.utils.system import SystemUtils @@ -30,6 +30,13 @@ class TransmissionModule(_ModuleBase, _DownloaderBase[Transmission]): def get_name() -> str: return "Transmission" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Downloader + def stop(self): pass diff --git a/app/modules/vocechat/__init__.py b/app/modules/vocechat/__init__.py index 479cd5f1..40a45a46 100644 --- a/app/modules/vocechat/__init__.py +++ b/app/modules/vocechat/__init__.py @@ -1,12 +1,12 @@ import json from typing import Optional, Union, List, Tuple, Any, Dict -from app.core.config import settings from app.core.context import Context, MediaInfo from app.log import logger from app.modules import _ModuleBase, _MessageBase from app.modules.vocechat.vocechat import VoceChat from app.schemas import MessageChannel, CommingMessage, Notification +from app.schemas.types import ModuleType class VoceChatModule(_ModuleBase, _MessageBase[VoceChat]): @@ -22,6 +22,13 @@ class VoceChatModule(_ModuleBase, _MessageBase[VoceChat]): def get_name() -> str: return "VoceChat" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Notification + def stop(self): pass diff --git a/app/modules/webpush/__init__.py b/app/modules/webpush/__init__.py index ef1fd2b9..70030614 100644 --- a/app/modules/webpush/__init__.py +++ b/app/modules/webpush/__init__.py @@ -7,6 +7,7 @@ from app.core.config import global_vars, settings from app.log import logger from app.modules import _ModuleBase, _MessageBase from app.schemas import Notification +from app.schemas.types import ModuleType class WebPushModule(_ModuleBase, _MessageBase): @@ -21,6 +22,13 @@ class WebPushModule(_ModuleBase, _MessageBase): def get_name() -> str: return "WebPush" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Notification + def stop(self): pass diff --git a/app/modules/wechat/__init__.py b/app/modules/wechat/__init__.py index 9e205291..37d9a15c 100644 --- a/app/modules/wechat/__init__.py +++ b/app/modules/wechat/__init__.py @@ -7,6 +7,7 @@ from app.modules import _ModuleBase, _MessageBase from app.modules.wechat.WXBizMsgCrypt3 import WXBizMsgCrypt from app.modules.wechat.wechat import WeChat from app.schemas import MessageChannel, CommingMessage, Notification +from app.schemas.types import ModuleType from app.utils.dom import DomUtils @@ -23,6 +24,13 @@ class WechatModule(_ModuleBase, _MessageBase[WeChat]): def get_name() -> str: return "微信" + @staticmethod + def get_type() -> ModuleType: + """ + 获取模块类型 + """ + return ModuleType.Notification + def stop(self): pass diff --git a/app/schemas/mediaserver.py b/app/schemas/mediaserver.py index a97b4fbc..80488dda 100644 --- a/app/schemas/mediaserver.py +++ b/app/schemas/mediaserver.py @@ -139,6 +139,7 @@ class WebhookEventInfo(BaseModel): """ event: Optional[str] = None channel: Optional[str] = None + server_name: Optional[str] = None item_type: Optional[str] = None item_name: Optional[str] = None item_id: Optional[str] = None diff --git a/app/schemas/types.py b/app/schemas/types.py index 65545982..e8bd5d46 100644 --- a/app/schemas/types.py +++ b/app/schemas/types.py @@ -179,3 +179,19 @@ class StorageSchema(Enum): Alipan = "alipan" U115 = "u115" Rclone = "rclone" + + +# 模块类型 +class ModuleType(Enum): + # 下载器 + Downloader = "downloader" + # 媒体服务器 + MediaServer = "mediaserver" + # 消息服务 + Notification = "notification" + # 媒体识别 + MediaRecognize = "mediarecognize" + # 站点索引 + Indexer = "indexer" + # 其它 + Other = "other" diff --git a/app/utils/string.py b/app/utils/string.py index 3d1e34a3..1960de63 100644 --- a/app/utils/string.py +++ b/app/utils/string.py @@ -185,7 +185,7 @@ class StringUtils: 忽略特殊字符 """ # 需要忽略的特殊字符 - CONVERT_EMPTY_CHARS = r"[、.。,,·::;;!!'’\"“”()()\[\]【】「」\-——\+\|\\_/&#~~]" + CONVERT_EMPTY_CHARS = r"[、.。,,·::;;!!'’\"“”()()\[\]【】「」\-—―\+\|\\_/&#~~]" if not text: return text if not isinstance(text, list): diff --git a/app/utils/web.py b/app/utils/web.py index 43340ab2..6145adb7 100644 --- a/app/utils/web.py +++ b/app/utils/web.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List from cachetools import TTLCache, cached @@ -94,7 +94,7 @@ class WebUtils: @staticmethod @cached(cache=TTLCache(maxsize=1, ttl=3600)) - def get_bing_wallpapers(num: int = 7) -> Optional[str]: + def get_bing_wallpapers(num: int = 7) -> List[str]: """ 获取7天的Bing每日壁纸 """ @@ -107,4 +107,4 @@ class WebUtils: return [f"https://cn.bing.com{image.get('url')}" for image in result.get('images') or []] except Exception as err: print(str(err)) - return None + return [] diff --git a/requirements.in b/requirements.in index 85babab9..82c50a61 100644 --- a/requirements.in +++ b/requirements.in @@ -23,7 +23,7 @@ APScheduler~=3.10.1 cryptography~=43.0.0 pytz~=2023.3 pycryptodome~=3.20.0 -qbittorrent-api==2023.5.48 +qbittorrent-api==2024.9.67 plexapi~=4.15.16 transmission-rpc~=4.3.0 Jinja2~=3.1.4 diff --git a/update b/update index 87915272..c28105e8 100644 --- a/update +++ b/update @@ -192,6 +192,46 @@ function test_connectivity_github() { esac } +function compare_versions() { + local v1="$1" + local v2="$2" + local parts1=() + local parts2=() + IFS='.-' read -ra parts1 <<< "$v1" + IFS='.-' read -ra parts2 <<< "$v2" + local i + for ((i = 0; i < ${#parts1[@]} || i < ${#parts2[@]}; i++)); do + local part1="${parts1[i]:-0}" + local part2="${parts2[i]:-0}" + if [[ $part1 =~ ^[0-9]+$ && $part2 =~ ^[0-9]+$ ]]; then + if ((part1 > part2)); then + return 1 + elif ((part1 < part2)); then + return 2 + fi + else + # 定义一个非数字的排序顺序的优先级,特殊后缀版本比较 + local order=(alpha beta rc stable) + local index1=-1 + local index2=-1 + for ((j = 0; j < ${#order[@]}; j++)); do + if [[ $part1 = "${order[j]}" ]]; then + index1=$j + fi + if [[ $part2 = "${order[j]}" ]]; then + index2=$j + fi + done + if ((index1 > index2)); then + return 1 + elif ((index1 < index2)); then + return 2 + fi + fi + done + return 0 +} + if [[ "${MOVIEPILOT_AUTO_UPDATE}" = "true" ]] || [[ "${MOVIEPILOT_AUTO_UPDATE}" = "release" ]] || [[ "${MOVIEPILOT_AUTO_UPDATE}" = "dev" ]]; then # 优先级:镜像站 > 全局 > 不代理 # pip @@ -231,11 +271,14 @@ if [[ "${MOVIEPILOT_AUTO_UPDATE}" = "true" ]] || [[ "${MOVIEPILOT_AUTO_UPDATE}" if [[ "${new_version}" == *v* ]]; then release_version=${new_version} INFO "最新版本号:${release_version}" - if [ "${current_version}" != "${release_version}" ]; then + # 使用版本号比较函数进行比较 + if compare_versions "${current_version}" "${release_version}"; then + WARN "当前版本已是最新版本,跳过更新步骤..." + elif [ $? -eq 2 ]; then INFO "发现新版本,开始自动升级..." install_backend_and_download_resources "tags/${release_version}.zip" else - INFO "未发现新版本,跳过更新步骤..." + WARN "当前版本高于远程版本,跳过更新步骤..." fi else WARN "最新版本号获取失败,继续启动..."