mirror of
https://git.mirrors.martin98.com/https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-11 00:29:03 +08:00
Add Clash and Subscription producer
This commit is contained in:
parent
8b626ffad3
commit
33ae67ab60
@ -20,6 +20,7 @@ $.http = HTTP({
|
|||||||
const SETTINGS_KEY = "settings";
|
const SETTINGS_KEY = "settings";
|
||||||
const SUBS_KEY = "subs";
|
const SUBS_KEY = "subs";
|
||||||
const COLLECTIONS_KEY = "collections";
|
const COLLECTIONS_KEY = "collections";
|
||||||
|
|
||||||
const AVAILABLE_FILTERS = {
|
const AVAILABLE_FILTERS = {
|
||||||
"Keyword Filter": KeywordFilter,
|
"Keyword Filter": KeywordFilter,
|
||||||
"Useless Filter": UselessFilter,
|
"Useless Filter": UselessFilter,
|
||||||
@ -41,13 +42,17 @@ const AVAILABLE_OPERATORS = {
|
|||||||
"Script Operator": ScriptOperator,
|
"Script Operator": ScriptOperator,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const AVAILABLE_PRODUCERS = [
|
||||||
|
Raw_Producer, URI_Producer,
|
||||||
|
Surge_Producer, Loon_Producer, QX_Producer, Clash_Producer, Sub_Producer
|
||||||
|
];
|
||||||
|
|
||||||
// SOME INITIALIZATIONS
|
// SOME INITIALIZATIONS
|
||||||
if (!$.read(SUBS_KEY)) $.write({}, SUBS_KEY);
|
if (!$.read(SUBS_KEY)) $.write({}, SUBS_KEY);
|
||||||
if (!$.read(COLLECTIONS_KEY)) $.write({}, COLLECTIONS_KEY);
|
if (!$.read(COLLECTIONS_KEY)) $.write({}, COLLECTIONS_KEY);
|
||||||
if (!$.read(SETTINGS_KEY)) $.write({}, SETTINGS_KEY);
|
if (!$.read(SETTINGS_KEY)) $.write({}, SETTINGS_KEY);
|
||||||
|
|
||||||
// BACKEND API
|
// BACKEND API
|
||||||
$.info("Initializing Express...");
|
|
||||||
|
|
||||||
// download
|
// download
|
||||||
$app.get("/download/collection/:name", downloadCollection);
|
$app.get("/download/collection/:name", downloadCollection);
|
||||||
@ -88,7 +93,6 @@ $app.all("/", async (req, res) => {
|
|||||||
res.send("Hello from Sub-Store! Made with ❤️ by Peng-YM.");
|
res.send("Hello from Sub-Store! Made with ❤️ by Peng-YM.");
|
||||||
});
|
});
|
||||||
|
|
||||||
$.info("Express initialized");
|
|
||||||
$app.start();
|
$app.start();
|
||||||
|
|
||||||
async function IP_API(req, res) {
|
async function IP_API(req, res) {
|
||||||
@ -115,7 +119,7 @@ async function downloadResource(url) {
|
|||||||
async function gistBackup(req, res) {
|
async function gistBackup(req, res) {
|
||||||
const {action} = req.query;
|
const {action} = req.query;
|
||||||
// read token
|
// read token
|
||||||
const { gistToken } = $.read(SETTINGS_KEY);
|
const {gistToken} = $.read(SETTINGS_KEY);
|
||||||
if (!gistToken) {
|
if (!gistToken) {
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
status: "failed",
|
status: "failed",
|
||||||
@ -123,7 +127,7 @@ async function gistBackup(req, res) {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const gist = new Gist("Auto Generated Sub-Store Backup", gistToken);
|
const gist = new Gist("Auto Generated Sub-Store Backup", gistToken);
|
||||||
try{
|
try {
|
||||||
let content;
|
let content;
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "upload":
|
case "upload":
|
||||||
@ -134,7 +138,7 @@ async function gistBackup(req, res) {
|
|||||||
case "download":
|
case "download":
|
||||||
content = await gist.download();
|
content = await gist.download();
|
||||||
// restore settings
|
// restore settings
|
||||||
$.write(content,"#sub-store");
|
$.write(content, "#sub-store");
|
||||||
$.info(`还原备份中...`);
|
$.info(`还原备份中...`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -175,7 +179,7 @@ async function updateSettings(req, res) {
|
|||||||
// refresh resource
|
// refresh resource
|
||||||
async function refreshResource(req, res) {
|
async function refreshResource(req, res) {
|
||||||
const Base64 = new Base64Code();
|
const Base64 = new Base64Code();
|
||||||
const { url } = req.body;
|
const {url} = req.body;
|
||||||
const raw = await downloadResource(url);
|
const raw = await downloadResource(url);
|
||||||
$.write(raw, `#${Base64.safeEncode(url)}`);
|
$.write(raw, `#${Base64.safeEncode(url)}`);
|
||||||
res.json({
|
res.json({
|
||||||
@ -185,7 +189,7 @@ async function refreshResource(req, res) {
|
|||||||
|
|
||||||
// download subscription, for APP only
|
// download subscription, for APP only
|
||||||
async function downloadSub(req, res) {
|
async function downloadSub(req, res) {
|
||||||
const { name } = req.params;
|
const {name} = req.params;
|
||||||
const platform = req.query.target || getPlatformFromHeaders(req.headers);
|
const platform = req.query.target || getPlatformFromHeaders(req.headers);
|
||||||
const allSubs = $.read(SUBS_KEY);
|
const allSubs = $.read(SUBS_KEY);
|
||||||
if (allSubs[name]) {
|
if (allSubs[name]) {
|
||||||
@ -268,7 +272,7 @@ async function parseSub(sub, platform) {
|
|||||||
let script;
|
let script;
|
||||||
// process script
|
// process script
|
||||||
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") {
|
||||||
// if this is remote script, download it
|
// if this is remote script, download it
|
||||||
script = await $.http
|
script = await $.http
|
||||||
@ -324,13 +328,7 @@ async function parseSub(sub, platform) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Producers
|
// Producers
|
||||||
$parser.addProducers([
|
$parser.addProducers(AVAILABLE_PRODUCERS);
|
||||||
QX_Producer,
|
|
||||||
Loon_Producer,
|
|
||||||
Surge_Producer,
|
|
||||||
Raw_Producer,
|
|
||||||
URI_Producer,
|
|
||||||
]);
|
|
||||||
return $parser.produce(proxies);
|
return $parser.produce(proxies);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,7 +373,7 @@ function getFlowHeaders(headers, proxies) {
|
|||||||
|
|
||||||
// Subscriptions
|
// Subscriptions
|
||||||
async function getSub(req, res) {
|
async function getSub(req, res) {
|
||||||
const { name } = req.params;
|
const {name} = req.params;
|
||||||
const sub = $.read(SUBS_KEY)[name];
|
const sub = $.read(SUBS_KEY)[name];
|
||||||
if (sub) {
|
if (sub) {
|
||||||
res.json({
|
res.json({
|
||||||
@ -416,7 +414,7 @@ async function newSub(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function updateSub(req, res) {
|
async function updateSub(req, res) {
|
||||||
const { name } = req.params;
|
const {name} = req.params;
|
||||||
$.info(`Updating subscription: ${name}`);
|
$.info(`Updating subscription: ${name}`);
|
||||||
let sub = req.body;
|
let sub = req.body;
|
||||||
const allSubs = $.read(SUBS_KEY);
|
const allSubs = $.read(SUBS_KEY);
|
||||||
@ -455,7 +453,7 @@ async function updateSub(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function deleteSub(req, res) {
|
async function deleteSub(req, res) {
|
||||||
const { name } = req.params;
|
const {name} = req.params;
|
||||||
// delete from subscriptions
|
// delete from subscriptions
|
||||||
let allSubs = $.read(SUBS_KEY);
|
let allSubs = $.read(SUBS_KEY);
|
||||||
delete allSubs[name];
|
delete allSubs[name];
|
||||||
@ -490,7 +488,7 @@ async function deleteAllSubs(req, res) {
|
|||||||
|
|
||||||
// Collections
|
// Collections
|
||||||
async function downloadCollection(req, res) {
|
async function downloadCollection(req, res) {
|
||||||
const { name } = req.params;
|
const {name} = req.params;
|
||||||
const collection = $.read(COLLECTIONS_KEY)[name];
|
const collection = $.read(COLLECTIONS_KEY)[name];
|
||||||
const platform = getPlatformFromHeaders(req.headers);
|
const platform = getPlatformFromHeaders(req.headers);
|
||||||
if (collection) {
|
if (collection) {
|
||||||
@ -517,7 +515,7 @@ async function downloadCollection(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getCollection(req, res) {
|
async function getCollection(req, res) {
|
||||||
const { name } = req.params;
|
const {name} = req.params;
|
||||||
const collection = $.read(COLLECTIONS_KEY)[name];
|
const collection = $.read(COLLECTIONS_KEY)[name];
|
||||||
if (collection) {
|
if (collection) {
|
||||||
res.json({
|
res.json({
|
||||||
@ -558,7 +556,7 @@ async function newCollection(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function updateCollection(req, res) {
|
async function updateCollection(req, res) {
|
||||||
const { name } = req.params;
|
const {name} = req.params;
|
||||||
let collection = req.body;
|
let collection = req.body;
|
||||||
const allCol = $.read(COLLECTIONS_KEY);
|
const allCol = $.read(COLLECTIONS_KEY);
|
||||||
if (allCol[name]) {
|
if (allCol[name]) {
|
||||||
@ -583,7 +581,7 @@ async function updateCollection(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function deleteCollection(req, res) {
|
async function deleteCollection(req, res) {
|
||||||
const { name } = req.params;
|
const {name} = req.params;
|
||||||
let allCol = $.read(COLLECTIONS_KEY);
|
let allCol = $.read(COLLECTIONS_KEY);
|
||||||
delete allCol[name];
|
delete allCol[name];
|
||||||
$.write(allCol, COLLECTIONS_KEY);
|
$.write(allCol, COLLECTIONS_KEY);
|
||||||
@ -633,7 +631,7 @@ function ProxyParser(targetPlatform) {
|
|||||||
if (line.startsWith("#")) continue; // skip comments
|
if (line.startsWith("#")) continue; // skip comments
|
||||||
let matched = false;
|
let matched = false;
|
||||||
for (const p of parsers) {
|
for (const p of parsers) {
|
||||||
const { patternTest, func } = p;
|
const {patternTest, func} = p;
|
||||||
|
|
||||||
// some lines with weird format may produce errors!
|
// some lines with weird format may produce errors!
|
||||||
let patternMatched;
|
let patternMatched;
|
||||||
@ -676,6 +674,7 @@ function ProxyParser(targetPlatform) {
|
|||||||
function produce(proxies) {
|
function produce(proxies) {
|
||||||
for (const p of producers) {
|
for (const p of producers) {
|
||||||
if (p.targetPlatform === targetPlatform) {
|
if (p.targetPlatform === targetPlatform) {
|
||||||
|
if (typeof p.type === 'undefined' || p.type === "SINGLE") {
|
||||||
return proxies
|
return proxies
|
||||||
.map((proxy) => {
|
.map((proxy) => {
|
||||||
try {
|
try {
|
||||||
@ -691,6 +690,10 @@ function ProxyParser(targetPlatform) {
|
|||||||
})
|
})
|
||||||
.filter((v) => v.length > 0) // discard empty lines
|
.filter((v) => v.length > 0) // discard empty lines
|
||||||
.join("\n");
|
.join("\n");
|
||||||
|
} else if (p.type === 'ALL') {
|
||||||
|
return p.output(proxies);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -884,7 +887,7 @@ function URI_SS() {
|
|||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse URI SSR format, such as ssr://xxx
|
// Parse URI SSR format, such as ssr://xxx
|
||||||
@ -946,7 +949,7 @@ function URI_SSR() {
|
|||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
|
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
// V2rayN URI VMess format
|
// V2rayN URI VMess format
|
||||||
@ -1043,7 +1046,7 @@ function URI_VMess() {
|
|||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trojan URI format
|
// Trojan URI format
|
||||||
@ -1075,7 +1078,7 @@ function URI_Trojan() {
|
|||||||
supported,
|
supported,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************** Clash ***************************************/
|
/**************************** Clash ***************************************/
|
||||||
@ -1084,7 +1087,7 @@ function Clash_All() {
|
|||||||
return line.indexOf("{") !== -1;
|
return line.indexOf("{") !== -1;
|
||||||
};
|
};
|
||||||
const func = (line) => JSON.parse(line);
|
const func = (line) => JSON.parse(line);
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************** Quantumult X ***************************************/
|
/**************************** Quantumult X ***************************************/
|
||||||
@ -1142,7 +1145,7 @@ function QX_SS() {
|
|||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function QX_SSR() {
|
function QX_SSR() {
|
||||||
@ -1181,7 +1184,7 @@ function QX_SSR() {
|
|||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function QX_VMess() {
|
function QX_VMess() {
|
||||||
@ -1217,7 +1220,7 @@ function QX_VMess() {
|
|||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
|
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function QX_Trojan() {
|
function QX_Trojan() {
|
||||||
@ -1239,7 +1242,7 @@ function QX_Trojan() {
|
|||||||
proxy.scert = !JSON.parse(params["tls-verification"] || "true");
|
proxy.scert = !JSON.parse(params["tls-verification"] || "true");
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function QX_Http() {
|
function QX_Http() {
|
||||||
@ -1266,7 +1269,7 @@ function QX_Http() {
|
|||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
|
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getQXParams(line) {
|
function getQXParams(line) {
|
||||||
@ -1316,7 +1319,7 @@ function Loon_SS() {
|
|||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function Loon_SSR() {
|
function Loon_SSR() {
|
||||||
@ -1347,7 +1350,7 @@ function Loon_SSR() {
|
|||||||
"obfs-param": params[8].match(/{(.*)}/)[1],
|
"obfs-param": params[8].match(/{(.*)}/)[1],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function Loon_VMess() {
|
function Loon_VMess() {
|
||||||
@ -1395,7 +1398,7 @@ function Loon_VMess() {
|
|||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function Loon_Trojan() {
|
function Loon_Trojan() {
|
||||||
@ -1426,7 +1429,7 @@ function Loon_Trojan() {
|
|||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
|
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function Loon_Http() {
|
function Loon_Http() {
|
||||||
@ -1457,7 +1460,7 @@ function Loon_Http() {
|
|||||||
|
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************** Surge ***************************************/
|
/**************************** Surge ***************************************/
|
||||||
@ -1487,7 +1490,7 @@ function Surge_SS() {
|
|||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function Surge_VMess() {
|
function Surge_VMess() {
|
||||||
@ -1523,7 +1526,7 @@ function Surge_VMess() {
|
|||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function Surge_Trojan() {
|
function Surge_Trojan() {
|
||||||
@ -1546,7 +1549,7 @@ function Surge_Trojan() {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function Surge_Http() {
|
function Surge_Http() {
|
||||||
@ -1573,7 +1576,7 @@ function Surge_Http() {
|
|||||||
if (params.password !== "none") proxy.password = params.password;
|
if (params.password !== "none") proxy.password = params.password;
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { patternTest, func };
|
return {patternTest, func};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSurgeParams(line) {
|
function getSurgeParams(line) {
|
||||||
@ -1605,7 +1608,7 @@ function QX_Producer() {
|
|||||||
obfs_opts = `,obfs=${proxy["plugin-opts"].mode},obfs-host=${proxy["plugin-opts"].host}`;
|
obfs_opts = `,obfs=${proxy["plugin-opts"].mode},obfs-host=${proxy["plugin-opts"].host}`;
|
||||||
}
|
}
|
||||||
if (proxy.plugin === "v2ray-plugin") {
|
if (proxy.plugin === "v2ray-plugin") {
|
||||||
const { tls, host, path } = proxy["plugin-opts"];
|
const {tls, host, path} = proxy["plugin-opts"];
|
||||||
obfs_opts = `,obfs=${tls ? "wss" : "ws"},obfs-host=${host}${
|
obfs_opts = `,obfs=${tls ? "wss" : "ws"},obfs-host=${host}${
|
||||||
path ? ",obfs-uri=" + path : ""
|
path ? ",obfs-uri=" + path : ""
|
||||||
}`;
|
}`;
|
||||||
@ -1684,7 +1687,7 @@ function QX_Producer() {
|
|||||||
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`
|
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return { targetPlatform, output };
|
return {targetPlatform, output};
|
||||||
}
|
}
|
||||||
|
|
||||||
function Loon_Producer() {
|
function Loon_Producer() {
|
||||||
@ -1696,7 +1699,7 @@ function Loon_Producer() {
|
|||||||
obfs_opts = ",,";
|
obfs_opts = ",,";
|
||||||
if (proxy.plugin) {
|
if (proxy.plugin) {
|
||||||
if (proxy.plugin === "obfs") {
|
if (proxy.plugin === "obfs") {
|
||||||
const { mode, host } = proxy["plugin-opts"];
|
const {mode, host} = proxy["plugin-opts"];
|
||||||
obfs_opts = `,${mode},${host}`;
|
obfs_opts = `,${mode},${host}`;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -1745,7 +1748,7 @@ function Loon_Producer() {
|
|||||||
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`
|
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return { targetPlatform, output };
|
return {targetPlatform, output};
|
||||||
}
|
}
|
||||||
|
|
||||||
function Surge_Producer() {
|
function Surge_Producer() {
|
||||||
@ -1813,7 +1816,7 @@ function Surge_Producer() {
|
|||||||
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`
|
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return { targetPlatform, output };
|
return {targetPlatform, output};
|
||||||
}
|
}
|
||||||
|
|
||||||
function Raw_Producer() {
|
function Raw_Producer() {
|
||||||
@ -1821,7 +1824,7 @@ function Raw_Producer() {
|
|||||||
const output = (proxy) => {
|
const output = (proxy) => {
|
||||||
return JSON.stringify(proxy);
|
return JSON.stringify(proxy);
|
||||||
};
|
};
|
||||||
return { targetPlatform, output };
|
return {targetPlatform, output};
|
||||||
}
|
}
|
||||||
|
|
||||||
function URI_Producer() {
|
function URI_Producer() {
|
||||||
@ -1860,7 +1863,7 @@ function URI_Producer() {
|
|||||||
result += `#${encodeURIComponent(proxy.name)}`;
|
result += `#${encodeURIComponent(proxy.name)}`;
|
||||||
break;
|
break;
|
||||||
case "ssr":
|
case "ssr":
|
||||||
result = `${proxy.server}:${proxy.port}:${proxy.protocol}:${
|
result = `ssr://${proxy.server}:${proxy.port}:${proxy.protocol}:${
|
||||||
proxy.cipher
|
proxy.cipher
|
||||||
}:${proxy.obfs}:${Base64.safeEncode(proxy.password)}/`;
|
}:${proxy.obfs}:${Base64.safeEncode(proxy.password)}/`;
|
||||||
result += `?remarks=${proxy.name}${
|
result += `?remarks=${proxy.name}${
|
||||||
@ -1872,7 +1875,6 @@ function URI_Producer() {
|
|||||||
? "&protocolparam=" + Base64.safeEncode(proxy["protocol-param"])
|
? "&protocolparam=" + Base64.safeEncode(proxy["protocol-param"])
|
||||||
: ""
|
: ""
|
||||||
}`;
|
}`;
|
||||||
result = "vmess://" + Base64.safeEncode(result);
|
|
||||||
break;
|
break;
|
||||||
case "vmess":
|
case "vmess":
|
||||||
// V2RayN URI format
|
// V2RayN URI format
|
||||||
@ -1891,7 +1893,7 @@ function URI_Producer() {
|
|||||||
result.path = proxy["ws-path"] || "/";
|
result.path = proxy["ws-path"] || "/";
|
||||||
result.host = proxy["ws-headers"].Host || proxy.server;
|
result.host = proxy["ws-headers"].Host || proxy.server;
|
||||||
}
|
}
|
||||||
result = Base64.safeEncode(JSON.stringify(result));
|
result = "vmess://" + Base64.safeEncode(JSON.stringify(result));
|
||||||
break;
|
break;
|
||||||
case "trojan":
|
case "trojan":
|
||||||
result = `trojan://${proxy.password}@${proxy.server}:${proxy.port}#${proxy.name}`;
|
result = `trojan://${proxy.password}@${proxy.server}:${proxy.port}#${proxy.name}`;
|
||||||
@ -1901,12 +1903,41 @@ function URI_Producer() {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
return { targetPlatform, output };
|
return {targetPlatform, output};
|
||||||
|
}
|
||||||
|
|
||||||
|
function Clash_Producer() {
|
||||||
|
const targetPlatform = "Clash";
|
||||||
|
const type = "ALL";
|
||||||
|
const output = (proxies) => {
|
||||||
|
return "proxies:\n" + proxies.map(proxy => {
|
||||||
|
delete proxy.supported;
|
||||||
|
return " - " + JSON.stringify(proxy) + "\n";
|
||||||
|
}).join("");
|
||||||
|
};
|
||||||
|
return {targetPlatform, type, output};
|
||||||
|
}
|
||||||
|
|
||||||
|
function Sub_Producer() {
|
||||||
|
const targetPlatform = "Sub";
|
||||||
|
const type = "ALL";
|
||||||
|
const output = (proxies) => {
|
||||||
|
const urls = proxies.map(proxy => {
|
||||||
|
try {
|
||||||
|
return URI_Producer().output(proxy) + "\n";
|
||||||
|
} catch (e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}).join("");
|
||||||
|
const Base64 = new Base64Code();
|
||||||
|
return Base64.encode(urls);
|
||||||
|
};
|
||||||
|
return {targetPlatform, type, output};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************** Operators ***************************************/
|
/**************************** Operators ***************************************/
|
||||||
// force to set some properties (e.g., scert, udp, tfo, etc.)
|
// force to set some properties (e.g., scert, udp, tfo, etc.)
|
||||||
function SetPropertyOperator({ key, value }) {
|
function SetPropertyOperator({key, value}) {
|
||||||
return {
|
return {
|
||||||
name: "Set Property Operator",
|
name: "Set Property Operator",
|
||||||
func: (proxies) => {
|
func: (proxies) => {
|
||||||
@ -1998,7 +2029,7 @@ function KeywordRenameOperator(keywords) {
|
|||||||
name: "Keyword Rename Operator",
|
name: "Keyword Rename Operator",
|
||||||
func: (proxies) => {
|
func: (proxies) => {
|
||||||
return proxies.map((proxy) => {
|
return proxies.map((proxy) => {
|
||||||
for (const { old, now } of keywords) {
|
for (const {old, now} of keywords) {
|
||||||
proxy.name = proxy.name.replaceAll(old, now).trim();
|
proxy.name = proxy.name.replaceAll(old, now).trim();
|
||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
@ -2014,7 +2045,7 @@ function RegexRenameOperator(regex) {
|
|||||||
name: "Regex Rename Operator",
|
name: "Regex Rename Operator",
|
||||||
func: (proxies) => {
|
func: (proxies) => {
|
||||||
return proxies.map((proxy) => {
|
return proxies.map((proxy) => {
|
||||||
for (const { expr, now } of regex) {
|
for (const {expr, now} of regex) {
|
||||||
proxy.name = proxy.name.replace(new RegExp(expr, "g"), now).trim();
|
proxy.name = proxy.name.replace(new RegExp(expr, "g"), now).trim();
|
||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
@ -2092,7 +2123,7 @@ function ScriptOperator(script) {
|
|||||||
|
|
||||||
/**************************** Filters ***************************************/
|
/**************************** Filters ***************************************/
|
||||||
// filter by keywords
|
// filter by keywords
|
||||||
function KeywordFilter({ keywords = [], keep = true }) {
|
function KeywordFilter({keywords = [], keep = true}) {
|
||||||
return {
|
return {
|
||||||
name: "Keyword Filter",
|
name: "Keyword Filter",
|
||||||
func: (proxies) => {
|
func: (proxies) => {
|
||||||
@ -2147,7 +2178,7 @@ function RegionFilter(regions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// filter by regex
|
// filter by regex
|
||||||
function RegexFilter({ regex = [], keep = true }) {
|
function RegexFilter({regex = [], keep = true}) {
|
||||||
return {
|
return {
|
||||||
name: "Regex Filter",
|
name: "Regex Filter",
|
||||||
func: (proxies) => {
|
func: (proxies) => {
|
||||||
@ -2476,21 +2507,23 @@ function ENV() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function HTTP(defaultOptions = {}) {
|
function HTTP(defaultOptions = {}) {
|
||||||
const { isQX, isLoon, isSurge } = ENV();
|
const {isQX, isLoon, isSurge} = ENV();
|
||||||
const methods = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"];
|
const methods = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"];
|
||||||
|
|
||||||
function send(method, options) {
|
function send(method, options) {
|
||||||
options = options.hasOwnProperty("url") ? options : { url: options };
|
options = options.hasOwnProperty("url") ? options : {url: options};
|
||||||
options.url = defaultOptions.baseURL
|
options.url = defaultOptions.baseURL
|
||||||
? defaultOptions.baseURL + options.url
|
? defaultOptions.baseURL + options.url
|
||||||
: options.url;
|
: options.url;
|
||||||
options = { ...defaultOptions, ...options };
|
options = {...defaultOptions, ...options};
|
||||||
const timeout = options.timeout;
|
const timeout = options.timeout;
|
||||||
const events = {
|
const events = {
|
||||||
...{
|
...{
|
||||||
onRequest: () => {},
|
onRequest: () => {
|
||||||
|
},
|
||||||
onResponse: (resp) => resp,
|
onResponse: (resp) => resp,
|
||||||
onTimeout: () => {},
|
onTimeout: () => {
|
||||||
|
},
|
||||||
},
|
},
|
||||||
...options.events,
|
...options.events,
|
||||||
};
|
};
|
||||||
@ -2499,7 +2532,7 @@ function HTTP(defaultOptions = {}) {
|
|||||||
|
|
||||||
let worker;
|
let worker;
|
||||||
if (isQX) {
|
if (isQX) {
|
||||||
worker = $task.fetch({ method, ...options });
|
worker = $task.fetch({method, ...options});
|
||||||
} else {
|
} else {
|
||||||
worker = new Promise((resolve, reject) => {
|
worker = new Promise((resolve, reject) => {
|
||||||
const request = isSurge || isLoon ? $httpClient : require("request");
|
const request = isSurge || isLoon ? $httpClient : require("request");
|
||||||
@ -2545,7 +2578,7 @@ function HTTP(defaultOptions = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function API(name = "untitled", debug = false) {
|
function API(name = "untitled", debug = false) {
|
||||||
const { isQX, isLoon, isSurge, isNode, isJSBox, isScriptable } = ENV();
|
const {isQX, isLoon, isSurge, isNode, isJSBox, isScriptable} = ENV();
|
||||||
return new (class {
|
return new (class {
|
||||||
constructor(name, debug) {
|
constructor(name, debug) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@ -2593,7 +2626,7 @@ function API(name = "untitled", debug = false) {
|
|||||||
this.node.fs.writeFileSync(
|
this.node.fs.writeFileSync(
|
||||||
fpath,
|
fpath,
|
||||||
JSON.stringify({}),
|
JSON.stringify({}),
|
||||||
{ flag: "wx" },
|
{flag: "wx"},
|
||||||
(err) => console.log(err)
|
(err) => console.log(err)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -2605,7 +2638,7 @@ function API(name = "untitled", debug = false) {
|
|||||||
this.node.fs.writeFileSync(
|
this.node.fs.writeFileSync(
|
||||||
fpath,
|
fpath,
|
||||||
JSON.stringify({}),
|
JSON.stringify({}),
|
||||||
{ flag: "wx" },
|
{flag: "wx"},
|
||||||
(err) => console.log(err)
|
(err) => console.log(err)
|
||||||
);
|
);
|
||||||
this.cache = {};
|
this.cache = {};
|
||||||
@ -2626,13 +2659,13 @@ function API(name = "untitled", debug = false) {
|
|||||||
this.node.fs.writeFileSync(
|
this.node.fs.writeFileSync(
|
||||||
`${this.name}.json`,
|
`${this.name}.json`,
|
||||||
data,
|
data,
|
||||||
{ flag: "w" },
|
{flag: "w"},
|
||||||
(err) => console.log(err)
|
(err) => console.log(err)
|
||||||
);
|
);
|
||||||
this.node.fs.writeFileSync(
|
this.node.fs.writeFileSync(
|
||||||
"root.json",
|
"root.json",
|
||||||
JSON.stringify(this.root),
|
JSON.stringify(this.root),
|
||||||
{ flag: "w" },
|
{flag: "w"},
|
||||||
(err) => console.log(err)
|
(err) => console.log(err)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -2766,7 +2799,7 @@ function API(name = "untitled", debug = false) {
|
|||||||
|
|
||||||
/*********************************** Mini Express *************************************/
|
/*********************************** Mini Express *************************************/
|
||||||
function express(port = 3000) {
|
function express(port = 3000) {
|
||||||
const { isNode } = ENV();
|
const {isNode} = ENV();
|
||||||
const DEFAULT_HEADERS = {
|
const DEFAULT_HEADERS = {
|
||||||
"Content-Type": "text/plain;charset=UTF-8",
|
"Content-Type": "text/plain;charset=UTF-8",
|
||||||
"Access-Control-Allow-Origin": "*",
|
"Access-Control-Allow-Origin": "*",
|
||||||
@ -2780,9 +2813,9 @@ function express(port = 3000) {
|
|||||||
const express_ = require("express");
|
const express_ = require("express");
|
||||||
const bodyParser = require("body-parser");
|
const bodyParser = require("body-parser");
|
||||||
const app = express_();
|
const app = express_();
|
||||||
app.use(bodyParser.json({ verify: rawBodySaver }));
|
app.use(bodyParser.json({verify: rawBodySaver}));
|
||||||
app.use(bodyParser.urlencoded({ verify: rawBodySaver, extended: true }));
|
app.use(bodyParser.urlencoded({verify: rawBodySaver, extended: true}));
|
||||||
app.use(bodyParser.raw({ verify: rawBodySaver, type: "*/*" }));
|
app.use(bodyParser.raw({verify: rawBodySaver, type: "*/*"}));
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
res.set(DEFAULT_HEADERS);
|
res.set(DEFAULT_HEADERS);
|
||||||
next();
|
next();
|
||||||
@ -2814,19 +2847,19 @@ function express(port = 3000) {
|
|||||||
|
|
||||||
// dispatch url to route
|
// dispatch url to route
|
||||||
const dispatch = (request, start = 0) => {
|
const dispatch = (request, start = 0) => {
|
||||||
let { method, url, headers, body } = request;
|
let {method, url, headers, body} = request;
|
||||||
if (/json/i.test(headers["Content-Type"])) {
|
if (/json/i.test(headers["Content-Type"])) {
|
||||||
body = JSON.parse(body);
|
body = JSON.parse(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
method = method.toUpperCase();
|
method = method.toUpperCase();
|
||||||
const { path, query } = extractURL(url);
|
const {path, query} = extractURL(url);
|
||||||
let handler = null;
|
let handler = null;
|
||||||
let i;
|
let i;
|
||||||
|
|
||||||
for (i = start; i < handlers.length; i++) {
|
for (i = start; i < handlers.length; i++) {
|
||||||
if (handlers[i].method === "ALL" || method === handlers[i].method) {
|
if (handlers[i].method === "ALL" || method === handlers[i].method) {
|
||||||
const { pattern } = handlers[i];
|
const {pattern} = handlers[i];
|
||||||
if (patternMatched(pattern, path)) {
|
if (patternMatched(pattern, path)) {
|
||||||
handler = handlers[i];
|
handler = handlers[i];
|
||||||
break;
|
break;
|
||||||
@ -2870,7 +2903,7 @@ function express(port = 3000) {
|
|||||||
METHODS_NAMES.forEach((method) => {
|
METHODS_NAMES.forEach((method) => {
|
||||||
app[method.toLowerCase()] = (pattern, callback) => {
|
app[method.toLowerCase()] = (pattern, callback) => {
|
||||||
// add handler
|
// add handler
|
||||||
handlers.push({ method, pattern, callback });
|
handlers.push({method, pattern, callback});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2880,7 +2913,7 @@ function express(port = 3000) {
|
|||||||
METHODS_NAMES.forEach((method) => {
|
METHODS_NAMES.forEach((method) => {
|
||||||
chainApp[method.toLowerCase()] = (callback) => {
|
chainApp[method.toLowerCase()] = (callback) => {
|
||||||
// add handler
|
// add handler
|
||||||
handlers.push({ method, pattern, callback });
|
handlers.push({method, pattern, callback});
|
||||||
return chainApp;
|
return chainApp;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -2905,7 +2938,7 @@ function express(port = 3000) {
|
|||||||
|
|
||||||
function Response() {
|
function Response() {
|
||||||
let statusCode = 200;
|
let statusCode = 200;
|
||||||
const { isQX, isLoon, isSurge } = ENV();
|
const {isQX, isLoon, isSurge} = ENV();
|
||||||
const headers = DEFAULT_HEADERS;
|
const headers = DEFAULT_HEADERS;
|
||||||
const STATUS_CODE_MAP = {
|
const STATUS_CODE_MAP = {
|
||||||
200: "HTTP/1.1 200 OK",
|
200: "HTTP/1.1 200 OK",
|
||||||
@ -3060,10 +3093,10 @@ function Gist(backupKey, token) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.upload = async function(content) {
|
this.upload = async function (content) {
|
||||||
const id = await locate();
|
const id = await locate();
|
||||||
const files = {
|
const files = {
|
||||||
[FILE_NAME]: { content }
|
[FILE_NAME]: {content}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (id === -1) {
|
if (id === -1) {
|
||||||
@ -3080,18 +3113,18 @@ function Gist(backupKey, token) {
|
|||||||
// update an existing gist
|
// update an existing gist
|
||||||
return http.patch({
|
return http.patch({
|
||||||
url: `/gists/${id}`,
|
url: `/gists/${id}`,
|
||||||
body: JSON.stringify({ files })
|
body: JSON.stringify({files})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.download = async function() {
|
this.download = async function () {
|
||||||
const id = await locate();
|
const id = await locate();
|
||||||
if (id === -1) {
|
if (id === -1) {
|
||||||
return Promise.reject("未找到Gist备份!");
|
return Promise.reject("未找到Gist备份!");
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const { files } = await http
|
const {files} = await http
|
||||||
.get(`/gists/${id}`)
|
.get(`/gists/${id}`)
|
||||||
.then(resp => JSON.parse(resp.body));
|
.then(resp => JSON.parse(resp.body));
|
||||||
const url = files[FILE_NAME].raw_url;
|
const url = files[FILE_NAME].raw_url;
|
||||||
@ -3102,6 +3135,7 @@ function Gist(backupKey, token) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************** Base 64 *********************************************/
|
/******************************** Base 64 *********************************************/
|
||||||
// Base64 Coding Library
|
// Base64 Coding Library
|
||||||
// https://github.com/dankogai/js-base64#readme
|
// https://github.com/dankogai/js-base64#readme
|
||||||
|
2
backend/sub-store.min.js
vendored
2
backend/sub-store.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user