mirror of
https://git.mirrors.martin98.com/https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-09 23:59:01 +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();
|
||||
|
||||
// SOME CONSTANTS
|
||||
const FALL_BACK_TARGET = "Loon";
|
||||
const DEFAULT_SUPPORTED_PLATFORMS = {
|
||||
QX: true,
|
||||
Loon: true,
|
||||
Surge: 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 ***************************************/
|
||||
// download subscription, for APP only
|
||||
async function downloadSub(req, res) {
|
||||
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);
|
||||
if (allSubs[name]) {
|
||||
const sub = allSubs[name];
|
||||
@ -50,34 +76,41 @@ async function downloadSub(req, res) {
|
||||
message: err
|
||||
});
|
||||
});
|
||||
const platform = getPlatformFromHeaders(req.headers);
|
||||
const $parser = ProxyParser(platform);
|
||||
let proxies = $parser.parse(raw);
|
||||
|
||||
// filters
|
||||
const $filter = ProxyFilter();
|
||||
$filter.addFilters(
|
||||
RegionFilter(['HK', 'TW', 'SG', 'US', 'JP']),
|
||||
DiscardKeywordFilter("试用")
|
||||
);
|
||||
proxies = $filter.process(proxies);
|
||||
// create filters from sub conf
|
||||
const userFilters = [];
|
||||
for (const item of sub.filters) {
|
||||
const filter = AVAILABLE_FILTERS[item.type];
|
||||
if (filter) {
|
||||
userFilters.push(filter(...(item.args || [])));
|
||||
console.log(`Filter "${item.type}" added. Arguments: ${item.args || "None"}`);
|
||||
}
|
||||
}
|
||||
$filter.addFilters(...userFilters);
|
||||
|
||||
// operators
|
||||
const $operator = ProxyOperator();
|
||||
$operator.addOperators(
|
||||
// SetPropertyOperator('tfo', true),
|
||||
// SetPropertyOperator('udp', true),
|
||||
FlagOperator(1),
|
||||
KeywordRenameOperator([
|
||||
{old: "Hong Kong", now: "HK"},
|
||||
{old: "Japan", now: "JP"},
|
||||
{old: "Taiwan", now: "TW"},
|
||||
{old: "Singapore", now: "SG"},
|
||||
{old: "USA", now: "US"}
|
||||
]),
|
||||
KeywordSortOperator(['HK', 'TW', 'SG', 'US', 'JP']),
|
||||
);
|
||||
const userOperators = [];
|
||||
for (const item of sub.operators) {
|
||||
const operator = AVAILABLE_OPERATORS[item.type];
|
||||
if (operator) {
|
||||
userOperators.push(operator(...(item.args || [])));
|
||||
console.log(`Operator "${item.type}" added. Arguments: ${item.args || "None"}`);
|
||||
}
|
||||
}
|
||||
$operator.addOperators(...userOperators);
|
||||
|
||||
// process filters and operators
|
||||
console.log("\nApplying filters...");
|
||||
proxies = $filter.process(proxies);
|
||||
console.log("\nApplying operators...");
|
||||
proxies = $operator.process(proxies);
|
||||
|
||||
// convert to target platform and output
|
||||
res.send($parser.produce(proxies));
|
||||
} else {
|
||||
res.status(404).json({
|
||||
@ -1161,7 +1194,7 @@ function SetPropertyOperator(key, val) {
|
||||
// add or remove flag for proxies
|
||||
function FlagOperator(type) {
|
||||
return {
|
||||
name: "Flag",
|
||||
name: "Flag Operator",
|
||||
func: proxies => {
|
||||
return proxies.map(proxy => {
|
||||
switch (type) {
|
||||
@ -1189,7 +1222,7 @@ function FlagOperator(type) {
|
||||
// sort proxies according to their names
|
||||
function SortOperator(order = 'asc') {
|
||||
return {
|
||||
name: "Sort",
|
||||
name: "Sort Operator",
|
||||
func: proxies => {
|
||||
switch (order) {
|
||||
case "asc":
|
||||
@ -1209,10 +1242,9 @@ function SortOperator(order = 'asc') {
|
||||
}
|
||||
|
||||
// sort by keywords
|
||||
function KeywordSortOperator(keywords) {
|
||||
if (!(keywords instanceof Array)) keywords = [keywords];
|
||||
function KeywordSortOperator(...keywords) {
|
||||
return {
|
||||
name: "Keyword Sort",
|
||||
name: "Keyword Sort Operator",
|
||||
func: proxies => proxies.sort((a, b) => {
|
||||
const oA = getKeywordOrder(keywords, a.name);
|
||||
const oB = getKeywordOrder(keywords, b.name);
|
||||
@ -1237,9 +1269,9 @@ function getKeywordOrder(keywords, str) {
|
||||
|
||||
// rename by keywords
|
||||
// keywords: [{old: "old", now: "now"}]
|
||||
function KeywordRenameOperator(keywords) {
|
||||
function KeywordRenameOperator(...keywords) {
|
||||
return {
|
||||
name: "Keyword Rename",
|
||||
name: "Keyword Rename Operator",
|
||||
func: proxies => {
|
||||
return proxies.map(proxy => {
|
||||
for (const {old, now} of keywords) {
|
||||
@ -1253,10 +1285,9 @@ function KeywordRenameOperator(keywords) {
|
||||
|
||||
// rename by regex
|
||||
// keywords: [{expr: "string format regex", now: "now"}]
|
||||
function RegexRenameOperator(regex) {
|
||||
if (!(regex instanceof Array)) regex = [regex];
|
||||
function RegexRenameOperator(...regex) {
|
||||
return {
|
||||
name: "Regex Rename",
|
||||
name: "Regex Rename Operator",
|
||||
func: proxies => {
|
||||
return proxies.map(proxy => {
|
||||
for (const {expr, now} of regex) {
|
||||
@ -1270,8 +1301,7 @@ function RegexRenameOperator(regex) {
|
||||
|
||||
// delete keywords operator
|
||||
// keywords: ['a', 'b', 'c']
|
||||
function KeywordDeleteOperator(keywords) {
|
||||
if (!(keywords instanceof Array)) keywords = [keywords];
|
||||
function KeywordDeleteOperator(...keywords) {
|
||||
const keywords_ = keywords.map(k => {
|
||||
return {
|
||||
old: k,
|
||||
@ -1279,15 +1309,14 @@ function KeywordDeleteOperator(keywords) {
|
||||
}
|
||||
})
|
||||
return {
|
||||
name: "Keyword Delete",
|
||||
name: "Keyword Delete Operator",
|
||||
func: KeywordRenameOperator(keywords_).func
|
||||
}
|
||||
}
|
||||
|
||||
// delete regex operator
|
||||
// regex: ['a', 'b', 'c']
|
||||
function RegexDeleteOperator(regex) {
|
||||
if (!(regex instanceof Array)) regex = [regex];
|
||||
function RegexDeleteOperator(...regex) {
|
||||
const regex_ = regex.map(r => {
|
||||
return {
|
||||
expr: r,
|
||||
@ -1295,7 +1324,7 @@ function RegexDeleteOperator(regex) {
|
||||
}
|
||||
});
|
||||
return {
|
||||
name: "Regex Delete",
|
||||
name: "Regex Delete Operator",
|
||||
func: RegexRenameOperator(regex_).func
|
||||
}
|
||||
}
|
||||
@ -1330,8 +1359,7 @@ function ScriptOperator(script, encoded = true) {
|
||||
|
||||
/**************************** Filters ***************************************/
|
||||
// filter by keywords
|
||||
function KeywordFilter(keywords) {
|
||||
if (!(keywords instanceof Array)) keywords = [keywords];
|
||||
function KeywordFilter(...keywords) {
|
||||
return {
|
||||
name: "Keyword Filter",
|
||||
func: (proxies) => {
|
||||
@ -1340,8 +1368,7 @@ function KeywordFilter(keywords) {
|
||||
}
|
||||
}
|
||||
|
||||
function DiscardKeywordFilter(keywords) {
|
||||
if (!(keywords instanceof Array)) keywords = [keywords];
|
||||
function DiscardKeywordFilter(...keywords) {
|
||||
return {
|
||||
name: "Discard Keyword Filter",
|
||||
func: proxies => {
|
||||
@ -1361,8 +1388,7 @@ function UselessFilter() {
|
||||
}
|
||||
|
||||
// filter by regions
|
||||
function RegionFilter(regions) {
|
||||
if (!(regions instanceof Array)) regions = [regions];
|
||||
function RegionFilter(...regions) {
|
||||
const REGION_MAP = {
|
||||
"HK": "🇭🇰",
|
||||
"TW": "🇹🇼",
|
||||
@ -1385,8 +1411,7 @@ function RegionFilter(regions) {
|
||||
}
|
||||
|
||||
// filter by regex
|
||||
function RegexFilter(regex) {
|
||||
if (!(regex instanceof Array)) regex = [regex];
|
||||
function RegexFilter(...regex) {
|
||||
return {
|
||||
name: "Regex Filter",
|
||||
func: (proxies) => {
|
||||
@ -1395,8 +1420,7 @@ function RegexFilter(regex) {
|
||||
}
|
||||
}
|
||||
|
||||
function DiscardRegexFilter(regex) {
|
||||
if (!(regex instanceof Array)) regex = [regex];
|
||||
function DiscardRegexFilter(...regex) {
|
||||
return {
|
||||
name: "Discard Regex Filter",
|
||||
func: proxies => {
|
||||
@ -1407,8 +1431,7 @@ function DiscardRegexFilter(regex) {
|
||||
}
|
||||
|
||||
// filter by proxy types
|
||||
function TypeFilter(types) {
|
||||
if (!(types instanceof Array)) types = [types];
|
||||
function TypeFilter(...types) {
|
||||
return {
|
||||
name: "Type Filter",
|
||||
func: (proxies) => {
|
||||
@ -1579,7 +1602,7 @@ function getPlatformFromHeaders(headers) {
|
||||
} else if (UA.indexOf("Decar") !== -1) {
|
||||
return "Loon";
|
||||
} 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