Skip to content

Commit

Permalink
Feat: support Clash Meta mrs format
Browse files Browse the repository at this point in the history
  • Loading branch information
SukkaW committed Aug 6, 2024
1 parent 03f1a00 commit 32c35a2
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 10 deletions.
3 changes: 2 additions & 1 deletion Build/build-apple-cdn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ export const buildAppleCdn = task(require.main === module, __filename)(async (sp
domainset,
'domainset',
path.resolve(__dirname, '../List/domainset/apple_cdn.conf'),
path.resolve(__dirname, '../Clash/domainset/apple_cdn.txt')
path.resolve(__dirname, '../Clash/domainset/apple_cdn.txt'),
path.resolve(__dirname, '../Clash/clash_mrs_domain/apple_cdn.mrs')
)
]);
});
6 changes: 4 additions & 2 deletions Build/build-cdn-download-conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ export const buildCdnDownloadConf = task(require.main === module, __filename)(as
sortDomains(domainDeduper(cdnDomainsList)),
'domainset',
path.resolve(__dirname, '../List/domainset/cdn.conf'),
path.resolve(__dirname, '../Clash/domainset/cdn.txt')
path.resolve(__dirname, '../Clash/domainset/cdn.txt'),
path.resolve(__dirname, '../Clash/clash_mrs_domain/cdn.mrs')
),
createRuleset(
span,
Expand All @@ -92,7 +93,8 @@ export const buildCdnDownloadConf = task(require.main === module, __filename)(as
sortDomains(domainDeduper(downloadDomainSet)),
'domainset',
path.resolve(__dirname, '../List/domainset/download.conf'),
path.resolve(__dirname, '../Clash/domainset/download.txt')
path.resolve(__dirname, '../Clash/domainset/download.txt'),
path.resolve(__dirname, '../Clash/clash_mrs_domain/download.mrs')
)
]);
});
4 changes: 3 additions & 1 deletion Build/build-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ function transformDomainset(parentSpan: Span, sourcePath: string, relativePath:
description = SHARED_DESCRIPTION;
}

const clashFileBasename = relativePath.slice(0, -path.extname(relativePath).length);

return createRuleset(
span,
title,
Expand All @@ -135,7 +137,7 @@ function transformDomainset(parentSpan: Span, sourcePath: string, relativePath:
deduped,
'domainset',
path.resolve(outputSurgeDir, relativePath),
path.resolve(outputClashDir, `${relativePath.slice(0, -path.extname(relativePath).length)}.txt`)
path.resolve(outputClashDir, `${clashFileBasename}.txt`)
);
}
);
Expand Down
6 changes: 4 additions & 2 deletions Build/build-reject-domainset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ export const buildRejectDomainSet = task(require.main === module, __filename)(as
span.traceChildSync('sort reject domainset (base)', () => sortDomains(dudupedDominArray, domainArrayMainDomainMap, domainArraySubdomainMap)),
'domainset',
path.resolve(__dirname, '../List/domainset/reject.conf'),
path.resolve(__dirname, '../Clash/domainset/reject.txt')
path.resolve(__dirname, '../Clash/domainset/reject.txt'),
path.resolve(__dirname, '../Clash/clash_mrs_domain/reject.mrs')
),
createRuleset(
span,
Expand All @@ -211,7 +212,8 @@ export const buildRejectDomainSet = task(require.main === module, __filename)(as
span.traceChildSync('sort reject domainset (extra)', () => sortDomains(dudupedDominArrayExtra, domainArrayMainDomainMap, domainArraySubdomainMap)),
'domainset',
path.resolve(__dirname, '../List/domainset/reject_extra.conf'),
path.resolve(__dirname, '../Clash/domainset/reject_extra.txt')
path.resolve(__dirname, '../Clash/domainset/reject_extra.txt'),
path.resolve(__dirname, '../Clash/clash_mrs_domain/reject_extra.mrs')
),
compareAndWriteFile(
span,
Expand Down
3 changes: 2 additions & 1 deletion Build/build-speedtest-domainset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ export const buildSpeedtestDomainSet = task(require.main === module, __filename)
deduped,
'domainset',
path.resolve(__dirname, '../List/domainset/speedtest.conf'),
path.resolve(__dirname, '../Clash/domainset/speedtest.txt')
path.resolve(__dirname, '../Clash/domainset/speedtest.txt'),
path.resolve(__dirname, '../Clash/clash_mrs_domain/speedtest.mrs')
);
});
57 changes: 57 additions & 0 deletions Build/lib/convert-clash-meta-mrs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import path from 'path';
import fs from 'fs';
import fsp from 'fs/promises';
import { Readable } from 'stream';
import { pipeline } from 'stream/promises';
import zlib from 'zlib';
import { async as ezspawn } from '@jsdevtools/ez-spawn';

