Merge pull request #858 from wumode/clashruleprovider

This commit is contained in:
jxxghp
2025-07-23 15:07:24 +08:00
committed by GitHub
11 changed files with 23877 additions and 388 deletions

View File

@@ -435,11 +435,12 @@
"name": "IMDb源",
"description": "让探索推荐和媒体识别支持IMDb数据源。",
"labels": "探索",
"version": "1.5.0",
"version": "1.5.1",
"icon": "IMDb_IOS-OSX_App.png",
"author": "wumode",
"level": 1,
"history": {
"v1.5.1": "改进媒体id转换; 支持二级分类和自定义推荐",
"v1.5.0": "支持媒体识别",
"v1.4.4": "更新数据源",
"v1.4.3": "为仪表盘组件添加缓存",
@@ -459,11 +460,12 @@
"name": "Clash Rule Provider",
"description": "随时为Clash添加一些额外的规则。",
"labels": "工具",
"version": "1.2.7",
"version": "1.2.8",
"icon": "Mihomo_Meta_A.png",
"author": "wumode",
"level": 1,
"history": {
"v1.2.8": "改进导入界面",
"v1.2.7": "修复分享链接解析错误",
"v1.2.6": "修复代理组修改丢失问题",
"v1.2.4": "支持geo规则补全; 代理组编辑",

View File

@@ -39,7 +39,7 @@ class ClashRuleProvider(_PluginBase):
# 插件图标
plugin_icon = "Mihomo_Meta_A.png"
# 插件版本
plugin_version = "1.2.7"
plugin_version = "1.2.8"
# 插件作者
plugin_author = "wumode"
# 作者主页
@@ -813,22 +813,25 @@ class ClashRuleProvider(_PluginBase):
return schemas.Response(success=False, message='无可用节点')
result = True
message = ''
for proxy in extra_proxies:
name = proxy.get('name')
if not name or any(x.get('name') == name for x in self.clash_outbound()):
logger.warning(f"The proxy name {proxy['name']} already exists. Skipping...")
message = f"The proxy name {proxy['name']} already exists. Skipping..."
result = False
continue
required_fields = {'name', 'type', 'server', 'port'}
if not required_fields.issubset(proxy.keys()):
missing = required_fields - proxy.keys()
logger.error(f"Required field is missing: {missing}")
message = f"Required field is missing: {missing}"
result = False
continue
self._extra_proxies.append(proxy)
self.save_data('extra_proxies', self._extra_proxies)
try:
for proxy in extra_proxies:
name = proxy.get('name')
if not name or any(x.get('name') == name for x in self.clash_outbound()):
logger.warning(f"The proxy name {name} already exists. Skipping ...")
message = f"The proxy name {name} already exists. Skipping ..."
result = False
continue
required_fields = {'name', 'type', 'server', 'port'}
if not required_fields.issubset(proxy.keys()):
missing = required_fields - proxy.keys()
logger.error(f"Required field is missing: {missing}")
message = f"Required field is missing: {missing}"
result = False
continue
self._extra_proxies.append(proxy)
self.save_data('extra_proxies', self._extra_proxies)
except Exception as err:
return schemas.Response(success=False, message=f'{err}')
return schemas.Response(success=result, message=message)
def delete_extra_proxy(self, params: dict = Body(...)) -> schemas.Response:

View File

@@ -0,0 +1,4 @@
.plugin-config[data-v-c67dff26] {
margin: 0 auto;
}

View File

@@ -1,7 +1,8 @@
import { importShared } from './__federation_fn_import-JrT3xvdd.js';
import { V as VAceEditor } from './theme-monokai-Bn79mBHh.js';
import { _ as _export_sfc } from './_plugin-vue_export-helper-pcqpp-6-.js';
const {createTextVNode:_createTextVNode,resolveComponent:_resolveComponent,withCtx:_withCtx,createVNode:_createVNode,toDisplayString:_toDisplayString,openBlock:_openBlock,createBlock:_createBlock,createCommentVNode:_createCommentVNode,createElementVNode:_createElementVNode,mergeProps:_mergeProps,withModifiers:_withModifiers,Fragment:_Fragment,createElementBlock:_createElementBlock} = await importShared('vue');
const {createTextVNode:_createTextVNode,resolveComponent:_resolveComponent,withCtx:_withCtx,createVNode:_createVNode,toDisplayString:_toDisplayString,openBlock:_openBlock,createBlock:_createBlock,createCommentVNode:_createCommentVNode,createElementVNode:_createElementVNode,mergeProps:_mergeProps,withModifiers:_withModifiers,unref:_unref,Fragment:_Fragment,createElementBlock:_createElementBlock} = await importShared('vue');
const _hoisted_1 = { class: "plugin-config" };
@@ -12,8 +13,6 @@ const _hoisted_4 = { class: "text-body-2" };
const {ref,reactive,onMounted,computed} = await importShared('vue');
// Props
const _sfc_main = {
__name: 'Config',
props: {
@@ -30,6 +29,20 @@ const _sfc_main = {
emits: ['save', 'close'],
setup(__props, { emit: __emit }) {
const editorOptions = {
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true,
showLineNumbers: true,
tabSize: 2
};
const configPlaceholder = ref(
`profile:
store-selected: true
mode: rule
log-level: silent`
);
// Props
const props = __props;
// 状态变量
@@ -255,7 +268,6 @@ return (_ctx, _cache) => {
const _component_v_spacer = _resolveComponent("v-spacer");
const _component_v_card_actions = _resolveComponent("v-card-actions");
const _component_v_card = _resolveComponent("v-card");
const _component_v_textarea = _resolveComponent("v-textarea");
const _component_v_dialog = _resolveComponent("v-dialog");
return (_openBlock(), _createElementBlock(_Fragment, null, [
@@ -826,12 +838,16 @@ return (_ctx, _cache) => {
]),
_: 1
}),
_createVNode(_component_v_col, { cols: "3" }, {
_createVNode(_component_v_col, {
cols: "12",
md: "3",
class: "d-flex align-end"
}, {
default: _withCtx(() => [
_createVNode(_component_v_btn, {
color: "primary",
onClick: openClashTemplateDialog,
class: "mr-2"
block: ""
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
@@ -975,7 +991,7 @@ return (_ctx, _cache) => {
])),
_: 1
}),
_createVNode(_component_v_card_text, { style: {"max-height":"600px","overflow-y":"auto"} }, {
_createVNode(_component_v_card_text, { style: {"max-height":"900px","overflow-y":"auto"} }, {
default: _withCtx(() => [
_createVNode(_component_v_select, {
modelValue: clashTemplateType.value,
@@ -984,16 +1000,28 @@ return (_ctx, _cache) => {
label: "配置类型",
class: "mb-4"
}, null, 8, ["modelValue"]),
_createVNode(_component_v_textarea, {
modelValue: clashTemplateContent.value,
"onUpdate:modelValue": _cache[24] || (_cache[24] = $event => ((clashTemplateContent).value = $event)),
label: "配置内容",
"auto-grow": "",
placeholder: "mixed-port: 7890",
_createVNode(_unref(VAceEditor), {
value: clashTemplateContent.value,
"onUpdate:value": _cache[24] || (_cache[24] = $event => ((clashTemplateContent).value = $event)),
lang: "yaml",
theme: "monokai",
hint: "",
options: editorOptions,
placeholder: configPlaceholder.value,
style: {"height":"30rem","width":"100%","margin-bottom":"16px"}
}, null, 8, ["value", "placeholder"]),
_createVNode(_component_v_alert, {
type: "info",
dense: "",
text: "",
class: "mb-4",
hint: "规则和出站代理会被添加在配置模板上",
style: {"max-height":"600px","padding-top":"12px","line-height":"1.5"}
}, null, 8, ["modelValue"])
variant: "tonal"
}, {
default: _withCtx(() => _cache[54] || (_cache[54] = [
_createTextVNode("规则和出站代理会被添加在配置模板上 ")
])),
_: 1
})
]),
_: 1
}),
@@ -1004,7 +1032,7 @@ return (_ctx, _cache) => {
text: "",
onClick: _cache[25] || (_cache[25] = $event => (clashTemplateDialog.value = false))
}, {
default: _withCtx(() => _cache[54] || (_cache[54] = [
default: _withCtx(() => _cache[55] || (_cache[55] = [
_createTextVNode("取消")
])),
_: 1
@@ -1013,7 +1041,7 @@ return (_ctx, _cache) => {
color: "primary",
onClick: saveClashTemplate
}, {
default: _withCtx(() => _cache[55] || (_cache[55] = [
default: _withCtx(() => _cache[56] || (_cache[56] = [
_createTextVNode("确定")
])),
_: 1
@@ -1032,6 +1060,6 @@ return (_ctx, _cache) => {
}
};
const ConfigComponent = /*#__PURE__*/_export_sfc(_sfc_main, [['__scopeId',"data-v-03cdd879"]]);
const ConfigComponent = /*#__PURE__*/_export_sfc(_sfc_main, [['__scopeId',"data-v-c67dff26"]]);
export { ConfigComponent as default };

View File

@@ -1,4 +0,0 @@
.plugin-config[data-v-03cdd879] {
margin: 0 auto;
}

View File

@@ -1,13 +1,13 @@
.plugin-page[data-v-0e274fe6] {
.plugin-page[data-v-c476bdad] {
margin: 0 auto;
}
/* 使卡片等宽并适应移动端 */
.d-flex.flex-wrap[data-v-0e274fe6] {
.d-flex.flex-wrap[data-v-c476bdad] {
gap: 16px;
}
.url-display[data-v-0e274fe6] {
.url-display[data-v-c476bdad] {
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-0e274fe6] {
.d-flex.flex-wrap[data-v-c476bdad] {
flex-direction: column;
}
}
/* Add visual distinction between sections */
.ruleset-section[data-v-0e274fe6] {
.ruleset-section[data-v-c476bdad] {
border: 1px solid #e0e0e0;
border-radius: 4px;
padding: 16px;
background-color: #f5f5f5;
}
.top-section[data-v-0e274fe6] {
.top-section[data-v-c476bdad] {
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-0e274fe6] {
.ruleset-section[data-v-c476bdad] {
border-left: 4px solid #2196F3; /* Blue accent */
}
.top-section[data-v-0e274fe6] {
.top-section[data-v-c476bdad] {
border-left: 4px solid #4CAF50; /* Green accent */
}
.drag-handle[data-v-0e274fe6] {
.drag-handle[data-v-c476bdad] {
cursor: move;
}
.gap-2[data-v-0e274fe6] {
.gap-2[data-v-c476bdad] {
gap: 8px;
}

View File

@@ -1,4 +1,5 @@
import { importShared } from './__federation_fn_import-JrT3xvdd.js';
import { c as commonjsGlobal, g as getDefaultExportFromCjs, V as VAceEditor } from './theme-monokai-Bn79mBHh.js';
import { _ as _export_sfc } from './_plugin-vue_export-helper-pcqpp-6-.js';
/*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT */
@@ -3849,12 +3850,6 @@ var jsYaml = {
safeDump: safeDump
};
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
/**
* lodash (Custom Build) <https://lodash.com/>
* Build: `lodash modularize exports="npm" -o ./`
@@ -4235,14 +4230,14 @@ var lodash_debounce = debounce;
const debounce$1 = /*@__PURE__*/getDefaultExportFromCjs(lodash_debounce);
const {createTextVNode:_createTextVNode,resolveComponent:_resolveComponent,withCtx:_withCtx,createVNode:_createVNode,toDisplayString:_toDisplayString,openBlock:_openBlock,createBlock:_createBlock,createCommentVNode:_createCommentVNode,createElementVNode:_createElementVNode,withModifiers:_withModifiers,normalizeClass:_normalizeClass,mergeProps:_mergeProps,renderList:_renderList,Fragment:_Fragment,createElementBlock:_createElementBlock} = await importShared('vue');
const {createTextVNode:_createTextVNode,resolveComponent:_resolveComponent,withCtx:_withCtx,createVNode:_createVNode,toDisplayString:_toDisplayString,openBlock:_openBlock,createBlock:_createBlock,createCommentVNode:_createCommentVNode,createElementVNode:_createElementVNode,withModifiers:_withModifiers,normalizeClass:_normalizeClass,mergeProps:_mergeProps,renderList:_renderList,Fragment:_Fragment,createElementBlock:_createElementBlock,unref:_unref} = await importShared('vue');
const _hoisted_1 = { class: "plugin-page" };
const _hoisted_2 = { key: 2 };
const _hoisted_3 = { class: "mb-6" };
const _hoisted_4 = { class: "pa-4" };
const _hoisted_5 = { class: "d-flex justify-space-between align-center mb-4" };
const _hoisted_5 = { class: "d-flex justify-space-between align-center" };
const _hoisted_6 = { class: "d-flex align-center" };
const _hoisted_7 = ["onDragstart", "onDragover", "onDrop"];
const _hoisted_8 = {
@@ -4253,7 +4248,7 @@ const _hoisted_9 = { class: "d-flex justify-center" };
const _hoisted_10 = { style: {"position":"absolute","right":"0","bottom":"0"} };
const _hoisted_11 = { class: "mb-6" };
const _hoisted_12 = { class: "pa-4" };
const _hoisted_13 = { class: "d-flex justify-space-between align-center mb-4" };
const _hoisted_13 = { class: "d-flex justify-space-between align-center" };
const _hoisted_14 = { class: "d-flex align-center" };
const _hoisted_15 = ["onDragstart", "onDragover", "onDrop"];
const _hoisted_16 = {
@@ -4264,7 +4259,7 @@ const _hoisted_17 = { class: "d-flex justify-center" };
const _hoisted_18 = { style: {"position":"absolute","right":"0","bottom":"0"} };
const _hoisted_19 = { class: "mb-6" };
const _hoisted_20 = { class: "pa-4" };
const _hoisted_21 = { class: "d-flex justify-space-between align-center mb-4" };
const _hoisted_21 = { class: "d-flex justify-space-between align-center" };
const _hoisted_22 = { class: "d-flex" };
const _hoisted_23 = {
class: "position-relative px-4 py-2",
@@ -4274,7 +4269,7 @@ const _hoisted_24 = { class: "d-flex justify-center" };
const _hoisted_25 = { style: {"position":"absolute","right":"0","bottom":"0"} };
const _hoisted_26 = { class: "mb-6" };
const _hoisted_27 = { class: "pa-4" };
const _hoisted_28 = { class: "d-flex justify-space-between align-center mb-4" };
const _hoisted_28 = { class: "d-flex justify-space-between align-center" };
const _hoisted_29 = { class: "d-flex" };
const _hoisted_30 = {
class: "position-relative px-4 py-2",
@@ -4284,7 +4279,7 @@ const _hoisted_31 = { class: "d-flex justify-center" };
const _hoisted_32 = { style: {"position":"absolute","right":"0","bottom":"0"} };
const _hoisted_33 = { class: "mb-6" };
const _hoisted_34 = { class: "pa-4" };
const _hoisted_35 = { class: "d-flex justify-space-between align-center mb-4" };
const _hoisted_35 = { class: "d-flex justify-space-between align-center" };
const _hoisted_36 = { class: "d-flex align-center" };
const _hoisted_37 = {
class: "position-relative px-4 py-2",
@@ -4323,7 +4318,7 @@ const _hoisted_58 = { class: "d-flex justify-space-between mb-2" };
const _hoisted_59 = { class: "d-flex justify-space-between text-caption text-grey" };
const {ref,onMounted,computed} = await importShared('vue');
// v-data-table 的 headers 定义
const _sfc_main = {
__name: 'Page',
@@ -4342,6 +4337,23 @@ const _sfc_main = {
emits: ['action', 'switch', 'close'],
setup(__props, { emit: __emit }) {
const editorOptions = {
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true,
showLineNumbers: true,
tabSize: 2
};
const proxiesPlaceholder = ref(
`proxies:
- name: "ss node"
type: "ss"`
);
const rulesPlaceholder = ref(
`rules:
- DOMAIN,gemini.google.com,Openai`
);
// v-data-table 的 headers 定义
const headers = ref([
{title: '优先级', key: 'priority', sortable: true}, // 可以根据需要设置是否可排序
{title: '类型', key: 'type', sortable: false},
@@ -5398,7 +5410,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
default: _withCtx(() => _cache[80] || (_cache[80] = [
default: _withCtx(() => _cache[81] || (_cache[81] = [
_createTextVNode("mdi-close")
])),
_: 1
@@ -5409,7 +5421,7 @@ return (_ctx, _cache) => {
]),
default: _withCtx(() => [
_createVNode(_component_v_card_title, null, {
default: _withCtx(() => _cache[79] || (_cache[79] = [
default: _withCtx(() => _cache[80] || (_cache[80] = [
_createTextVNode("Clash Rule Provider")
])),
_: 1
@@ -5445,31 +5457,31 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_tab, null, {
default: _withCtx(() => _cache[81] || (_cache[81] = [
default: _withCtx(() => _cache[82] || (_cache[82] = [
_createTextVNode("规则集规则")
])),
_: 1
}),
_createVNode(_component_v_tab, null, {
default: _withCtx(() => _cache[82] || (_cache[82] = [
default: _withCtx(() => _cache[83] || (_cache[83] = [
_createTextVNode("置顶规则")
])),
_: 1
}),
_createVNode(_component_v_tab, null, {
default: _withCtx(() => _cache[83] || (_cache[83] = [
default: _withCtx(() => _cache[84] || (_cache[84] = [
_createTextVNode("代理组")
])),
_: 1
}),
_createVNode(_component_v_tab, null, {
default: _withCtx(() => _cache[84] || (_cache[84] = [
default: _withCtx(() => _cache[85] || (_cache[85] = [
_createTextVNode("出站代理")
])),
_: 1
}),
_createVNode(_component_v_tab, null, {
default: _withCtx(() => _cache[85] || (_cache[85] = [
default: _withCtx(() => _cache[86] || (_cache[86] = [
_createTextVNode("规则集合")
])),
_: 1
@@ -5487,7 +5499,7 @@ return (_ctx, _cache) => {
_createElementVNode("div", _hoisted_3, [
_createElementVNode("div", _hoisted_4, [
_createElementVNode("div", _hoisted_5, [
_cache[88] || (_cache[88] = _createElementVNode("div", { class: "text-h6" }, "规则集规则", -1)),
_cache[89] || (_cache[89] = _createElementVNode("div", { class: "text-h6" }, "规则集规则", -1)),
_createElementVNode("div", _hoisted_6, [
_createVNode(_component_v_text_field, {
modelValue: searchRulesetRule.value,
@@ -5506,12 +5518,12 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
default: _withCtx(() => _cache[86] || (_cache[86] = [
default: _withCtx(() => _cache[87] || (_cache[87] = [
_createTextVNode("mdi-plus")
])),
_: 1
}),
_cache[87] || (_cache[87] = _createTextVNode(" 添加规则 "))
_cache[88] || (_cache[88] = _createTextVNode(" 添加规则 "))
]),
_: 1
})
@@ -5540,7 +5552,7 @@ return (_ctx, _cache) => {
}, [
_createElementVNode("td", null, [
_createVNode(_component_v_icon, { class: "drag-handle" }, {
default: _withCtx(() => _cache[89] || (_cache[89] = [
default: _withCtx(() => _cache[90] || (_cache[90] = [
_createTextVNode("mdi-drag")
])),
_: 1
@@ -5571,7 +5583,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[90] || (_cache[90] = [
default: _withCtx(() => _cache[91] || (_cache[91] = [
_createTextVNode("mdi-pencil")
])),
_: 1
@@ -5588,7 +5600,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[91] || (_cache[91] = [
default: _withCtx(() => _cache[92] || (_cache[92] = [
_createTextVNode("mdi-delete")
])),
_: 1
@@ -5628,7 +5640,7 @@ return (_ctx, _cache) => {
]),
_: 1
}, 8, ["headers", "items", "search", "page", "items-per-page", "items-per-page-options"]),
_cache[92] || (_cache[92] = _createElementVNode("div", { class: "text-caption text-grey mt-2" }, " *对规则集中规则的修改可以在Clash中立即生效。 ", -1))
_cache[93] || (_cache[93] = _createElementVNode("div", { class: "text-caption text-grey mt-2" }, " *对规则集中规则的修改可以在Clash中立即生效。 ", -1))
])
]),
_: 1
@@ -5638,7 +5650,7 @@ return (_ctx, _cache) => {
_createElementVNode("div", _hoisted_11, [
_createElementVNode("div", _hoisted_12, [
_createElementVNode("div", _hoisted_13, [
_cache[97] || (_cache[97] = _createElementVNode("div", { class: "text-h6" }, "置顶规则", -1)),
_cache[98] || (_cache[98] = _createElementVNode("div", { class: "text-h6" }, "置顶规则", -1)),
_createElementVNode("div", _hoisted_14, [
_createVNode(_component_v_text_field, {
modelValue: searchTopRule.value,
@@ -5658,12 +5670,12 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
default: _withCtx(() => _cache[93] || (_cache[93] = [
default: _withCtx(() => _cache[94] || (_cache[94] = [
_createTextVNode("mdi-import")
])),
_: 1
}),
_cache[94] || (_cache[94] = _createTextVNode(" 导入规则 "))
_cache[95] || (_cache[95] = _createTextVNode(" 导入规则 "))
]),
_: 1
}),
@@ -5673,12 +5685,12 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
default: _withCtx(() => _cache[95] || (_cache[95] = [
default: _withCtx(() => _cache[96] || (_cache[96] = [
_createTextVNode("mdi-plus")
])),
_: 1
}),
_cache[96] || (_cache[96] = _createTextVNode(" 添加规则 "))
_cache[97] || (_cache[97] = _createTextVNode(" 添加规则 "))
]),
_: 1
})
@@ -5707,7 +5719,7 @@ return (_ctx, _cache) => {
}, [
_createElementVNode("td", null, [
_createVNode(_component_v_icon, { class: "drag-handle" }, {
default: _withCtx(() => _cache[98] || (_cache[98] = [
default: _withCtx(() => _cache[99] || (_cache[99] = [
_createTextVNode("mdi-drag")
])),
_: 1
@@ -5738,7 +5750,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[99] || (_cache[99] = [
default: _withCtx(() => _cache[100] || (_cache[100] = [
_createTextVNode("mdi-pencil")
])),
_: 1
@@ -5756,7 +5768,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[100] || (_cache[100] = [
default: _withCtx(() => _cache[101] || (_cache[101] = [
_createTextVNode("mdi-delete")
])),
_: 1
@@ -5770,7 +5782,7 @@ return (_ctx, _cache) => {
activator: "parent",
location: "top"
}, {
default: _withCtx(() => _cache[101] || (_cache[101] = [
default: _withCtx(() => _cache[102] || (_cache[102] = [
_createTextVNode(" 根据规则集自动添加 ")
])),
_: 1
@@ -5808,8 +5820,8 @@ return (_ctx, _cache) => {
]),
_: 1
}, 8, ["headers", "search", "items", "page", "items-per-page"]),
_cache[102] || (_cache[102] = _createElementVNode("div", { class: "text-caption text-grey mt-2" }, " *置顶规则用于管理来自规则集的匹配规则,这些规则会动态更新。 ", -1)),
_cache[103] || (_cache[103] = _createElementVNode("div", { class: "text-caption text-grey mt-2" }, " *对置顶规则的修改只有Clash更新配置后才会生效。 ", -1))
_cache[103] || (_cache[103] = _createElementVNode("div", { class: "text-caption text-grey mt-2" }, " *置顶规则用于管理来自规则集的匹配规则,这些规则会动态更新。 ", -1)),
_cache[104] || (_cache[104] = _createElementVNode("div", { class: "text-caption text-grey mt-2" }, " *对置顶规则的修改只有Clash更新配置后才会生效。 ", -1))
])
]),
_: 1
@@ -5819,7 +5831,7 @@ return (_ctx, _cache) => {
_createElementVNode("div", _hoisted_19, [
_createElementVNode("div", _hoisted_20, [
_createElementVNode("div", _hoisted_21, [
_cache[106] || (_cache[106] = _createElementVNode("div", { class: "text-h6" }, "代理组", -1)),
_cache[107] || (_cache[107] = _createElementVNode("div", { class: "text-h6" }, "代理组", -1)),
_createElementVNode("div", _hoisted_22, [
_createVNode(_component_v_btn, {
color: "primary",
@@ -5827,12 +5839,12 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
default: _withCtx(() => _cache[104] || (_cache[104] = [
default: _withCtx(() => _cache[105] || (_cache[105] = [
_createTextVNode("mdi-plus")
])),
_: 1
}),
_cache[105] || (_cache[105] = _createTextVNode(" 添加代理组 "))
_cache[106] || (_cache[106] = _createTextVNode(" 添加代理组 "))
]),
_: 1
})
@@ -5864,7 +5876,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[107] || (_cache[107] = [
default: _withCtx(() => _cache[108] || (_cache[108] = [
_createTextVNode("mdi-code-json")
])),
_: 1
@@ -5882,7 +5894,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[108] || (_cache[108] = [
default: _withCtx(() => _cache[109] || (_cache[109] = [
_createTextVNode("mdi-pencil")
])),
_: 1
@@ -5900,7 +5912,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[109] || (_cache[109] = [
default: _withCtx(() => _cache[110] || (_cache[110] = [
_createTextVNode("mdi-delete")
])),
_: 1
@@ -5914,7 +5926,7 @@ return (_ctx, _cache) => {
activator: "parent",
location: "top"
}, {
default: _withCtx(() => _cache[110] || (_cache[110] = [
default: _withCtx(() => _cache[111] || (_cache[111] = [
_createTextVNode(" 非手动添加 ")
])),
_: 1
@@ -5952,7 +5964,7 @@ return (_ctx, _cache) => {
]),
_: 1
}, 8, ["headers", "items", "page", "items-per-page"]),
_cache[111] || (_cache[111] = _createElementVNode("div", { class: "text-caption text-grey mt-2" }, null, -1))
_cache[112] || (_cache[112] = _createElementVNode("div", { class: "text-caption text-grey mt-2" }, null, -1))
])
]),
_: 1
@@ -5962,7 +5974,7 @@ return (_ctx, _cache) => {
_createElementVNode("div", _hoisted_26, [
_createElementVNode("div", _hoisted_27, [
_createElementVNode("div", _hoisted_28, [
_cache[114] || (_cache[114] = _createElementVNode("div", { class: "text-h6" }, "出站代理", -1)),
_cache[115] || (_cache[115] = _createElementVNode("div", { class: "text-h6" }, "出站代理", -1)),
_createElementVNode("div", _hoisted_29, [
_createVNode(_component_v_btn, {
color: "primary",
@@ -5970,12 +5982,12 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
default: _withCtx(() => _cache[112] || (_cache[112] = [
default: _withCtx(() => _cache[113] || (_cache[113] = [
_createTextVNode("mdi-plus")
])),
_: 1
}),
_cache[113] || (_cache[113] = _createTextVNode(" 导入节点 "))
_cache[114] || (_cache[114] = _createTextVNode(" 导入节点 "))
]),
_: 1
})
@@ -6009,7 +6021,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[115] || (_cache[115] = [
default: _withCtx(() => _cache[116] || (_cache[116] = [
_createTextVNode("mdi-code-json")
])),
_: 1
@@ -6027,7 +6039,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[116] || (_cache[116] = [
default: _withCtx(() => _cache[117] || (_cache[117] = [
_createTextVNode("mdi-delete")
])),
_: 1
@@ -6041,7 +6053,7 @@ return (_ctx, _cache) => {
activator: "parent",
location: "top"
}, {
default: _withCtx(() => _cache[117] || (_cache[117] = [
default: _withCtx(() => _cache[118] || (_cache[118] = [
_createTextVNode(" 非手动添加 ")
])),
_: 1
@@ -6079,7 +6091,7 @@ return (_ctx, _cache) => {
]),
_: 1
}, 8, ["headers", "items", "page", "items-per-page"]),
_cache[118] || (_cache[118] = _createElementVNode("div", { class: "text-caption text-grey mt-2" }, null, -1))
_cache[119] || (_cache[119] = _createElementVNode("div", { class: "text-caption text-grey mt-2" }, null, -1))
])
]),
_: 1
@@ -6089,7 +6101,7 @@ return (_ctx, _cache) => {
_createElementVNode("div", _hoisted_33, [
_createElementVNode("div", _hoisted_34, [
_createElementVNode("div", _hoisted_35, [
_cache[121] || (_cache[121] = _createElementVNode("div", { class: "text-h6" }, "规则集合", -1)),
_cache[122] || (_cache[122] = _createElementVNode("div", { class: "text-h6" }, "规则集合", -1)),
_createElementVNode("div", _hoisted_36, [
_createVNode(_component_v_text_field, {
modelValue: searchRuleProviders.value,
@@ -6108,12 +6120,12 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
default: _withCtx(() => _cache[119] || (_cache[119] = [
default: _withCtx(() => _cache[120] || (_cache[120] = [
_createTextVNode("mdi-plus")
])),
_: 1
}),
_cache[120] || (_cache[120] = _createTextVNode(" 添加规则集合 "))
_cache[121] || (_cache[121] = _createTextVNode(" 添加规则集合 "))
]),
_: 1
})
@@ -6150,7 +6162,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[122] || (_cache[122] = [
default: _withCtx(() => _cache[123] || (_cache[123] = [
_createTextVNode("mdi-pencil")
])),
_: 1
@@ -6168,7 +6180,7 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[123] || (_cache[123] = [
default: _withCtx(() => _cache[124] || (_cache[124] = [
_createTextVNode("mdi-delete")
])),
_: 1
@@ -6182,7 +6194,7 @@ return (_ctx, _cache) => {
activator: "parent",
location: "top"
}, {
default: _withCtx(() => _cache[124] || (_cache[124] = [
default: _withCtx(() => _cache[125] || (_cache[125] = [
_createTextVNode(" 非手动添加 ")
])),
_: 1
@@ -6241,7 +6253,7 @@ return (_ctx, _cache) => {
_createVNode(_component_v_card, { class: "h-100" }, {
default: _withCtx(() => [
_createVNode(_component_v_card_title, { class: "text-h6 font-weight-medium" }, {
default: _withCtx(() => _cache[125] || (_cache[125] = [
default: _withCtx(() => _cache[126] || (_cache[126] = [
_createTextVNode("状态信息")
])),
_: 1
@@ -6250,7 +6262,7 @@ return (_ctx, _cache) => {
default: _withCtx(() => [
_createElementVNode("div", _hoisted_40, [
_createElementVNode("div", _hoisted_41, [
_cache[126] || (_cache[126] = _createElementVNode("span", null, "状态", -1)),
_cache[127] || (_cache[127] = _createElementVNode("span", null, "状态", -1)),
_createVNode(_component_v_chip, {
size: "small",
color: status.value === 'running' ? 'success' : 'warning'
@@ -6262,23 +6274,23 @@ return (_ctx, _cache) => {
}, 8, ["color"])
]),
_createElementVNode("div", _hoisted_42, [
_cache[127] || (_cache[127] = _createElementVNode("span", null, "订阅配置规则数", -1)),
_cache[128] || (_cache[128] = _createElementVNode("span", null, "订阅配置规则数", -1)),
_createElementVNode("span", null, _toDisplayString(subscriptionInfo.value.rule_size), 1)
]),
_createElementVNode("div", _hoisted_43, [
_cache[128] || (_cache[128] = _createElementVNode("span", null, "置顶规则数", -1)),
_cache[129] || (_cache[129] = _createElementVNode("span", null, "置顶规则数", -1)),
_createElementVNode("span", null, _toDisplayString(sortedRules.value.length), 1)
]),
_createElementVNode("div", _hoisted_44, [
_cache[129] || (_cache[129] = _createElementVNode("span", null, "规则集规则数", -1)),
_cache[130] || (_cache[130] = _createElementVNode("span", null, "规则集规则数", -1)),
_createElementVNode("span", null, _toDisplayString(sortedRulesetRules.value.length), 1)
]),
_createElementVNode("div", _hoisted_45, [
_cache[130] || (_cache[130] = _createElementVNode("span", null, "代理组数", -1)),
_cache[131] || (_cache[131] = _createElementVNode("span", null, "代理组数", -1)),
_createElementVNode("span", null, _toDisplayString(proxyGroups.value.length), 1)
]),
_createElementVNode("div", _hoisted_46, [
_cache[131] || (_cache[131] = _createElementVNode("span", null, "最后更新", -1)),
_cache[132] || (_cache[132] = _createElementVNode("span", null, "最后更新", -1)),
_createElementVNode("span", null, _toDisplayString(lastUpdated.value), 1)
])
])
@@ -6300,7 +6312,7 @@ return (_ctx, _cache) => {
default: _withCtx(() => [
_createVNode(_component_v_card_title, { class: "d-flex justify-space-between align-center" }, {
default: _withCtx(() => [
_cache[133] || (_cache[133] = _createElementVNode("span", { class: "text-h6 font-weight-medium" }, "订阅链接", -1)),
_cache[134] || (_cache[134] = _createElementVNode("span", { class: "text-h6 font-weight-medium" }, "订阅链接", -1)),
_createVNode(_component_v_tooltip, {
location: "top",
text: "复制链接"
@@ -6316,7 +6328,7 @@ return (_ctx, _cache) => {
}), {
default: _withCtx(() => [
_createVNode(_component_v_icon, null, {
default: _withCtx(() => _cache[132] || (_cache[132] = [
default: _withCtx(() => _cache[133] || (_cache[133] = [
_createTextVNode("mdi-content-copy")
])),
_: 1
@@ -6340,12 +6352,12 @@ return (_ctx, _cache) => {
color: "grey",
class: "mr-2"
}, {
default: _withCtx(() => _cache[134] || (_cache[134] = [
default: _withCtx(() => _cache[135] || (_cache[135] = [
_createTextVNode("mdi-link")
])),
_: 1
}),
_cache[135] || (_cache[135] = _createElementVNode("span", { class: "text-grey-darken-1" }, "原始链接:", -1))
_cache[136] || (_cache[136] = _createElementVNode("span", { class: "text-grey-darken-1" }, "原始链接:", -1))
]),
_createElementVNode("div", _hoisted_49, [
(Object.keys(subscriptionsInfo.value).length > 0)
@@ -6366,7 +6378,7 @@ return (_ctx, _cache) => {
]),
_createElementVNode("div", _hoisted_51, [
_createVNode(_component_v_icon, { color: "blue" }, {
default: _withCtx(() => _cache[136] || (_cache[136] = [
default: _withCtx(() => _cache[137] || (_cache[137] = [
_createTextVNode("mdi-arrow-down-bold")
])),
_: 1
@@ -6377,12 +6389,12 @@ return (_ctx, _cache) => {
color: "primary",
class: "mr-2"
}, {
default: _withCtx(() => _cache[137] || (_cache[137] = [
default: _withCtx(() => _cache[138] || (_cache[138] = [
_createTextVNode("mdi-link-variant")
])),
_: 1
}),
_cache[138] || (_cache[138] = _createElementVNode("span", { class: "text-grey-darken-1" }, "生成链接:", -1))
_cache[139] || (_cache[139] = _createElementVNode("span", { class: "text-grey-darken-1" }, "生成链接:", -1))
]),
_createElementVNode("div", _hoisted_53, [
_createElementVNode("a", {
@@ -6416,12 +6428,12 @@ return (_ctx, _cache) => {
_createVNode(_component_v_expansion_panel_title, null, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
default: _withCtx(() => _cache[139] || (_cache[139] = [
default: _withCtx(() => _cache[140] || (_cache[140] = [
_createTextVNode("mdi-cloud-download")
])),
_: 1
}),
_cache[140] || (_cache[140] = _createElementVNode("span", { class: "text-subtitle-1 font-weight-medium" }, "订阅管理", -1))
_cache[141] || (_cache[141] = _createElementVNode("span", { class: "text-subtitle-1 font-weight-medium" }, "订阅管理", -1))
]),
_: 1
}),
@@ -6434,7 +6446,7 @@ return (_ctx, _cache) => {
variant: "tonal",
class: "mb-4"
}, {
default: _withCtx(() => _cache[141] || (_cache[141] = [
default: _withCtx(() => _cache[142] || (_cache[142] = [
_createTextVNode(" 暂无订阅信息,请先添加订阅链接 ")
])),
_: 1
@@ -6520,11 +6532,11 @@ return (_ctx, _cache) => {
: _createCommentVNode("", true)
]),
_createElementVNode("div", _hoisted_57, [
_cache[142] || (_cache[142] = _createElementVNode("span", null, "已用流量:", -1)),
_cache[143] || (_cache[143] = _createElementVNode("span", null, "已用流量:", -1)),
_createElementVNode("strong", null, _toDisplayString(formatBytes(info.download + info.upload)), 1)
]),
_createElementVNode("div", _hoisted_58, [
_cache[143] || (_cache[143] = _createElementVNode("span", null, "剩余流量:", -1)),
_cache[144] || (_cache[144] = _createElementVNode("span", null, "剩余流量:", -1)),
_createElementVNode("strong", null, _toDisplayString(formatBytes(info.total - info.download)), 1)
]),
_createVNode(_component_v_progress_linear, {
@@ -6553,12 +6565,12 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
default: _withCtx(() => _cache[144] || (_cache[144] = [
default: _withCtx(() => _cache[145] || (_cache[145] = [
_createTextVNode("mdi-cloud-sync")
])),
_: 1
}),
_cache[145] || (_cache[145] = _createTextVNode(" 更新订阅 "))
_cache[146] || (_cache[146] = _createTextVNode(" 更新订阅 "))
]),
_: 2
}, 1032, ["onClick", "loading"])
@@ -6592,12 +6604,12 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
default: _withCtx(() => _cache[146] || (_cache[146] = [
default: _withCtx(() => _cache[147] || (_cache[147] = [
_createTextVNode("mdi-refresh")
])),
_: 1
}),
_cache[147] || (_cache[147] = _createTextVNode(" 刷新数据 "))
_cache[148] || (_cache[148] = _createTextVNode(" 刷新数据 "))
]),
_: 1
}, 8, ["loading"]),
@@ -6608,12 +6620,12 @@ return (_ctx, _cache) => {
}, {
default: _withCtx(() => [
_createVNode(_component_v_icon, { left: "" }, {
default: _withCtx(() => _cache[148] || (_cache[148] = [
default: _withCtx(() => _cache[149] || (_cache[149] = [
_createTextVNode("mdi-cog")
])),
_: 1
}),
_cache[149] || (_cache[149] = _createTextVNode(" 配置 "))
_cache[150] || (_cache[150] = _createTextVNode(" 配置 "))
]),
_: 1
})
@@ -6768,7 +6780,7 @@ return (_ctx, _cache) => {
color: "secondary",
onClick: closeRuleDialog
}, {
default: _withCtx(() => _cache[150] || (_cache[150] = [
default: _withCtx(() => _cache[151] || (_cache[151] = [
_createTextVNode("取消")
])),
_: 1
@@ -6777,7 +6789,7 @@ return (_ctx, _cache) => {
color: "primary",
type: "submit"
}, {
default: _withCtx(() => _cache[151] || (_cache[151] = [
default: _withCtx(() => _cache[152] || (_cache[152] = [
_createTextVNode("保存")
])),
_: 1
@@ -6993,7 +7005,7 @@ return (_ctx, _cache) => {
}, {
"prepend-inner": _withCtx(() => [
_createVNode(_component_v_icon, { color: "warning" }, {
default: _withCtx(() => _cache[152] || (_cache[152] = [
default: _withCtx(() => _cache[153] || (_cache[153] = [
_createTextVNode("mdi-timer")
])),
_: 1
@@ -7023,7 +7035,7 @@ return (_ctx, _cache) => {
}, {
"prepend-inner": _withCtx(() => [
_createVNode(_component_v_icon, { color: "warning" }, {
default: _withCtx(() => _cache[153] || (_cache[153] = [
default: _withCtx(() => _cache[154] || (_cache[154] = [
_createTextVNode("mdi-timer")
])),
_: 1
@@ -7155,7 +7167,7 @@ return (_ctx, _cache) => {
class: "mb-6",
variant: "tonal"
}, {
default: _withCtx(() => _cache[154] || (_cache[154] = [
default: _withCtx(() => _cache[155] || (_cache[155] = [
_createTextVNode(" 参考"),
_createElementVNode("a", {
href: "https://wiki.metacubex.one/config/proxy-groups/",
@@ -7171,7 +7183,7 @@ return (_ctx, _cache) => {
color: "secondary",
onClick: _cache[55] || (_cache[55] = $event => (proxyGroupDialog.value = false))
}, {
default: _withCtx(() => _cache[155] || (_cache[155] = [
default: _withCtx(() => _cache[156] || (_cache[156] = [
_createTextVNode("取消")
])),
_: 1
@@ -7180,7 +7192,7 @@ return (_ctx, _cache) => {
color: "primary",
type: "submit"
}, {
default: _withCtx(() => _cache[156] || (_cache[156] = [
default: _withCtx(() => _cache[157] || (_cache[157] = [
_createTextVNode("保存")
])),
_: 1
@@ -7206,7 +7218,7 @@ return (_ctx, _cache) => {
_createVNode(_component_v_card, null, {
default: _withCtx(() => [
_createVNode(_component_v_card_title, { class: "headline" }, {
default: _withCtx(() => _cache[157] || (_cache[157] = [
default: _withCtx(() => _cache[158] || (_cache[158] = [
_createTextVNode("YAML 配置")
])),
_: 1
@@ -7224,7 +7236,7 @@ return (_ctx, _cache) => {
color: "primary",
onClick: _cache[57] || (_cache[57] = $event => (copyToClipboard(displayedYaml.value)))
}, {
default: _withCtx(() => _cache[158] || (_cache[158] = [
default: _withCtx(() => _cache[159] || (_cache[159] = [
_createTextVNode("复制")
])),
_: 1
@@ -7233,7 +7245,7 @@ return (_ctx, _cache) => {
color: "primary",
onClick: _cache[58] || (_cache[58] = $event => (yamlDialog.value = false))
}, {
default: _withCtx(() => _cache[159] || (_cache[159] = [
default: _withCtx(() => _cache[160] || (_cache[160] = [
_createTextVNode("关闭")
])),
_: 1
@@ -7256,12 +7268,12 @@ return (_ctx, _cache) => {
_createVNode(_component_v_card, null, {
default: _withCtx(() => [
_createVNode(_component_v_card_title, null, {
default: _withCtx(() => _cache[160] || (_cache[160] = [
default: _withCtx(() => _cache[161] || (_cache[161] = [
_createTextVNode("导入规则")
])),
_: 1
}),
_createVNode(_component_v_card_text, { style: {"max-height":"600px","overflow-y":"auto"} }, {
_createVNode(_component_v_card_text, { style: {"max-height":"900px","overflow-y":"auto"} }, {
default: _withCtx(() => [
_createVNode(_component_v_select, {
modelValue: importRules.value.type,
@@ -7271,17 +7283,15 @@ return (_ctx, _cache) => {
required: "",
class: "mb-4"
}, null, 8, ["modelValue"]),
_createVNode(_component_v_textarea, {
modelValue: importRules.value.payload,
"onUpdate:modelValue": _cache[61] || (_cache[61] = $event => ((importRules.value.payload) = $event)),
label: "内容",
required: "",
placeholder: "rules: []",
class: "mb-4",
rows: "4",
"auto-grow": "",
style: {"max-height":"600px","overflow-y":"auto"}
}, null, 8, ["modelValue"]),
_createVNode(_unref(VAceEditor), {
value: importRules.value.payload,
"onUpdate:value": _cache[61] || (_cache[61] = $event => ((importRules.value.payload) = $event)),
lang: "yaml",
theme: "monokai",
options: editorOptions,
placeholder: rulesPlaceholder.value,
style: {"height":"30rem","width":"100%","margin-bottom":"16px"}
}, null, 8, ["value", "placeholder"]),
_createVNode(_component_v_alert, {
type: "info",
dense: "",
@@ -7289,7 +7299,7 @@ return (_ctx, _cache) => {
class: "mb-4",
variant: "tonal"
}, {
default: _withCtx(() => _cache[161] || (_cache[161] = [
default: _withCtx(() => _cache[162] || (_cache[162] = [
_createTextVNode(" 请输入 Clash 规则中的 "),
_createElementVNode("strong", null, "rules", -1),
_createTextVNode(" 字段,例如:"),
@@ -7312,7 +7322,7 @@ return (_ctx, _cache) => {
color: "secondary",
onClick: _cache[62] || (_cache[62] = $event => (importRuleDialog.value = false, error.value=null))
}, {
default: _withCtx(() => _cache[162] || (_cache[162] = [
default: _withCtx(() => _cache[163] || (_cache[163] = [
_createTextVNode("取消")
])),
_: 1
@@ -7321,7 +7331,7 @@ return (_ctx, _cache) => {
color: "primary",
onClick: importRule
}, {
default: _withCtx(() => _cache[163] || (_cache[163] = [
default: _withCtx(() => _cache[164] || (_cache[164] = [
_createTextVNode("导入")
])),
_: 1
@@ -7337,19 +7347,19 @@ return (_ctx, _cache) => {
}, 8, ["modelValue"]),
_createVNode(_component_v_dialog, {
modelValue: importExtraProxiesDialog.value,
"onUpdate:modelValue": _cache[67] || (_cache[67] = $event => ((importExtraProxiesDialog).value = $event)),
"onUpdate:modelValue": _cache[68] || (_cache[68] = $event => ((importExtraProxiesDialog).value = $event)),
"max-width": "600"
}, {
default: _withCtx(() => [
_createVNode(_component_v_card, null, {
default: _withCtx(() => [
_createVNode(_component_v_card_title, null, {
default: _withCtx(() => _cache[164] || (_cache[164] = [
default: _withCtx(() => _cache[165] || (_cache[165] = [
_createTextVNode("导入节点")
])),
_: 1
}),
_createVNode(_component_v_card_text, { style: {"max-height":"600px","overflow-y":"auto"} }, {
_createVNode(_component_v_card_text, { style: {"max-height":"900px","overflow-y":"auto"} }, {
default: _withCtx(() => [
_createVNode(_component_v_select, {
modelValue: importExtraProxies.value.type,
@@ -7359,26 +7369,38 @@ return (_ctx, _cache) => {
required: "",
class: "mb-4"
}, null, 8, ["modelValue"]),
_createVNode(_component_v_textarea, {
modelValue: importExtraProxies.value.payload,
"onUpdate:modelValue": _cache[65] || (_cache[65] = $event => ((importExtraProxies.value.payload) = $event)),
label: "内容",
required: "",
placeholder: importExtraProxiesPlaceholderText.value,
class: "mb-4",
rows: "4",
"auto-grow": ""
}, null, 8, ["modelValue", "placeholder"]),
(importExtraProxies.value.type === 'YAML')
? (_openBlock(), _createBlock(_unref(VAceEditor), {
key: 0,
value: importExtraProxies.value.payload,
"onUpdate:value": _cache[65] || (_cache[65] = $event => ((importExtraProxies.value.payload) = $event)),
lang: "yaml",
theme: "monokai",
options: editorOptions,
placeholder: proxiesPlaceholder.value,
style: {"height":"30rem","width":"100%","margin-bottom":"16px"}
}, null, 8, ["value", "placeholder"]))
: (_openBlock(), _createBlock(_component_v_textarea, {
key: 1,
modelValue: importExtraProxies.value.payload,
"onUpdate:modelValue": _cache[66] || (_cache[66] = $event => ((importExtraProxies.value.payload) = $event)),
label: "内容",
required: "",
placeholder: importExtraProxiesPlaceholderText.value,
class: "mb-4",
rows: "4",
"auto-grow": ""
}, null, 8, ["modelValue", "placeholder"])),
(importExtraProxies.value.type === 'YAML')
? (_openBlock(), _createBlock(_component_v_alert, {
key: 0,
key: 2,
type: "info",
dense: "",
text: "",
class: "mb-4",
variant: "tonal"
}, {
default: _withCtx(() => _cache[165] || (_cache[165] = [
default: _withCtx(() => _cache[166] || (_cache[166] = [
_createTextVNode(" 请输入 Clash 规则中的 "),
_createElementVNode("strong", null, "proxies", -1),
_createTextVNode(" 字段,例如:"),
@@ -7393,14 +7415,14 @@ return (_ctx, _cache) => {
: _createCommentVNode("", true),
(importExtraProxies.value.type === 'LINK')
? (_openBlock(), _createBlock(_component_v_alert, {
key: 1,
key: 3,
type: "info",
dense: "",
text: "",
class: "mb-4",
variant: "tonal"
}, {
default: _withCtx(() => _cache[166] || (_cache[166] = [
default: _withCtx(() => _cache[167] || (_cache[167] = [
_createTextVNode(" 请输入 V2RayN 格式的分享链接,例如:"),
_createElementVNode("br", null, null, -1),
_createElementVNode("code", null, "vmess://xxxx", -1),
@@ -7418,9 +7440,9 @@ return (_ctx, _cache) => {
_createVNode(_component_v_spacer),
_createVNode(_component_v_btn, {
color: "secondary",
onClick: _cache[66] || (_cache[66] = $event => (importExtraProxiesDialog.value=false, error.value=null))
onClick: _cache[67] || (_cache[67] = $event => (importExtraProxiesDialog.value=false, error.value=null))
}, {
default: _withCtx(() => _cache[167] || (_cache[167] = [
default: _withCtx(() => _cache[168] || (_cache[168] = [
_createTextVNode("取消")
])),
_: 1
@@ -7430,7 +7452,7 @@ return (_ctx, _cache) => {
onClick: importExtraProxiesFun,
loading: importProxiesLoading.value
}, {
default: _withCtx(() => _cache[168] || (_cache[168] = [
default: _withCtx(() => _cache[169] || (_cache[169] = [
_createTextVNode(" 导入 ")
])),
_: 1
@@ -7446,7 +7468,7 @@ return (_ctx, _cache) => {
}, 8, ["modelValue"]),
_createVNode(_component_v_dialog, {
modelValue: ruleProviderDialog.value,
"onUpdate:modelValue": _cache[78] || (_cache[78] = $event => ((ruleProviderDialog).value = $event)),
"onUpdate:modelValue": _cache[79] || (_cache[79] = $event => ((ruleProviderDialog).value = $event)),
"max-width": "600"
}, {
default: _withCtx(() => [
@@ -7468,7 +7490,7 @@ return (_ctx, _cache) => {
default: _withCtx(() => [
_createVNode(_component_v_text_field, {
modelValue: newRuleProvider.value.name,
"onUpdate:modelValue": _cache[68] || (_cache[68] = $event => ((newRuleProvider.value.name) = $event)),
"onUpdate:modelValue": _cache[69] || (_cache[69] = $event => ((newRuleProvider.value.name) = $event)),
label: "name",
required: "",
rules: [v => !!v || '名称不能为空'],
@@ -7476,7 +7498,7 @@ return (_ctx, _cache) => {
}, null, 8, ["modelValue", "rules"]),
_createVNode(_component_v_select, {
modelValue: newRuleProvider.value.type,
"onUpdate:modelValue": _cache[69] || (_cache[69] = $event => ((newRuleProvider.value.type) = $event)),
"onUpdate:modelValue": _cache[70] || (_cache[70] = $event => ((newRuleProvider.value.type) = $event)),
items: ruleProviderTypes,
label: "type",
required: "",
@@ -7487,7 +7509,7 @@ return (_ctx, _cache) => {
? (_openBlock(), _createBlock(_component_v_text_field, {
key: 0,
modelValue: newRuleProvider.value.url,
"onUpdate:modelValue": _cache[70] || (_cache[70] = $event => ((newRuleProvider.value.url) = $event)),
"onUpdate:modelValue": _cache[71] || (_cache[71] = $event => ((newRuleProvider.value.url) = $event)),
label: "url",
required: "",
rules: [(v) => !!v || 'URL 不能为空', (v) => isValidUrl(v) || '请输入有效的 URL',],
@@ -7499,7 +7521,7 @@ return (_ctx, _cache) => {
? (_openBlock(), _createBlock(_component_v_text_field, {
key: 1,
modelValue: newRuleProvider.value.path,
"onUpdate:modelValue": _cache[71] || (_cache[71] = $event => ((newRuleProvider.value.path) = $event)),
"onUpdate:modelValue": _cache[72] || (_cache[72] = $event => ((newRuleProvider.value.path) = $event)),
label: "path",
required: "",
rules: [v => !!v || '当类型为文件时,路径不能为空'],
@@ -7509,7 +7531,7 @@ return (_ctx, _cache) => {
: _createCommentVNode("", true),
_createVNode(_component_v_text_field, {
modelValue: newRuleProvider.value.interval,
"onUpdate:modelValue": _cache[72] || (_cache[72] = $event => ((newRuleProvider.value.interval) = $event)),
"onUpdate:modelValue": _cache[73] || (_cache[73] = $event => ((newRuleProvider.value.interval) = $event)),
modelModifiers: { number: true },
label: "interval",
class: "mb-4",
@@ -7521,7 +7543,7 @@ return (_ctx, _cache) => {
}, null, 8, ["modelValue", "rules"]),
_createVNode(_component_v_select, {
modelValue: newRuleProvider.value.behavior,
"onUpdate:modelValue": _cache[73] || (_cache[73] = $event => ((newRuleProvider.value.behavior) = $event)),
"onUpdate:modelValue": _cache[74] || (_cache[74] = $event => ((newRuleProvider.value.behavior) = $event)),
items: ruleProviderBehaviorTypes,
label: "behavior",
class: "mb-4",
@@ -7529,7 +7551,7 @@ return (_ctx, _cache) => {
}, null, 8, ["modelValue"]),
_createVNode(_component_v_select, {
modelValue: newRuleProvider.value.format,
"onUpdate:modelValue": _cache[74] || (_cache[74] = $event => ((newRuleProvider.value.format) = $event)),
"onUpdate:modelValue": _cache[75] || (_cache[75] = $event => ((newRuleProvider.value.format) = $event)),
items: ruleProviderFormatTypes,
label: "format",
class: "mb-4",
@@ -7537,7 +7559,7 @@ return (_ctx, _cache) => {
}, null, 8, ["modelValue"]),
_createVNode(_component_v_text_field, {
modelValue: newRuleProvider.value['size-limit'],
"onUpdate:modelValue": _cache[75] || (_cache[75] = $event => ((newRuleProvider.value['size-limit']) = $event)),
"onUpdate:modelValue": _cache[76] || (_cache[76] = $event => ((newRuleProvider.value['size-limit']) = $event)),
modelModifiers: { number: true },
label: "size-limit",
class: "mb-4",
@@ -7551,7 +7573,7 @@ return (_ctx, _cache) => {
? (_openBlock(), _createBlock(_component_v_combobox, {
key: 2,
modelValue: newRuleProvider.value.payload,
"onUpdate:modelValue": _cache[76] || (_cache[76] = $event => ((newRuleProvider.value.payload) = $event)),
"onUpdate:modelValue": _cache[77] || (_cache[77] = $event => ((newRuleProvider.value.payload) = $event)),
multiple: "",
chips: "",
"closable-chips": "",
@@ -7585,9 +7607,9 @@ return (_ctx, _cache) => {
_createVNode(_component_v_spacer),
_createVNode(_component_v_btn, {
color: "secondary",
onClick: _cache[77] || (_cache[77] = $event => (ruleProviderDialog.value = false, error.value=null))
onClick: _cache[78] || (_cache[78] = $event => (ruleProviderDialog.value = false, error.value=null))
}, {
default: _withCtx(() => _cache[169] || (_cache[169] = [
default: _withCtx(() => _cache[170] || (_cache[170] = [
_createTextVNode("取消")
])),
_: 1
@@ -7596,7 +7618,7 @@ return (_ctx, _cache) => {
color: "primary",
type: "submit"
}, {
default: _withCtx(() => _cache[170] || (_cache[170] = [
default: _withCtx(() => _cache[171] || (_cache[171] = [
_createTextVNode("保存")
])),
_: 1
@@ -7618,6 +7640,6 @@ return (_ctx, _cache) => {
}
};
const PageComponent = /*#__PURE__*/_export_sfc(_sfc_main, [['__scopeId',"data-v-0e274fe6"]]);
const PageComponent = /*#__PURE__*/_export_sfc(_sfc_main, [['__scopeId',"data-v-c476bdad"]]);
export { PageComponent as default };

View File

@@ -2,11 +2,11 @@ const currentImports = {};
const exportSet = new Set(['Module', '__esModule', 'default', '_export_sfc']);
let moduleMap = {
"./Page":()=>{
dynamicLoadingCss(["__federation_expose_Page-DEA-0_Sq.css"], false, './Page');
return __federation_import('./__federation_expose_Page-y2yjbals.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},
dynamicLoadingCss(["__federation_expose_Page-BYQOdJxf.css"], false, './Page');
return __federation_import('./__federation_expose_Page-D07z4AMB.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},
"./Config":()=>{
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)},
dynamicLoadingCss(["__federation_expose_Config-CibZbOMJ.css"], false, './Config');
return __federation_import('./__federation_expose_Config-D6fcnbk5.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},
"./Dashboard":()=>{
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)},};

File diff suppressed because one or more lines are too long

View File

@@ -28,7 +28,7 @@ class ImdbSource(_PluginBase):
# 插件图标
plugin_icon = "IMDb_IOS-OSX_App.png"
# 插件版本
plugin_version = "1.5.0"
plugin_version = "1.5.1"
# 插件作者
plugin_author = "wumode"
# 作者主页
@@ -45,13 +45,13 @@ class ImdbSource(_PluginBase):
_proxy: bool = False
_staff_picks: bool = False
_recognize_media: bool = False
_interests: List[str] = []
_component_size: str = 'medium'
_recognition_mode = 'auxiliary'
# 私有属性
_imdb_helper = None
_cache = {"discover": [], "trending": [], "trending_in_anime": [], "trending_in_sitcom": [],
"trending_in_documentary": [], "imdb_top_250": [], "staff_picks": {}}
_cache = {"discover": [], "trending": [], "imdb_top_250": [], "staff_picks": {}}
_img_proxy_prefix = ''
_scheduler: Optional[BackgroundScheduler] = None
_original_method = None
@@ -59,6 +59,7 @@ class ImdbSource(_PluginBase):
def init_plugin(self, config: dict = None):
plugin_instance = self
def patched_recognize_media(chain_self, meta: MetaBase = None,
mtype: Optional[MediaType] = None,
tmdbid: Optional[int] = None,
@@ -75,6 +76,7 @@ class ImdbSource(_PluginBase):
logger.info(f"通过插件 {plugin_instance.plugin_name} 执行recognize_media ...")
return plugin_instance.recognize_media(meta, mtype)
return result
# 给 patch 函数加唯一标记
patched_recognize_media._patched_by = id(self)
# 保存原始方法
@@ -87,9 +89,16 @@ class ImdbSource(_PluginBase):
self._proxy = config.get("proxy")
self._staff_picks = config.get("staff_picks")
self._recognize_media = config.get("recognize_media")
if 'interests' not in config:
self._interests = ['Anime', 'Documentary', 'Sitcom']
else:
self._interests = config.get("interests")
if isinstance(self._interests, str):
self._interests = [self._interests]
self._component_size = config.get("component_size") or "medium"
self._recognition_mode = config.get("recognition_mode") or "auxiliary"
self._imdb_helper = ImdbHelper(proxies=settings.PROXY if self._proxy else None)
self.__update_config()
if "media-amazon.com" not in settings.SECURITY_IMAGE_DOMAINS:
settings.SECURITY_IMAGE_DOMAINS.append("media-amazon.com")
if "media-imdb.com" not in settings.SECURITY_IMAGE_DOMAINS:
@@ -112,7 +121,6 @@ class ImdbSource(_PluginBase):
else:
self.stop_service()
def get_state(self) -> bool:
return self._enabled
@@ -210,7 +218,7 @@ class ImdbSource(_PluginBase):
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')), '')
if image.get("id") == entry.get('rmconst')), '')
primary_img_url = f'{self._img_proxy_prefix}{primary_img_url}'
item1 = {
'component': 'VCarouselItem',
@@ -480,6 +488,76 @@ class ImdbSource(_PluginBase):
"""
拼装插件配置页面需要返回两块数据1、页面配置2、数据结构
"""
option_groups = []
for i, v in self._imdb_helper.interests.items():
options = []
for name, in_id in v.items():
option = {
'component': 'VCol',
'props': {'cols': 12, 'md': 3},
'content': [
{
'component': 'VCheckbox',
'props': {'label': name, 'value': name, 'model': 'interests'},
}
]
}
options.append(option)
group = {
'component': 'VExpansionPanel',
'content': [
{
'component': 'VExpansionPanelTitle',
'text': i
},
{
'component': 'VExpansionPanelText',
'content': [
{
'component': 'VRow',
'content': options
}
]
}
]
}
option_groups.append(group)
interests_ui = {
'component': 'VExpansionPanels',
'props': {
'multiple': False,
'popout': True
},
'content': [
{
'component': 'VExpansionPanel',
'content': [
{
'component': 'VExpansionPanelTitle',
'text': '推荐'
},
{
'component': 'VExpansionPanelText',
'content': [
{
'component': 'VRow',
'content': [
{
'component': 'VExpansionPanels',
'props': {
'multiple': True,
'popout': True
},
'content': option_groups
}
]
}
]
}
]
}
]
}
return [
{
"component": "VForm",
@@ -495,7 +573,7 @@ class ImdbSource(_PluginBase):
"component": "VSwitch",
"props": {
"model": "enabled",
"label": "启用插件",
"label": "启用插件"
},
}
],
@@ -511,7 +589,7 @@ class ImdbSource(_PluginBase):
'component': 'VSwitch',
'props': {
'model': 'proxy',
'label': '使用代理服务器',
'label': '使用代理服务器'
}
}
]
@@ -527,7 +605,7 @@ class ImdbSource(_PluginBase):
'component': 'VSwitch',
'props': {
'model': 'staff_picks',
'label': 'IMDb 编辑精选组件',
'label': 'IMDb 编辑精选组件'
}
}
]
@@ -543,7 +621,7 @@ class ImdbSource(_PluginBase):
'component': 'VSwitch',
'props': {
'model': 'recognize_media',
'label': '媒体识别',
'label': '媒体识别'
}
}
]
@@ -567,7 +645,7 @@ class ImdbSource(_PluginBase):
'label': '组件规格',
'items': [
{"title": "小型", "value": "small"},
{"title": "中型", "value": "medium"},
{"title": "中型", "value": "medium"}
]
}
}
@@ -594,14 +672,30 @@ class ImdbSource(_PluginBase):
]
}
]
},
{
"component": "VRow",
"content": [
{
'component': 'VCol',
'props': {
'cols': 12,
'md': 12
},
'content': [
interests_ui
]
}
]
}
],
]
}
], {
"enabled": False,
"proxy": False,
"staff_picks": False,
"recognize_media": False,
"interests": ['Anime', 'Documentary', 'Sitcom'],
"component_size": "medium",
"recognition_mode": "auxiliary"
}
@@ -631,6 +725,19 @@ class ImdbSource(_PluginBase):
modules['recognize_media'] = self.recognize_media
return modules
def __update_config(self):
self.update_config(
{
"enabled": self._enabled,
"proxy": self._proxy,
"staff_picks": self._staff_picks,
"recognize_media": self._recognize_media,
"interests": self._interests,
"component_size": self._component_size,
"recognition_mode": self._recognition_mode,
}
)
def __cache_staff_picks(self):
entries = self._imdb_helper.staff_picks()
imdb_items = None
@@ -732,29 +839,30 @@ class ImdbSource(_PluginBase):
return True
return False
def trending_in_documentary(self, apikey: str, page: int = 1, count: int = 30) -> List[schemas.MediaInfo]:
if apikey != settings.API_TOKEN:
return []
def trending(self, interest: str, page: int = 1) -> List[schemas.MediaInfo]:
if not self._imdb_helper:
return []
title_types = ("tvSeries", "tvMiniSeries", "tvShort", 'movie')
if interest not in self._imdb_helper.interest_id:
return []
count = 30
title_types = ("tvSeries", "tvMiniSeries", "tvShort", 'tvMovie', 'movie')
first_page = False
if page == 1:
first_page = True
self._cache["trending_in_documentary"] = [] # 清空缓存
self._cache[interest] = [] # 清空缓存
results = []
if len(self._cache["trending_in_documentary"]) >= count:
results = self._cache["trending_in_documentary"][:count]
self._cache["trending_in_documentary"] = self._cache["trending_in_documentary"][count:]
if len(self._cache[interest]) >= count:
results = self._cache[interest][:count]
self._cache[interest] = self._cache[interest][count:]
else:
results.extend(self._cache["trending_in_documentary"])
results.extend(self._cache[interest])
remaining = count - len(results)
self._cache["trending_in_documentary"] = [] # 清空缓存
self._cache[interest] = [] # 清空缓存
data = self._imdb_helper.advanced_title_search(first_page=first_page,
title_types=title_types,
sort_by="POPULARITY",
sort_order="ASC",
interests=("Documentary",)
interests=(interest,)
)
if not data:
new_results = []
@@ -762,7 +870,7 @@ class ImdbSource(_PluginBase):
new_results = data.get("edges")
if new_results:
results.extend(new_results[:remaining])
self._cache["trending_in_documentary"] = new_results[remaining:]
self._cache[interest] = new_results[remaining:]
res = []
for item in results:
title_type_id = item.get('node').get("title").get("titleType", {}).get("id")
@@ -773,9 +881,7 @@ class ImdbSource(_PluginBase):
res.append(self.__series_to_media(item.get('node').get("title")))
return res
def imdb_top_250(self, apikey: str, page: int = 1, count: int = 30) -> List[schemas.MediaInfo]:
if apikey != settings.API_TOKEN:
return []
def imdb_top_250(self, page: int = 1, count: int = 30) -> List[schemas.MediaInfo]:
if not self._imdb_helper:
return []
title_types = ("movie",)
@@ -812,89 +918,7 @@ class ImdbSource(_PluginBase):
res.append(self.__movie_to_media(item.get('node').get("title")))
return res
def trending_in_sitcom(self, apikey: str, page: int = 1, count: int = 30) -> List[schemas.MediaInfo]:
if apikey != settings.API_TOKEN:
return []
if not self._imdb_helper:
return []
title_types = ("tvSeries", "tvMiniSeries", "tvShort")
first_page = False
if page == 1:
first_page = True
self._cache["trending_in_sitcom"] = [] # 清空缓存
results = []
if len(self._cache["trending_in_sitcom"]) >= count:
results = self._cache["trending_in_sitcom"][:count]
self._cache["trending_in_sitcom"] = self._cache["trending_in_sitcom"][count:]
else:
results.extend(self._cache["trending_in_sitcom"])
remaining = count - len(results)
self._cache["trending_in_sitcom"] = [] # 清空缓存
data = self._imdb_helper.advanced_title_search(first_page=first_page,
title_types=title_types,
sort_by="POPULARITY",
sort_order="ASC",
interests=("Sitcom",)
)
if not data:
new_results = []
else:
new_results = data.get("edges")
if new_results:
results.extend(new_results[:remaining])
self._cache["trending_in_sitcom"] = new_results[remaining:]
res = []
for item in results:
title_type_id = item.get('node').get("title").get("titleType", {}).get("id")
mtype = ImdbHelper.type_to_mtype(title_type_id)
if mtype == MediaType.TV:
res.append(self.__series_to_media(item.get('node').get("title")))
return res
def trending_in_anime(self, apikey: str, page: int = 1, count: int = 30) -> List[schemas.MediaInfo]:
if apikey != settings.API_TOKEN:
return []
if not self._imdb_helper:
return []
title_types = ("tvSeries", "tvMiniSeries", "tvShort", 'movie')
first_page = False
if page == 1:
first_page = True
self._cache["trending_in_anime"] = [] # 清空缓存
results = []
if len(self._cache["trending_in_anime"]) >= count:
results = self._cache["trending_in_anime"][:count]
self._cache["trending_in_anime"] = self._cache["trending_in_anime"][count:]
else:
results.extend(self._cache["trending_in_anime"])
remaining = count - len(results)
self._cache["trending_in_anime"] = [] # 清空缓存
data = self._imdb_helper.advanced_title_search(first_page=first_page,
title_types=title_types,
sort_by="POPULARITY",
sort_order="ASC",
interests=("Anime",)
)
if not data:
new_results = []
else:
new_results = data.get("edges")
if new_results:
results.extend(new_results[:remaining])
self._cache["trending_in_anime"] = new_results[remaining:]
res = []
for item in results:
title_type_id = item.get('node').get("title").get("titleType", {}).get("id")
mtype = ImdbHelper.type_to_mtype(title_type_id)
if mtype == MediaType.MOVIE:
res.append(self.__movie_to_media(item.get('node').get("title")))
elif mtype == MediaType.TV:
res.append(self.__series_to_media(item.get('node').get("title")))
return res
def imdb_trending(self, apikey: str, page: int = 1, count: int = 30) -> List[schemas.MediaInfo]:
if apikey != settings.API_TOKEN:
return []
def imdb_trending(self, page: int = 1, count: int = 30) -> List[schemas.MediaInfo]:
if not self._imdb_helper:
return []
title_types = ("tvSeries", "tvMiniSeries", "tvShort", 'movie')
@@ -932,7 +956,7 @@ class ImdbSource(_PluginBase):
res.append(self.__series_to_media(item.get('node').get("title")))
return res
def imdb_discover(self, apikey: str, mtype: str = "series",
def imdb_discover(self, mtype: str = "series",
country: str = None,
lang: str = None,
genre: str = None,
@@ -945,8 +969,6 @@ class ImdbSource(_PluginBase):
ranked_list: str = None,
page: int = 1, count: int = 30) -> List[schemas.MediaInfo]:
if apikey != settings.API_TOKEN:
return []
if not self._imdb_helper:
return []
title_type = ("tvSeries", "tvMiniSeries", "tvShort")
@@ -1055,50 +1077,41 @@ class ImdbSource(_PluginBase):
"summary": "API说明"
}]
"""
return [
apis = [
{
"path": "/imdb_discover",
"path": "/imdb-discover",
"endpoint": self.imdb_discover,
"methods": ["GET"],
"auth": 'bear',
"summary": "IMDb探索数据源",
"description": "获取 IMDb探索 数据",
},
{
"path": "/imdb_trending",
"path": "/imdb-trending",
"endpoint": self.imdb_trending,
"methods": ["GET"],
"auth": 'bear',
"summary": "IMDb Trending",
"description": "获取 IMDb Trending 数据",
},
{
"path": "/trending_in_anime",
"endpoint": self.trending_in_anime,
"methods": ["GET"],
"summary": "IMDb Trending in Anime",
"description": "获取 IMDb Trending in Anime 数据",
},
{
"path": "/trending_in_sitcom",
"endpoint": self.trending_in_sitcom,
"methods": ["GET"],
"summary": "IMDb Trending in Sitcom",
"description": "获取 IMDb Trending in Sitcom 数据",
},
{
"path": "/imdb_top_250",
"path": "/imdb-top-250",
"endpoint": self.imdb_top_250,
"methods": ["GET"],
"auth": 'bear',
"summary": "IMDb Top 250 Movies",
"description": "获取 IMDb Top 250 Movies 数据",
},
{
"path": "/trending_in_documentary",
"endpoint": self.trending_in_documentary,
"path": "/trending",
"endpoint": self.trending,
"methods": ["GET"],
"summary": "IMDb Trending in Documentary",
"description": "获取 IMDb Trending in Documentary 数据",
"auth": 'bear',
"summary": f"Trending on IMDb",
"description": f"获取 Trending on IMDb 数据",
}
]
return apis
@staticmethod
def imdb_filter_ui() -> List[dict]:
@@ -1638,7 +1651,7 @@ class ImdbSource(_PluginBase):
imdb_source = schemas.DiscoverMediaSource(
name="IMDb",
mediaid_prefix="imdb",
api_path=f"plugin/ImdbSource/imdb_discover?apikey={settings.API_TOKEN}",
api_path=f"plugin/ImdbSource/imdb-discover",
filter_params={
"mtype": "series",
"company": None,
@@ -1672,25 +1685,14 @@ class ImdbSource(_PluginBase):
event_data: MediaRecognizeConvertEventData = event.event_data
if not event_data:
return
api_key = settings.TMDB_API_KEY
if event_data.convert_type != "themoviedb" or not api_key:
if event_data.convert_type != "themoviedb":
return
if not event_data.mediaid.startswith("imdb"):
return
imdb_id = event_data.mediaid[5:]
api_url = f"https://{settings.TMDB_API_DOMAIN}/3/find/{imdb_id}?api_key={api_key}&external_source=imdb_id"
ret = RequestUtils(accept_type="application/json").get_res(api_url)
if ret:
data = ret.json()
all_results = []
for result_type in ["movie_results", "tv_results"]:
if data.get(result_type):
all_results.extend(data[result_type])
if not all_results:
return # 无匹配结果
# 按 popularity 降序排序,取最高人气的条目
most_popular_item = max(all_results, key=lambda x: x.get("popularity", -1))
event_data.media_dict["id"] = most_popular_item.get("id")
tmdb_id = ImdbSource.imdb_to_tmdb(imdb_id)
if tmdb_id is not None:
event_data.media_dict["id"] = tmdb_id
@eventmanager.register(ChainEventType.RecommendSource)
def recommend_source(self, event: Event):
@@ -1701,31 +1703,27 @@ class ImdbSource(_PluginBase):
return
imdb_trending: schemas.RecommendMediaSource = schemas.RecommendMediaSource(
name="IMDb Trending",
api_path=f"plugin/ImdbSource/imdb_trending?apikey={settings.API_TOKEN}",
api_path=f"plugin/ImdbSource/imdb-trending",
type='Rankings'
)
trending_in_anime: schemas.RecommendMediaSource = schemas.RecommendMediaSource(
name="Trending Anime on IMDb",
api_path=f"plugin/ImdbSource/trending_in_anime?apikey={settings.API_TOKEN}",
type='Anime'
)
trending_in_sitcom: schemas.RecommendMediaSource = schemas.RecommendMediaSource(
name="Trending Sitcom on IMDb",
api_path=f"plugin/ImdbSource/trending_in_sitcom?apikey={settings.API_TOKEN}",
type='TV Shows'
)
imdb_top_250: schemas.RecommendMediaSource = schemas.RecommendMediaSource(
name="IMDb Top 250 Movies",
api_path=f"plugin/ImdbSource/imdb_top_250?apikey={settings.API_TOKEN}",
api_path=f"plugin/ImdbSource/imdb-top-250",
type='Movies'
)
imdb_documentary: schemas.RecommendMediaSource = schemas.RecommendMediaSource(
name="Trending Documentary on IMDb",
api_path=f"plugin/ImdbSource/trending_in_documentary?apikey={settings.API_TOKEN}",
type='Rankings'
)
trending_source = [imdb_trending, trending_in_anime, trending_in_sitcom, imdb_top_250, imdb_documentary]
trending_source = [imdb_trending, imdb_top_250]
for interest in self._interests:
source_type = 'Rankings'
if interest in self._imdb_helper.interests['Anime']:
source_type = 'Anime'
elif interest in ['Sitcom']:
source_type = 'TV Shows'
source = schemas.RecommendMediaSource(
name=f"Trending {interest} on IMDb",
api_path=f"plugin/ImdbSource/trending?interest={interest}",
type=source_type
)
trending_source.append(source)
if not event_data.extra_sources:
event_data.extra_sources = trending_source
else:
@@ -1780,8 +1778,11 @@ class ImdbSource(_PluginBase):
if info:
break
if info:
info = self._imdb_helper.update_info(info.get('id'), info=info) or {}
info = self._imdb_helper.update_info(info.get('id'), info=info) or info
mediainfo = ImdbSource._convert_mediainfo(info)
mediainfo.tmdb_id = ImdbSource.imdb_to_tmdb(info.get('id'), mediainfo)
cat = ImdbHelper.get_category(info.get('media_type'), info)
mediainfo.set_category(cat)
logger.info(f"{meta.name} IMDb 识别结果:{mediainfo.type.value} "
f"{mediainfo.title_year} "
f"{mediainfo.imdb_id}")
@@ -1826,3 +1827,72 @@ class ImdbSource(_PluginBase):
if not mediainfo.release_date:
mediainfo.release_date = air_date
return mediainfo
@staticmethod
def imdb_to_tmdb(imdb_id: str, media_info: Optional[MediaInfo] = None) -> Optional[int]:
api_key = settings.TMDB_API_KEY
api_url = (
f"https://{settings.TMDB_API_DOMAIN}/3/find/{imdb_id}"
f"?api_key={api_key}&external_source=imdb_id"
)
ret = RequestUtils(accept_type="application/json").get_res(api_url)
if not ret:
return None
data = ret.json()
# 合并两种结果
all_results = []
for key in ["movie_results", "tv_results"]:
all_results.extend(data.get(key, []))
if not all_results:
return None # 无匹配结果
def pick_most_popular(results):
return max(results, key=lambda x: x.get("popularity", -1), default=None)
# 未提供 media_info直接返回人气最高的
if not media_info:
most_popular = pick_most_popular(all_results)
return most_popular.get("id") if most_popular else None
# 按类型过滤
type_map = {
MediaType.TV: ['tv'],
MediaType.MOVIE: ['movie'],
None: ['tv', 'movie']
}
allowed_types = type_map.get(media_info.type, ['tv', 'movie'])
filtered = [res for res in all_results if res.get('type') in allowed_types]
# 定义一个过滤链:每次过滤后如果只剩一个结果就返回
def filter_and_return(results, predicate):
filtered_res = [res for res in results if predicate(res)]
if not filtered_res:
return None, []
if len(filtered_res) == 1:
return filtered_res[0].get("id"), []
return None, filtered_res
# 通过年份过滤
if media_info.year:
def match_year(res):
date = res.get('first_air_date') or res.get('release_date') or ''
return date[:4] == media_info.year
result_id, filtered = filter_and_return(filtered, match_year)
if result_id:
return result_id
if not filtered:
return None
# 通过名称过滤
if media_info.names:
def match_name(res):
name = res.get('name') or res.get('title') or ''
return ImdbHelper.compare_names(name, media_info.names)
result_id, filtered = filter_and_return(filtered, match_name)
if result_id:
return result_id
if not filtered:
return None
# 最终按人气返回
most_popular = pick_most_popular(filtered)
return most_popular.get("id") if most_popular else None

File diff suppressed because one or more lines are too long