mirror of
https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-10 00:52:40 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de1f419d63 | ||
|
|
bfa1b11a0e | ||
|
|
7d60aed50d | ||
|
|
e20d0c1dc9 | ||
|
|
c5660024fb |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sub-store",
|
"name": "sub-store",
|
||||||
"version": "2.19.74",
|
"version": "2.19.78",
|
||||||
"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": {
|
||||||
|
|||||||
@@ -105,11 +105,11 @@ wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/under
|
|||||||
proxy.type = "wireguard-surge";
|
proxy.type = "wireguard-surge";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/fast_open/tfo/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* {
|
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* {
|
||||||
proxy.type = "hysteria2";
|
proxy.type = "hysteria2";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
socks5 = tag equals "socks5" address (username password)? (usernamek passwordk)? (udp_relay/no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
socks5 = tag equals "socks5" address (username password)? (usernamek passwordk)? (udp_relay/no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/fast_open/tfo/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "socks5";
|
proxy.type = "socks5";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,6 @@ socks5_tls = tag equals "socks5-tls" address (username password)? (usernamek pas
|
|||||||
direct = tag equals "direct" (udp_relay/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/block_quic/others)* {
|
direct = tag equals "direct" (udp_relay/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/tfo/block_quic/others)* {
|
||||||
proxy.type = "direct";
|
proxy.type = "direct";
|
||||||
}
|
}
|
||||||
|
|
||||||
address = comma server:server comma port:port {
|
address = comma server:server comma port:port {
|
||||||
proxy.server = server;
|
proxy.server = server;
|
||||||
proxy.port = port;
|
proxy.port = port;
|
||||||
@@ -212,11 +211,11 @@ ws_headers = comma "ws-headers" equals headers:$[^,]+ {
|
|||||||
const result = {};
|
const result = {};
|
||||||
pairs.forEach(pair => {
|
pairs.forEach(pair => {
|
||||||
const [key, value] = pair.trim().split(":");
|
const [key, value] = pair.trim().split(":");
|
||||||
result[key.trim()] = value.trim();
|
result[key.trim()] = value.trim().replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1');
|
||||||
})
|
})
|
||||||
obfs["ws-headers"] = result;
|
obfs["ws-headers"] = result;
|
||||||
}
|
}
|
||||||
ws_path = comma "ws-path" equals path:uri { obfs.path = path; }
|
ws_path = comma "ws-path" equals path:uri { obfs.path = path.trim().replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
|
||||||
|
|
||||||
obfs = comma "obfs" equals type:("http"/"tls") { obfs.type = type; }
|
obfs = comma "obfs" equals type:("http"/"tls") { obfs.type = type; }
|
||||||
obfs_host = comma "obfs-host" equals host:domain { obfs.host = host; };
|
obfs_host = comma "obfs-host" equals host:domain { obfs.host = host; };
|
||||||
|
|||||||
@@ -209,11 +209,11 @@ ws_headers = comma "ws-headers" equals headers:$[^,]+ {
|
|||||||
const result = {};
|
const result = {};
|
||||||
pairs.forEach(pair => {
|
pairs.forEach(pair => {
|
||||||
const [key, value] = pair.trim().split(":");
|
const [key, value] = pair.trim().split(":");
|
||||||
result[key.trim()] = value.trim();
|
result[key.trim()] = value.trim().replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1');
|
||||||
})
|
})
|
||||||
obfs["ws-headers"] = result;
|
obfs["ws-headers"] = result;
|
||||||
}
|
}
|
||||||
ws_path = comma "ws-path" equals path:uri { obfs.path = path; }
|
ws_path = comma "ws-path" equals path:uri { obfs.path = path.trim().replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
|
||||||
|
|
||||||
obfs = comma "obfs" equals type:("http"/"tls") { obfs.type = type; }
|
obfs = comma "obfs" equals type:("http"/"tls") { obfs.type = type; }
|
||||||
obfs_host = comma "obfs-host" equals host:domain { obfs.host = host; };
|
obfs_host = comma "obfs-host" equals host:domain { obfs.host = host; };
|
||||||
|
|||||||
@@ -119,10 +119,11 @@ export default function serve() {
|
|||||||
$app.start();
|
$app.start();
|
||||||
|
|
||||||
if ($.env.isNode) {
|
if ($.env.isNode) {
|
||||||
// Deprecated: SUB_STORE_BACKEND_CRON
|
// Deprecated: SUB_STORE_BACKEND_CRON, SUB_STORE_CRON
|
||||||
const backend_sync_cron =
|
const backend_sync_cron = eval(
|
||||||
eval('process.env.SUB_STORE_BACKEND_SYNC_CRON') ||
|
'process.env.SUB_STORE_BACKEND_SYNC_CRON',
|
||||||
eval('process.env.SUB_STORE_BACKEND_CRON');
|
);
|
||||||
|
|
||||||
if (backend_sync_cron) {
|
if (backend_sync_cron) {
|
||||||
$.info(`[SYNC CRON] ${backend_sync_cron} enabled`);
|
$.info(`[SYNC CRON] ${backend_sync_cron} enabled`);
|
||||||
const { CronJob } = eval(`require("cron")`);
|
const { CronJob } = eval(`require("cron")`);
|
||||||
@@ -145,6 +146,17 @@ export default function serve() {
|
|||||||
true, // start
|
true, // start
|
||||||
// 'Asia/Shanghai' // timeZone
|
// 'Asia/Shanghai' // timeZone
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
if (eval('process.env.SUB_STORE_BACKEND_CRON')) {
|
||||||
|
$.error(
|
||||||
|
`[SYNC CRON] SUB_STORE_BACKEND_CRON 已弃用, 请使用 SUB_STORE_BACKEND_SYNC_CRON`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (eval('process.env.SUB_STORE_CRON')) {
|
||||||
|
$.error(
|
||||||
|
`[SYNC CRON] SUB_STORE_CRON 已弃用, 请使用 SUB_STORE_BACKEND_SYNC_CRON`,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 格式: 0 */2 * * *,sub,a;0 */3 * * *,col,b
|
// 格式: 0 */2 * * *,sub,a;0 */3 * * *,col,b
|
||||||
// 每 2 小时处理一次单条订阅 a, 每 3 小时处理一次组合订阅 b
|
// 每 2 小时处理一次单条订阅 a, 每 3 小时处理一次组合订阅 b
|
||||||
|
|||||||
@@ -120,8 +120,10 @@ async function gistBackupAction(action) {
|
|||||||
switch (action) {
|
switch (action) {
|
||||||
case 'upload':
|
case 'upload':
|
||||||
try {
|
try {
|
||||||
content = $.read('#sub-store');
|
content = JSON.parse($.read('#sub-store'));
|
||||||
if ($.env.isNode) content = JSON.stringify($.cache, null, ` `);
|
if ($.env.isNode) content = { ...$.cache };
|
||||||
|
content.settings.gistToken = '恢复后请重新设置 GitHub Token';
|
||||||
|
content = JSON.stringify(content, null, ` `);
|
||||||
$.info(`下载备份, 与本地内容对比...`);
|
$.info(`下载备份, 与本地内容对比...`);
|
||||||
const onlineContent = await gist.download(
|
const onlineContent = await gist.download(
|
||||||
GIST_BACKUP_FILE_NAME,
|
GIST_BACKUP_FILE_NAME,
|
||||||
@@ -137,8 +139,10 @@ async function gistBackupAction(action) {
|
|||||||
// update syncTime
|
// update syncTime
|
||||||
settings.syncTime = new Date().getTime();
|
settings.syncTime = new Date().getTime();
|
||||||
$.write(settings, SETTINGS_KEY);
|
$.write(settings, SETTINGS_KEY);
|
||||||
content = $.read('#sub-store');
|
content = JSON.parse($.read('#sub-store'));
|
||||||
if ($.env.isNode) content = JSON.stringify($.cache, null, ` `);
|
if ($.env.isNode) content = { ...$.cache };
|
||||||
|
content.settings.gistToken = '恢复后请重新设置 GitHub Token';
|
||||||
|
content = JSON.stringify(content, null, ` `);
|
||||||
$.info(`上传备份中...`);
|
$.info(`上传备份中...`);
|
||||||
try {
|
try {
|
||||||
await gist.upload({
|
await gist.upload({
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import $ from '@/core/app';
|
|||||||
import { findByName } from '@/utils/database';
|
import { findByName } from '@/utils/database';
|
||||||
import { produceArtifact } from '@/restful/sync';
|
import { produceArtifact } from '@/restful/sync';
|
||||||
import PROXY_PREPROCESSORS from '@/core/proxy-utils/preprocessors';
|
import PROXY_PREPROCESSORS from '@/core/proxy-utils/preprocessors';
|
||||||
|
import { ProxyUtils } from '@/core/proxy-utils';
|
||||||
|
|
||||||
const clashPreprocessor = PROXY_PREPROCESSORS.find(
|
const clashPreprocessor = PROXY_PREPROCESSORS.find(
|
||||||
(processor) => processor.name === 'Clash Pre-processor',
|
(processor) => processor.name === 'Clash Pre-processor',
|
||||||
);
|
);
|
||||||
@@ -261,10 +263,34 @@ export default async function download(
|
|||||||
if (shouldCache) {
|
if (shouldCache) {
|
||||||
resourceCache.set(id, body);
|
resourceCache.set(id, body);
|
||||||
if (customCacheKey) {
|
if (customCacheKey) {
|
||||||
$.info(
|
let shouldWriteCustomCacheKey = true;
|
||||||
`URL ${url}\n写入自定义缓存 ${$arguments?.cacheKey}`,
|
if (preprocess) {
|
||||||
);
|
try {
|
||||||
$.write(body, customCacheKey);
|
const proxies = ProxyUtils.parse(body);
|
||||||
|
if (
|
||||||
|
!Array.isArray(proxies) ||
|
||||||
|
proxies.length === 0
|
||||||
|
) {
|
||||||
|
$.error(
|
||||||
|
`URL ${url} 不包含有效节点\n不写入自定义缓存 ${$arguments?.cacheKey}`,
|
||||||
|
);
|
||||||
|
shouldWriteCustomCacheKey = false;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
$.error(
|
||||||
|
`URL ${url} 尝试解析节点失败 ${
|
||||||
|
e.message ?? e
|
||||||
|
}\n不写入自定义缓存 ${$arguments?.cacheKey}`,
|
||||||
|
);
|
||||||
|
shouldWriteCustomCacheKey = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shouldWriteCustomCacheKey) {
|
||||||
|
$.info(
|
||||||
|
`URL ${url}\n写入自定义缓存 ${$arguments?.cacheKey}`,
|
||||||
|
);
|
||||||
|
$.write(body, customCacheKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -334,7 +334,22 @@ export function normalizeFlowHeader(flowHeaders) {
|
|||||||
if (!kvMap.has(key)) {
|
if (!kvMap.has(key)) {
|
||||||
try {
|
try {
|
||||||
// 解码 URI 组件并保留原始值作为 fallback
|
// 解码 URI 组件并保留原始值作为 fallback
|
||||||
const decodedValue = decodeURIComponent(encodedValue);
|
let decodedValue = decodeURIComponent(encodedValue);
|
||||||
|
if (
|
||||||
|
['upload', 'download', 'total', 'expire'].includes(
|
||||||
|
key,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
decodedValue = Number(decodedValue).toFixed(0);
|
||||||
|
} catch (e) {
|
||||||
|
$.error(
|
||||||
|
`Failed to convert value for key "${key}=${encodedValue}": ${
|
||||||
|
e.message ?? e
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
kvMap.set(key, decodedValue);
|
kvMap.set(key, decodedValue);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
kvMap.set(key, encodedValue);
|
kvMap.set(key, encodedValue);
|
||||||
|
|||||||
@@ -247,14 +247,14 @@ function operator(proxies = [], targetPlatform, context) {
|
|||||||
// 这个历史遗留原因, 是有点复杂. 提供一个例子, 用来取当前脚本所在的组合订阅或单条订阅名称
|
// 这个历史遗留原因, 是有点复杂. 提供一个例子, 用来取当前脚本所在的组合订阅或单条订阅名称
|
||||||
|
|
||||||
// let name = ''
|
// let name = ''
|
||||||
// for (const [key, value] of Object.entries(env.source)) {
|
// for (const [key, value] of Object.entries(context.source)) {
|
||||||
// if (!key.startsWith('_')) {
|
// if (!key.startsWith('_')) {
|
||||||
// name = value.displayName || value.name
|
// name = value.displayName || value.name
|
||||||
// break
|
// break
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// if (!name) {
|
// if (!name) {
|
||||||
// const collection = env.source._collection
|
// const collection = context.source._collection
|
||||||
// name = collection.displayName || collection.name
|
// name = collection.displayName || collection.name
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user