feat: 远程订阅 URL 新增参数 validCheck 将检查订阅有效期和剩余流量

This commit is contained in:
xream 2024-01-30 14:14:57 +08:00
parent 1248e6b32a
commit a91f978042
No known key found for this signature in database
GPG Key ID: 1D2C5225471789F9
4 changed files with 65 additions and 31 deletions

View File

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

@ -14,6 +14,7 @@ import {
getFlowField, getFlowField,
getFlowHeaders, getFlowHeaders,
parseFlowHeaders, parseFlowHeaders,
validCheck,
flowTransfer, flowTransfer,
} from '@/utils/flow'; } from '@/utils/flow';
@ -806,6 +807,7 @@ function createDynamicFunction(name, script, $arguments) {
getFlowHeaders, getFlowHeaders,
parseFlowHeaders, parseFlowHeaders,
flowTransfer, flowTransfer,
validCheck,
}; };
if ($.env.isLoon) { if ($.env.isLoon) {
return new Function( return new Function(

View File

@ -4,7 +4,12 @@ import { HTTP, ENV } from '@/vendor/open-api';
import { hex_md5 } from '@/vendor/md5'; import { hex_md5 } from '@/vendor/md5';
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 { getFlowField } from '@/utils/flow'; import {
getFlowField,
getFlowHeaders,
parseFlowHeaders,
validCheck,
} from '@/utils/flow';
import $ from '@/core/app'; import $ from '@/core/app';
const tasks = new Map(); const tasks = new Map();
@ -64,36 +69,40 @@ export default async function download(rawUrl, ua, timeout) {
timeout: requestTimeout, timeout: requestTimeout,
}); });
const result = new Promise((resolve, reject) => { let result;
// try to find in app cache
const cached = resourceCache.get(id); // try to find in app cache
if (!$arguments?.noCache && cached) { const cached = resourceCache.get(id);
resolve(cached); if (!$arguments?.noCache && cached) {
} else { result = cached;
$.info( } else {
`Downloading...\nUser-Agent: ${userAgent}\nTimeout: ${requestTimeout}\nURL: ${url}`, $.info(
); `Downloading...\nUser-Agent: ${userAgent}\nTimeout: ${requestTimeout}\nURL: ${url}`,
http.get(url) );
.then((resp) => { try {
const { body, headers } = resp; const { body, headers } = await http.get(url);
if (headers) {
const flowInfo = getFlowField(headers); if (headers) {
if (flowInfo) { const flowInfo = getFlowField(headers);
headersResourceCache.set(url, flowInfo); if (flowInfo) {
} headersResourceCache.set(url, flowInfo);
} }
if (body.replace(/\s/g, '').length === 0) }
reject(new Error('远程资源内容为空!')); if (body.replace(/\s/g, '').length === 0)
else { throw new Error(new Error('远程资源内容为空'));
resourceCache.set(id, body);
resolve(body); resourceCache.set(id, body);
} result = body;
}) } catch (e) {
.catch(() => { throw new Error(`无法下载 URL ${url}: ${e.message ?? e}`);
reject(new Error(`无法下载 URL${url}`));
});
} }
}); }
// 检查订阅有效性
if ($arguments?.validCheck) {
await validCheck(parseFlowHeaders(await getFlowHeaders(url)));
}
if (!isNode) { if (!isNode) {
tasks.set(id, result); tasks.set(id, result);

View File

@ -120,3 +120,26 @@ export function flowTransfer(flow, unit = 'B') {
? { value: flow.toFixed(1), unit: unit } ? { value: flow.toFixed(1), unit: unit }
: flowTransfer(flow / 1024, unitList[++unitIndex]); : flowTransfer(flow / 1024, unitList[++unitIndex]);
} }
export function validCheck(flow) {
if (!flow) {
throw new Error('没有流量信息');
}
if (flow?.expires && flow.expires * 1000 < Date.now()) {
const date = new Date(flow.expires * 1000).toLocaleDateString();
throw new Error(`订阅已过期: ${date}`);
}
if (flow?.total) {
const upload = flow.usage?.upload || 0;
const download = flow.usage?.download || 0;
if (flow.total - upload - download < 0) {
const current = upload + download;
const currT = flowTransfer(Math.abs(current));
currT.value = current < 0 ? '-' + currT.value : currT.value;
const totalT = flowTransfer(flow.total);
throw new Error(
`流量已用完: ${currT.value} ${currT.unit} / ${totalT.value} ${totalT.unit}`,
);
}
}
}