mirror of
https://git.mirrors.martin98.com/https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-12 02:29:00 +08:00
feat: 模块接口; 脚本参数支持 JSON 和 URL编码
This commit is contained in:
parent
33a17c2d66
commit
3211fbf357
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sub-store",
|
"name": "sub-store",
|
||||||
"version": "2.14.53",
|
"version": "2.14.54",
|
||||||
"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": {
|
||||||
|
@ -3,6 +3,7 @@ export const SETTINGS_KEY = 'settings';
|
|||||||
export const SUBS_KEY = 'subs';
|
export const SUBS_KEY = 'subs';
|
||||||
export const COLLECTIONS_KEY = 'collections';
|
export const COLLECTIONS_KEY = 'collections';
|
||||||
export const FILES_KEY = 'files';
|
export const FILES_KEY = 'files';
|
||||||
|
export const MODULES_KEY = 'modules';
|
||||||
export const ARTIFACTS_KEY = 'artifacts';
|
export const ARTIFACTS_KEY = 'artifacts';
|
||||||
export const RULES_KEY = 'rules';
|
export const RULES_KEY = 'rules';
|
||||||
export const GIST_BACKUP_KEY = 'Auto Generated Sub-Store Backup';
|
export const GIST_BACKUP_KEY = 'Auto Generated Sub-Store Backup';
|
||||||
|
@ -67,7 +67,7 @@ async function process(proxies, operators = [], targetPlatform) {
|
|||||||
for (const item of operators) {
|
for (const item of operators) {
|
||||||
// process script
|
// process script
|
||||||
let script;
|
let script;
|
||||||
const $arguments = {};
|
let $arguments = {};
|
||||||
if (item.type.indexOf('Script') !== -1) {
|
if (item.type.indexOf('Script') !== -1) {
|
||||||
const { mode, content } = item.args;
|
const { mode, content } = item.args;
|
||||||
if (mode === 'link') {
|
if (mode === 'link') {
|
||||||
@ -75,10 +75,19 @@ async function process(proxies, operators = [], targetPlatform) {
|
|||||||
// extract link arguments
|
// extract link arguments
|
||||||
const rawArgs = url.split('#');
|
const rawArgs = url.split('#');
|
||||||
if (rawArgs.length > 1) {
|
if (rawArgs.length > 1) {
|
||||||
|
try {
|
||||||
|
// 支持 `#${encodeURIComponent(JSON.stringify({arg1: "1"}))}`
|
||||||
|
$arguments = JSON.parse(decodeURIComponent(rawArgs[1]));
|
||||||
|
} catch (e) {
|
||||||
for (const pair of rawArgs[1].split('&')) {
|
for (const pair of rawArgs[1].split('&')) {
|
||||||
const key = pair.split('=')[0];
|
const key = pair.split('=')[0];
|
||||||
const value = pair.split('=')[1] || true;
|
const value = pair.split('=')[1];
|
||||||
$arguments[key] = value;
|
// 部分兼容之前的逻辑 const value = pair.split('=')[1] || true;
|
||||||
|
$arguments[key] =
|
||||||
|
value == null || value === ''
|
||||||
|
? true
|
||||||
|
: decodeURIComponent(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import registerSubscriptionRoutes from './subscriptions';
|
|||||||
import registerCollectionRoutes from './collections';
|
import registerCollectionRoutes from './collections';
|
||||||
import registerArtifactRoutes from './artifacts';
|
import registerArtifactRoutes from './artifacts';
|
||||||
import registerFileRoutes from './file';
|
import registerFileRoutes from './file';
|
||||||
|
import registerModuleRoutes from './module';
|
||||||
import registerSyncRoutes from './sync';
|
import registerSyncRoutes from './sync';
|
||||||
import registerDownloadRoutes from './download';
|
import registerDownloadRoutes from './download';
|
||||||
import registerSettingRoutes from './settings';
|
import registerSettingRoutes from './settings';
|
||||||
@ -25,6 +26,7 @@ export default function serve() {
|
|||||||
registerSettingRoutes($app);
|
registerSettingRoutes($app);
|
||||||
registerArtifactRoutes($app);
|
registerArtifactRoutes($app);
|
||||||
registerFileRoutes($app);
|
registerFileRoutes($app);
|
||||||
|
registerModuleRoutes($app);
|
||||||
registerSyncRoutes($app);
|
registerSyncRoutes($app);
|
||||||
registerNodeInfoRoutes($app);
|
registerNodeInfoRoutes($app);
|
||||||
registerMiscRoutes($app);
|
registerMiscRoutes($app);
|
||||||
|
112
backend/src/restful/module.js
Normal file
112
backend/src/restful/module.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import { deleteByName, findByName, updateByName } from '@/utils/database';
|
||||||
|
import { MODULES_KEY } from '@/constants';
|
||||||
|
import { failed, success } from '@/restful/response';
|
||||||
|
import $ from '@/core/app';
|
||||||
|
import { RequestInvalidError, ResourceNotFoundError } from '@/restful/errors';
|
||||||
|
import { hex_md5 } from '@/vendor/md5';
|
||||||
|
|
||||||
|
export default function register($app) {
|
||||||
|
if (!$.read(MODULES_KEY)) $.write([], MODULES_KEY);
|
||||||
|
|
||||||
|
$app.route('/api/module/:name')
|
||||||
|
.get(getModule)
|
||||||
|
.patch(updateModule)
|
||||||
|
.delete(deleteModule);
|
||||||
|
|
||||||
|
$app.route('/api/modules')
|
||||||
|
.get(getAllModules)
|
||||||
|
.post(createModule)
|
||||||
|
.put(replaceModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
// module API
|
||||||
|
function createModule(req, res) {
|
||||||
|
const module = req.body;
|
||||||
|
module.name = module.name ?? hex_md5(JSON.stringify(module));
|
||||||
|
$.info(`正在创建模块:${module.name}`);
|
||||||
|
const allModules = $.read(MODULES_KEY);
|
||||||
|
if (findByName(allModules, module.name)) {
|
||||||
|
failed(
|
||||||
|
res,
|
||||||
|
new RequestInvalidError(
|
||||||
|
'DUPLICATE_KEY',
|
||||||
|
`已存在相同的模块 请勿重复添加`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
allModules.push(module);
|
||||||
|
$.write(allModules, MODULES_KEY);
|
||||||
|
success(res, module, 201);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getModule(req, res) {
|
||||||
|
let { name } = req.params;
|
||||||
|
name = decodeURIComponent(name);
|
||||||
|
const allModules = $.read(MODULES_KEY);
|
||||||
|
const module = findByName(allModules, name);
|
||||||
|
if (module) {
|
||||||
|
success(res, module);
|
||||||
|
} else {
|
||||||
|
failed(
|
||||||
|
res,
|
||||||
|
new ResourceNotFoundError(
|
||||||
|
`MODULE_NOT_FOUND`,
|
||||||
|
`Module ${name} does not exist`,
|
||||||
|
404,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateModule(req, res) {
|
||||||
|
let { name } = req.params;
|
||||||
|
name = decodeURIComponent(name);
|
||||||
|
let module = req.body;
|
||||||
|
const allModules = $.read(MODULES_KEY);
|
||||||
|
const oldModule = findByName(allModules, name);
|
||||||
|
if (oldModule) {
|
||||||
|
const newModule = {
|
||||||
|
...oldModule,
|
||||||
|
...module,
|
||||||
|
};
|
||||||
|
$.info(`正在更新模块:${name}...`);
|
||||||
|
|
||||||
|
updateByName(allModules, name, newModule);
|
||||||
|
$.write(allModules, MODULES_KEY);
|
||||||
|
success(res, newModule);
|
||||||
|
} else {
|
||||||
|
failed(
|
||||||
|
res,
|
||||||
|
new ResourceNotFoundError(
|
||||||
|
'RESOURCE_NOT_FOUND',
|
||||||
|
`Module ${name} does not exist!`,
|
||||||
|
),
|
||||||
|
404,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteModule(req, res) {
|
||||||
|
let { name } = req.params;
|
||||||
|
name = decodeURIComponent(name);
|
||||||
|
$.info(`正在删除模块:${name}`);
|
||||||
|
let allModules = $.read(MODULES_KEY);
|
||||||
|
deleteByName(allModules, name);
|
||||||
|
$.write(allModules, MODULES_KEY);
|
||||||
|
success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllModules(req, res) {
|
||||||
|
const allModules = $.read(MODULES_KEY);
|
||||||
|
success(
|
||||||
|
res,
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
allModules.map(({ content, ...rest }) => rest),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceModule(req, res) {
|
||||||
|
const allModules = req.body;
|
||||||
|
$.write(allModules, MODULES_KEY);
|
||||||
|
success(res);
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { FILES_KEY } from '@/constants';
|
import { FILES_KEY, MODULES_KEY } from '@/constants';
|
||||||
import { findByName } from '@/utils/database';
|
import { findByName } from '@/utils/database';
|
||||||
import { HTTP, ENV } from '@/vendor/open-api';
|
import { HTTP, ENV } from '@/vendor/open-api';
|
||||||
import { hex_md5 } from '@/vendor/md5';
|
import { hex_md5 } from '@/vendor/md5';
|
||||||
@ -8,19 +8,21 @@ import $ from '@/core/app';
|
|||||||
const tasks = new Map();
|
const tasks = new Map();
|
||||||
|
|
||||||
export default async function download(url, ua) {
|
export default async function download(url, ua) {
|
||||||
const downloadUrlMatch = url.match(/^\/api\/file\/(.+)/);
|
const downloadUrlMatch = url.match(/^\/api\/(file|module)\/(.+)/);
|
||||||
if (downloadUrlMatch) {
|
if (downloadUrlMatch) {
|
||||||
let fileName = downloadUrlMatch?.[1];
|
let type = downloadUrlMatch?.[1];
|
||||||
if (fileName == null) {
|
let name = downloadUrlMatch?.[2];
|
||||||
throw new Error(`本地文件 URL 无效: ${url}`);
|
if (name == null) {
|
||||||
|
throw new Error(`本地 ${type} URL 无效: ${url}`);
|
||||||
}
|
}
|
||||||
fileName = decodeURIComponent(fileName);
|
name = decodeURIComponent(name);
|
||||||
const allFiles = $.read(FILES_KEY);
|
const key = type === 'module' ? MODULES_KEY : FILES_KEY;
|
||||||
const file = findByName(allFiles, fileName);
|
const item = findByName($.read(key), name);
|
||||||
if (!file) {
|
if (!item) {
|
||||||
throw new Error(`找不到本地文件: ${fileName}`);
|
throw new Error(`找不到本地 ${type}: ${name}`);
|
||||||
}
|
}
|
||||||
return file.content;
|
|
||||||
|
return item.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { isNode } = ENV();
|
const { isNode } = ENV();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user