mirror of
https://git.mirrors.martin98.com/https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-11 18:49:03 +08:00
feat: 支持使用代理/节点/策略获取订阅
This commit is contained in:
parent
ca65e4209e
commit
80d46597b4
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sub-store",
|
"name": "sub-store",
|
||||||
"version": "2.14.249",
|
"version": "2.14.251",
|
||||||
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
|
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
|
||||||
"main": "src/main.js",
|
"main": "src/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -111,7 +111,12 @@ async function downloadSubscription(req, res) {
|
|||||||
}
|
}
|
||||||
if (!$arguments.noFlow) {
|
if (!$arguments.noFlow) {
|
||||||
// forward flow headers
|
// forward flow headers
|
||||||
const flowInfo = await getFlowHeaders(url);
|
const flowInfo = await getFlowHeaders(
|
||||||
|
url,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
sub.proxy,
|
||||||
|
);
|
||||||
if (flowInfo) {
|
if (flowInfo) {
|
||||||
res.set('subscription-userinfo', flowInfo);
|
res.set('subscription-userinfo', flowInfo);
|
||||||
}
|
}
|
||||||
@ -243,7 +248,12 @@ async function downloadCollection(req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$arguments.noFlow) {
|
if (!$arguments.noFlow) {
|
||||||
const flowInfo = await getFlowHeaders(url);
|
const flowInfo = await getFlowHeaders(
|
||||||
|
url,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
sub.proxy,
|
||||||
|
);
|
||||||
if (flowInfo) {
|
if (flowInfo) {
|
||||||
res.set('subscription-userinfo', flowInfo);
|
res.set('subscription-userinfo', flowInfo);
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,12 @@ async function compareSub(req, res) {
|
|||||||
.filter((i) => i.length)
|
.filter((i) => i.length)
|
||||||
.map(async (url) => {
|
.map(async (url) => {
|
||||||
try {
|
try {
|
||||||
return await download(url, sub.ua);
|
return await download(
|
||||||
|
url,
|
||||||
|
sub.ua,
|
||||||
|
undefined,
|
||||||
|
sub.proxy,
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
errors[url] = err;
|
errors[url] = err;
|
||||||
$.error(
|
$.error(
|
||||||
@ -195,7 +200,12 @@ async function compareCollection(req, res) {
|
|||||||
.filter((i) => i.length)
|
.filter((i) => i.length)
|
||||||
.map(async (url) => {
|
.map(async (url) => {
|
||||||
try {
|
try {
|
||||||
return await download(url, sub.ua);
|
return await download(
|
||||||
|
url,
|
||||||
|
sub.ua,
|
||||||
|
undefined,
|
||||||
|
sub.proxy,
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
errors[url] = err;
|
errors[url] = err;
|
||||||
$.error(
|
$.error(
|
||||||
|
@ -113,7 +113,12 @@ async function getFlowInfo(req, res) {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const flowHeaders = await getFlowHeaders(url);
|
const flowHeaders = await getFlowHeaders(
|
||||||
|
url,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
sub.proxy,
|
||||||
|
);
|
||||||
if (!flowHeaders) {
|
if (!flowHeaders) {
|
||||||
failed(
|
failed(
|
||||||
res,
|
res,
|
||||||
|
@ -62,7 +62,12 @@ async function produceArtifact({
|
|||||||
.filter((i) => i.length)
|
.filter((i) => i.length)
|
||||||
.map(async (url) => {
|
.map(async (url) => {
|
||||||
try {
|
try {
|
||||||
return await download(url, ua || sub.ua);
|
return await download(
|
||||||
|
url,
|
||||||
|
ua || sub.ua,
|
||||||
|
undefined,
|
||||||
|
sub.proxy,
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
errors[url] = err;
|
errors[url] = err;
|
||||||
$.error(
|
$.error(
|
||||||
@ -102,7 +107,12 @@ async function produceArtifact({
|
|||||||
.filter((i) => i.length)
|
.filter((i) => i.length)
|
||||||
.map(async (url) => {
|
.map(async (url) => {
|
||||||
try {
|
try {
|
||||||
return await download(url, ua || sub.ua);
|
return await download(
|
||||||
|
url,
|
||||||
|
ua || sub.ua,
|
||||||
|
undefined,
|
||||||
|
sub.proxy,
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
errors[url] = err;
|
errors[url] = err;
|
||||||
$.error(
|
$.error(
|
||||||
@ -198,7 +208,12 @@ async function produceArtifact({
|
|||||||
.filter((i) => i.length)
|
.filter((i) => i.length)
|
||||||
.map(async (url) => {
|
.map(async (url) => {
|
||||||
try {
|
try {
|
||||||
return await download(url, sub.ua);
|
return await download(
|
||||||
|
url,
|
||||||
|
sub.ua,
|
||||||
|
undefined,
|
||||||
|
sub.proxy,
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
errors[url] = err;
|
errors[url] = err;
|
||||||
$.error(
|
$.error(
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { SETTINGS_KEY } from '@/constants';
|
import { SETTINGS_KEY } from '@/constants';
|
||||||
import { HTTP, ENV } from '@/vendor/open-api';
|
import { HTTP, ENV } from '@/vendor/open-api';
|
||||||
import { hex_md5 } from '@/vendor/md5';
|
import { hex_md5 } from '@/vendor/md5';
|
||||||
|
import { getPolicyDescriptor } from '@/utils';
|
||||||
import resourceCache from '@/utils/resource-cache';
|
import resourceCache from '@/utils/resource-cache';
|
||||||
import headersResourceCache from '@/utils/headers-resource-cache';
|
import headersResourceCache from '@/utils/headers-resource-cache';
|
||||||
import {
|
import {
|
||||||
@ -13,7 +14,7 @@ import $ from '@/core/app';
|
|||||||
|
|
||||||
const tasks = new Map();
|
const tasks = new Map();
|
||||||
|
|
||||||
export default async function download(rawUrl, ua, timeout) {
|
export default async function download(rawUrl, ua, timeout, proxy) {
|
||||||
let $arguments = {};
|
let $arguments = {};
|
||||||
let url = rawUrl.replace(/#noFlow$/, '');
|
let url = rawUrl.replace(/#noFlow$/, '');
|
||||||
const rawArgs = url.split('#');
|
const rawArgs = url.split('#');
|
||||||
@ -52,7 +53,7 @@ export default async function download(rawUrl, ua, timeout) {
|
|||||||
// return item.content;
|
// return item.content;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const { isNode } = ENV();
|
const { isNode, isStash } = ENV();
|
||||||
const { defaultUserAgent, defaultTimeout, cacheThreshold } =
|
const { defaultUserAgent, defaultTimeout, cacheThreshold } =
|
||||||
$.read(SETTINGS_KEY);
|
$.read(SETTINGS_KEY);
|
||||||
const userAgent = ua || defaultUserAgent || 'clash.meta';
|
const userAgent = ua || defaultUserAgent || 'clash.meta';
|
||||||
@ -65,6 +66,8 @@ export default async function download(rawUrl, ua, timeout) {
|
|||||||
const http = HTTP({
|
const http = HTTP({
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': userAgent,
|
'User-Agent': userAgent,
|
||||||
|
'X-Stash-Selected-Proxy':
|
||||||
|
isStash && proxy ? encodeURIComponent(proxy) : undefined,
|
||||||
},
|
},
|
||||||
timeout: requestTimeout,
|
timeout: requestTimeout,
|
||||||
});
|
});
|
||||||
@ -78,10 +81,14 @@ export default async function download(rawUrl, ua, timeout) {
|
|||||||
result = cached;
|
result = cached;
|
||||||
} else {
|
} else {
|
||||||
$.info(
|
$.info(
|
||||||
`Downloading...\nUser-Agent: ${userAgent}\nTimeout: ${requestTimeout}\nURL: ${url}`,
|
`Downloading...\nUser-Agent: ${userAgent}\nTimeout: ${requestTimeout}\nProxy: ${proxy}\nURL: ${url}`,
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
const { body, headers } = await http.get(url);
|
const { body, headers } = await http.get({
|
||||||
|
url,
|
||||||
|
proxy,
|
||||||
|
...getPolicyDescriptor(proxy),
|
||||||
|
});
|
||||||
|
|
||||||
if (headers) {
|
if (headers) {
|
||||||
const flowInfo = getFlowField(headers);
|
const flowInfo = getFlowField(headers);
|
||||||
@ -116,7 +123,11 @@ export default async function download(rawUrl, ua, timeout) {
|
|||||||
// 检查订阅有效性
|
// 检查订阅有效性
|
||||||
|
|
||||||
if ($arguments?.validCheck) {
|
if ($arguments?.validCheck) {
|
||||||
await validCheck(parseFlowHeaders(await getFlowHeaders(url)));
|
await validCheck(
|
||||||
|
parseFlowHeaders(
|
||||||
|
await getFlowHeaders(url, undefined, undefined, proxy),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNode) {
|
if (!isNode) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { SETTINGS_KEY } from '@/constants';
|
import { SETTINGS_KEY } from '@/constants';
|
||||||
import { HTTP } from '@/vendor/open-api';
|
import { HTTP, ENV } from '@/vendor/open-api';
|
||||||
|
import { getPolicyDescriptor } from '@/utils';
|
||||||
import $ from '@/core/app';
|
import $ from '@/core/app';
|
||||||
import headersResourceCache from '@/utils/headers-resource-cache';
|
import headersResourceCache from '@/utils/headers-resource-cache';
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ export function getFlowField(headers) {
|
|||||||
)[0];
|
)[0];
|
||||||
return headers[subkey];
|
return headers[subkey];
|
||||||
}
|
}
|
||||||
export async function getFlowHeaders(rawUrl, ua, timeout) {
|
export async function getFlowHeaders(rawUrl, ua, timeout, proxy) {
|
||||||
let url = rawUrl;
|
let url = rawUrl;
|
||||||
let $arguments = {};
|
let $arguments = {};
|
||||||
const rawArgs = url.split('#');
|
const rawArgs = url.split('#');
|
||||||
@ -33,6 +34,7 @@ export async function getFlowHeaders(rawUrl, ua, timeout) {
|
|||||||
if ($arguments?.noFlow) {
|
if ($arguments?.noFlow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const { isStash } = ENV();
|
||||||
const cached = headersResourceCache.get(url);
|
const cached = headersResourceCache.get(url);
|
||||||
let flowInfo;
|
let flowInfo;
|
||||||
if (!$arguments?.noCache && cached) {
|
if (!$arguments?.noCache && cached) {
|
||||||
@ -55,8 +57,14 @@ export async function getFlowHeaders(rawUrl, ua, timeout) {
|
|||||||
.filter((i) => i.length)[0],
|
.filter((i) => i.length)[0],
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': userAgent,
|
'User-Agent': userAgent,
|
||||||
|
'X-Stash-Selected-Proxy':
|
||||||
|
isStash && proxy
|
||||||
|
? encodeURIComponent(proxy)
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
timeout: requestTimeout,
|
timeout: requestTimeout,
|
||||||
|
proxy,
|
||||||
|
...getPolicyDescriptor(proxy),
|
||||||
});
|
});
|
||||||
flowInfo = getFlowField(headers);
|
flowInfo = getFlowField(headers);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -178,7 +186,7 @@ export function getRmainingDays(opt = {}) {
|
|||||||
|
|
||||||
return daysDiff;
|
return daysDiff;
|
||||||
} else {
|
} else {
|
||||||
if (!resetDay) throw new Error('未提供月重置日 resetDay');
|
if (!resetDay) return;
|
||||||
resetDay = parseInt(resetDay);
|
resetDay = parseInt(resetDay);
|
||||||
if (isNaN(resetDay) || resetDay <= 0 || resetDay > 31)
|
if (isNaN(resetDay) || resetDay <= 0 || resetDay > 31)
|
||||||
throw new Error('月重置日应为 1-31 之间的整数');
|
throw new Error('月重置日应为 1-31 之间的整数');
|
||||||
|
@ -35,6 +35,17 @@ function getIfPresent(obj, defaultValue) {
|
|||||||
return isPresent(obj) ? obj : defaultValue;
|
return isPresent(obj) ? obj : defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPolicyDescriptor(str) {
|
||||||
|
if (!str) return {};
|
||||||
|
return /^.+?\s*?=\s*?.+?\s*?,.+?/.test(str)
|
||||||
|
? {
|
||||||
|
'policy-descriptor': str,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
policy: str,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const utf8ArrayToStr =
|
const utf8ArrayToStr =
|
||||||
typeof TextDecoder !== 'undefined'
|
typeof TextDecoder !== 'undefined'
|
||||||
? (v) => new TextDecoder().decode(new Uint8Array(v))
|
? (v) => new TextDecoder().decode(new Uint8Array(v))
|
||||||
@ -91,4 +102,5 @@ export {
|
|||||||
isPresent,
|
isPresent,
|
||||||
getIfPresent,
|
getIfPresent,
|
||||||
utf8ArrayToStr,
|
utf8ArrayToStr,
|
||||||
|
getPolicyDescriptor,
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user