mirror of
https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-10 00:52:40 +00:00
feat: 脚本内部 produceArtifact 支持指定 produceType: 'internal', produceOpts: { 'include-unsupported-proxy': true } 来获得内部的数据结构; 订阅链接参数支持 type=internal&includeUnsupportedProxy=true; 文件支持 nunjucks 模板, 为 sing-box 增加的 Filter 用法 sub/col 为订阅/组合订阅中的节点名 {{ '订阅的name' | sub('美国|🇺🇸|us', 'i') }}, subNode/colNode 为订阅/组合订阅中的节点 {{ '订阅的name' | subNode('美国|🇺🇸|us', 'i') }}, 底层 produceArtifact('subscription', 'sing-box', 'internal', '美国|🇺🇸|us', 'i')
This commit is contained in:
@@ -20,7 +20,7 @@ export function getPlatformFromHeaders(headers) {
|
||||
} else if (UA.indexOf('Decar') !== -1 || UA.indexOf('Loon') !== -1) {
|
||||
return 'Loon';
|
||||
} else if (UA.indexOf('Shadowrocket') !== -1) {
|
||||
return 'ShadowRocket';
|
||||
return 'Shadowrocket';
|
||||
} else if (UA.indexOf('Stash') !== -1) {
|
||||
return 'Stash';
|
||||
} else if (
|
||||
|
||||
210
backend/src/utils/tpl.js
Normal file
210
backend/src/utils/tpl.js
Normal file
@@ -0,0 +1,210 @@
|
||||
import nunjucks from 'nunjucks';
|
||||
import { ProxyUtils } from '@/core/proxy-utils';
|
||||
import { produceArtifact } from '@/restful/sync';
|
||||
import lodash from 'lodash';
|
||||
import $ from '@/core/app';
|
||||
import scriptResourceCache from '@/utils/script-resource-cache';
|
||||
import { getFlowHeaders, parseFlowHeaders, flowTransfer } from '@/utils/flow';
|
||||
const flowUtils = { getFlowHeaders, parseFlowHeaders, flowTransfer };
|
||||
const n = nunjucks.configure({ autoescape: false });
|
||||
|
||||
n.addFilter(
|
||||
'produceArtifact',
|
||||
(...args) => {
|
||||
const callback = args.pop();
|
||||
const name = args[0];
|
||||
const type = args[1];
|
||||
const platform = args[2];
|
||||
const produceType = args[3];
|
||||
const nameRegex = args[4];
|
||||
const nameRegexFlags = args[5];
|
||||
produceArtifact({
|
||||
type,
|
||||
name,
|
||||
platform,
|
||||
produceType,
|
||||
})
|
||||
.then((artifact) => {
|
||||
callback(
|
||||
null,
|
||||
artifact.filter(({ tag }) =>
|
||||
nameRegex
|
||||
? new RegExp(nameRegex, nameRegexFlags).test(tag)
|
||||
: true,
|
||||
),
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
$.error(`produceArtifact filter error: ${e.message ?? e}`);
|
||||
callback(e);
|
||||
});
|
||||
},
|
||||
true,
|
||||
);
|
||||
n.addFilter(
|
||||
'subNode',
|
||||
(...args) => {
|
||||
const callback = args.pop();
|
||||
const name = args[0];
|
||||
const nameRegex = args[1];
|
||||
const nameRegexFlags = args[2];
|
||||
produceArtifact({
|
||||
type: 'subscription',
|
||||
name,
|
||||
platform: 'sing-box',
|
||||
produceType: 'internal',
|
||||
})
|
||||
.then((artifact) => {
|
||||
callback(
|
||||
null,
|
||||
JSON.stringify(
|
||||
artifact.filter(({ tag }) =>
|
||||
nameRegex
|
||||
? new RegExp(nameRegex, nameRegexFlags).test(
|
||||
tag,
|
||||
)
|
||||
: true,
|
||||
),
|
||||
).replace(/(^\[|\]$)/g, ''),
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
$.error(`subNode filter error: ${e.message ?? e}`);
|
||||
callback(e);
|
||||
});
|
||||
},
|
||||
true,
|
||||
);
|
||||
n.addFilter(
|
||||
'colNode',
|
||||
(...args) => {
|
||||
const callback = args.pop();
|
||||
const name = args[0];
|
||||
const nameRegex = args[1];
|
||||
const nameRegexFlags = args[2];
|
||||
produceArtifact({
|
||||
type: 'collection',
|
||||
name,
|
||||
platform: 'sing-box',
|
||||
produceType: 'internal',
|
||||
})
|
||||
.then((artifact) => {
|
||||
callback(
|
||||
null,
|
||||
JSON.stringify(
|
||||
artifact.filter(({ tag }) =>
|
||||
nameRegex
|
||||
? new RegExp(nameRegex, nameRegexFlags).test(
|
||||
tag,
|
||||
)
|
||||
: true,
|
||||
),
|
||||
).replace(/(^\[|\]$)/g, ''),
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
$.error(`colNode filter error: ${e.message ?? e}`);
|
||||
callback(e);
|
||||
});
|
||||
},
|
||||
true,
|
||||
);
|
||||
n.addFilter(
|
||||
'sub',
|
||||
(...args) => {
|
||||
const callback = args.pop();
|
||||
const name = args[0];
|
||||
const nameRegex = args[1];
|
||||
const nameRegexFlags = args[2];
|
||||
produceArtifact({
|
||||
type: 'subscription',
|
||||
name,
|
||||
platform: 'sing-box',
|
||||
produceType: 'internal',
|
||||
})
|
||||
.then((artifact) => {
|
||||
callback(
|
||||
null,
|
||||
JSON.stringify(
|
||||
artifact
|
||||
.filter(({ tag }) =>
|
||||
nameRegex
|
||||
? new RegExp(
|
||||
nameRegex,
|
||||
nameRegexFlags,
|
||||
).test(tag)
|
||||
: true,
|
||||
)
|
||||
.map((p) => p.tag),
|
||||
).replace(/(^\[|\]$)/g, ''),
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
$.error(`sub filter error: ${e.message ?? e}`);
|
||||
callback(e);
|
||||
});
|
||||
},
|
||||
true,
|
||||
);
|
||||
n.addFilter(
|
||||
'col',
|
||||
(...args) => {
|
||||
const callback = args.pop();
|
||||
const name = args[0];
|
||||
const nameRegex = args[1];
|
||||
const nameRegexFlags = args[2];
|
||||
produceArtifact({
|
||||
type: 'collection',
|
||||
name,
|
||||
platform: 'sing-box',
|
||||
produceType: 'internal',
|
||||
})
|
||||
.then((artifact) => {
|
||||
callback(
|
||||
null,
|
||||
JSON.stringify(
|
||||
artifact
|
||||
.filter(({ tag }) =>
|
||||
nameRegex
|
||||
? new RegExp(
|
||||
nameRegex,
|
||||
nameRegexFlags,
|
||||
).test(tag)
|
||||
: true,
|
||||
)
|
||||
.map((p) => p.tag),
|
||||
).replace(/(^\[|\]$)/g, ''),
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
$.error(`col filter error: ${e.message ?? e}`);
|
||||
callback(e);
|
||||
});
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
export const render = async (tpl = '', data = {}) => {
|
||||
return new Promise((resolve) => {
|
||||
n.renderString(
|
||||
tpl,
|
||||
{
|
||||
$substore: $,
|
||||
lodash: lodash,
|
||||
ProxyUtils: ProxyUtils,
|
||||
scriptResourceCache: scriptResourceCache,
|
||||
flowUtils: flowUtils,
|
||||
// produceArtifact: produceArtifact,
|
||||
...data,
|
||||
},
|
||||
(e, result) => {
|
||||
if (e) {
|
||||
$.error(`rendering error: ${e.message ?? e}`);
|
||||
resolve('');
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user