mirror of
https://git.mirrors.martin98.com/https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-10 22:19:00 +08:00
Implemented API
This commit is contained in:
parent
0ef1161ec4
commit
2d72f810f0
4
collection.json
Normal file
4
collection.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"name": "Surge",
|
||||||
|
"subscriptions": ["AAEX", "Nexitally"]
|
||||||
|
}
|
119
parser.js
119
parser.js
@ -28,17 +28,43 @@ $app.all("/", (req, res) => {
|
|||||||
$app.start();
|
$app.start();
|
||||||
|
|
||||||
// SOME CONSTANTS
|
// SOME CONSTANTS
|
||||||
|
const FALL_BACK_TARGET = "Loon";
|
||||||
const DEFAULT_SUPPORTED_PLATFORMS = {
|
const DEFAULT_SUPPORTED_PLATFORMS = {
|
||||||
QX: true,
|
QX: true,
|
||||||
Loon: true,
|
Loon: true,
|
||||||
Surge: true,
|
Surge: true,
|
||||||
Node: true
|
Node: true
|
||||||
}
|
}
|
||||||
|
const AVAILABLE_FILTERS = {
|
||||||
|
"Keyword Filter": KeywordFilter,
|
||||||
|
"Discard Keyword Filter": DiscardKeywordFilter,
|
||||||
|
"Useless Filter": UselessFilter,
|
||||||
|
"Region Filter": RegionFilter,
|
||||||
|
"Regex Filter": RegexFilter,
|
||||||
|
"Discard Regex Filter": DiscardRegexFilter,
|
||||||
|
"Type Filter": TypeFilter,
|
||||||
|
"Script Filter": ScriptFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
const AVAILABLE_OPERATORS = {
|
||||||
|
"Set Property Operator": SetPropertyOperator,
|
||||||
|
"Flag Operator": FlagOperator,
|
||||||
|
"Sort Operator": SortOperator,
|
||||||
|
"Keyword Sort Operator": KeywordSortOperator,
|
||||||
|
"Keyword Rename Operator": KeywordRenameOperator,
|
||||||
|
"Keyword Delete Operator": KeywordDeleteOperator,
|
||||||
|
"Regex Rename Operator": RegexRenameOperator,
|
||||||
|
"Regex Delete Operator": RegexDeleteOperator,
|
||||||
|
"Script Operator": ScriptOperator
|
||||||
|
}
|
||||||
|
|
||||||
/**************************** API -- Subscriptions ***************************************/
|
/**************************** API -- Subscriptions ***************************************/
|
||||||
// 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 = getPlatformFromHeaders(req.headers);
|
||||||
|
console.log('=======================================')
|
||||||
|
console.log(`Downloading subscription: ${name}. Target platform ==> ${platform}\n`);
|
||||||
const allSubs = $.read(SUBS_KEY);
|
const allSubs = $.read(SUBS_KEY);
|
||||||
if (allSubs[name]) {
|
if (allSubs[name]) {
|
||||||
const sub = allSubs[name];
|
const sub = allSubs[name];
|
||||||
@ -50,34 +76,41 @@ async function downloadSub(req, res) {
|
|||||||
message: err
|
message: err
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const platform = getPlatformFromHeaders(req.headers);
|
|
||||||
const $parser = ProxyParser(platform);
|
const $parser = ProxyParser(platform);
|
||||||
let proxies = $parser.parse(raw);
|
let proxies = $parser.parse(raw);
|
||||||
|
|
||||||
// filters
|
// filters
|
||||||
const $filter = ProxyFilter();
|
const $filter = ProxyFilter();
|
||||||
$filter.addFilters(
|
// create filters from sub conf
|
||||||
RegionFilter(['HK', 'TW', 'SG', 'US', 'JP']),
|
const userFilters = [];
|
||||||
DiscardKeywordFilter("试用")
|
for (const item of sub.filters) {
|
||||||
);
|
const filter = AVAILABLE_FILTERS[item.type];
|
||||||
proxies = $filter.process(proxies);
|
if (filter) {
|
||||||
|
userFilters.push(filter(...(item.args || [])));
|
||||||
|
console.log(`Filter "${item.type}" added. Arguments: ${item.args || "None"}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$filter.addFilters(...userFilters);
|
||||||
|
|
||||||
// operators
|
// operators
|
||||||
const $operator = ProxyOperator();
|
const $operator = ProxyOperator();
|
||||||
$operator.addOperators(
|
const userOperators = [];
|
||||||
// SetPropertyOperator('tfo', true),
|
for (const item of sub.operators) {
|
||||||
// SetPropertyOperator('udp', true),
|
const operator = AVAILABLE_OPERATORS[item.type];
|
||||||
FlagOperator(1),
|
if (operator) {
|
||||||
KeywordRenameOperator([
|
userOperators.push(operator(...(item.args || [])));
|
||||||
{old: "Hong Kong", now: "HK"},
|
console.log(`Operator "${item.type}" added. Arguments: ${item.args || "None"}`);
|
||||||
{old: "Japan", now: "JP"},
|
}
|
||||||
{old: "Taiwan", now: "TW"},
|
}
|
||||||
{old: "Singapore", now: "SG"},
|
$operator.addOperators(...userOperators);
|
||||||
{old: "USA", now: "US"}
|
|
||||||
]),
|
// process filters and operators
|
||||||
KeywordSortOperator(['HK', 'TW', 'SG', 'US', 'JP']),
|
console.log("\nApplying filters...");
|
||||||
);
|
proxies = $filter.process(proxies);
|
||||||
|
console.log("\nApplying operators...");
|
||||||
proxies = $operator.process(proxies);
|
proxies = $operator.process(proxies);
|
||||||
|
|
||||||
|
// convert to target platform and output
|
||||||
res.send($parser.produce(proxies));
|
res.send($parser.produce(proxies));
|
||||||
} else {
|
} else {
|
||||||
res.status(404).json({
|
res.status(404).json({
|
||||||
@ -1161,7 +1194,7 @@ function SetPropertyOperator(key, val) {
|
|||||||
// add or remove flag for proxies
|
// add or remove flag for proxies
|
||||||
function FlagOperator(type) {
|
function FlagOperator(type) {
|
||||||
return {
|
return {
|
||||||
name: "Flag",
|
name: "Flag Operator",
|
||||||
func: proxies => {
|
func: proxies => {
|
||||||
return proxies.map(proxy => {
|
return proxies.map(proxy => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -1189,7 +1222,7 @@ function FlagOperator(type) {
|
|||||||
// sort proxies according to their names
|
// sort proxies according to their names
|
||||||
function SortOperator(order = 'asc') {
|
function SortOperator(order = 'asc') {
|
||||||
return {
|
return {
|
||||||
name: "Sort",
|
name: "Sort Operator",
|
||||||
func: proxies => {
|
func: proxies => {
|
||||||
switch (order) {
|
switch (order) {
|
||||||
case "asc":
|
case "asc":
|
||||||
@ -1209,10 +1242,9 @@ function SortOperator(order = 'asc') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sort by keywords
|
// sort by keywords
|
||||||
function KeywordSortOperator(keywords) {
|
function KeywordSortOperator(...keywords) {
|
||||||
if (!(keywords instanceof Array)) keywords = [keywords];
|
|
||||||
return {
|
return {
|
||||||
name: "Keyword Sort",
|
name: "Keyword Sort Operator",
|
||||||
func: proxies => proxies.sort((a, b) => {
|
func: proxies => proxies.sort((a, b) => {
|
||||||
const oA = getKeywordOrder(keywords, a.name);
|
const oA = getKeywordOrder(keywords, a.name);
|
||||||
const oB = getKeywordOrder(keywords, b.name);
|
const oB = getKeywordOrder(keywords, b.name);
|
||||||
@ -1237,9 +1269,9 @@ function getKeywordOrder(keywords, str) {
|
|||||||
|
|
||||||
// rename by keywords
|
// rename by keywords
|
||||||
// keywords: [{old: "old", now: "now"}]
|
// keywords: [{old: "old", now: "now"}]
|
||||||
function KeywordRenameOperator(keywords) {
|
function KeywordRenameOperator(...keywords) {
|
||||||
return {
|
return {
|
||||||
name: "Keyword Rename",
|
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) {
|
||||||
@ -1253,10 +1285,9 @@ function KeywordRenameOperator(keywords) {
|
|||||||
|
|
||||||
// rename by regex
|
// rename by regex
|
||||||
// keywords: [{expr: "string format regex", now: "now"}]
|
// keywords: [{expr: "string format regex", now: "now"}]
|
||||||
function RegexRenameOperator(regex) {
|
function RegexRenameOperator(...regex) {
|
||||||
if (!(regex instanceof Array)) regex = [regex];
|
|
||||||
return {
|
return {
|
||||||
name: "Regex Rename",
|
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) {
|
||||||
@ -1270,8 +1301,7 @@ function RegexRenameOperator(regex) {
|
|||||||
|
|
||||||
// delete keywords operator
|
// delete keywords operator
|
||||||
// keywords: ['a', 'b', 'c']
|
// keywords: ['a', 'b', 'c']
|
||||||
function KeywordDeleteOperator(keywords) {
|
function KeywordDeleteOperator(...keywords) {
|
||||||
if (!(keywords instanceof Array)) keywords = [keywords];
|
|
||||||
const keywords_ = keywords.map(k => {
|
const keywords_ = keywords.map(k => {
|
||||||
return {
|
return {
|
||||||
old: k,
|
old: k,
|
||||||
@ -1279,15 +1309,14 @@ function KeywordDeleteOperator(keywords) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
name: "Keyword Delete",
|
name: "Keyword Delete Operator",
|
||||||
func: KeywordRenameOperator(keywords_).func
|
func: KeywordRenameOperator(keywords_).func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete regex operator
|
// delete regex operator
|
||||||
// regex: ['a', 'b', 'c']
|
// regex: ['a', 'b', 'c']
|
||||||
function RegexDeleteOperator(regex) {
|
function RegexDeleteOperator(...regex) {
|
||||||
if (!(regex instanceof Array)) regex = [regex];
|
|
||||||
const regex_ = regex.map(r => {
|
const regex_ = regex.map(r => {
|
||||||
return {
|
return {
|
||||||
expr: r,
|
expr: r,
|
||||||
@ -1295,7 +1324,7 @@ function RegexDeleteOperator(regex) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
name: "Regex Delete",
|
name: "Regex Delete Operator",
|
||||||
func: RegexRenameOperator(regex_).func
|
func: RegexRenameOperator(regex_).func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1330,8 +1359,7 @@ function ScriptOperator(script, encoded = true) {
|
|||||||
|
|
||||||
/**************************** Filters ***************************************/
|
/**************************** Filters ***************************************/
|
||||||
// filter by keywords
|
// filter by keywords
|
||||||
function KeywordFilter(keywords) {
|
function KeywordFilter(...keywords) {
|
||||||
if (!(keywords instanceof Array)) keywords = [keywords];
|
|
||||||
return {
|
return {
|
||||||
name: "Keyword Filter",
|
name: "Keyword Filter",
|
||||||
func: (proxies) => {
|
func: (proxies) => {
|
||||||
@ -1340,8 +1368,7 @@ function KeywordFilter(keywords) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function DiscardKeywordFilter(keywords) {
|
function DiscardKeywordFilter(...keywords) {
|
||||||
if (!(keywords instanceof Array)) keywords = [keywords];
|
|
||||||
return {
|
return {
|
||||||
name: "Discard Keyword Filter",
|
name: "Discard Keyword Filter",
|
||||||
func: proxies => {
|
func: proxies => {
|
||||||
@ -1361,8 +1388,7 @@ function UselessFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// filter by regions
|
// filter by regions
|
||||||
function RegionFilter(regions) {
|
function RegionFilter(...regions) {
|
||||||
if (!(regions instanceof Array)) regions = [regions];
|
|
||||||
const REGION_MAP = {
|
const REGION_MAP = {
|
||||||
"HK": "🇭🇰",
|
"HK": "🇭🇰",
|
||||||
"TW": "🇹🇼",
|
"TW": "🇹🇼",
|
||||||
@ -1385,8 +1411,7 @@ function RegionFilter(regions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// filter by regex
|
// filter by regex
|
||||||
function RegexFilter(regex) {
|
function RegexFilter(...regex) {
|
||||||
if (!(regex instanceof Array)) regex = [regex];
|
|
||||||
return {
|
return {
|
||||||
name: "Regex Filter",
|
name: "Regex Filter",
|
||||||
func: (proxies) => {
|
func: (proxies) => {
|
||||||
@ -1395,8 +1420,7 @@ function RegexFilter(regex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function DiscardRegexFilter(regex) {
|
function DiscardRegexFilter(...regex) {
|
||||||
if (!(regex instanceof Array)) regex = [regex];
|
|
||||||
return {
|
return {
|
||||||
name: "Discard Regex Filter",
|
name: "Discard Regex Filter",
|
||||||
func: proxies => {
|
func: proxies => {
|
||||||
@ -1407,8 +1431,7 @@ function DiscardRegexFilter(regex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// filter by proxy types
|
// filter by proxy types
|
||||||
function TypeFilter(types) {
|
function TypeFilter(...types) {
|
||||||
if (!(types instanceof Array)) types = [types];
|
|
||||||
return {
|
return {
|
||||||
name: "Type Filter",
|
name: "Type Filter",
|
||||||
func: (proxies) => {
|
func: (proxies) => {
|
||||||
@ -1579,7 +1602,7 @@ function getPlatformFromHeaders(headers) {
|
|||||||
} else if (UA.indexOf("Decar") !== -1) {
|
} else if (UA.indexOf("Decar") !== -1) {
|
||||||
return "Loon";
|
return "Loon";
|
||||||
} else {
|
} else {
|
||||||
return "Loon"
|
return FALL_BACK_TARGET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
{"subs":{"Nexitally":{"name":"Nexitally","url":"http://127.0.0.1:8080/nex.list"},"SSR":{"name":"SSR","url":"http://127.0.0.1:8080/SSR.list"},"SSR_SS":{"name":"SSR_SS","url":"http://127.0.0.1:8080/SSR_SS.list"},"AAEX":{"name":"AAEX","url":"http://127.0.0.1:8080/AAEX.list"}}}
|
{"subs":{"Nexitally":{"name":"Nexitally","url":"http://127.0.0.1:8080/nex.list","filters":[{"type":"Region Filter","args":["HK","JP","TW"]},{"type":"Discard Keyword Filter","args":["Premium"]}],"operators":[{"type":"Flag Operator","args":[1]},{"type":"Keyword Sort Operator","args":["Hong Kong","Taiwan","Japan"]}]}}}
|
27
sub.json
Normal file
27
sub.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "The Name of Subscription",
|
||||||
|
"url": "The URL of Subscription",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"type": "Useless Filter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Keyword Filter",
|
||||||
|
"args": ["IEPL", "IPLC"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Region Filter",
|
||||||
|
"args": ["HK", "TW", "JP"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"operators": [
|
||||||
|
{
|
||||||
|
"type": "Flag Operator",
|
||||||
|
"args": [1]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Keyword Sort Operator",
|
||||||
|
"args": ["HK", "TW", "JP"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user