mirror of
https://github.com/jxxghp/MoviePilot-Plugins.git
synced 2026-05-24 23:16:49 +00:00
- 数据模型重构: 全面引入 Pydantic 模型(ClashConfig, Proxy, ProxyGroup 等)替代原有字典结构,提供更严格的数据验证与类型安全。 - 数据迁移机制: 新增 v2.1.0 数据升级脚本,支持将旧版代理、策略组及规则数据自动迁移至新架构。 - 配置补丁系统: 实现基于 JSON Patch 的细粒度配置修补机制,替代旧版覆盖逻辑,提升配置修改的灵活性。 - 服务层优化: 重写 ClashRuleProviderService 以适配新对象模型,增强代码可维护性与扩展性。 - API模型同步: 更新相关 API 数据模型以保持与内部数据结构的一致性。 - 用户界面: 批量规则管理和数据项隐藏支持
91 lines
3.1 KiB
Python
91 lines
3.1 KiB
Python
from typing import List, Optional
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
|
|
from .models.api import ClashApi
|
|
|
|
|
|
class SubscriptionConfig(BaseModel):
|
|
url: str
|
|
rules: Optional[bool] = True
|
|
rule_providers: Optional[bool] = Field(default=True, alias='rule-providers')
|
|
proxies: Optional[bool] = True
|
|
proxy_groups: Optional[bool] = Field(default=True, alias='proxy-groups')
|
|
proxy_providers: Optional[bool] = Field(default=True, alias='proxy-providers')
|
|
|
|
@field_validator('url')
|
|
@classmethod
|
|
def validate_url(cls, v: str) -> str:
|
|
return v.strip()
|
|
|
|
|
|
class PluginConfig(BaseModel):
|
|
"""
|
|
A dataclass to hold all the configuration of the ClashRuleProvider plugin.
|
|
"""
|
|
model_config = ConfigDict(
|
|
str_strip_whitespace=True,
|
|
)
|
|
|
|
enabled: bool = False
|
|
proxy: bool = False
|
|
notify: bool = False
|
|
subscriptions_config: list[SubscriptionConfig] = Field(default_factory=list)
|
|
movie_pilot_url: str = ''
|
|
cron_string: str = '30 12 * * *'
|
|
timeout: int = 10
|
|
retry_times: int = 3
|
|
filter_keywords: List[str] = Field(default_factory=list)
|
|
auto_update_subscriptions: bool = True
|
|
ruleset_prefix: str = '📂<='
|
|
acl4ssr_prefix: str = '🗂️=>'
|
|
group_by_region: bool = False
|
|
group_by_country: bool = False
|
|
refresh_delay: int = 5
|
|
enable_acl4ssr: bool = False
|
|
dashboard_components: List[str] = Field(default_factory=list)
|
|
clash_template: str = ''
|
|
hint_geo_dat: bool = False
|
|
best_cf_ip: List[str] = Field(default_factory=list)
|
|
apikey: Optional[str] = None
|
|
clash_dashboards: List[ClashApi] = Field(default_factory=list)
|
|
active_dashboard: Optional[int] = None
|
|
identifiers: list[str] = Field(default_factory=list)
|
|
cache_ttl: int = 3600
|
|
|
|
@field_validator('clash_dashboards')
|
|
@classmethod
|
|
def validate_clash_dashboards(cls, v: List[ClashApi]):
|
|
for item in v:
|
|
url = item.url.rstrip('/')
|
|
if not (url.startswith('http://') or url.startswith('https://')):
|
|
url = 'http://' + url
|
|
item.url = url
|
|
return v
|
|
|
|
@field_validator('movie_pilot_url')
|
|
@classmethod
|
|
def validate_movie_pilot_url(cls, v: str):
|
|
return v.rstrip('/')
|
|
|
|
@property
|
|
def sub_links(self) -> List[str]:
|
|
return [sub.url for sub in self.subscriptions_config]
|
|
|
|
@property
|
|
def dashboard_url(self) -> str:
|
|
dashboard_url = ''
|
|
if self.active_dashboard is not None and self.active_dashboard in range(len(self.clash_dashboards)):
|
|
dashboard_url = self.clash_dashboards[self.active_dashboard].url
|
|
return dashboard_url
|
|
|
|
@property
|
|
def dashboard_secret(self) -> str:
|
|
dashboard_secret = ''
|
|
if self.active_dashboard is not None and self.active_dashboard in range(len(self.clash_dashboards)):
|
|
dashboard_secret = self.clash_dashboards[self.active_dashboard].secret
|
|
return dashboard_secret
|
|
|
|
def get_sub_conf(self, url: str) -> SubscriptionConfig:
|
|
return next((conf for conf in self.subscriptions_config if conf.url == url), SubscriptionConfig(url=url))
|