Skip to content

Commit 9f1420d

Browse files
committed
feat: 文件 mihomo 配置新增操作: 从订阅添加节点
1 parent fd74d98 commit 9f1420d

3 files changed

Lines changed: 148 additions & 1 deletion

File tree

backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sub-store",
3-
"version": "2.29.0",
3+
"version": "2.30.0",
44
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.",
55
"main": "src/main.js",
66
"packageManager": "pnpm@11.0.9",

backend/src/core/proxy-utils/processors/index.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,66 @@ function ScriptOperator(
475475
};
476476
}
477477

478+
const ADD_PROXIES_FROM_SUBSCRIPTION_OPERATOR =
479+
'Add Proxies From Subscription Operator';
480+
481+
function normalizeMihomoConfig(content) {
482+
if (!content) return {};
483+
484+
const config = YAML.safeLoad(content);
485+
return isPlainObject(config) ? config : {};
486+
}
487+
488+
function getMihomoProfileProxies(config) {
489+
return Array.isArray(config?.proxies) ? config.proxies : [];
490+
}
491+
492+
function AddProxiesFromSubscriptionOperator({
493+
sourceType = 'subscription',
494+
sourceName,
495+
includeUnsupportedProxy,
496+
position = 'replace',
497+
} = {}) {
498+
const apply = async (input) => {
499+
if (input?.$file?.type !== 'mihomoProfile') return input;
500+
501+
const config = normalizeMihomoConfig(input.$content);
502+
const currentProxies = getMihomoProfileProxies(config);
503+
const proxies = await produceArtifact({
504+
type: sourceType,
505+
name: sourceName,
506+
platform: 'mihomo',
507+
produceType: 'internal',
508+
produceOpts: {
509+
'delete-underscore-fields': true,
510+
'include-unsupported-proxy': includeUnsupportedProxy,
511+
},
512+
});
513+
514+
switch (position) {
515+
case 'front':
516+
config.proxies = [...proxies, ...currentProxies];
517+
break;
518+
case 'back':
519+
config.proxies = [...currentProxies, ...proxies];
520+
break;
521+
case 'replace':
522+
default:
523+
config.proxies = proxies;
524+
break;
525+
}
526+
527+
input.$content = ProxyUtils.yaml.safeDump(config);
528+
return input;
529+
};
530+
531+
return {
532+
name: ADD_PROXIES_FROM_SUBSCRIPTION_OPERATOR,
533+
func: apply,
534+
nodeFunc: apply,
535+
};
536+
}
537+
478538
function parseIP4P(IP4P) {
479539
let server;
480540
let port;
@@ -1136,6 +1196,8 @@ export default {
11361196
'Regex Rename Operator': RegexRenameOperator,
11371197
'Regex Delete Operator': RegexDeleteOperator,
11381198
'Script Operator': ScriptOperator,
1199+
[ADD_PROXIES_FROM_SUBSCRIPTION_OPERATOR]:
1200+
AddProxiesFromSubscriptionOperator,
11391201
[RESPONSE_TRANSFORMER]: ResponseTransformer,
11401202
'Handle Duplicate Operator': HandleDuplicateOperator,
11411203
'Resolve Domain Operator': ResolveDomainOperator,

backend/src/test/restful/mihomo-profile-file.spec.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,4 +299,89 @@ describe('mihomo profile file routes', function () {
299299
expect(res.sent).to.include('mixed-port: 7892');
300300
expect(res.sent).to.include('name: Unsupported');
301301
});
302+
303+
it('adds subscription proxies to mihomoProfile files without moving an existing proxies key', async function () {
304+
state[FILES_KEY] = [
305+
{
306+
name: 'add-proxies-file',
307+
type: 'mihomoProfile',
308+
sourceType: 'none',
309+
process: [
310+
{
311+
type: 'Script Operator',
312+
args: {
313+
mode: 'script',
314+
content:
315+
'mixed-port: 7890\n' +
316+
'proxies:\n' +
317+
' note: not-array\n' +
318+
'proxy-groups:\n' +
319+
' - name: Auto\n' +
320+
' type: select\n' +
321+
' proxies: [Supported]',
322+
},
323+
},
324+
{
325+
type: 'Add Proxies From Subscription Operator',
326+
args: {
327+
sourceType: 'subscription',
328+
sourceName: 'demo-sub',
329+
includeUnsupportedProxy: false,
330+
position: 'back',
331+
},
332+
},
333+
],
334+
},
335+
];
336+
337+
const res = await requestFile('add-proxies-file');
338+
339+
expect(res.statusCode).to.equal(200);
340+
expect(res.sent.indexOf('mixed-port:')).to.be.lessThan(
341+
res.sent.indexOf('proxies:'),
342+
);
343+
expect(res.sent.indexOf('proxies:')).to.be.lessThan(
344+
res.sent.indexOf('proxy-groups:'),
345+
);
346+
expect(res.sent).to.include('name: Supported');
347+
expect(res.sent).to.not.include('name: Unsupported');
348+
});
349+
350+
it('can insert subscription proxies before existing mihomoProfile proxies', async function () {
351+
state[FILES_KEY] = [
352+
{
353+
name: 'insert-proxies-file',
354+
type: 'mihomoProfile',
355+
sourceType: 'none',
356+
process: [
357+
{
358+
type: 'Script Operator',
359+
args: {
360+
mode: 'script',
361+
content:
362+
'proxies:\n' +
363+
' - name: Existing\n' +
364+
' type: direct',
365+
},
366+
},
367+
{
368+
type: 'Add Proxies From Subscription Operator',
369+
args: {
370+
sourceType: 'subscription',
371+
sourceName: 'demo-sub',
372+
includeUnsupportedProxy: false,
373+
position: 'front',
374+
},
375+
},
376+
],
377+
},
378+
];
379+
380+
const res = await requestFile('insert-proxies-file');
381+
382+
expect(res.statusCode).to.equal(200);
383+
expect(res.sent.indexOf('name: Supported')).to.be.lessThan(
384+
res.sent.indexOf('name: Existing'),
385+
);
386+
});
302387
});

0 commit comments

Comments
 (0)