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",
"version": "2.14.194",
"version": "2.14.195",
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
"main": "src/main.js",
"scripts": {

View File

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

View File

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

View File

@ -120,3 +120,26 @@ export function flowTransfer(flow, unit = 'B') {
? { value: flow.toFixed(1), unit: unit }
: 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}`,
);
}
}
}