mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 23:47:41 +08:00
refactor: 收口 V3 分层架构与插件兼容边界
This commit is contained in:
@@ -8,11 +8,11 @@ from pathlib import Path
|
||||
from typing import Optional, Any, Tuple, List, Set, Union, Dict
|
||||
|
||||
from app.application.chain.context import ChainRuntimeContext, get_chain_runtime_context
|
||||
from app.application.chain.data import get_chain_data_ports
|
||||
from app.chain._messaging import MessageProcessingMixin, NotificationMixin
|
||||
from app.chain._recognition import RecognitionMixin
|
||||
from app.domain.context import Context, MediaInfo, SubtitleInfo, TorrentInfo
|
||||
from app.domain.meta.metabase import MetaBase
|
||||
from app.runtime.extensions.module.dispatcher import ModuleInvocationDispatcher
|
||||
from app.runtime.log import logger
|
||||
from app.schemas.exception import RateLimitExceededException
|
||||
from app.schemas.transfer import TransferInfo
|
||||
@@ -52,7 +52,8 @@ class ChainBase(RecognitionMixin, MessageProcessingMixin, NotificationMixin,
|
||||
self.pluginmanager = context.plugin_manager
|
||||
self.filecache = context.file_cache
|
||||
self.async_filecache = context.async_file_cache
|
||||
self._module_dispatcher = ModuleInvocationDispatcher(
|
||||
self.data_ports = context.data_ports or get_chain_data_ports()
|
||||
self._module_dispatcher = context.module_dispatcher_factory(
|
||||
module_catalog=self.modulemanager,
|
||||
plugin_catalog=self.pluginmanager,
|
||||
plugin_error_handler=self.__handle_plugin_error,
|
||||
|
||||
@@ -8,13 +8,13 @@ import copy
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
from app.db.oper.user import UserOper
|
||||
from app.application.chain.data import UserPortProxy as UserOper
|
||||
from app.domain.context import Context, MediaInfo, MusicInfo, TorrentInfo
|
||||
from app.domain.meta.metabase import MetaBase
|
||||
from app.foundation.identity import normalize_internal_user_id
|
||||
from app.application.messaging.message import MessageTemplateHelper
|
||||
from app.runtime.config import settings
|
||||
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.message import MessageResponse
|
||||
from app.schemas.message import Message
|
||||
|
||||
+6
-5
@@ -9,9 +9,8 @@ from app.application.subscription.contract import (
|
||||
from app.chain.download import DownloadChain
|
||||
from app.chain.media import MediaChain
|
||||
from app.chain.search import SearchChain
|
||||
from app.db.models.subscribe import Subscribe
|
||||
from app.db.oper.subscribe import SubscribeOper
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.application.chain.data import SubscribePortProxy as SubscribeOper
|
||||
from app.application.configuration import get_configured_system_config
|
||||
from app.domain.context import Context, MediaInfo, MusicInfo
|
||||
from app.domain.media import MUSIC_SUBSCRIBABLE_TYPES
|
||||
from app.domain.meta.metamusic import MetaMusic
|
||||
@@ -23,6 +22,8 @@ from app.schemas.types import (
|
||||
SystemConfigKey,
|
||||
)
|
||||
|
||||
Subscribe = Any
|
||||
|
||||
|
||||
def _normalize_music_total_tracks(value: Any) -> Optional[int]:
|
||||
"""将专辑曲目总数归一为正整数,无效或未知值返回 None。"""
|
||||
@@ -255,7 +256,7 @@ class MusicSubscribeMixin:
|
||||
sites = self.get_sub_sites(subscribe)
|
||||
default_rule_key = SystemConfigKey.BestVersionFilterRuleGroups \
|
||||
if subscribe.best_version else SystemConfigKey.SubscribeFilterRuleGroups
|
||||
rule_groups = subscribe.filter_groups or SystemConfigOper().get(default_rule_key) or []
|
||||
rule_groups = subscribe.filter_groups or get_configured_system_config().get(default_rule_key) or []
|
||||
torrent_helper = TorrentHelper()
|
||||
matched: List[Context] = []
|
||||
for source_context in contexts or []:
|
||||
@@ -369,7 +370,7 @@ class MusicSubscribeMixin:
|
||||
sites = self.get_sub_sites(subscribe)
|
||||
default_rule_key = SystemConfigKey.BestVersionFilterRuleGroups \
|
||||
if subscribe.best_version else SystemConfigKey.SubscribeFilterRuleGroups
|
||||
rule_groups = subscribe.filter_groups or SystemConfigOper().get(default_rule_key) or []
|
||||
rule_groups = subscribe.filter_groups or get_configured_system_config().get(default_rule_key) or []
|
||||
keywords = [subscribe.keyword] if subscribe.keyword else SearchChain.music_site_keywords(mediainfo)
|
||||
if not keywords:
|
||||
keywords = [subscribe.name]
|
||||
|
||||
@@ -10,7 +10,7 @@ from typing import Optional
|
||||
from fastapi.concurrency import run_in_threadpool
|
||||
|
||||
from app.adapters.external.server import MoviePilotServerHelper
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.application.configuration import get_configured_system_config
|
||||
from app.domain.context import MediaInfo, MusicInfo
|
||||
from app.domain.meta.metabase import MetaBase
|
||||
from app.domain.meta.metamusic import MetaMusic
|
||||
@@ -85,7 +85,7 @@ class RecognitionMixin:
|
||||
def _record_media_recognize_share_hit() -> None:
|
||||
"""记录一次共享媒体识别成功命中,统计失败不影响识别结果。"""
|
||||
try:
|
||||
SystemConfigOper().increment(SystemConfigKey.MediaRecognizeShareCount)
|
||||
get_configured_system_config().increment(SystemConfigKey.MediaRecognizeShareCount)
|
||||
except Exception as err:
|
||||
logger.error(f"记录共享媒体识别命中次数失败:{str(err)}")
|
||||
|
||||
|
||||
+10
-6
@@ -22,11 +22,11 @@ from app.application.transfer import TransferTask, job_lock
|
||||
from app.chain.media import MediaChain
|
||||
from app.chain.storage import StorageChain
|
||||
from app.chain.subscribe import SubscribeChain
|
||||
from app.db.models.downloadhistory import DownloadFiles, DownloadHistory
|
||||
from app.db.models.transferhistory import TransferHistory
|
||||
from app.db.oper.downloadhistory import DownloadHistoryOper
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.db.oper.transferhistory import TransferHistoryOper
|
||||
from app.application.chain.data import (
|
||||
DownloadHistoryPortProxy as DownloadHistoryOper,
|
||||
TransferHistoryPortProxy as TransferHistoryOper,
|
||||
)
|
||||
from app.application.configuration import get_configured_system_config
|
||||
from app.domain.context import MediaInfo, MusicInfo
|
||||
from app.domain.media import normalize_music_type
|
||||
from app.domain.meta.metabase import MetaBase
|
||||
@@ -48,6 +48,10 @@ from app.schemas.types import (
|
||||
SystemConfigKey,
|
||||
)
|
||||
|
||||
DownloadFiles = Any
|
||||
DownloadHistory = Any
|
||||
TransferHistory = Any
|
||||
|
||||
# 字幕文件常见的语言/默认/强制标记,整理同名字幕时只允许剥离这些字幕专属尾缀。
|
||||
SUBTITLE_STEM_TAGS = {
|
||||
"cc",
|
||||
@@ -725,7 +729,7 @@ class EpisodeFormatMixin:
|
||||
"""
|
||||
获取启用的集数定位规则
|
||||
"""
|
||||
rule_items = SystemConfigOper().get(SystemConfigKey.EpisodeFormatRuleTable) or []
|
||||
rule_items = get_configured_system_config().get(SystemConfigKey.EpisodeFormatRuleTable) or []
|
||||
rules: List[_SchemaEpisodeFormatRule] = []
|
||||
for item in rule_items:
|
||||
if not isinstance(item, dict):
|
||||
|
||||
@@ -28,9 +28,11 @@ from app.runtime.events import eventmanager, Event
|
||||
from app.domain.meta.metabase import MetaBase
|
||||
from app.domain.meta.metamusic import MetaMusic
|
||||
from app.domain.metainfo import MetaInfo
|
||||
from app.db.oper.downloadfailure import DownloadFailureOper
|
||||
from app.db.oper.downloadhistory import DownloadHistoryOper
|
||||
from app.db.oper.mediaserver import MediaServerOper
|
||||
from app.application.chain.data import (
|
||||
DownloadFailurePortProxy as DownloadFailureOper,
|
||||
DownloadHistoryPortProxy as DownloadHistoryOper,
|
||||
MediaServerPortProxy as MediaServerOper,
|
||||
)
|
||||
from app.application.directory import DirectoryHelper, validate_download_save_path
|
||||
from app.application.download.tasks import DownloadTaskService
|
||||
from app.runtime.thread import ThreadHelper
|
||||
@@ -53,7 +55,9 @@ from app.foundation import text as text_tools
|
||||
from app.adapters.system.host import SystemUtils
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.db.models.downloadfailure import DownloadFailure
|
||||
from typing import Any
|
||||
|
||||
DownloadFailure = Any
|
||||
|
||||
|
||||
DOWNLOAD_FAILURE_RESOURCE_TTL_SECONDS = 24 * 60 * 60
|
||||
|
||||
@@ -13,7 +13,7 @@ from app.application.messaging.media import (
|
||||
media_interaction_manager,
|
||||
)
|
||||
from app.application.torrent import TorrentHelper
|
||||
from app.db.oper.user import UserOper
|
||||
from app.application.chain.data import UserPortProxy as UserOper
|
||||
from app.domain import episode as episode_rules
|
||||
from app.domain import title as title_rules
|
||||
from app.domain.context import Context, MediaInfo
|
||||
|
||||
@@ -4,8 +4,8 @@ from typing import Callable, Dict, List, Union, Optional, Generator, Any
|
||||
|
||||
from app.chain import ChainBase
|
||||
from app.runtime.config import global_vars
|
||||
from app.db.oper.mediaserver import MediaServerOper
|
||||
from app.runtime.extensions.service_registry import ServiceConfigHelper
|
||||
from app.application.chain.data import MediaServerPortProxy as MediaServerOper
|
||||
from app.runtime.extensions.service_config import ServiceConfigHelper
|
||||
from app.runtime.log import logger
|
||||
from app.schemas.mediaserver import MediaServerLibrary
|
||||
from app.schemas.mediaserver import MediaServerItem
|
||||
|
||||
@@ -23,7 +23,7 @@ from app.runtime.events import eventmanager, Event
|
||||
from app.domain.meta.metabase import MetaBase
|
||||
from app.domain.meta.metamusic import MetaMusic
|
||||
from app.domain.metainfo import MetaInfo, MetaInfoPath
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.application.configuration import get_configured_system_config
|
||||
from app.application.audio import AudioMetadataHelper
|
||||
from app.runtime.log import logger
|
||||
from app.schemas.workflow import FileItem
|
||||
@@ -146,7 +146,7 @@ class ScrapingConfig:
|
||||
|
||||
:return: MediaScrapingConfig 实例
|
||||
"""
|
||||
user_config = SystemConfigOper().get(SystemConfigKey.ScrapingSwitchs) or {}
|
||||
user_config = get_configured_system_config().get(SystemConfigKey.ScrapingSwitchs) or {}
|
||||
return cls(user_config)
|
||||
|
||||
@staticmethod
|
||||
|
||||
+13
-13
@@ -21,7 +21,7 @@ from app.runtime.events import eventmanager, Event
|
||||
from app.domain.meta.metamusic import MetaMusic
|
||||
from app.domain.metainfo import MetaInfo
|
||||
from app.domain.context import MusicInfo
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.application.configuration import get_configured_system_config
|
||||
from app.runtime.progress import ProgressHelper
|
||||
from app.application.site.sites import SitesHelper # pylint: disable=no-name-in-module
|
||||
from app.application.search.state import (
|
||||
@@ -1039,7 +1039,7 @@ class SearchChain(ChainBase):
|
||||
# 记录过滤前的候选资源数,供前端在全部被过滤时给出友好提示
|
||||
candidate_count = 0
|
||||
if rule_groups is None:
|
||||
rule_groups = SystemConfigOper().get(SystemConfigKey.SearchFilterRuleGroups) or []
|
||||
rule_groups = get_configured_system_config().get(SystemConfigKey.SearchFilterRuleGroups) or []
|
||||
async for event in self.__async_search_all_sites_stream(
|
||||
keyword=title, sites=sites, page=page, mtype=mtype):
|
||||
result = event.pop("items", []) or []
|
||||
@@ -1104,7 +1104,7 @@ class SearchChain(ChainBase):
|
||||
return []
|
||||
|
||||
if rule_groups is None:
|
||||
rule_groups = SystemConfigOper().get(SystemConfigKey.SearchFilterRuleGroups) or []
|
||||
rule_groups = get_configured_system_config().get(SystemConfigKey.SearchFilterRuleGroups) or []
|
||||
if not rule_groups:
|
||||
return torrents
|
||||
|
||||
@@ -1311,7 +1311,7 @@ class SearchChain(ChainBase):
|
||||
# 开始过滤规则过滤
|
||||
if rule_groups is None:
|
||||
# 取搜索过滤规则
|
||||
rule_groups: List[str] = SystemConfigOper().get(SystemConfigKey.SearchFilterRuleGroups)
|
||||
rule_groups: List[str] = get_configured_system_config().get(SystemConfigKey.SearchFilterRuleGroups)
|
||||
if rule_groups:
|
||||
logger.info(f'开始过滤规则/剧集过滤,使用规则组:{rule_groups} ...')
|
||||
torrents = __do_parallel_filter(torrents)
|
||||
@@ -1439,7 +1439,7 @@ class SearchChain(ChainBase):
|
||||
if torrenthelper.filter_torrent(torrent, filter_params)
|
||||
]
|
||||
if rule_groups is None:
|
||||
rule_groups = SystemConfigOper().get(SystemConfigKey.SearchFilterRuleGroups) or []
|
||||
rule_groups = get_configured_system_config().get(SystemConfigKey.SearchFilterRuleGroups) or []
|
||||
if rule_groups and torrents:
|
||||
torrents = self.filter_torrents(
|
||||
rule_groups=rule_groups,
|
||||
@@ -2272,7 +2272,7 @@ class SearchChain(ChainBase):
|
||||
|
||||
# 配置的索引站点
|
||||
if not sites:
|
||||
sites = SystemConfigOper().get(SystemConfigKey.IndexerSites) or []
|
||||
sites = get_configured_system_config().get(SystemConfigKey.IndexerSites) or []
|
||||
|
||||
for indexer in SitesHelper().get_indexers():
|
||||
# 检查站点索引开关
|
||||
@@ -2386,7 +2386,7 @@ class SearchChain(ChainBase):
|
||||
|
||||
# 配置的索引站点
|
||||
if not sites:
|
||||
sites = SystemConfigOper().get(SystemConfigKey.IndexerSites) or []
|
||||
sites = get_configured_system_config().get(SystemConfigKey.IndexerSites) or []
|
||||
|
||||
for indexer in await SitesHelper().async_get_indexers():
|
||||
# 检查站点索引开关
|
||||
@@ -2509,7 +2509,7 @@ class SearchChain(ChainBase):
|
||||
indexer_sites = []
|
||||
|
||||
if not sites:
|
||||
sites = SystemConfigOper().get(SystemConfigKey.IndexerSites) or []
|
||||
sites = get_configured_system_config().get(SystemConfigKey.IndexerSites) or []
|
||||
|
||||
for indexer in await SitesHelper().async_get_indexers():
|
||||
if not sites or indexer.get("id") in sites:
|
||||
@@ -2646,7 +2646,7 @@ class SearchChain(ChainBase):
|
||||
indexer_sites = []
|
||||
|
||||
if not sites:
|
||||
sites = SystemConfigOper().get(SystemConfigKey.IndexerSites) or []
|
||||
sites = get_configured_system_config().get(SystemConfigKey.IndexerSites) or []
|
||||
|
||||
for indexer in await SitesHelper().async_get_indexers():
|
||||
if not indexer.get("subtitles"):
|
||||
@@ -2742,7 +2742,7 @@ class SearchChain(ChainBase):
|
||||
indexer_sites = []
|
||||
|
||||
if not sites:
|
||||
sites = SystemConfigOper().get(SystemConfigKey.IndexerSites) or []
|
||||
sites = get_configured_system_config().get(SystemConfigKey.IndexerSites) or []
|
||||
|
||||
for indexer in await SitesHelper().async_get_indexers():
|
||||
if not indexer.get("subtitles"):
|
||||
@@ -2871,10 +2871,10 @@ class SearchChain(ChainBase):
|
||||
return
|
||||
if site_id == "*":
|
||||
# 清空搜索站点
|
||||
SystemConfigOper().set(SystemConfigKey.IndexerSites, [])
|
||||
get_configured_system_config().set(SystemConfigKey.IndexerSites, [])
|
||||
return
|
||||
# 从选中的rss站点中移除
|
||||
selected_sites = SystemConfigOper().get(SystemConfigKey.IndexerSites) or []
|
||||
selected_sites = get_configured_system_config().get(SystemConfigKey.IndexerSites) or []
|
||||
if site_id in selected_sites:
|
||||
selected_sites.remove(site_id)
|
||||
SystemConfigOper().set(SystemConfigKey.IndexerSites, selected_sites)
|
||||
get_configured_system_config().set(SystemConfigKey.IndexerSites, selected_sites)
|
||||
|
||||
+11
-6
@@ -1,7 +1,7 @@
|
||||
import base64
|
||||
import re
|
||||
from datetime import datetime
|
||||
from typing import Callable, Optional, Tuple, Union, Dict
|
||||
from typing import Any, Callable, Optional, Tuple, Union, Dict
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from app.application.site.sites import SitesHelper # pylint: disable=no-name-in-module
|
||||
@@ -11,9 +11,8 @@ from app.chain import ChainBase
|
||||
from app.chain._interaction import InteractionChainMixin
|
||||
from app.runtime.config import global_vars, settings
|
||||
from app.runtime.events import Event, eventmanager
|
||||
from app.db.models.site import Site
|
||||
from app.db.oper.site import SiteOper
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.application.chain.data import SitePortProxy as SiteOper
|
||||
from app.application.configuration import get_configured_system_config
|
||||
from app.adapters.network.browser import PlaywrightHelper
|
||||
from app.adapters.network.cloudflare import under_challenge
|
||||
from app.application.security.cookie import CookieHelper
|
||||
@@ -32,6 +31,8 @@ from app.foundation import size as size_tools
|
||||
from app.foundation import url as url_tools
|
||||
from app.foundation.dom import DomUtils
|
||||
|
||||
Site = Any
|
||||
|
||||
|
||||
class SiteChain(InteractionChainMixin, ChainBase):
|
||||
"""
|
||||
@@ -640,7 +641,7 @@ class SiteChain(InteractionChainMixin, ChainBase):
|
||||
# 获取主域名中间那段
|
||||
domain_host = url_tools.host_label(domain)
|
||||
# 查询以"site.domain_host"开头的配置项,并清除
|
||||
systemconfig = SystemConfigOper()
|
||||
systemconfig = get_configured_system_config()
|
||||
site_keys = systemconfig.all().keys()
|
||||
for key in site_keys:
|
||||
if key.startswith(f"site.{domain_host}"):
|
||||
@@ -751,7 +752,11 @@ class SiteChain(InteractionChainMixin, ChainBase):
|
||||
|
||||
def _interaction_handler(self) -> "SiteInteractionHandler":
|
||||
"""构造 /sites 交互处理器,Cookie 更新动作由本链提供。"""
|
||||
return SiteInteractionHandler(messenger=self, cookie_updater=self.update_cookie)
|
||||
return SiteInteractionHandler(
|
||||
messenger=self,
|
||||
cookie_updater=self.update_cookie,
|
||||
repository=SiteOper(),
|
||||
)
|
||||
|
||||
def remote_disable(self, arg_str: str, channel: NotificationChannel,
|
||||
userid: Union[str, int] = None, source: Optional[str] = None):
|
||||
|
||||
+59
-16
@@ -33,11 +33,12 @@ from app.domain.meta.metabase import MetaBase
|
||||
from app.domain.meta.metamusic import MetaMusic
|
||||
from app.domain.meta.words import WordsMatcher
|
||||
from app.domain.metainfo import MetaInfo
|
||||
from app.db.oper.downloadhistory import DownloadHistoryOper
|
||||
from app.db.models.subscribe import Subscribe
|
||||
from app.db.oper.site import SiteOper
|
||||
from app.db.oper.subscribe import SubscribeOper
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.application.chain.data import (
|
||||
DownloadHistoryPortProxy as DownloadHistoryOper,
|
||||
SitePortProxy as SiteOper,
|
||||
SubscribePortProxy as SubscribeOper,
|
||||
)
|
||||
from app.application.configuration import get_configured_system_config
|
||||
from app.application.messaging.subscribe import SubscribeInteractionHandler
|
||||
from app.application.mediaserver import MediaServerHelper
|
||||
from app.application.subscribe import add_subscribe, async_add_subscribe
|
||||
@@ -56,6 +57,43 @@ from app.schemas.types import MUSIC_ENTITY_ALBUM, MediaSource, MediaType, System
|
||||
ContentType
|
||||
from app.schemas.media import normalize_media_source, resolve_media_identity
|
||||
|
||||
if hasattr(_SchemaSubscribe, "model_fields"):
|
||||
Subscribe = _SchemaSubscribe
|
||||
else:
|
||||
class Subscribe(_SchemaSubscribe):
|
||||
"""隔离测试或旧插件缺少完整订阅模型时使用的轻量快照。"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""初始化兼容快照并补齐链路必需的运行字段。"""
|
||||
super().__init__(**kwargs)
|
||||
for field, default in {
|
||||
"best_version_full": 0,
|
||||
"current_priority": None,
|
||||
"episode_priority": None,
|
||||
"total_episode": 0,
|
||||
"start_episode": 0,
|
||||
"lack_episode": 0,
|
||||
"note": [],
|
||||
}.items():
|
||||
if not hasattr(self, field):
|
||||
setattr(self, field, default)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""返回快照字段,兼容整理链的响应转换。"""
|
||||
return dict(self.__dict__)
|
||||
|
||||
# 旧测试与第三方扩展可能替换该名字;它现在只是应用配置端口的本地别名,
|
||||
# 不再指向数据库 Oper。
|
||||
SystemConfigOper = get_configured_system_config
|
||||
_DEFAULT_SYSTEM_CONFIG_PROVIDER = get_configured_system_config
|
||||
|
||||
|
||||
def _system_config():
|
||||
"""返回配置端口,并兼容旧测试对本地别名的替换。"""
|
||||
if SystemConfigOper is not _DEFAULT_SYSTEM_CONFIG_PROVIDER:
|
||||
return SystemConfigOper()
|
||||
return get_configured_system_config()
|
||||
|
||||
|
||||
def build_subscribe_meta(subscribe: Subscribe) -> MetaBase:
|
||||
"""兼容旧导入路径,转发订阅媒体元数据构造。"""
|
||||
@@ -1345,10 +1383,10 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
||||
# 优先级过滤规则
|
||||
if subscribe.best_version:
|
||||
rule_groups = subscribe.filter_groups \
|
||||
or SystemConfigOper().get(SystemConfigKey.BestVersionFilterRuleGroups) or []
|
||||
or _system_config().get(SystemConfigKey.BestVersionFilterRuleGroups) or []
|
||||
else:
|
||||
rule_groups = subscribe.filter_groups \
|
||||
or SystemConfigOper().get(SystemConfigKey.SubscribeFilterRuleGroups) or []
|
||||
or _system_config().get(SystemConfigKey.SubscribeFilterRuleGroups) or []
|
||||
|
||||
# 搜索,同时电视剧会过滤掉不需要的剧集
|
||||
contexts = SearchChain().process(mediainfo=mediainfo,
|
||||
@@ -1631,7 +1669,7 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
||||
:return: 涉及的站点清单
|
||||
"""
|
||||
# 从系统配置获取默认订阅站点
|
||||
default_sites = SystemConfigOper().get(SystemConfigKey.RssSites) or []
|
||||
default_sites = _system_config().get(SystemConfigKey.RssSites) or []
|
||||
# 如果订阅未指定站点,直接返回默认站点
|
||||
if not subscribe.sites:
|
||||
return default_sites
|
||||
@@ -1832,7 +1870,7 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
||||
# 遍历预识别后的种子
|
||||
_match_context = []
|
||||
torrenthelper = TorrentHelper()
|
||||
systemconfig = SystemConfigOper()
|
||||
systemconfig = _system_config()
|
||||
wordsmatcher = WordsMatcher()
|
||||
for domain, contexts in processed_torrents.items():
|
||||
if global_vars.is_system_stopped:
|
||||
@@ -2231,7 +2269,7 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
||||
|
||||
:param progress_callback: 定时服务进度更新回调
|
||||
"""
|
||||
follow_users: List[str] = SystemConfigOper().get(SystemConfigKey.FollowSubscribers)
|
||||
follow_users: List[str] = _system_config().get(SystemConfigKey.FollowSubscribers)
|
||||
if not follow_users:
|
||||
if progress_callback:
|
||||
progress_callback(value=100, text="未配置 Follow 订阅用户,跳过刷新")
|
||||
@@ -2835,7 +2873,12 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
||||
|
||||
def _interaction_handler(self) -> "SubscribeInteractionHandler":
|
||||
"""构造 /subscribes 交互处理器,业务动作由本链提供。"""
|
||||
return SubscribeInteractionHandler(messenger=self, actions=self)
|
||||
return SubscribeInteractionHandler(
|
||||
messenger=self,
|
||||
actions=self,
|
||||
repository=SubscribeOper(),
|
||||
report_deleted=MoviePilotServerHelper.sub_done_async,
|
||||
)
|
||||
|
||||
def remote_delete(self, arg_str: str, channel: NotificationChannel,
|
||||
userid: Union[str, int] = None, source: Optional[str] = None):
|
||||
@@ -3012,7 +3055,7 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
||||
subscribeoper = SubscribeOper()
|
||||
if site_id == "*":
|
||||
# 站点被重置
|
||||
SystemConfigOper().set(SystemConfigKey.RssSites, [])
|
||||
_system_config().set(SystemConfigKey.RssSites, [])
|
||||
for subscribe in subscribeoper.list():
|
||||
if not subscribe.sites:
|
||||
continue
|
||||
@@ -3021,10 +3064,10 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
||||
})
|
||||
return
|
||||
# 从选中的rss站点中移除
|
||||
selected_sites = SystemConfigOper().get(SystemConfigKey.RssSites) or []
|
||||
selected_sites = _system_config().get(SystemConfigKey.RssSites) or []
|
||||
if site_id in selected_sites:
|
||||
selected_sites.remove(site_id)
|
||||
SystemConfigOper().set(SystemConfigKey.RssSites, selected_sites)
|
||||
_system_config().set(SystemConfigKey.RssSites, selected_sites)
|
||||
# 查询所有订阅
|
||||
for subscribe in subscribeoper.list():
|
||||
if not subscribe.sites:
|
||||
@@ -3057,7 +3100,7 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
||||
if hasattr(settings, default_subscribe_key):
|
||||
value = getattr(settings, default_subscribe_key)
|
||||
else:
|
||||
value = SystemConfigOper().get(default_subscribe_key)
|
||||
value = _system_config().get(default_subscribe_key)
|
||||
|
||||
if not value:
|
||||
return None
|
||||
@@ -3069,7 +3112,7 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
|
||||
获取订阅默认参数
|
||||
"""
|
||||
# 默认过滤规则
|
||||
default_rule = SystemConfigOper().get(SystemConfigKey.SubscribeDefaultParams) or {}
|
||||
default_rule = _system_config().get(SystemConfigKey.SubscribeDefaultParams) or {}
|
||||
return {
|
||||
key: value for key, value in {
|
||||
"include": subscribe.include or default_rule.get("include"),
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ from typing import Union, Optional
|
||||
|
||||
from app.chain import ChainBase
|
||||
from app.runtime.config import settings
|
||||
from app.runtime.extensions.plugin_manager import PluginManager
|
||||
from app.application.plugin.runtime import get_plugin_manager
|
||||
from app.runtime.state import SystemHelper
|
||||
from app.runtime.log import logger
|
||||
from app.schemas.message import Message
|
||||
@@ -154,7 +154,7 @@ class SystemChain(ChainBase):
|
||||
logger.info(f"插件恢复完成,共恢复 {restored_count} 个项目")
|
||||
|
||||
# 安装缺少的依赖
|
||||
PluginManager.install_plugin_missing_dependencies()
|
||||
get_plugin_manager().install_plugin_missing_dependencies()
|
||||
|
||||
# 删除备份目录
|
||||
try:
|
||||
|
||||
@@ -12,8 +12,8 @@ from app.domain.context import TorrentInfo, Context, MediaInfo
|
||||
from app.domain.context import MusicInfo
|
||||
from app.domain.meta.metamusic import MetaMusic
|
||||
from app.domain.metainfo import MetaInfo
|
||||
from app.db.oper.site import SiteOper
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.application.chain.data import SitePortProxy as SiteOper
|
||||
from app.application.configuration import get_configured_system_config
|
||||
from app.application.rss import RssHelper
|
||||
from app.application.torrent import TorrentHelper
|
||||
from app.runtime.log import logger
|
||||
@@ -556,7 +556,7 @@ class TorrentsChain(ChainBase):
|
||||
|
||||
# 刷新站点
|
||||
if not sites:
|
||||
sites = SystemConfigOper().get(SystemConfigKey.RssSites) or []
|
||||
sites = get_configured_system_config().get(SystemConfigKey.RssSites) or []
|
||||
|
||||
# 读取缓存,影视与音乐分别独立存储
|
||||
if stype == 'spider':
|
||||
|
||||
+17
-9
@@ -18,11 +18,13 @@ from app.runtime.events import eventmanager
|
||||
from app.domain.meta.metabase import MetaBase
|
||||
from app.domain.meta.metamusic import MetaMusic
|
||||
from app.domain.metainfo import MetaInfoPath
|
||||
from app.db.oper.downloadhistory import DownloadHistoryOper
|
||||
from app.db.models.downloadhistory import DownloadHistory
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.db.oper.transferpending import TransferPendingOper
|
||||
from app.db.oper.transferhistory import TransferHistoryOper
|
||||
from app.application.chain.data import (
|
||||
DownloadHistoryPortProxy as DownloadHistoryOper,
|
||||
TransferPendingPortProxy as TransferPendingOper,
|
||||
TransferHistoryPortProxy as TransferHistoryOper,
|
||||
)
|
||||
DownloadHistory = Any
|
||||
from app.application.configuration import get_configured_system_config
|
||||
from app.application.directory import DirectoryHelper
|
||||
from app.application.formatting import FormatParser
|
||||
from app.runtime.progress import ProgressHelper
|
||||
@@ -53,8 +55,14 @@ from app.schemas.types import (
|
||||
MediaSource,
|
||||
)
|
||||
from app.runtime.reload import ConfigReloadMixin
|
||||
from app.application.transfer import (FailedRetryScheduler, JobManager,
|
||||
TransferQueueService, TransferTask, job_lock)
|
||||
from app.application.transfer import (
|
||||
FailedRetryScheduler,
|
||||
JobManager,
|
||||
TransferQueue,
|
||||
TransferQueueService,
|
||||
TransferTask,
|
||||
job_lock,
|
||||
)
|
||||
from app.chain._transfer import (EpisodeFormatMixin, FailedRetryMixin,
|
||||
FileFilterMixin, FileKeyMixin,
|
||||
HistoryMatchMixin, ManualHistoryMixin,
|
||||
@@ -437,7 +445,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
||||
tasks = self.jobview.success_tasks(
|
||||
task.mediainfo, task.meta.begin_season
|
||||
)
|
||||
system_config_oper = SystemConfigOper()
|
||||
system_config_oper = get_configured_system_config()
|
||||
# 获取整理屏蔽词
|
||||
transfer_exclude_words = system_config_oper.get(
|
||||
SystemConfigKey.TransferExcludeWords
|
||||
@@ -1579,7 +1587,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
||||
)
|
||||
|
||||
# 整理屏蔽词
|
||||
transfer_exclude_words = SystemConfigOper().get(
|
||||
transfer_exclude_words = get_configured_system_config().get(
|
||||
SystemConfigKey.TransferExcludeWords
|
||||
)
|
||||
# 汇总错误信息
|
||||
|
||||
+4
-4
@@ -1,12 +1,11 @@
|
||||
import secrets
|
||||
from dataclasses import dataclass
|
||||
from typing import Literal, Optional, Tuple, Union
|
||||
from typing import Any, Literal, Optional, Tuple, Union
|
||||
|
||||
from app.chain import ChainBase
|
||||
from app.runtime.config import settings
|
||||
from app.application.security.access import get_password_hash, verify_password
|
||||
from app.db.models.user import User
|
||||
from app.db.oper.user import UserOper
|
||||
from app.application.security.token import get_password_hash, verify_password
|
||||
from app.application.chain.data import UserPortProxy as UserOper
|
||||
from app.runtime.log import logger
|
||||
from app.schemas.event import AuthCredentials
|
||||
from app.schemas.event import AuthInterceptCredentials
|
||||
@@ -14,6 +13,7 @@ from app.schemas.types import ChainEventType
|
||||
from app.application.security.otp import OtpUtils
|
||||
|
||||
PASSWORD_INVALID_CREDENTIALS_MESSAGE = "用户名、密码或验证码错误"
|
||||
User = Any
|
||||
|
||||
|
||||
MfaMethod = Literal["otp"]
|
||||
|
||||
@@ -15,8 +15,7 @@ from pydantic import BaseModel
|
||||
from app.chain import ChainBase
|
||||
from app.runtime.config import global_vars
|
||||
from app.runtime.events import Event, eventmanager
|
||||
from app.db.models import Workflow
|
||||
from app.db.oper.workflow import WorkflowOper
|
||||
from app.application.chain.data import WorkflowPortProxy as WorkflowOper
|
||||
from app.runtime.log import logger
|
||||
from app.schemas.workflow import ActionContext
|
||||
from app.schemas.workflow import ActionFlow
|
||||
@@ -29,6 +28,7 @@ from app.workflow import WorkFlowManager
|
||||
ARTIFACT_FIELDS = {"torrents", "medias", "fileitems", "downloads", "sites", "subscribes"}
|
||||
DEFAULT_WORKFLOW_MAX_WORKERS = 4
|
||||
CIRCULAR_REFERENCE_PLACEHOLDER = "[Circular]"
|
||||
Workflow = Any
|
||||
|
||||
|
||||
def _serialize_workflow_key(key: Any) -> Any:
|
||||
|
||||
Reference in New Issue
Block a user