mirror of
https://github.com/d0zingcat/MoviePilot-Plugins.git
synced 2026-05-13 15:09:12 +00:00
Merge pull request #834 from wumode/clashruleprovider
This commit is contained in:
@@ -434,11 +434,12 @@
|
||||
"name": "IMDb源",
|
||||
"description": "让探索和推荐支持IMDb数据源。",
|
||||
"labels": "探索",
|
||||
"version": "1.4.2",
|
||||
"version": "1.4.3",
|
||||
"icon": "IMDb_IOS-OSX_App.png",
|
||||
"author": "wumode",
|
||||
"level": 1,
|
||||
"history": {
|
||||
"v1.4.3": "为仪表盘组件添加缓存",
|
||||
"v1.4.2": "优化小屏幕组件显示",
|
||||
"v1.4.1": "优化亮色主题显示",
|
||||
"v1.4.0":"添加仪表盘组件: IMDb 编辑精选",
|
||||
@@ -455,11 +456,12 @@
|
||||
"name": "Clash Rule Provider",
|
||||
"description": "随时为Clash添加一些额外的规则。",
|
||||
"labels": "工具",
|
||||
"version": "1.2.3",
|
||||
"version": "1.2.4",
|
||||
"icon": "Mihomo_Meta_A.png",
|
||||
"author": "wumode",
|
||||
"level": 1,
|
||||
"history": {
|
||||
"v1.2.4": "支持geo规则补全; 代理组编辑",
|
||||
"v1.2.3": "修复规则集名称错误",
|
||||
"v1.2.2": "展示更多信息; 修复交互问题",
|
||||
"v1.2.1": "修复配置模板错误",
|
||||
|
||||
@@ -26,9 +26,9 @@ from app.log import logger
|
||||
from app.plugins import _PluginBase
|
||||
from app.schemas.types import NotificationType
|
||||
from app.utils.http import RequestUtils
|
||||
from app.plugins.clashruleprovider.clash_rule_parser import ClashRuleParser, Converter
|
||||
from app.plugins.clashruleprovider.clash_rule_parser import Action, RuleType, ClashRule, MatchRule, LogicRule
|
||||
from app.plugins.clashruleprovider.clash_rule_parser import ProxyGroup, RuleProvider
|
||||
from app.plugins.clashruleprovider.clashruleparser import ClashRuleParser, Converter
|
||||
from app.plugins.clashruleprovider.clashruleparser import Action, RuleType, ClashRule, MatchRule, LogicRule
|
||||
from app.plugins.clashruleprovider.clashruleparser import ProxyGroup, RuleProvider
|
||||
|
||||
|
||||
class ClashRuleProvider(_PluginBase):
|
||||
@@ -39,7 +39,7 @@ class ClashRuleProvider(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "Mihomo_Meta_A.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.2.3"
|
||||
plugin_version = "1.2.4"
|
||||
# 插件作者
|
||||
plugin_author = "wumode"
|
||||
# 作者主页
|
||||
@@ -75,10 +75,10 @@ class ClashRuleProvider(_PluginBase):
|
||||
_discard_rules: bool = False
|
||||
_enable_acl4ssr: bool = False
|
||||
_dashboard_components: List[str] = []
|
||||
_clash_template_yaml = ''
|
||||
_clash_template_yaml: str = ''
|
||||
_hint_geo_dat: bool = False
|
||||
|
||||
# 插件数据
|
||||
# 综合多个订阅的配置
|
||||
_top_rules: List[str] = []
|
||||
_ruleset_rules: List[str] = []
|
||||
_rule_provider: Dict[str, Any] = {}
|
||||
@@ -98,6 +98,7 @@ class ClashRuleProvider(_PluginBase):
|
||||
_clash_template: Optional[Dict[str, Any]] = None
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
_countries: Optional[List[Dict[str, str]]] = None
|
||||
_geo_rules: Dict[str, List[str]] = {'geoip': [], 'geosite': []}
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
self._ruleset_rules = self.get_data("ruleset_rules")
|
||||
@@ -138,6 +139,7 @@ class ClashRuleProvider(_PluginBase):
|
||||
self._enable_acl4ssr = config.get("enable_acl4ssr") or False
|
||||
self._dashboard_components = config.get("dashboard_components") or []
|
||||
self._clash_template_yaml = config.get("clash_template") or ''
|
||||
self._hint_geo_dat = config.get("hint_geo_dat", False)
|
||||
self._clash_rule_parser = ClashRuleParser()
|
||||
self._ruleset_rule_parser = ClashRuleParser()
|
||||
self._clash_template = {}
|
||||
@@ -168,10 +170,15 @@ class ClashRuleProvider(_PluginBase):
|
||||
# 更新订阅
|
||||
self._scheduler.add_job(self.refresh_subscriptions, "date",
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=2))
|
||||
if self._hint_geo_dat:
|
||||
self._scheduler.add_job(self.__refresh_geo_dat, "date",
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3))
|
||||
else:
|
||||
self._geo_rules = {'geoip': [], 'geosite': []}
|
||||
# 更新acl4ssr
|
||||
if self._enable_acl4ssr:
|
||||
self._scheduler.add_job(self.__refresh_acl4ssr, "date",
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=5))
|
||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=4))
|
||||
else:
|
||||
self._acl4ssr_providers = {}
|
||||
|
||||
@@ -337,6 +344,14 @@ class ClashRuleProvider(_PluginBase):
|
||||
"summary": "添加一个代理组",
|
||||
"description": "添加一个代理组"
|
||||
},
|
||||
{
|
||||
"path": "/proxy-group",
|
||||
"endpoint": self.update_proxy_group,
|
||||
"methods": ["PUT"],
|
||||
"auth": "bear",
|
||||
"summary": "更新一个代理组",
|
||||
"description": "更新一个代理组"
|
||||
},
|
||||
{
|
||||
"path": "/ruleset",
|
||||
"endpoint": self.get_ruleset,
|
||||
@@ -570,6 +585,7 @@ class ClashRuleProvider(_PluginBase):
|
||||
"data": {"state": self._enabled,
|
||||
"ruleset_prefix": self._ruleset_prefix,
|
||||
"clash": {"rule_size": rule_size},
|
||||
"geoRules": self._geo_rules,
|
||||
"subscription_info": self._subscription_info,
|
||||
"sub_url": f"{self._movie_pilot_url}/api/v1/plugin/ClashRuleProvider/config?"
|
||||
f"apikey={settings.API_TOKEN}"}}
|
||||
@@ -604,7 +620,7 @@ class ClashRuleProvider(_PluginBase):
|
||||
res = self.delete_rule_by_priority(params.get('priority'), self._ruleset_rule_parser)
|
||||
if res:
|
||||
self.__add_notification_job(
|
||||
f"{self._ruleset_prefix}{res.action.value if isinstance(res.action, Action) else res.action}")
|
||||
[f"{self._ruleset_prefix}{res.action.value if isinstance(res.action, Action) else res.action}",])
|
||||
else:
|
||||
self.delete_rule_by_priority(params.get('priority'), self._clash_rule_parser)
|
||||
return schemas.Response(success=True, message='')
|
||||
@@ -632,7 +648,7 @@ class ClashRuleProvider(_PluginBase):
|
||||
try:
|
||||
if params.get('type') == 'ruleset':
|
||||
self.__reorder_rules(self._ruleset_rule_parser, moved_priority, target_priority)
|
||||
self.__add_notification_job(f"{self._ruleset_prefix}{params.get('rule_data').get('action')}")
|
||||
self.__add_notification_job([f"{self._ruleset_prefix}{params.get('rule_data').get('action')}"])
|
||||
else:
|
||||
self.__reorder_rules(self._clash_rule_parser, moved_priority, target_priority)
|
||||
except Exception as e:
|
||||
@@ -652,11 +668,15 @@ class ClashRuleProvider(_PluginBase):
|
||||
if not self._enabled:
|
||||
return {"success": False, "message": ""}
|
||||
if params.get('type') == 'ruleset':
|
||||
original_rule = self._ruleset_rule_parser.get_rule_at_priority(params.get('priority'))
|
||||
res = self.update_rule_by_priority(params.get('rule_data'),
|
||||
params.get('priority'),
|
||||
self._ruleset_rule_parser)
|
||||
if res:
|
||||
self.__add_notification_job(f"{self._ruleset_prefix}{params.get('rule_data').get('action')}")
|
||||
ruleset_to_notify = [f"{self._ruleset_prefix}{params.get('rule_data').get('action')}"]
|
||||
if params.get('rule_data').get('action') != original_rule.action:
|
||||
ruleset_to_notify.append(f"{self._ruleset_prefix}{original_rule.action}")
|
||||
self.__add_notification_job(ruleset_to_notify)
|
||||
else:
|
||||
res = self.update_rule_by_priority(params.get('rule_data'), params.get('priority'), self._clash_rule_parser)
|
||||
return {"success": bool(res), "message": None}
|
||||
@@ -667,7 +687,7 @@ class ClashRuleProvider(_PluginBase):
|
||||
if params.get('type') == 'ruleset':
|
||||
res = self.add_rule_by_priority(params.get('rule_data'), self._ruleset_rule_parser)
|
||||
if res:
|
||||
self.__add_notification_job(f"{self._ruleset_prefix}{params.get('rule_data').get('action')}")
|
||||
self.__add_notification_job([f"{self._ruleset_prefix}{params.get('rule_data').get('action')}",])
|
||||
else:
|
||||
res = self.add_rule_by_priority(params.get('rule_data'), self._clash_rule_parser)
|
||||
return schemas.Response(success=bool(res), message='')
|
||||
@@ -844,6 +864,37 @@ class ClashRuleProvider(_PluginBase):
|
||||
self.save_data('proxy_groups', self._proxy_groups)
|
||||
return schemas.Response(success=True)
|
||||
|
||||
def update_proxy_group(self, params: Dict[str, Any]) -> schemas.Response:
|
||||
if not self._enabled:
|
||||
return schemas.Response(success=False, message='')
|
||||
proxy_group = params.get('proxy_group', {})
|
||||
name = params.get('name')
|
||||
if not name or not proxy_group:
|
||||
return schemas.Response(success=False, message='Invalid params')
|
||||
try:
|
||||
ProxyGroup.parse_obj(proxy_group)
|
||||
except Exception as e:
|
||||
error_message = f"Failed to parse proxy group: Invalid data={proxy_group}, error={repr(e)}"
|
||||
logger.error(error_message)
|
||||
return schemas.Response(success=False, message=str(error_message))
|
||||
index = next((i for i, x in enumerate(self._proxy_groups) if x.get('name') == name), None)
|
||||
# whether new name exists
|
||||
new_name_index = next((i for i, x in enumerate(self._proxy_groups) if x.get('name') == proxy_group.get('name')),
|
||||
None
|
||||
)
|
||||
if new_name_index and new_name_index != index:
|
||||
return schemas.Response(success=False,
|
||||
message=f"The proxy group name {proxy_group.get('name')} already exists")
|
||||
new_item = {}
|
||||
for k, v in proxy_group.items():
|
||||
if v == '':
|
||||
continue
|
||||
if v is None:
|
||||
continue
|
||||
new_item[k] = v
|
||||
self._proxy_groups[index] = new_item
|
||||
return schemas.Response(success=True)
|
||||
|
||||
def delete_proxy_group(self, params: dict = Body(...)) -> schemas.Response:
|
||||
if not self._enabled:
|
||||
return schemas.Response(success=False, message='')
|
||||
@@ -1015,7 +1066,7 @@ class ClashRuleProvider(_PluginBase):
|
||||
)
|
||||
|
||||
def __refresh_acl4ssr(self):
|
||||
logger.info(f"Refreshing ACL4SSR")
|
||||
logger.info(f"Refreshing ACL4SSR ...")
|
||||
# 配置参数
|
||||
owner = 'ACL4SSR'
|
||||
repo = 'ACL4SSR'
|
||||
@@ -1038,6 +1089,26 @@ class ClashRuleProvider(_PluginBase):
|
||||
self._acl4ssr_providers[name] = provider
|
||||
self.save_data('acl4ssr_providers', self._acl4ssr_providers)
|
||||
|
||||
def __refresh_geo_dat(self):
|
||||
logger.info(f"Refreshing Geo Rules ...")
|
||||
owner = 'MetaCubeX'
|
||||
repo = 'meta-rules-dat'
|
||||
branch = 'meta'
|
||||
api_url = f"https://api.github.com/repos/{owner}/{repo}/contents/geo"
|
||||
resp = RequestUtils().get_res(api_url, headers=settings.GITHUB_HEADERS, params={'ref': branch})
|
||||
for path in resp.json():
|
||||
if path["type"] == "dir" and path["name"] in self._geo_rules:
|
||||
tree_sha = path["sha"]
|
||||
url = f"https://api.github.com/repos/{owner}/{repo}/git/trees/{tree_sha}"
|
||||
res = RequestUtils().get_res(url, headers=settings.GITHUB_HEADERS, params={'ref': branch})
|
||||
if not res:
|
||||
continue
|
||||
tree = res.json()
|
||||
yaml_files = [item["path"][:item["path"].rfind('.')] for item in tree["tree"] if
|
||||
item["type"] == "blob" and item['path'].endswith((".yaml", ".yml"))]
|
||||
self._geo_rules[path["name"]] = yaml_files
|
||||
print(len(self._geo_rules['geosite']))
|
||||
|
||||
def refresh_subscriptions(self) -> Dict[str, bool]:
|
||||
"""
|
||||
更新全部订阅链接
|
||||
@@ -1157,15 +1228,16 @@ class ClashRuleProvider(_PluginBase):
|
||||
return continents_names[country['continent']]
|
||||
return None
|
||||
|
||||
def __add_notification_job(self, ruleset: str):
|
||||
if ruleset in self._rule_provider:
|
||||
self._scheduler.add_job(self.notify_clash, "date",
|
||||
run_date=datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + timedelta(seconds=self._refresh_delay),
|
||||
args=[ruleset],
|
||||
id='CRP-notify-clash',
|
||||
replace_existing=True
|
||||
)
|
||||
def __add_notification_job(self, ruleset_names: List[str]):
|
||||
for ruleset in ruleset_names:
|
||||
if ruleset in self._rule_provider:
|
||||
self._scheduler.add_job(self.notify_clash, "date",
|
||||
run_date=datetime.now(
|
||||
tz=pytz.timezone(settings.TZ)) + timedelta(seconds=self._refresh_delay),
|
||||
args=[ruleset],
|
||||
id=f'CRP-notify-clash{ruleset}',
|
||||
replace_existing=True
|
||||
)
|
||||
|
||||
def __remove_nodes_by_keywords(self, clash_config: Dict[str, Any]) -> Dict[str, Any]:
|
||||
removed_proxies = []
|
||||
|
||||
@@ -141,6 +141,11 @@ ProxyGroupUnion = Union[SelectGroup, RelayGroup, FallbackGroup, UrlTestGroup, Lo
|
||||
class ProxyGroup(BaseModel):
|
||||
__root__: ProxyGroupUnion
|
||||
|
||||
class AdditionalParam(Enum):
|
||||
NO_RESOLVE = 'no-resolve'
|
||||
SRC = 'src'
|
||||
|
||||
|
||||
class RuleType(Enum):
|
||||
"""Enumeration of all supported Clash rule types"""
|
||||
DOMAIN = "DOMAIN"
|
||||
@@ -201,14 +206,10 @@ class ClashRule:
|
||||
rule_type: RuleType
|
||||
payload: str
|
||||
action: Union[Action, str] # Can be Action enum or custom proxy group name
|
||||
additional_params: Optional[List[str]] = None
|
||||
additional_params: Optional[AdditionalParam] = None
|
||||
raw_rule: str = ""
|
||||
priority: int = 0
|
||||
|
||||
def __post_init__(self):
|
||||
if self.additional_params is None:
|
||||
self.additional_params = []
|
||||
|
||||
def condition_string(self) -> str:
|
||||
return f"{self.rule_type.value},{self.payload}"
|
||||
|
||||
@@ -282,6 +283,8 @@ class ClashRuleParser:
|
||||
rule = ClashRuleParser._parse_match_rule(raw_rule)
|
||||
else:
|
||||
raw_rule = f"{clash_rule.get('type')},{clash_rule.get('payload')},{clash_rule.get('action')}"
|
||||
if clash_rule.get('additional_params'):
|
||||
raw_rule += f",{clash_rule.get('additional_params')}"
|
||||
rule = ClashRuleParser._parse_regular_rule(raw_rule)
|
||||
if rule and 'priority' in clash_rule:
|
||||
rule.priority = clash_rule['priority']
|
||||
@@ -310,7 +313,7 @@ class ClashRuleParser:
|
||||
"""Parse a regular (non-logic) rule"""
|
||||
parts = line.split(',')
|
||||
|
||||
if len(parts) < 3:
|
||||
if len(parts) < 3 or len(parts) > 4:
|
||||
raise ValueError(f"Invalid rule format: {line}")
|
||||
|
||||
rule_type_str = parts[0].upper()
|
||||
@@ -320,7 +323,7 @@ class ClashRuleParser:
|
||||
if not payload or not rule_type_str:
|
||||
raise ValueError(f"Invalid rule format: {line}")
|
||||
|
||||
additional_params = parts[3:] if len(parts) > 3 else []
|
||||
additional_params = parts[3] if len(parts) > 3 else None
|
||||
|
||||
# Validate rule type
|
||||
try:
|
||||
@@ -543,6 +546,12 @@ class ClashRuleParser:
|
||||
self.insert_rule_at_priority(clash_rule, clash_rule.priority)
|
||||
return True
|
||||
|
||||
def get_rule_at_priority(self, priority: int) -> Optional[Union[ClashRule, LogicRule, MatchRule]]:
|
||||
for rule in self.rules:
|
||||
if rule.priority == priority:
|
||||
return rule
|
||||
return None
|
||||
|
||||
def remove_rule_at_priority(self, priority: int) -> Optional[Union[ClashRule, LogicRule, MatchRule]]:
|
||||
"""Remove rule at specific priority and adjust remaining priorities"""
|
||||
rule_to_remove = None
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
.plugin-config[data-v-106fe9f8] {
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -74,7 +74,8 @@ const defaultConfig = {
|
||||
discard_rules: false,
|
||||
enable_acl4ssr: false,
|
||||
dashboard_components: [],
|
||||
clash_template: ''
|
||||
clash_template: '',
|
||||
hint_geo_dat: false,
|
||||
};
|
||||
|
||||
// 响应式配置对象
|
||||
@@ -271,7 +272,7 @@ return (_ctx, _cache) => {
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { left: "" }, {
|
||||
default: _withCtx(() => _cache[27] || (_cache[27] = [
|
||||
default: _withCtx(() => _cache[28] || (_cache[28] = [
|
||||
_createTextVNode("mdi-close")
|
||||
])),
|
||||
_: 1
|
||||
@@ -282,7 +283,7 @@ return (_ctx, _cache) => {
|
||||
]),
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_card_title, null, {
|
||||
default: _withCtx(() => _cache[26] || (_cache[26] = [
|
||||
default: _withCtx(() => _cache[27] || (_cache[27] = [
|
||||
_createTextVNode("Clash Rule Provider 插件配置")
|
||||
])),
|
||||
_: 1
|
||||
@@ -308,11 +309,11 @@ return (_ctx, _cache) => {
|
||||
ref_key: "form",
|
||||
ref: form,
|
||||
modelValue: isFormValid.value,
|
||||
"onUpdate:modelValue": _cache[20] || (_cache[20] = $event => ((isFormValid).value = $event)),
|
||||
"onUpdate:modelValue": _cache[21] || (_cache[21] = $event => ((isFormValid).value = $event)),
|
||||
onSubmit: _withModifiers(saveConfig, ["prevent"])
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_cache[41] || (_cache[41] = _createElementVNode("div", { class: "text-subtitle-1 font-weight-bold mt-4 mb-2" }, "基本设置", -1)),
|
||||
_cache[42] || (_cache[42] = _createElementVNode("div", { class: "text-subtitle-1 font-weight-bold mt-4 mb-2" }, "基本设置", -1)),
|
||||
_createVNode(_component_v_row, null, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_col, {
|
||||
@@ -386,7 +387,7 @@ return (_ctx, _cache) => {
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
_cache[42] || (_cache[42] = _createElementVNode("div", { class: "text-subtitle-1 font-weight-bold mt-4 mb-2" }, "订阅配置", -1)),
|
||||
_cache[43] || (_cache[43] = _createElementVNode("div", { class: "text-subtitle-1 font-weight-bold mt-4 mb-2" }, "订阅配置", -1)),
|
||||
_createVNode(_component_v_row, null, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_col, { cols: "12" }, {
|
||||
@@ -450,7 +451,7 @@ return (_ctx, _cache) => {
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
_cache[43] || (_cache[43] = _createElementVNode("div", { class: "text-subtitle-1 font-weight-bold mt-4 mb-2" }, "Clash 面板设置", -1)),
|
||||
_cache[44] || (_cache[44] = _createElementVNode("div", { class: "text-subtitle-1 font-weight-bold mt-4 mb-2" }, "Clash 面板设置", -1)),
|
||||
_createVNode(_component_v_row, null, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_col, { cols: "12" }, {
|
||||
@@ -466,7 +467,7 @@ return (_ctx, _cache) => {
|
||||
}, {
|
||||
"prepend-inner": _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { color: "primary" }, {
|
||||
default: _withCtx(() => _cache[28] || (_cache[28] = [
|
||||
default: _withCtx(() => _cache[29] || (_cache[29] = [
|
||||
_createTextVNode("mdi-web")
|
||||
])),
|
||||
_: 1
|
||||
@@ -495,7 +496,7 @@ return (_ctx, _cache) => {
|
||||
}, {
|
||||
"prepend-inner": _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { color: "warning" }, {
|
||||
default: _withCtx(() => _cache[29] || (_cache[29] = [
|
||||
default: _withCtx(() => _cache[30] || (_cache[30] = [
|
||||
_createTextVNode("mdi-key")
|
||||
])),
|
||||
_: 1
|
||||
@@ -525,7 +526,7 @@ return (_ctx, _cache) => {
|
||||
}, {
|
||||
"prepend-inner": _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { color: "info" }, {
|
||||
default: _withCtx(() => _cache[30] || (_cache[30] = [
|
||||
default: _withCtx(() => _cache[31] || (_cache[31] = [
|
||||
_createTextVNode("mdi-view-dashboard")
|
||||
])),
|
||||
_: 1
|
||||
@@ -539,7 +540,7 @@ return (_ctx, _cache) => {
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
_cache[44] || (_cache[44] = _createElementVNode("div", { class: "text-subtitle-1 font-weight-bold mt-4 mb-2" }, "MoviePilot 设置", -1)),
|
||||
_cache[45] || (_cache[45] = _createElementVNode("div", { class: "text-subtitle-1 font-weight-bold mt-4 mb-2" }, "MoviePilot 设置", -1)),
|
||||
_createVNode(_component_v_row, null, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_col, { cols: "12" }, {
|
||||
@@ -555,7 +556,7 @@ return (_ctx, _cache) => {
|
||||
}, {
|
||||
"prepend-inner": _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { color: "success" }, {
|
||||
default: _withCtx(() => _cache[31] || (_cache[31] = [
|
||||
default: _withCtx(() => _cache[32] || (_cache[32] = [
|
||||
_createTextVNode("mdi-movie")
|
||||
])),
|
||||
_: 1
|
||||
@@ -569,7 +570,7 @@ return (_ctx, _cache) => {
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
_cache[45] || (_cache[45] = _createElementVNode("div", { class: "text-subtitle-1 font-weight-bold mt-4 mb-2" }, "执行设置", -1)),
|
||||
_cache[46] || (_cache[46] = _createElementVNode("div", { class: "text-subtitle-1 font-weight-bold mt-4 mb-2" }, "执行设置", -1)),
|
||||
_createVNode(_component_v_row, null, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_col, { cols: "12" }, {
|
||||
@@ -583,7 +584,7 @@ return (_ctx, _cache) => {
|
||||
}, {
|
||||
"prepend-inner": _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { color: "info" }, {
|
||||
default: _withCtx(() => _cache[32] || (_cache[32] = [
|
||||
default: _withCtx(() => _cache[33] || (_cache[33] = [
|
||||
_createTextVNode("mdi-clock-time-four-outline")
|
||||
])),
|
||||
_: 1
|
||||
@@ -634,7 +635,7 @@ return (_ctx, _cache) => {
|
||||
}, {
|
||||
"prepend-inner": _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { color: "info" }, {
|
||||
default: _withCtx(() => _cache[33] || (_cache[33] = [
|
||||
default: _withCtx(() => _cache[34] || (_cache[34] = [
|
||||
_createTextVNode("mdi-refresh")
|
||||
])),
|
||||
_: 1
|
||||
@@ -658,12 +659,12 @@ return (_ctx, _cache) => {
|
||||
_createVNode(_component_v_expansion_panel_title, null, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { class: "mr-2" }, {
|
||||
default: _withCtx(() => _cache[34] || (_cache[34] = [
|
||||
default: _withCtx(() => _cache[35] || (_cache[35] = [
|
||||
_createTextVNode("mdi-cog")
|
||||
])),
|
||||
_: 1
|
||||
}),
|
||||
_cache[35] || (_cache[35] = _createTextVNode(" 高级选项 "))
|
||||
_cache[36] || (_cache[36] = _createTextVNode(" 高级选项 "))
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
@@ -687,6 +688,22 @@ return (_ctx, _cache) => {
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
_createVNode(_component_v_col, {
|
||||
cols: "12",
|
||||
md: "3"
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_switch, {
|
||||
modelValue: config.hint_geo_dat,
|
||||
"onUpdate:modelValue": _cache[15] || (_cache[15] = $event => ((config.hint_geo_dat) = $event)),
|
||||
label: "Geo规则补全",
|
||||
color: "primary",
|
||||
inset: "",
|
||||
hint: "获取官方Geo数据库, 并在输入时补全"
|
||||
}, null, 8, ["modelValue"])
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
_createVNode(_component_v_col, {
|
||||
cols: "12",
|
||||
md: "3"
|
||||
@@ -694,7 +711,7 @@ return (_ctx, _cache) => {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_switch, {
|
||||
modelValue: config.enable_acl4ssr,
|
||||
"onUpdate:modelValue": _cache[15] || (_cache[15] = $event => ((config.enable_acl4ssr) = $event)),
|
||||
"onUpdate:modelValue": _cache[16] || (_cache[16] = $event => ((config.enable_acl4ssr) = $event)),
|
||||
label: "ACL4SSR规则集",
|
||||
color: "primary",
|
||||
inset: "",
|
||||
@@ -710,7 +727,7 @@ return (_ctx, _cache) => {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_switch, {
|
||||
modelValue: config.group_by_region,
|
||||
"onUpdate:modelValue": _cache[16] || (_cache[16] = $event => ((config.group_by_region) = $event)),
|
||||
"onUpdate:modelValue": _cache[17] || (_cache[17] = $event => ((config.group_by_region) = $event)),
|
||||
label: "按大洲分组节点",
|
||||
color: "primary",
|
||||
inset: "",
|
||||
@@ -718,27 +735,6 @@ return (_ctx, _cache) => {
|
||||
}, null, 8, ["modelValue"])
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
_createVNode(_component_v_col, { cols: "3" }, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_btn, {
|
||||
color: "primary",
|
||||
onClick: openClashTemplateDialog,
|
||||
class: "mr-2"
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { left: "" }, {
|
||||
default: _withCtx(() => _cache[36] || (_cache[36] = [
|
||||
_createTextVNode("mdi-import")
|
||||
])),
|
||||
_: 1
|
||||
}),
|
||||
_cache[37] || (_cache[37] = _createTextVNode(" Clash 配置模板 "))
|
||||
]),
|
||||
_: 1
|
||||
})
|
||||
]),
|
||||
_: 1
|
||||
})
|
||||
]),
|
||||
_: 1
|
||||
@@ -747,12 +743,12 @@ return (_ctx, _cache) => {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_col, {
|
||||
cols: "12",
|
||||
md: "4"
|
||||
md: "3"
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_text_field, {
|
||||
modelValue: config.ruleset_prefix,
|
||||
"onUpdate:modelValue": _cache[17] || (_cache[17] = $event => ((config.ruleset_prefix) = $event)),
|
||||
"onUpdate:modelValue": _cache[18] || (_cache[18] = $event => ((config.ruleset_prefix) = $event)),
|
||||
label: "规则集前缀",
|
||||
variant: "outlined",
|
||||
placeholder: "📂<=",
|
||||
@@ -761,6 +757,33 @@ return (_ctx, _cache) => {
|
||||
}, {
|
||||
"prepend-inner": _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { color: "info" }, {
|
||||
default: _withCtx(() => _cache[37] || (_cache[37] = [
|
||||
_createTextVNode("mdi-palette")
|
||||
])),
|
||||
_: 1
|
||||
})
|
||||
]),
|
||||
_: 1
|
||||
}, 8, ["modelValue", "rules"])
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
_createVNode(_component_v_col, {
|
||||
cols: "12",
|
||||
md: "3"
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_text_field, {
|
||||
modelValue: config.acl4ssr_prefix,
|
||||
"onUpdate:modelValue": _cache[19] || (_cache[19] = $event => ((config.acl4ssr_prefix) = $event)),
|
||||
label: "ACL4SSR 规则集前缀",
|
||||
variant: "outlined",
|
||||
placeholder: "🗂️=>",
|
||||
rules: [v => !!v || '规则集前缀不能为空'],
|
||||
hint: "ACL4SSR 规则集前缀"
|
||||
}, {
|
||||
"prepend-inner": _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { color: "primary" }, {
|
||||
default: _withCtx(() => _cache[38] || (_cache[38] = [
|
||||
_createTextVNode("mdi-palette")
|
||||
])),
|
||||
@@ -774,39 +797,12 @@ return (_ctx, _cache) => {
|
||||
}),
|
||||
_createVNode(_component_v_col, {
|
||||
cols: "12",
|
||||
md: "4"
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_text_field, {
|
||||
modelValue: config.acl4ssr_prefix,
|
||||
"onUpdate:modelValue": _cache[18] || (_cache[18] = $event => ((config.acl4ssr_prefix) = $event)),
|
||||
label: "ACL4SSR 规则集前缀",
|
||||
variant: "outlined",
|
||||
placeholder: "🗂️=>",
|
||||
rules: [v => !!v || '规则集前缀不能为空'],
|
||||
hint: "ACL4SSR 规则集前缀"
|
||||
}, {
|
||||
"prepend-inner": _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { color: "primary" }, {
|
||||
default: _withCtx(() => _cache[39] || (_cache[39] = [
|
||||
_createTextVNode("mdi-palette")
|
||||
])),
|
||||
_: 1
|
||||
})
|
||||
]),
|
||||
_: 1
|
||||
}, 8, ["modelValue", "rules"])
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
_createVNode(_component_v_col, {
|
||||
cols: "12",
|
||||
md: "4"
|
||||
md: "3"
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_text_field, {
|
||||
modelValue: config.refresh_delay,
|
||||
"onUpdate:modelValue": _cache[19] || (_cache[19] = $event => ((config.refresh_delay) = $event)),
|
||||
"onUpdate:modelValue": _cache[20] || (_cache[20] = $event => ((config.refresh_delay) = $event)),
|
||||
modelModifiers: { number: true },
|
||||
label: "刷新延迟",
|
||||
variant: "outlined",
|
||||
@@ -819,7 +815,7 @@ return (_ctx, _cache) => {
|
||||
}, {
|
||||
"prepend-inner": _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { color: "info" }, {
|
||||
default: _withCtx(() => _cache[40] || (_cache[40] = [
|
||||
default: _withCtx(() => _cache[39] || (_cache[39] = [
|
||||
_createTextVNode("mdi-clock-outline")
|
||||
])),
|
||||
_: 1
|
||||
@@ -829,6 +825,27 @@ return (_ctx, _cache) => {
|
||||
}, 8, ["modelValue", "rules"])
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
_createVNode(_component_v_col, { cols: "3" }, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_btn, {
|
||||
color: "primary",
|
||||
onClick: openClashTemplateDialog,
|
||||
class: "mr-2"
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { left: "" }, {
|
||||
default: _withCtx(() => _cache[40] || (_cache[40] = [
|
||||
_createTextVNode("mdi-import")
|
||||
])),
|
||||
_: 1
|
||||
}),
|
||||
_cache[41] || (_cache[41] = _createTextVNode(" Clash 配置模板 "))
|
||||
]),
|
||||
_: 1
|
||||
})
|
||||
]),
|
||||
_: 1
|
||||
})
|
||||
]),
|
||||
_: 1
|
||||
@@ -854,7 +871,7 @@ return (_ctx, _cache) => {
|
||||
class: "mb-6",
|
||||
variant: "tonal"
|
||||
}, {
|
||||
default: _withCtx(() => _cache[46] || (_cache[46] = [
|
||||
default: _withCtx(() => _cache[47] || (_cache[47] = [
|
||||
_createTextVNode(" 配置说明参考: "),
|
||||
_createElementVNode("a", {
|
||||
href: "https://github.com/wumode/MoviePilot-Plugins/tree/main/plugins.v2/clashruleprovider/README.md",
|
||||
@@ -871,12 +888,12 @@ return (_ctx, _cache) => {
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_icon, { left: "" }, {
|
||||
default: _withCtx(() => _cache[47] || (_cache[47] = [
|
||||
default: _withCtx(() => _cache[48] || (_cache[48] = [
|
||||
_createTextVNode("mdi-view-dashboard-edit")
|
||||
])),
|
||||
_: 1
|
||||
}),
|
||||
_cache[48] || (_cache[48] = _createTextVNode(" 规则 "))
|
||||
_cache[49] || (_cache[49] = _createTextVNode(" 规则 "))
|
||||
]),
|
||||
_: 1
|
||||
}),
|
||||
@@ -884,7 +901,7 @@ return (_ctx, _cache) => {
|
||||
color: "secondary",
|
||||
onClick: resetForm
|
||||
}, {
|
||||
default: _withCtx(() => _cache[49] || (_cache[49] = [
|
||||
default: _withCtx(() => _cache[50] || (_cache[50] = [
|
||||
_createTextVNode("重置")
|
||||
])),
|
||||
_: 1
|
||||
@@ -894,7 +911,7 @@ return (_ctx, _cache) => {
|
||||
onClick: testConnection,
|
||||
loading: testing.value
|
||||
}, {
|
||||
default: _withCtx(() => _cache[50] || (_cache[50] = [
|
||||
default: _withCtx(() => _cache[51] || (_cache[51] = [
|
||||
_createTextVNode("测试连接")
|
||||
])),
|
||||
_: 1
|
||||
@@ -906,7 +923,7 @@ return (_ctx, _cache) => {
|
||||
onClick: saveConfig,
|
||||
loading: saving.value
|
||||
}, {
|
||||
default: _withCtx(() => _cache[51] || (_cache[51] = [
|
||||
default: _withCtx(() => _cache[52] || (_cache[52] = [
|
||||
_createTextVNode(" 保存配置 ")
|
||||
])),
|
||||
_: 1
|
||||
@@ -921,7 +938,7 @@ return (_ctx, _cache) => {
|
||||
variant: "tonal",
|
||||
closable: "",
|
||||
class: "ma-4 mt-0",
|
||||
"onClick:close": _cache[21] || (_cache[21] = $event => (testResult.show = false))
|
||||
"onClick:close": _cache[22] || (_cache[22] = $event => (testResult.show = false))
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_createElementVNode("div", _hoisted_2, [
|
||||
@@ -946,14 +963,14 @@ return (_ctx, _cache) => {
|
||||
]),
|
||||
_createVNode(_component_v_dialog, {
|
||||
modelValue: clashTemplateDialog.value,
|
||||
"onUpdate:modelValue": _cache[25] || (_cache[25] = $event => ((clashTemplateDialog).value = $event)),
|
||||
"onUpdate:modelValue": _cache[26] || (_cache[26] = $event => ((clashTemplateDialog).value = $event)),
|
||||
"max-width": "600"
|
||||
}, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_card, null, {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_card_title, null, {
|
||||
default: _withCtx(() => _cache[52] || (_cache[52] = [
|
||||
default: _withCtx(() => _cache[53] || (_cache[53] = [
|
||||
_createTextVNode("Clash 配置模板")
|
||||
])),
|
||||
_: 1
|
||||
@@ -962,14 +979,14 @@ return (_ctx, _cache) => {
|
||||
default: _withCtx(() => [
|
||||
_createVNode(_component_v_select, {
|
||||
modelValue: clashTemplateType.value,
|
||||
"onUpdate:modelValue": _cache[22] || (_cache[22] = $event => ((clashTemplateType).value = $event)),
|
||||
"onUpdate:modelValue": _cache[23] || (_cache[23] = $event => ((clashTemplateType).value = $event)),
|
||||
items: ['YAML'],
|
||||
label: "配置类型",
|
||||
class: "mb-4"
|
||||
}, null, 8, ["modelValue"]),
|
||||
_createVNode(_component_v_textarea, {
|
||||
modelValue: clashTemplateContent.value,
|
||||
"onUpdate:modelValue": _cache[23] || (_cache[23] = $event => ((clashTemplateContent).value = $event)),
|
||||
"onUpdate:modelValue": _cache[24] || (_cache[24] = $event => ((clashTemplateContent).value = $event)),
|
||||
label: "配置内容",
|
||||
"auto-grow": "",
|
||||
placeholder: "mixed-port: 7890",
|
||||
@@ -985,9 +1002,9 @@ return (_ctx, _cache) => {
|
||||
_createVNode(_component_v_spacer),
|
||||
_createVNode(_component_v_btn, {
|
||||
text: "",
|
||||
onClick: _cache[24] || (_cache[24] = $event => (clashTemplateDialog.value = false))
|
||||
onClick: _cache[25] || (_cache[25] = $event => (clashTemplateDialog.value = false))
|
||||
}, {
|
||||
default: _withCtx(() => _cache[53] || (_cache[53] = [
|
||||
default: _withCtx(() => _cache[54] || (_cache[54] = [
|
||||
_createTextVNode("取消")
|
||||
])),
|
||||
_: 1
|
||||
@@ -996,7 +1013,7 @@ return (_ctx, _cache) => {
|
||||
color: "primary",
|
||||
onClick: saveClashTemplate
|
||||
}, {
|
||||
default: _withCtx(() => _cache[54] || (_cache[54] = [
|
||||
default: _withCtx(() => _cache[55] || (_cache[55] = [
|
||||
_createTextVNode("确定")
|
||||
])),
|
||||
_: 1
|
||||
@@ -1015,6 +1032,6 @@ return (_ctx, _cache) => {
|
||||
}
|
||||
|
||||
};
|
||||
const ConfigComponent = /*#__PURE__*/_export_sfc(_sfc_main, [['__scopeId',"data-v-106fe9f8"]]);
|
||||
const ConfigComponent = /*#__PURE__*/_export_sfc(_sfc_main, [['__scopeId',"data-v-03cdd879"]]);
|
||||
|
||||
export { ConfigComponent as default };
|
||||
4
plugins.v2/clashruleprovider/dist/assets/__federation_expose_Config-s4NWY2Hy.css
vendored
Normal file
4
plugins.v2/clashruleprovider/dist/assets/__federation_expose_Config-s4NWY2Hy.css
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
.plugin-config[data-v-03cdd879] {
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -15460,13 +15460,13 @@ const _sfc_main = /* @__PURE__ */ _defineComponent({
|
||||
_createElementVNode("div", _hoisted_9, [
|
||||
clashInfo.value.version.meta ? (_openBlock(), _createBlock(_component_v_img, {
|
||||
key: 0,
|
||||
src: "/api/v1/system/img/0?imgurl=https://raw.githubusercontent.com/MetaCubeX/mihomo/refs/heads/Meta/Meta.png",
|
||||
src: "/api/v1/system/img/1?cache=1&imgurl=https://raw.githubusercontent.com/MetaCubeX/mihomo/refs/heads/Meta/Meta.png",
|
||||
alt: "Logo",
|
||||
"max-height": "48",
|
||||
contain: ""
|
||||
})) : (_openBlock(), _createBlock(_component_v_img, {
|
||||
key: 1,
|
||||
src: "/api/v1/system/img/0?imgurl=https://raw.githubusercontent.com/jxxghp/MoviePilot-Plugins/refs/heads/main/icons/Clash_A.png",
|
||||
src: "/api/v1/system/img/1?cache=1&imgurl=https://raw.githubusercontent.com/jxxghp/MoviePilot-Plugins/refs/heads/main/icons/Clash_A.png",
|
||||
alt: "Logo",
|
||||
"max-height": "48",
|
||||
contain: ""
|
||||
@@ -15514,6 +15514,6 @@ const _sfc_main = /* @__PURE__ */ _defineComponent({
|
||||
}
|
||||
});
|
||||
|
||||
const DashboardComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9093476d"]]);
|
||||
const DashboardComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-de7a088e"]]);
|
||||
|
||||
export { DashboardComponent as default };
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
.dashboard-widget[data-v-9093476d] {
|
||||
.dashboard-widget[data-v-de7a088e] {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,13 @@
|
||||
|
||||
.plugin-page[data-v-a60e548e] {
|
||||
.plugin-page[data-v-40c8d8f5] {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* 使卡片等宽并适应移动端 */
|
||||
.d-flex.flex-wrap[data-v-a60e548e] {
|
||||
.d-flex.flex-wrap[data-v-40c8d8f5] {
|
||||
gap: 16px;
|
||||
}
|
||||
.url-display[data-v-a60e548e] {
|
||||
.url-display[data-v-40c8d8f5] {
|
||||
word-break: break-all;
|
||||
padding: 8px;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
@@ -16,19 +16,19 @@
|
||||
|
||||
/* 移动端堆叠布局 */
|
||||
@media (max-width: 768px) {
|
||||
.d-flex.flex-wrap[data-v-a60e548e] {
|
||||
.d-flex.flex-wrap[data-v-40c8d8f5] {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add visual distinction between sections */
|
||||
.ruleset-section[data-v-a60e548e] {
|
||||
.ruleset-section[data-v-40c8d8f5] {
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.top-section[data-v-a60e548e] {
|
||||
.top-section[data-v-40c8d8f5] {
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
@@ -36,15 +36,15 @@
|
||||
}
|
||||
|
||||
/* Optional: Add different border colors to further distinguish */
|
||||
.ruleset-section[data-v-a60e548e] {
|
||||
.ruleset-section[data-v-40c8d8f5] {
|
||||
border-left: 4px solid #2196F3; /* Blue accent */
|
||||
}
|
||||
.top-section[data-v-a60e548e] {
|
||||
.top-section[data-v-40c8d8f5] {
|
||||
border-left: 4px solid #4CAF50; /* Green accent */
|
||||
}
|
||||
.drag-handle[data-v-a60e548e] {
|
||||
.drag-handle[data-v-40c8d8f5] {
|
||||
cursor: move;
|
||||
}
|
||||
.gap-2[data-v-a60e548e] {
|
||||
.gap-2[data-v-40c8d8f5] {
|
||||
gap: 8px;
|
||||
}
|
||||
@@ -2,14 +2,14 @@ const currentImports = {};
|
||||
const exportSet = new Set(['Module', '__esModule', 'default', '_export_sfc']);
|
||||
let moduleMap = {
|
||||
"./Page":()=>{
|
||||
dynamicLoadingCss(["__federation_expose_Page-eylW2iyA.css"], false, './Page');
|
||||
return __federation_import('./__federation_expose_Page-Bt1EwqOk.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},
|
||||
dynamicLoadingCss(["__federation_expose_Page-DMGoo00L.css"], false, './Page');
|
||||
return __federation_import('./__federation_expose_Page-BNbsW3Id.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},
|
||||
"./Config":()=>{
|
||||
dynamicLoadingCss(["__federation_expose_Config-BAzyOCdJ.css"], false, './Config');
|
||||
return __federation_import('./__federation_expose_Config-BWBZ5vgt.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},
|
||||
dynamicLoadingCss(["__federation_expose_Config-s4NWY2Hy.css"], false, './Config');
|
||||
return __federation_import('./__federation_expose_Config-HFXrSiMi.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},
|
||||
"./Dashboard":()=>{
|
||||
dynamicLoadingCss(["__federation_expose_Dashboard-D6WU_Ejn.css"], false, './Dashboard');
|
||||
return __federation_import('./__federation_expose_Dashboard-BFVr4jq_.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},};
|
||||
dynamicLoadingCss(["__federation_expose_Dashboard-vS9Qm2ZB.css"], false, './Dashboard');
|
||||
return __federation_import('./__federation_expose_Dashboard-BDSt5WaH.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},};
|
||||
const seen = {};
|
||||
const dynamicLoadingCss = (cssFilePaths, dontAppendStylesToHead, exposeItemName) => {
|
||||
const metaUrl = import.meta.url;
|
||||
|
||||
@@ -2,6 +2,8 @@ from typing import Optional, Any, List, Dict, Tuple
|
||||
from datetime import datetime
|
||||
import re
|
||||
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.event import eventmanager, Event
|
||||
from app.plugins import _PluginBase
|
||||
@@ -20,7 +22,7 @@ class ImdbSource(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "IMDb_IOS-OSX_App.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.4.2"
|
||||
plugin_version = "1.4.3"
|
||||
# 插件作者
|
||||
plugin_author = "wumode"
|
||||
# 作者主页
|
||||
@@ -41,7 +43,9 @@ class ImdbSource(_PluginBase):
|
||||
# 私有属性
|
||||
_imdb_helper = None
|
||||
_cache = {"discover": [], "trending": [], "trending_in_anime": [], "trending_in_sitcom": [],
|
||||
"trending_in_documentary": [], "imdb_top_250": []}
|
||||
"trending_in_documentary": [], "imdb_top_250": [], "staff_picks": {}}
|
||||
_img_proxy_prefix = ''
|
||||
_scheduler: Optional[BackgroundScheduler] = None
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
if config:
|
||||
@@ -55,6 +59,10 @@ class ImdbSource(_PluginBase):
|
||||
settings.SECURITY_IMAGE_DOMAINS.append("media-amazon.com")
|
||||
if "media-imdb.com" not in settings.SECURITY_IMAGE_DOMAINS:
|
||||
settings.SECURITY_IMAGE_DOMAINS.append("media-imdb.com")
|
||||
if self._enabled:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
self._scheduler.start()
|
||||
self._scheduler.add_job(self.__cache_staff_picks, trigger='date', run_date=None)
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled
|
||||
@@ -85,15 +93,15 @@ class ImdbSource(_PluginBase):
|
||||
if not self._staff_picks:
|
||||
return None
|
||||
|
||||
def year_and_type(entry: Dict) -> Tuple[MediaType, str, str]:
|
||||
title = next((t for t in titles if t.get("id") == entry.get('ttconst')), None)
|
||||
def year_and_type(imdb_entry: Dict) -> Tuple[MediaType, str, str]:
|
||||
title = next((t for t in titles if t.get("id") == imdb_entry.get('ttconst')), None)
|
||||
if not title:
|
||||
return MediaType.MOVIE, datetime.now().date().strftime("%Y"), ''
|
||||
media_id = title.get('titleType', {}).get('id')
|
||||
release_year = title.get('releaseYear', {}).get('year') or datetime.now().date().strftime("%Y")
|
||||
media_type = ImdbSource.title_id_to_mtype(media_id)
|
||||
plot = title.get("plot", {}).get("plotText", {}).get("plainText", '')
|
||||
return media_type, release_year, plot
|
||||
media_plot = title.get("plot", {}).get("plotText", {}).get("plainText", '')
|
||||
return media_type, release_year, media_plot
|
||||
|
||||
# 列配置
|
||||
size_config = {
|
||||
@@ -112,16 +120,15 @@ class ImdbSource(_PluginBase):
|
||||
"border": False
|
||||
}
|
||||
# 获取流行越势数据
|
||||
entries = self._imdb_helper.staff_picks()
|
||||
items = None
|
||||
if entries:
|
||||
items = self._imdb_helper.vertical_list_page_items(
|
||||
titles=[entry.get('ttconst', '') for entry in entries],
|
||||
names=[item for entry in entries for item in entry.get("relatedconst", [])],
|
||||
images=[entry.get('rmconst', '') for entry in entries],
|
||||
)
|
||||
|
||||
if not entries or not items:
|
||||
entries = self._cache['staff_picks'].get('entries')
|
||||
imdb_items = self._cache['staff_picks'].get('imdb_items')
|
||||
if not entries or not imdb_items:
|
||||
self.__cache_staff_picks()
|
||||
entries = self._cache['staff_picks'].get('entries')
|
||||
imdb_items = self._cache['staff_picks'].get('imdb_items')
|
||||
else:
|
||||
self._scheduler.add_job(self.__cache_staff_picks, trigger='date', run_date=None)
|
||||
if not entries or not imdb_items:
|
||||
elements = [
|
||||
{
|
||||
'component': 'VCard',
|
||||
@@ -145,19 +152,21 @@ class ImdbSource(_PluginBase):
|
||||
}
|
||||
]
|
||||
return cols, attrs, elements
|
||||
images = items.get('images') or []
|
||||
names = items.get('names') or []
|
||||
titles = items.get('titles') or []
|
||||
images = imdb_items.get('images') or []
|
||||
names = imdb_items.get('names') or []
|
||||
titles = imdb_items.get('titles') or []
|
||||
contents = []
|
||||
for entry in entries:
|
||||
cast = [name for related in entry.get('relatedconst', []) for name in names if name.get('id') == related]
|
||||
mtype, year, plot = year_and_type(entry)
|
||||
mp_url = f"/media?mediaid=imdb:{entry.get('ttconst')}&title='{entry.get('name')}'&year={year}&type={mtype.value}"
|
||||
primary_img_url = next((f"{image.get('url')}" for image in images
|
||||
if image.get("id") == entry.get('rmconst')), '')
|
||||
primary_img_url = f'{self._img_proxy_prefix}{primary_img_url}'
|
||||
item1 = {
|
||||
'component': 'VCarouselItem',
|
||||
'props': {
|
||||
'src': next((f"{image.get('url')}" for image in images
|
||||
if image.get("id") == entry.get('rmconst')), None),
|
||||
'src': primary_img_url,
|
||||
'cover': True,
|
||||
'position': 'center',
|
||||
},
|
||||
@@ -225,8 +234,8 @@ class ImdbSource(_PluginBase):
|
||||
{
|
||||
'component': 'VImg',
|
||||
'props': {
|
||||
'src': cs.get('primaryImage', {}).get('url',
|
||||
''),
|
||||
'src': f"{self._img_proxy_prefix}"
|
||||
f"{cs.get('primaryImage', {}).get('url', '')}",
|
||||
'alt': cs.get('nameText', {}).get('text', 'Avatar'),
|
||||
'cover': True
|
||||
}
|
||||
@@ -251,6 +260,7 @@ class ImdbSource(_PluginBase):
|
||||
}
|
||||
poster_url = next((f"{title.get('primaryImage', {}).get('url')}" for title in titles if
|
||||
title.get("id") == entry.get('ttconst')), None)
|
||||
poster_url = f"{self._img_proxy_prefix}{poster_url}"
|
||||
poster_com = {
|
||||
'component': 'VImg',
|
||||
'props': {
|
||||
@@ -332,8 +342,7 @@ class ImdbSource(_PluginBase):
|
||||
item2 = {
|
||||
'component': 'VCarouselItem',
|
||||
'props': {
|
||||
'src': next((f"{image.get('url')}" for image in images
|
||||
if image.get("id") == entry.get('rmconst')), None),
|
||||
'src': primary_img_url,
|
||||
'cover': True,
|
||||
'position': 'center'
|
||||
},
|
||||
@@ -529,8 +538,20 @@ class ImdbSource(_PluginBase):
|
||||
"""
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def __movie_to_media(movie_info: dict) -> schemas.MediaInfo:
|
||||
def __cache_staff_picks(self):
|
||||
entries = self._imdb_helper.staff_picks()
|
||||
imdb_items = None
|
||||
if entries:
|
||||
imdb_items = self._imdb_helper.vertical_list_page_items(
|
||||
titles=[entry.get('ttconst', '') for entry in entries],
|
||||
names=[item for entry in entries for item in entry.get("relatedconst", [])],
|
||||
images=[entry.get('rmconst', '') for entry in entries],
|
||||
)
|
||||
if not entries or not imdb_items:
|
||||
return
|
||||
self._cache['staff_picks'] = {'entries': entries, 'imdb_items': imdb_items}
|
||||
|
||||
def __movie_to_media(self, movie_info: dict) -> schemas.MediaInfo:
|
||||
title = ""
|
||||
if movie_info.get("titleText"):
|
||||
title = movie_info.get("titleText", {}).get("text", "")
|
||||
@@ -542,6 +563,7 @@ class ImdbSource(_PluginBase):
|
||||
primary_image = movie_info.get("primaryImage").get("url")
|
||||
if primary_image:
|
||||
poster_path = primary_image.replace('@._V1', '@._V1_QL75_UY414_CR6,0,280,414_')
|
||||
poster_path = f"{self._img_proxy_prefix}{poster_path}"
|
||||
vote_average = 0
|
||||
if movie_info.get("ratingsSummary"):
|
||||
vote_average = movie_info.get("ratingsSummary").get("aggregateRating")
|
||||
@@ -565,8 +587,7 @@ class ImdbSource(_PluginBase):
|
||||
imdb_id=movie_info.get("id")
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def __series_to_media(series_info: dict) -> schemas.MediaInfo:
|
||||
def __series_to_media(self, series_info: dict) -> schemas.MediaInfo:
|
||||
title = ""
|
||||
if series_info.get("titleText"):
|
||||
title = series_info.get("titleText", {}).get("text", "")
|
||||
@@ -578,6 +599,7 @@ class ImdbSource(_PluginBase):
|
||||
primary_image = series_info.get("primaryImage").get("url")
|
||||
if primary_image:
|
||||
poster_path = primary_image.replace('@._V1', '@._V1_QL75_UY414_CR6,0,280,414_')
|
||||
poster_path = f"{self._img_proxy_prefix}{poster_path}"
|
||||
vote_average = 0
|
||||
if series_info.get("ratingsSummary"):
|
||||
vote_average = series_info.get("ratingsSummary").get("aggregateRating")
|
||||
|
||||
@@ -411,4 +411,4 @@ class ImdbHelper:
|
||||
if error:
|
||||
logger.error(f"Error querying VerticalListPageItems: {error}")
|
||||
return None
|
||||
return data
|
||||
return data
|
||||
|
||||
@@ -25,7 +25,7 @@ class ToBypassTrackers(_PluginBase):
|
||||
# 插件名称
|
||||
plugin_name = "绕过Trackers"
|
||||
# 插件描述
|
||||
plugin_desc = "提供tracker服务器IP地址列表,帮助IPv6连接绕过OpenClash"
|
||||
plugin_desc = "提供tracker服务器IP地址列表,帮助IPv6连接绕过OpenClash。"
|
||||
# 插件图标
|
||||
plugin_icon = "Clash_A.png"
|
||||
# 插件版本
|
||||
|
||||
Reference in New Issue
Block a user