feat: 支持忽略失败的远程订阅(前端版本 > 2.14.20)

This commit is contained in:
xream 2023-12-18 01:24:48 +08:00
parent f10e5913fb
commit 4ca5f5e355
No known key found for this signature in database
GPG Key ID: 1D2C5225471789F9
4 changed files with 197 additions and 79 deletions

View File

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

@ -20,7 +20,7 @@ async function downloadSubscription(req, res) {
req.query.target || getPlatformFromHeaders(req.headers) || 'JSON'; req.query.target || getPlatformFromHeaders(req.headers) || 'JSON';
$.info(`正在下载订阅:${name}`); $.info(`正在下载订阅:${name}`);
let { url, ua, content, mergeSources } = req.query; let { url, ua, content, mergeSources, ignoreFailedRemoteSub } = req.query;
if (url) { if (url) {
url = decodeURIComponent(url); url = decodeURIComponent(url);
$.info(`指定远程订阅 URL: ${url}`); $.info(`指定远程订阅 URL: ${url}`);
@ -37,6 +37,10 @@ async function downloadSubscription(req, res) {
mergeSources = decodeURIComponent(mergeSources); mergeSources = decodeURIComponent(mergeSources);
$.info(`指定合并来源: ${mergeSources}`); $.info(`指定合并来源: ${mergeSources}`);
} }
if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') {
ignoreFailedRemoteSub = decodeURIComponent(ignoreFailedRemoteSub);
$.info(`指定忽略失败的远程订阅: ${ignoreFailedRemoteSub}`);
}
const allSubs = $.read(SUBS_KEY); const allSubs = $.read(SUBS_KEY);
const sub = findByName(allSubs, name); const sub = findByName(allSubs, name);
@ -50,6 +54,7 @@ async function downloadSubscription(req, res) {
ua, ua,
content, content,
mergeSources, mergeSources,
ignoreFailedRemoteSub,
}); });
if (sub.source !== 'local' || url) { if (sub.source !== 'local' || url) {
@ -116,12 +121,20 @@ async function downloadCollection(req, res) {
$.info(`正在下载组合订阅:${name}`); $.info(`正在下载组合订阅:${name}`);
let { ignoreFailedRemoteSub } = req.query;
if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') {
ignoreFailedRemoteSub = decodeURIComponent(ignoreFailedRemoteSub);
$.info(`指定忽略失败的远程订阅: ${ignoreFailedRemoteSub}`);
}
if (collection) { if (collection) {
try { try {
const output = await produceArtifact({ const output = await produceArtifact({
type: 'collection', type: 'collection',
name, name,
platform, platform,
ignoreFailedRemoteSub,
}); });
// forward flow header from the first subscription in this collection // forward flow header from the first subscription in this collection

View File

@ -22,24 +22,31 @@ async function compareSub(req, res) {
) { ) {
content = sub.content; content = sub.content;
} else { } else {
try { const errors = {};
content = await Promise.all( content = await Promise.all(
sub.url sub.url
.split(/[\r\n]+/) .split(/[\r\n]+/)
.map((i) => i.trim()) .map((i) => i.trim())
.filter((i) => i.length) .filter((i) => i.length)
.map((url) => download(url, sub.ua)), .map(async (url) => {
); try {
return await download(url, sub.ua);
} catch (err) { } catch (err) {
failed( errors[url] = err;
res, $.error(
new NetworkError( `订阅 ${sub.name} 的远程订阅 ${url} 发生错误: ${err}`,
'FAILED_TO_DOWNLOAD_RESOURCE', );
'无法下载远程资源', return '';
`Reason: ${err}`, }
), }),
);
if (!sub.ignoreFailedRemoteSub && Object.keys(errors).length > 0) {
throw new Error(
`订阅 ${sub.name} 的远程订阅 ${Object.keys(errors).join(
', ',
)} 发生错误, 请查看日志`,
); );
return;
} }
if (sub.mergeSources === 'localFirst') { if (sub.mergeSources === 'localFirst') {
content.unshift(sub.content); content.unshift(sub.content);
@ -87,10 +94,9 @@ async function compareCollection(req, res) {
const collection = req.body; const collection = req.body;
const subnames = collection.subscriptions; const subnames = collection.subscriptions;
const results = {}; const results = {};
let hasError; const errors = {};
await Promise.all( await Promise.all(
subnames.map(async (name) => { subnames.map(async (name) => {
if (!hasError) {
const sub = findByName(allSubs, name); const sub = findByName(allSubs, name);
try { try {
let raw; let raw;
@ -102,13 +108,34 @@ async function compareCollection(req, res) {
) { ) {
raw = sub.content; raw = sub.content;
} else { } else {
const errors = {};
raw = await Promise.all( raw = await Promise.all(
sub.url sub.url
.split(/[\r\n]+/) .split(/[\r\n]+/)
.map((i) => i.trim()) .map((i) => i.trim())
.filter((i) => i.length) .filter((i) => i.length)
.map((url) => download(url, sub.ua)), .map(async (url) => {
try {
return await download(url, sub.ua);
} catch (err) {
errors[url] = err;
$.error(
`订阅 ${sub.name} 的远程订阅 ${url} 发生错误: ${err}`,
); );
return '';
}
}),
);
if (
!sub.ignoreFailedRemoteSub &&
Object.keys(errors).length > 0
) {
throw new Error(
`订阅 ${sub.name} 的远程订阅 ${Object.keys(
errors,
).join(', ')} 发生错误, 请查看日志`,
);
}
if (sub.mergeSources === 'localFirst') { if (sub.mergeSources === 'localFirst') {
raw.unshift(sub.content); raw.unshift(sub.content);
} else if (sub.mergeSources === 'remoteFirst') { } else if (sub.mergeSources === 'remoteFirst') {
@ -134,22 +161,28 @@ async function compareCollection(req, res) {
); );
results[name] = currentProxies; results[name] = currentProxies;
} catch (err) { } catch (err) {
if (!hasError) { errors[name] = err;
hasError = true;
failed( $.error(
res, `❌ 处理组合订阅中的子订阅: ${
new InternalServerError( sub.name
'PROCESS_FAILED', }时出现错误${err}进度--${
`处理子订阅 ${name} 失败`, 100 * (processed / subnames.length).toFixed(1)
`Reason: ${err}`, }%`,
),
); );
} }
}
}
}), }),
); );
if (hasError) return; if (
!collection.ignoreFailedRemoteSub &&
Object.keys(errors).length > 0
) {
throw new Error(
`组合订阅 ${collection.name} 中的子订阅 ${Object.keys(
errors,
).join(', ')} 发生错误, 请查看日志`,
);
}
// merge proxies with the original order // merge proxies with the original order
const original = Array.prototype.concat.apply( const original = Array.prototype.concat.apply(
[], [],

View File

@ -30,6 +30,7 @@ async function produceArtifact({
ua, ua,
content, content,
mergeSources, mergeSources,
ignoreFailedRemoteSub,
}) { }) {
platform = platform || 'JSON'; platform = platform || 'JSON';
@ -40,13 +41,35 @@ async function produceArtifact({
if (content && !['localFirst', 'remoteFirst'].includes(mergeSources)) { if (content && !['localFirst', 'remoteFirst'].includes(mergeSources)) {
raw = content; raw = content;
} else if (url) { } else if (url) {
const errors = {};
raw = await Promise.all( raw = await Promise.all(
url url
.split(/[\r\n]+/) .split(/[\r\n]+/)
.map((i) => i.trim()) .map((i) => i.trim())
.filter((i) => i.length) .filter((i) => i.length)
.map((url) => download(url, ua)), .map(async (url) => {
try {
return await download(url, ua || sub.ua);
} catch (err) {
errors[url] = err;
$.error(
`订阅 ${sub.name} 的远程订阅 ${url} 发生错误: ${err}`,
); );
return '';
}
}),
);
let subIgnoreFailedRemoteSub = sub.ignoreFailedRemoteSub;
if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') {
subIgnoreFailedRemoteSub = ignoreFailedRemoteSub;
}
if (!subIgnoreFailedRemoteSub && Object.keys(errors).length > 0) {
throw new Error(
`订阅 ${sub.name} 的远程订阅 ${Object.keys(errors).join(
', ',
)} 发生错误, 请查看日志`,
);
}
if (mergeSources === 'localFirst') { if (mergeSources === 'localFirst') {
raw.unshift(content); raw.unshift(content);
} else if (mergeSources === 'remoteFirst') { } else if (mergeSources === 'remoteFirst') {
@ -58,13 +81,35 @@ async function produceArtifact({
) { ) {
raw = sub.content; raw = sub.content;
} else { } else {
const errors = {};
raw = await Promise.all( raw = await Promise.all(
sub.url sub.url
.split(/[\r\n]+/) .split(/[\r\n]+/)
.map((i) => i.trim()) .map((i) => i.trim())
.filter((i) => i.length) .filter((i) => i.length)
.map((url) => download(url, sub.ua)), .map(async (url) => {
try {
return await download(url, ua || sub.ua);
} catch (err) {
errors[url] = err;
$.error(
`订阅 ${sub.name} 的远程订阅 ${url} 发生错误: ${err}`,
); );
return '';
}
}),
);
let subIgnoreFailedRemoteSub = sub.ignoreFailedRemoteSub;
if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') {
subIgnoreFailedRemoteSub = ignoreFailedRemoteSub;
}
if (!subIgnoreFailedRemoteSub && Object.keys(errors).length > 0) {
throw new Error(
`订阅 ${sub.name} 的远程订阅 ${Object.keys(errors).join(
', ',
)} 发生错误, 请查看日志`,
);
}
if (sub.mergeSources === 'localFirst') { if (sub.mergeSources === 'localFirst') {
raw.unshift(sub.content); raw.unshift(sub.content);
} else if (sub.mergeSources === 'remoteFirst') { } else if (sub.mergeSources === 'remoteFirst') {
@ -131,13 +176,34 @@ async function produceArtifact({
) { ) {
raw = sub.content; raw = sub.content;
} else { } else {
const errors = {};
raw = await await Promise.all( raw = await await Promise.all(
sub.url sub.url
.split(/[\r\n]+/) .split(/[\r\n]+/)
.map((i) => i.trim()) .map((i) => i.trim())
.filter((i) => i.length) .filter((i) => i.length)
.map((url) => download(url, sub.ua)), .map(async (url) => {
try {
return await download(url, sub.ua);
} catch (err) {
errors[url] = err;
$.error(
`订阅 ${sub.name} 的远程订阅 ${url} 发生错误: ${err}`,
); );
return '';
}
}),
);
if (
!sub.ignoreFailedRemoteSub &&
Object.keys(errors).length > 0
) {
throw new Error(
`订阅 ${sub.name} 的远程订阅 ${Object.keys(
errors,
).join(', ')} 发生错误, 请查看日志`,
);
}
if (sub.mergeSources === 'localFirst') { if (sub.mergeSources === 'localFirst') {
raw.unshift(sub.content); raw.unshift(sub.content);
} else if (sub.mergeSources === 'remoteFirst') { } else if (sub.mergeSources === 'remoteFirst') {
@ -174,15 +240,21 @@ async function produceArtifact({
$.error( $.error(
`❌ 处理组合订阅中的子订阅: ${ `❌ 处理组合订阅中的子订阅: ${
sub.name sub.name
}时出现错误${err}该订阅已被跳过进度--${ }时出现错误${err}进度--${
100 * (processed / subnames.length).toFixed(1) 100 * (processed / subnames.length).toFixed(1)
}%`, }%`,
); );
} }
}), }),
); );
let collectionIgnoreFailedRemoteSub = collection.ignoreFailedRemoteSub;
if (Object.keys(errors).length > 0) { if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') {
collectionIgnoreFailedRemoteSub = ignoreFailedRemoteSub;
}
if (
!collectionIgnoreFailedRemoteSub &&
Object.keys(errors).length > 0
) {
throw new Error( throw new Error(
`组合订阅 ${name} 中的子订阅 ${Object.keys(errors).join( `组合订阅 ${name} 中的子订阅 ${Object.keys(errors).join(
', ', ', ',