refactor(runtime): lazily activate host modules (#6331)

This commit is contained in:
InfinityPacer
2026-08-16 16:07:38 +08:00
committed by GitHub
parent 98276a68a8
commit 24671f8f18
67 changed files with 7364 additions and 253 deletions
+4 -1
View File
@@ -3,7 +3,7 @@ from abc import abstractmethod, ABCMeta
from typing import Generic, Tuple, Union, TypeVar, Type, Dict, Optional, Callable
from pathlib import Path
from app.runtime.extensions.service_registry import ServiceConfigHelper
from app.runtime.extensions.service_config import ServiceConfigHelper
from app.runtime.log import logger
from app.schemas import Notification, NotificationConf, MediaServerConf, DownloaderConf
from app.schemas.types import ModuleType, DownloaderType, MediaServerType, MessageChannel, StorageSchema, \
@@ -17,6 +17,9 @@ class _ModuleBase(ConfigReloadMixin, metaclass=ABCMeta):
输入参数与输出参数一致的,或没有输出的,可以被多个模块重复实现
"""
# Host Module 的配置事件由统一 Adapter 协调,避免同一 generation 被双重重载。
CONFIG_RELOAD_MANAGED_EXTERNALLY = True
def __init__(self) -> None:
"""初始化模块生命周期锁"""
super().__init__()
+19
View File
@@ -0,0 +1,19 @@
schema_version = 1
id = "AcoustIdModule"
kind = "host_module"
entrypoint = "app.modules.acoustid:AcoustIdModule"
depends_on = []
[metadata]
name = "AcoustID"
type = "other"
subtype = "AcoustId"
priority = 0
[activation]
policy = "when_configured"
watch = ["ACOUSTID_API_KEY"]
[activation.selector]
kind = "setting_truthy"
key = "ACOUSTID_API_KEY"
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "AniListModule"
kind = "host_module"
entrypoint = "app.modules.anilist:AniListModule"
depends_on = []
[metadata]
name = "AniList"
type = "mediarecognize"
subtype = "AniList"
priority = 4
[activation]
policy = "bootstrap"
watch = ["PROXY_HOST"]
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "BangumiModule"
kind = "host_module"
entrypoint = "app.modules.bangumi:BangumiModule"
depends_on = []
[metadata]
name = "Bangumi"
type = "mediarecognize"
subtype = "Bangumi"
priority = 3
[activation]
policy = "bootstrap"
watch = ["PROXY_HOST"]
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "DiscordModule"
kind = "host_module"
entrypoint = "app.modules.discord:DiscordModule"
depends_on = []
[metadata]
name = "Discord"
type = "notification"
subtype = "Discord"
priority = 4
[activation]
policy = "when_configured"
watch = ["Notifications"]
[activation.selector]
kind = "system_config_item"
key = "Notifications"
match_field = "type"
match_value = "discord"
enabled_field = "enabled"
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "DoubanModule"
kind = "host_module"
entrypoint = "app.modules.douban:DoubanModule"
depends_on = []
[metadata]
name = "豆瓣"
type = "mediarecognize"
subtype = "Douban"
priority = 2
[activation]
policy = "bootstrap"
watch = []
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "EmbyModule"
kind = "host_module"
entrypoint = "app.modules.emby:EmbyModule"
depends_on = []
[metadata]
name = "Emby"
type = "mediaserver"
subtype = "Emby"
priority = 1
[activation]
policy = "when_configured"
watch = ["MediaServers"]
[activation.selector]
kind = "system_config_item"
key = "MediaServers"
match_field = "type"
match_value = "emby"
enabled_field = "enabled"
+19
View File
@@ -0,0 +1,19 @@
schema_version = 1
id = "FanartModule"
kind = "host_module"
entrypoint = "app.modules.fanart:FanartModule"
depends_on = []
[metadata]
name = "Fanart"
type = "other"
subtype = "Fanart"
priority = 0
[activation]
policy = "when_configured"
watch = ["FANART_API_KEY"]
[activation.selector]
kind = "setting_truthy"
key = "FANART_API_KEY"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "FeishuModule"
kind = "host_module"
entrypoint = "app.modules.feishu:FeishuModule"
depends_on = []
[metadata]
name = "飞书"
type = "notification"
subtype = "Feishu"
priority = 2
[activation]
policy = "when_configured"
watch = ["Notifications"]
[activation.selector]
kind = "system_config_item"
key = "Notifications"
match_field = "type"
match_value = "feishu"
enabled_field = "enabled"
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "FileManagerModule"
kind = "host_module"
entrypoint = "app.modules.filemanager:FileManagerModule"
depends_on = []
[metadata]
name = "文件整理"
type = "other"
subtype = "FileManager"
priority = 4
[activation]
policy = "bootstrap"
watch = []
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "FilterModule"
kind = "host_module"
entrypoint = "app.modules.filter:FilterModule"
depends_on = []
[metadata]
name = "过滤器"
type = "other"
subtype = "Filter"
priority = 4
[activation]
policy = "bootstrap"
watch = ["CustomFilterRules", "CustomIdentifiers", "CustomReleaseGroups", "Customization"]
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "IndexerModule"
kind = "host_module"
entrypoint = "app.modules.indexer:IndexerModule"
depends_on = []
[metadata]
name = "站点索引"
type = "indexer"
subtype = "Indexer"
priority = 0
[activation]
policy = "bootstrap"
watch = []
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "JellyfinModule"
kind = "host_module"
entrypoint = "app.modules.jellyfin:JellyfinModule"
depends_on = []
[metadata]
name = "Jellyfin"
type = "mediaserver"
subtype = "Jellyfin"
priority = 2
[activation]
policy = "when_configured"
watch = ["MediaServers"]
[activation.selector]
kind = "system_config_item"
key = "MediaServers"
match_field = "type"
match_value = "jellyfin"
enabled_field = "enabled"
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "ListenBrainzModule"
kind = "host_module"
entrypoint = "app.modules.listenbrainz:ListenBrainzModule"
depends_on = []
[metadata]
name = "ListenBrainz"
type = "other"
subtype = "ListenBrainz"
priority = 5
[activation]
policy = "bootstrap"
watch = []
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "LrclibModule"
kind = "host_module"
entrypoint = "app.modules.lrclib:LrclibModule"
depends_on = []
[metadata]
name = "LRCLIB"
type = "other"
subtype = "Lrclib"
priority = 5
[activation]
policy = "bootstrap"
watch = []
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "MusicBrainzModule"
kind = "host_module"
entrypoint = "app.modules.musicbrainz:MusicBrainzModule"
depends_on = []
[metadata]
name = "MusicBrainz"
type = "mediarecognize"
subtype = "MusicBrainz"
priority = 0
[activation]
policy = "bootstrap"
watch = []
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "NavidromeModule"
kind = "host_module"
entrypoint = "app.modules.navidrome:NavidromeModule"
depends_on = []
[metadata]
name = "Navidrome"
type = "mediaserver"
subtype = "Navidrome"
priority = 7
[activation]
policy = "when_configured"
watch = ["MediaServers"]
[activation.selector]
kind = "system_config_item"
key = "MediaServers"
match_field = "type"
match_value = "navidrome"
enabled_field = "enabled"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "PlexModule"
kind = "host_module"
entrypoint = "app.modules.plex:PlexModule"
depends_on = []
[metadata]
name = "Plex"
type = "mediaserver"
subtype = "Plex"
priority = 3
[activation]
policy = "when_configured"
watch = ["MediaServers"]
[activation.selector]
kind = "system_config_item"
key = "MediaServers"
match_field = "type"
match_value = "plex"
enabled_field = "enabled"
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "PostgreSQLModule"
kind = "host_module"
entrypoint = "app.modules.postgresql:PostgreSQLModule"
depends_on = []
[metadata]
name = "PostgreSQL"
type = "other"
subtype = "PostgreSQL"
priority = 0
[activation]
policy = "bootstrap"
watch = []
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "QbittorrentModule"
kind = "host_module"
entrypoint = "app.modules.qbittorrent:QbittorrentModule"
depends_on = []
[metadata]
name = "Qbittorrent"
type = "downloader"
subtype = "Qbittorrent"
priority = 1
[activation]
policy = "when_configured"
watch = ["Downloaders"]
[activation.selector]
kind = "system_config_item"
key = "Downloaders"
match_field = "type"
match_value = "qbittorrent"
enabled_field = "enabled"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "QQBotModule"
kind = "host_module"
entrypoint = "app.modules.qqbot:QQBotModule"
depends_on = []
[metadata]
name = "QQ"
type = "notification"
subtype = "QQ"
priority = 10
[activation]
policy = "when_configured"
watch = ["Notifications"]
[activation.selector]
kind = "system_config_item"
key = "Notifications"
match_field = "type"
match_value = "qqbot"
enabled_field = "enabled"
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "RedisModule"
kind = "host_module"
entrypoint = "app.modules.redis:RedisModule"
depends_on = []
[metadata]
name = "Redis缓存"
type = "other"
subtype = "Redis"
priority = 0
[activation]
policy = "bootstrap"
watch = []
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "RtorrentModule"
kind = "host_module"
entrypoint = "app.modules.rtorrent:RtorrentModule"
depends_on = []
[metadata]
name = "Rtorrent"
type = "downloader"
subtype = "Rtorrent"
priority = 3
[activation]
policy = "when_configured"
watch = ["Downloaders"]
[activation.selector]
kind = "system_config_item"
key = "Downloaders"
match_field = "type"
match_value = "rtorrent"
enabled_field = "enabled"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "SlackModule"
kind = "host_module"
entrypoint = "app.modules.slack:SlackModule"
depends_on = []
[metadata]
name = "Slack"
type = "notification"
subtype = "Slack"
priority = 3
[activation]
policy = "when_configured"
watch = ["Notifications"]
[activation.selector]
kind = "system_config_item"
key = "Notifications"
match_field = "type"
match_value = "slack"
enabled_field = "enabled"
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "SubtitleModule"
kind = "host_module"
entrypoint = "app.modules.subtitle:SubtitleModule"
depends_on = []
[metadata]
name = "站点字幕"
type = "other"
subtype = "Subtitle"
priority = 0
[activation]
policy = "bootstrap"
watch = []
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "SynologyChatModule"
kind = "host_module"
entrypoint = "app.modules.synologychat:SynologyChatModule"
depends_on = []
[metadata]
name = "Synology Chat"
type = "notification"
subtype = "SynologyChat"
priority = 5
[activation]
policy = "when_configured"
watch = ["Notifications"]
[activation.selector]
kind = "system_config_item"
key = "Notifications"
match_field = "type"
match_value = "synologychat"
enabled_field = "enabled"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "TelegramModule"
kind = "host_module"
entrypoint = "app.modules.telegram:TelegramModule"
depends_on = []
[metadata]
name = "Telegram"
type = "notification"
subtype = "Telegram"
priority = 0
[activation]
policy = "when_configured"
watch = ["Notifications"]
[activation.selector]
kind = "system_config_item"
key = "Notifications"
match_field = "type"
match_value = "telegram"
enabled_field = "enabled"
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "TheAudioDbModule"
kind = "host_module"
entrypoint = "app.modules.theaudiodb:TheAudioDbModule"
depends_on = []
[metadata]
name = "TheAudioDB"
type = "mediarecognize"
subtype = "TheAudioDB"
priority = 1
[activation]
policy = "bootstrap"
watch = []
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "TheMovieDbModule"
kind = "host_module"
entrypoint = "app.modules.themoviedb:TheMovieDbModule"
depends_on = []
[metadata]
name = "TheMovieDb"
type = "mediarecognize"
subtype = "TMDB"
priority = 1
[activation]
policy = "bootstrap"
watch = ["PROXY_HOST", "TMDB_API_DOMAIN", "TMDB_API_KEY", "TMDB_LOCALE"]
+15
View File
@@ -0,0 +1,15 @@
schema_version = 1
id = "TheTvDbModule"
kind = "host_module"
entrypoint = "app.modules.thetvdb:TheTvDbModule"
depends_on = []
[metadata]
name = "TheTvDb"
type = "mediarecognize"
subtype = "TVDB"
priority = 4
[activation]
policy = "bootstrap"
watch = []
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "TransmissionModule"
kind = "host_module"
entrypoint = "app.modules.transmission:TransmissionModule"
depends_on = []
[metadata]
name = "Transmission"
type = "downloader"
subtype = "Transmission"
priority = 2
[activation]
policy = "when_configured"
watch = ["Downloaders"]
[activation.selector]
kind = "system_config_item"
key = "Downloaders"
match_field = "type"
match_value = "transmission"
enabled_field = "enabled"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "TrimeMediaModule"
kind = "host_module"
entrypoint = "app.modules.trimemedia:TrimeMediaModule"
depends_on = []
[metadata]
name = "飞牛影视"
type = "mediaserver"
subtype = "TrimeMedia"
priority = 4
[activation]
policy = "when_configured"
watch = ["MediaServers"]
[activation.selector]
kind = "system_config_item"
key = "MediaServers"
match_field = "type"
match_value = "trimemedia"
enabled_field = "enabled"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "UgreenModule"
kind = "host_module"
entrypoint = "app.modules.ugreen:UgreenModule"
depends_on = []
[metadata]
name = "绿联影视"
type = "mediaserver"
subtype = "Ugreen"
priority = 5
[activation]
policy = "when_configured"
watch = ["MediaServers"]
[activation.selector]
kind = "system_config_item"
key = "MediaServers"
match_field = "type"
match_value = "ugreen"
enabled_field = "enabled"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "VoceChatModule"
kind = "host_module"
entrypoint = "app.modules.vocechat:VoceChatModule"
depends_on = []
[metadata]
name = "VoceChat"
type = "notification"
subtype = "VoceChat"
priority = 4
[activation]
policy = "when_configured"
watch = ["Notifications"]
[activation.selector]
kind = "system_config_item"
key = "Notifications"
match_field = "type"
match_value = "vocechat"
enabled_field = "enabled"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "WebPushModule"
kind = "host_module"
entrypoint = "app.modules.webpush:WebPushModule"
depends_on = []
[metadata]
name = "WebPush"
type = "notification"
subtype = "WebPush"
priority = 6
[activation]
policy = "when_configured"
watch = ["Notifications"]
[activation.selector]
kind = "system_config_item"
key = "Notifications"
match_field = "type"
match_value = "webpush"
enabled_field = "enabled"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "WechatModule"
kind = "host_module"
entrypoint = "app.modules.wechat:WechatModule"
depends_on = []
[metadata]
name = "企业微信"
type = "notification"
subtype = "Wechat"
priority = 1
[activation]
policy = "when_configured"
watch = ["Notifications"]
[activation.selector]
kind = "system_config_item"
key = "Notifications"
match_field = "type"
match_value = "wechat"
enabled_field = "enabled"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "WechatClawBotModule"
kind = "host_module"
entrypoint = "app.modules.wechatclawbot:WechatClawBotModule"
depends_on = []
[metadata]
name = "微信 ClawBot"
type = "notification"
subtype = "WechatClawBot"
priority = 2
[activation]
policy = "when_configured"
watch = ["Notifications"]
[activation.selector]
kind = "system_config_item"
key = "Notifications"
match_field = "type"
match_value = "wechatclawbot"
enabled_field = "enabled"
+22
View File
@@ -0,0 +1,22 @@
schema_version = 1
id = "ZSpaceModule"
kind = "host_module"
entrypoint = "app.modules.zspace:ZSpaceModule"
depends_on = []
[metadata]
name = "极影视"
type = "mediaserver"
subtype = "ZSpace"
priority = 6
[activation]
policy = "when_configured"
watch = ["MediaServers"]
[activation.selector]
kind = "system_config_item"
key = "MediaServers"
match_field = "type"
match_value = "zspace"
enabled_field = "enabled"