Compare commits

..

6 Commits

Author SHA1 Message Date
xream
278beae99a feat: 支持 Egern 前置代理 prev_hop 和 Hysteria2 端口跳跃 2024-12-29 20:05:55 +08:00
xream
3aedd5943d feat: sing-box includeUnsupportedProxy 开启支持 Hysteria2 端口跳跃 2024-12-29 16:07:33 +08:00
xream
222551eb20 feat: Egern 增加默认 sni 2024-12-28 21:00:40 +08:00
xream
0d5e1ab38b feat: 下载订阅的日志中增加请求 target 和实际输出 2024-12-28 17:42:26 +08:00
xream
a3ec98caa9 feat: Clash 订阅仅缓存 proxies 数据 2024-12-27 21:55:13 +08:00
xream
d9e4d814bb feat: geo 更新 2024-12-27 21:35:51 +08:00
9 changed files with 73 additions and 12 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "sub-store", "name": "sub-store",
"version": "2.14.453", "version": "2.15.6",
"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": {

View File

@@ -72,6 +72,15 @@ export default function Egern_Producer() {
return true; return true;
}) })
.map((proxy) => { .map((proxy) => {
if (proxy.tls && !proxy.sni) {
proxy.sni = proxy.server;
}
const prev_hop =
proxy.prev_hop ||
proxy['underlying-proxy'] ||
proxy['dialer-proxy'] ||
proxy.detour;
if (proxy.type === 'http') { if (proxy.type === 'http') {
proxy = { proxy = {
type: 'http', type: 'http',
@@ -130,6 +139,8 @@ export default function Egern_Producer() {
next_hop: proxy.next_hop, next_hop: proxy.next_hop,
sni: proxy.sni, sni: proxy.sni,
skip_tls_verify: proxy['skip-cert-verify'], skip_tls_verify: proxy['skip-cert-verify'],
port_hopping: proxy.ports,
port_hopping_interval: proxy['hop-interval'],
}; };
if (proxy['obfs-password'] && proxy.obfs == 'salamander') { if (proxy['obfs-password'] && proxy.obfs == 'salamander') {
proxy.obfs = 'salamander'; proxy.obfs = 'salamander';
@@ -284,6 +295,7 @@ export default function Egern_Producer() {
[proxy.type]: { [proxy.type]: {
...proxy, ...proxy,
type: undefined, type: undefined,
prev_hop,
}, },
}; };
}); });

View File

@@ -568,7 +568,7 @@ const hysteriaParser = (proxy = {}) => {
smuxParser(proxy.smux, parsedProxy); smuxParser(proxy.smux, parsedProxy);
return parsedProxy; return parsedProxy;
}; };
const hysteria2Parser = (proxy = {}) => { const hysteria2Parser = (proxy = {}, includeUnsupportedProxy) => {
const parsedProxy = { const parsedProxy = {
tag: proxy.name, tag: proxy.name,
type: 'hysteria2', type: 'hysteria2',
@@ -580,6 +580,16 @@ const hysteria2Parser = (proxy = {}) => {
}; };
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535) if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
throw 'invalid port'; throw 'invalid port';
if (includeUnsupportedProxy) {
if (proxy['hop-interval'])
parsedProxy.hop_interval = /^\d+$/.test(proxy['hop-interval'])
? `${proxy['hop-interval']}s`
: proxy['hop-interval'];
if (proxy['ports'])
parsedProxy.server_ports = proxy['ports']
.split(/\s*,\s*/)
.map((p) => p.replace(/\s*-\s*/g, ':'));
}
if (proxy.up) parsedProxy.up_mbps = parseInt(`${proxy.up}`, 10); if (proxy.up) parsedProxy.up_mbps = parseInt(`${proxy.up}`, 10);
if (proxy.down) parsedProxy.down_mbps = parseInt(`${proxy.down}`, 10); if (proxy.down) parsedProxy.down_mbps = parseInt(`${proxy.down}`, 10);
if (proxy.obfs === 'salamander') parsedProxy.obfs.type = 'salamander'; if (proxy.obfs === 'salamander') parsedProxy.obfs.type = 'salamander';
@@ -790,7 +800,12 @@ export default function singbox_Producer() {
list.push(hysteriaParser(proxy)); list.push(hysteriaParser(proxy));
break; break;
case 'hysteria2': case 'hysteria2':
list.push(hysteria2Parser(proxy)); list.push(
hysteria2Parser(
proxy,
opts['include-unsupported-proxy'],
),
);
break; break;
case 'tuic': case 'tuic':
if (!proxy.token || proxy.token.length === 0) { if (!proxy.token || proxy.token.length === 0) {

View File

@@ -47,7 +47,16 @@ let resourceUrl = typeof $resourceUrl !== 'undefined' ? $resourceUrl : '';
if ((!result || /^\s*$/.test(result)) && resourceUrl) { if ((!result || /^\s*$/.test(result)) && resourceUrl) {
console.log(`解析器: 尝试从 ${resourceUrl} 获取订阅`); console.log(`解析器: 尝试从 ${resourceUrl} 获取订阅`);
try { try {
let raw = await download(resourceUrl, arg?.ua, arg?.timeout); let raw = await download(
resourceUrl,
arg?.ua,
arg?.timeout,
undefined,
undefined,
undefined,
undefined,
true,
);
let proxies = ProxyUtils.parse(raw); let proxies = ProxyUtils.parse(raw);
result = ProxyUtils.produce(proxies, 'Loon', undefined, { result = ProxyUtils.produce(proxies, 'Loon', undefined, {
'include-unsupported-proxy': arg?.includeUnsupportedProxy, 'include-unsupported-proxy': arg?.includeUnsupportedProxy,

View File

@@ -63,7 +63,7 @@ async function downloadSubscription(req, res) {
$.info( $.info(
`正在下载订阅:${name}\n请求 User-Agent: ${ `正在下载订阅:${name}\n请求 User-Agent: ${
req.headers['user-agent'] || req.headers['User-Agent'] req.headers['user-agent'] || req.headers['User-Agent']
}`, }\n请求 target: ${req.query.target}\n实际输出: ${platform}`,
); );
let { let {
url, url,
@@ -303,7 +303,7 @@ async function downloadCollection(req, res) {
$.info( $.info(
`正在下载组合订阅:${name}\n请求 User-Agent: ${ `正在下载组合订阅:${name}\n请求 User-Agent: ${
req.headers['user-agent'] || req.headers['User-Agent'] req.headers['user-agent'] || req.headers['User-Agent']
}`, }\n请求 target: ${req.query.target}\n实际输出: ${platform}`,
); );
let { let {

View File

@@ -62,6 +62,7 @@ async function getFile(req, res) {
mergeSources, mergeSources,
ignoreFailedRemoteFile, ignoreFailedRemoteFile,
proxy, proxy,
noCache,
} = req.query; } = req.query;
let $options = {}; let $options = {};
if (req.query.$options) { if (req.query.$options) {
@@ -113,6 +114,9 @@ async function getFile(req, res) {
ignoreFailedRemoteFile = decodeURIComponent(ignoreFailedRemoteFile); ignoreFailedRemoteFile = decodeURIComponent(ignoreFailedRemoteFile);
$.info(`指定忽略失败的远程文件: ${ignoreFailedRemoteFile}`); $.info(`指定忽略失败的远程文件: ${ignoreFailedRemoteFile}`);
} }
if (noCache) {
$.info(`指定不使用缓存: ${noCache}`);
}
const allFiles = $.read(FILES_KEY); const allFiles = $.read(FILES_KEY);
const file = findByName(allFiles, name); const file = findByName(allFiles, name);
@@ -128,6 +132,7 @@ async function getFile(req, res) {
ignoreFailedRemoteFile, ignoreFailedRemoteFile,
$options, $options,
proxy, proxy,
noCache,
}); });
try { try {

View File

@@ -114,6 +114,10 @@ async function compareSub(req, res) {
sub.ua, sub.ua,
undefined, undefined,
sub.proxy, sub.proxy,
undefined,
undefined,
undefined,
true,
); );
} catch (err) { } catch (err) {
errors[url] = err; errors[url] = err;
@@ -219,6 +223,10 @@ async function compareCollection(req, res) {
sub.ua, sub.ua,
undefined, undefined,
sub.proxy, sub.proxy,
undefined,
undefined,
undefined,
true,
); );
} catch (err) { } catch (err) {
errors[url] = err; errors[url] = err;

View File

@@ -74,6 +74,7 @@ async function produceArtifact({
undefined, undefined,
awaitCustomCache, awaitCustomCache,
noCache, noCache,
true,
); );
} catch (err) { } catch (err) {
errors[url] = err; errors[url] = err;
@@ -122,6 +123,7 @@ async function produceArtifact({
undefined, undefined,
awaitCustomCache, awaitCustomCache,
noCache, noCache,
true,
); );
} catch (err) { } catch (err) {
errors[url] = err; errors[url] = err;
@@ -243,6 +245,7 @@ async function produceArtifact({
undefined, undefined,
undefined, undefined,
noCache, noCache,
true,
); );
} catch (err) { } catch (err) {
errors[url] = err; errors[url] = err;

View File

@@ -26,6 +26,7 @@ export default async function download(
skipCustomCache, skipCustomCache,
awaitCustomCache, awaitCustomCache,
noCache, noCache,
preprocess,
) { ) {
let $arguments = {}; let $arguments = {};
let url = rawUrl.replace(/#noFlow$/, ''); let url = rawUrl.replace(/#noFlow$/, '');
@@ -91,6 +92,9 @@ export default async function download(
timeout, timeout,
proxy, proxy,
true, true,
undefined,
undefined,
preprocess,
); );
} catch (e) { } catch (e) {
$.error( $.error(
@@ -111,6 +115,9 @@ export default async function download(
timeout, timeout,
proxy, proxy,
true, true,
undefined,
undefined,
preprocess,
).catch((e) => { ).catch((e) => {
$.error( $.error(
`乐观缓存: URL ${url} 异步更新缓存发生错误 ${ `乐观缓存: URL ${url} 异步更新缓存发生错误 ${
@@ -173,7 +180,7 @@ export default async function download(
: { insecure: true } : { insecure: true }
: undefined; : undefined;
$.info( $.info(
`Downloading...\nUser-Agent: ${userAgent}\nTimeout: ${requestTimeout}\nProxy: ${proxy}\nInsecure: ${!!insecure}\nURL: ${url}`, `Downloading...\nUser-Agent: ${userAgent}\nTimeout: ${requestTimeout}\nProxy: ${proxy}\nInsecure: ${!!insecure}\nPreprocess: ${preprocess}\nURL: ${url}`,
); );
try { try {
let { body, headers, statusCode } = await http.get({ let { body, headers, statusCode } = await http.get({
@@ -197,12 +204,14 @@ export default async function download(
} }
if (body.replace(/\s/g, '').length === 0) if (body.replace(/\s/g, '').length === 0)
throw new Error(new Error('远程资源内容为空')); throw new Error(new Error('远程资源内容为空'));
try { if (preprocess) {
if (clashPreprocessor.test(body)) { try {
body = clashPreprocessor.parse(body); if (clashPreprocessor.test(body)) {
body = clashPreprocessor.parse(body);
}
} catch (e) {
$.error(`Clash Pre-processor error: ${e}`);
} }
} catch (e) {
$.error(`Clash Pre-processor error: ${e}`);
} }
let shouldCache = true; let shouldCache = true;
if (cacheThreshold) { if (cacheThreshold) {