Fetch ookla servers from speedtest-net-servers.cdn.skk.moe

This commit is contained in:
SukkaW
2025-02-08 22:04:48 +08:00
parent 4d99b9766e
commit b391de6521

View File

@@ -7,50 +7,35 @@ import { readFileIntoProcessedArray } from './lib/fetch-text-by-line';
import { DomainsetOutput } from './lib/rules/domainset'; import { DomainsetOutput } from './lib/rules/domainset';
import { OUTPUT_SURGE_DIR, SOURCE_DIR } from './constants/dir'; import { OUTPUT_SURGE_DIR, SOURCE_DIR } from './constants/dir';
import { newQueue } from '@henrygd/queue';
import { $$fetch } from './lib/fetch-retry'; import { $$fetch } from './lib/fetch-retry';
const KEYWORDS = [ interface SpeedTestServer {
'Hong Kong', url: string,
'Taiwan', lat: string,
'China Telecom', lon: string,
'China Mobile', distance: number,
'China Unicom', name: string,
'Japan', country: string,
'Tokyo', cc: string,
'Singapore', sponsor: string,
'Korea', id: string,
'Seoul', preferred: number,
'Canada', https_functional: number,
'Toronto', host: string
'Montreal', }
'Los Ang',
'San Jos',
'Seattle',
'New York',
'Dallas',
'Miami',
'Berlin',
'Frankfurt',
'London',
'Paris',
'Amsterdam',
'Moscow',
'Australia',
'Sydney',
'Brazil',
'Turkey'
];
const s = newQueue(2); const getSpeedtestHostsGroupsPromise = $$fetch('https://speedtest-net-servers.cdn.skk.moe/servers.json')
.then(res => res.json() as Promise<SpeedTestServer[]>)
.then((data) => data.reduce<string[]>((prev, cur) => {
const hn = tldts.getHostname(cur.host || cur.url, { detectIp: false, validateHostname: true });
if (hn) {
prev.push(hn);
}
return prev;
}, []));
const latestTopUserAgentsPromise = $$fetch('https://raw.githubusercontent.com/microlinkhq/top-user-agents/master/src/desktop.json') export const buildSpeedtestDomainSet = task(require.main === module, __filename)(
.then(res => res.json() as Promise<string[]>) async (span) => new DomainsetOutput(span, 'speedtest')
.then((userAgents: string[]) => userAgents.filter(ua => ua.startsWith('Mozilla/5.0 ')));
const getSpeedtestHostsGroupsPromise = Promise.all(KEYWORDS.flatMap(querySpeedtestApi));
export const buildSpeedtestDomainSet = task(require.main === module, __filename)(async (span) => {
const output = new DomainsetOutput(span, 'speedtest')
.withTitle('Sukka\'s Ruleset - Speedtest Domains') .withTitle('Sukka\'s Ruleset - Speedtest Domains')
.withDescription([ .withDescription([
...SHARED_DESCRIPTION, ...SHARED_DESCRIPTION,
@@ -58,55 +43,7 @@ export const buildSpeedtestDomainSet = task(require.main === module, __filename)
'This file contains common speedtest endpoints.' 'This file contains common speedtest endpoints.'
]) ])
.addFromDomainset(readFileIntoProcessedArray(path.resolve(SOURCE_DIR, 'domainset/speedtest.conf'))) .addFromDomainset(readFileIntoProcessedArray(path.resolve(SOURCE_DIR, 'domainset/speedtest.conf')))
.addFromDomainset(readFileIntoProcessedArray(path.resolve(OUTPUT_SURGE_DIR, 'domainset/speedtest.conf'))); .addFromDomainset(readFileIntoProcessedArray(path.resolve(OUTPUT_SURGE_DIR, 'domainset/speedtest.conf')))
.bulkAddDomain(await span.traceChildPromise('get speedtest hosts groups', getSpeedtestHostsGroupsPromise))
const hostnameGroup = await span.traceChildPromise('get speedtest hosts groups', getSpeedtestHostsGroupsPromise); .write()
hostnameGroup.forEach(output.bulkAddDomain.bind(output));
return output.write();
});
async function querySpeedtestApi(keyword: string) {
const topUserAgents = await latestTopUserAgentsPromise;
const url = `https://www.speedtest.net/api/js/servers?engine=js&search=${keyword}&limit=100`;
try {
const randomUserAgent = topUserAgents[Math.floor(Math.random() * topUserAgents.length)];
const data = await s.add<Array<{ url: string, host: string }>>(() => $$fetch(url, {
headers: {
dnt: '1',
Referer: 'https://www.speedtest.net/',
accept: 'application/json, text/plain, */*',
'User-Agent': randomUserAgent,
'Accept-Language': 'en-US,en;q=0.9',
...(randomUserAgent.includes('Chrome')
? {
'Sec-Ch-Ua-Mobile': '?0',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'Sec-Gpc': '1'
}
: {})
},
signal: AbortSignal.timeout(1000 * 60)
}).then(res => res.json() as any));
return data.reduce<string[]>(
(prev, cur) => {
const hn = tldts.getHostname(cur.host || cur.url, { detectIp: false, validateHostname: true });
if (hn) {
prev.push(hn);
}
return prev;
},
[]
); );
} catch (e) {
console.error(e);
return [];
}
}