const mihomoBinaryDir = path.join(__dirname, '../../node_modules/.cache/mihomo');
const mihomoBinaryPath = path.join(mihomoBinaryDir, 'mihomo');

const mihomoBinaryUrl: Partial<Record<NodeJS.Platform, Partial<Record<NodeJS.Architecture, string>>>> = {
linux: {
x64: 'https://github.com/MetaCubeX/mihomo/releases/download/v1.18.7/mihomo-linux-amd64-compatible-v1.18.7.gz'
},
darwin: {
x64: 'https://github.com/MetaCubeX/mihomo/releases/download/v1.18.7/mihomo-darwin-amd64-v1.18.7.gz',
arm64: 'https://github.com/MetaCubeX/mihomo/releases/download/v1.18.7/mihomo-darwin-arm64-v1.18.7.gz'
}
};

const ensureMihomoBinary = async () => {
await fsp.mkdir(mihomoBinaryDir, { recursive: true });
if (!fs.existsSync(mihomoBinaryPath)) {
const writeStream = fs.createWriteStream(mihomoBinaryPath);

const downloadUrl = mihomoBinaryUrl[process.platform]?.[process.arch];
if (!downloadUrl) {
throw new Error(`Unsupported platform: ${process.platform} ${process.arch}`);
}

const res = await fetch(downloadUrl);

if (!res.ok || !res.body) {
throw new Error(`Failed to download mihomo binary: ${res.statusText}`);
}

const gunzip = zlib.createGunzip();

await pipeline(
Readable.fromWeb(res.body),
gunzip,
writeStream
);
}
await fsp.chmod(mihomoBinaryPath, 0o755);
};

export const convertClashMetaMrs = async (type: 'domain', format: 'text', input: string, output: string) => {
await ensureMihomoBinary();

const { stderr } = await ezspawn(mihomoBinaryPath, ['convert-ruleset', type, format, input, output]);

if (stderr) {
throw new Error(stderr);
}
};
20 changes: 17 additions & 3 deletions Build/lib/create-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import path from 'path';
import fs from 'fs';
import { fastStringArrayJoin, writeFile } from './misc';
import { readFileByLine } from './fetch-text-by-line';
import { convertClashMetaMrs } from './convert-clash-meta-mrs';

export async function compareAndWriteFile(span: Span, linesA: string[], filePath: string) {
let isEqual = true;
Expand Down Expand Up @@ -151,8 +152,10 @@ const MARK = 'this_ruleset_is_made_by_sukkaw.ruleset.skk.moe';
export const createRuleset = (
parentSpan: Span,
title: string, description: string[] | readonly string[], date: Date, content: string[],
type: ('ruleset' | 'domainset' | string & {}), surgePath: string, clashPath: string
) => parentSpan.traceChild(`create ruleset: ${path.basename(surgePath, path.extname(surgePath))}`).traceAsyncFn((childSpan) => {
type: ('ruleset' | 'domainset' | string & {}),
surgePath: string, clashPath: string,
clashMrsPath?: string
) => parentSpan.traceChild(`create ruleset: ${path.basename(surgePath, path.extname(surgePath))}`).traceAsyncFn(async (childSpan) => {
const surgeContent = withBannerArray(
title, description, date,
sortRuleSet(type === 'domainset'
Expand All @@ -174,8 +177,19 @@ export const createRuleset = (
return withBannerArray(title, description, date, _clashContent);
});

return Promise.all([
await Promise.all([
compareAndWriteFile(childSpan, surgeContent, surgePath),
compareAndWriteFile(childSpan, clashContent, clashPath)
]);

if (clashMrsPath) {
if (type === 'domainset') {
await childSpan.traceChildAsync('clash meta mrs domain ' + clashMrsPath, async () => {
await fs.promises.mkdir(path.dirname(clashMrsPath), { recursive: true });
await convertClashMetaMrs(
'domain', 'text', clashPath, clashMrsPath
);
});
}
}
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"license": "ISC",
"dependencies": {
"@cliqz/adblocker": "^1.31.1",
"@jsdevtools/ez-spawn": "^3.0.4",
"async-retry": "^1.3.3",
"async-sema": "^3.1.1",
"better-sqlite3": "^11.1.2",
Expand Down
25 changes: 25 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 32c35a2

Please sign in to comment.