Refactoring

This commit is contained in:
daydreamer-json
2026-01-22 21:03:44 +09:00
parent 24c78b048f
commit 070627b522
2 changed files with 101 additions and 129 deletions

View File

@@ -2,7 +2,7 @@
Monitor changes to responses from various Arknights Endfield APIs and record them in this repository. Monitor changes to responses from various Arknights Endfield APIs and record them in this repository.
Updates are checked hourly and automatically pushed via GitHub Actions. Updates are checked about every 30 minutes and automatically pushed to GitHub Actions.
API outputs are stored in the [`output`](/output/) directory. API outputs are stored in the [`output`](/output/) directory.
The APIs currently being monitored are as follows: The APIs currently being monitored are as follows:

View File

@@ -7,24 +7,76 @@ import appConfig from '../utils/config.js';
import logger from '../utils/logger.js'; import logger from '../utils/logger.js';
import mathUtils from '../utils/math.js'; import mathUtils from '../utils/math.js';
function getObjectDiff(obj1: any, obj2: any) {
const diff: any = {};
const keys = new Set([...Object.keys(obj1 || {}), ...Object.keys(obj2 || {})]);
for (const key of keys) {
const val1 = obj1?.[key];
const val2 = obj2?.[key];
if (JSON.stringify(val1) !== JSON.stringify(val2)) {
if (typeof val1 === 'object' && val1 !== null && typeof val2 === 'object' && val2 !== null) {
const nestedDiff = getObjectDiff(val1, val2);
if (Object.keys(nestedDiff).length > 0) {
diff[key] = nestedDiff;
}
} else {
diff[key] = { old: val1, new: val2 };
}
}
}
return diff;
}
async function saveResult(
subPaths: string[],
version: string,
data: { req: any; rsp: any },
saveLatest: boolean = true,
) {
const outputDir = argvUtils.getArgv()['outputDir'];
const filePathBase = path.join(outputDir, ...subPaths);
const filesToCheck = [path.join(filePathBase, `v${version}.json`)];
if (saveLatest) {
filesToCheck.push(path.join(filePathBase, 'latest.json'));
}
const dataStr = JSON.stringify(data, null, 2);
const dataMinified = JSON.stringify(data);
for (const filePath of filesToCheck) {
const file = Bun.file(filePath);
const exists = await file.exists();
let currentData: any = null;
if (exists) {
currentData = await file.json();
}
if (!exists || JSON.stringify(currentData) !== dataMinified) {
if (exists) {
logger.trace(`Diff detected in ${filePath}:`, JSON.stringify(getObjectDiff(currentData, data), null, 2));
}
await Bun.write(filePath, dataStr);
}
}
const allFilePath = path.join(filePathBase, 'all.json');
const allFile = Bun.file(allFilePath);
let allData: any[] = [];
if (await allFile.exists()) {
allData = await allFile.json();
}
const exists = allData.some((e: any) => JSON.stringify({ req: e.req, rsp: e.rsp }) === dataMinified);
if (!exists) {
allData.push({ updatedAt: DateTime.now().toISO(), ...data });
await Bun.write(allFilePath, JSON.stringify(allData, null, 2));
}
}
async function mainCmdHandler() { async function mainCmdHandler() {
const cfg = appConfig.network.api.akEndfield; const cfg = appConfig.network.api.akEndfield;
const channelStr = String(cfg.channel.osWinRel);
// await (async () => {
// const channel = appConfig.network.api.akEndfield.channel.osWinRel;
// logger.debug('apiAkEndfield.launcher.web fetching ...');
// for (const fn of [
// apiUtils.apiAkEndfield.launcher.web.sidebar,
// apiUtils.apiAkEndfield.launcher.web.singleEnt,
// apiUtils.apiAkEndfield.launcher.web.mainBgImage,
// apiUtils.apiAkEndfield.launcher.web.banner,
// apiUtils.apiAkEndfield.launcher.web.announcement,
// ]) {
// console.dir(await fn(appConfig.network.api.akEndfield.appCode.osWinRel, channel, channel, 'ja-jp'), {
// depth: null,
// });
// }
// })();
await (async () => { await (async () => {
logger.debug('Fetching latestGame ...'); logger.debug('Fetching latestGame ...');
@@ -59,54 +111,31 @@ async function mainCmdHandler() {
}, },
rsp, rsp,
}; };
const filePathBase = path.join(
argvUtils.getArgv()['outputDir'], await saveResult(['akEndfield', 'launcher', 'game', channelStr], rsp.version, prettyRsp);
'akEndfield',
'launcher',
'game',
String(cfg.channel.osWinRel),
);
for (const filePath of [path.join(filePathBase, 'latest.json'), path.join(filePathBase, `v${rsp.version}.json`)]) {
if (
(await Bun.file(filePath).exists()) === false ||
JSON.stringify(await Bun.file(filePath).json()) !== JSON.stringify(prettyRsp)
) {
await Bun.write(filePath, JSON.stringify(prettyRsp, null, 2));
}
}
await (async () => {
let needWrite: boolean = true;
const tmp: ({ updatedAt: string } & typeof prettyRsp)[] = await Bun.file(
path.join(filePathBase, 'all.json'),
).json();
for (const dataStr of tmp.map((e) => JSON.stringify({ req: e.req, rsp: e.rsp }))) {
if (dataStr === JSON.stringify(prettyRsp)) {
needWrite = false;
}
}
if (needWrite) {
tmp.push({ updatedAt: DateTime.now().toISO(), ...prettyRsp });
await Bun.write(path.join(filePathBase, 'all.json'), JSON.stringify(tmp, null, 2));
}
})();
})(); })();
await (async () => { await (async () => {
logger.debug('Fetching latestGameRes ...'); logger.debug('Fetching latestGameRes ...');
const gameAllJsonPath = path.join(
argvUtils.getArgv()['outputDir'],
'akEndfield',
'launcher',
'game',
channelStr,
'all.json',
);
if (!(await Bun.file(gameAllJsonPath).exists())) {
logger.warn('Skipping latestGameRes: game/all.json not found');
return;
}
const versionInfoList = ( const versionInfoList = (
( (await Bun.file(gameAllJsonPath).json()).map((e: any) => e.rsp) as Awaited<
await Bun.file( ReturnType<typeof apiUtils.apiAkEndfield.launcher.latestGame>
path.join( >[]
argvUtils.getArgv()['outputDir'],
'akEndfield',
'launcher',
'game',
String(cfg.channel.osWinRel),
'all.json',
),
).json()
).map((e: any) => e.rsp) as Awaited<ReturnType<typeof apiUtils.apiAkEndfield.launcher.latestGame>>[]
) )
.map((e) => ({ .map((e) => ({
version: e.version, version: e.version,
@@ -114,13 +143,6 @@ async function mainCmdHandler() {
randStr: /_([^/]+)\/.+?$/.exec(e.pkg.file_path)![1], randStr: /_([^/]+)\/.+?$/.exec(e.pkg.file_path)![1],
})) }))
.sort((a, b) => semver.compare(b.version, a.version)); .sort((a, b) => semver.compare(b.version, a.version));
const filePathBase = path.join(
argvUtils.getArgv()['outputDir'],
'akEndfield',
'launcher',
'game_resources',
String(cfg.channel.osWinRel),
);
let isLatestWrote: boolean = false; let isLatestWrote: boolean = false;
for (const versionInfoEntry of versionInfoList) { for (const versionInfoEntry of versionInfoList) {
if (!versionInfoEntry.randStr) throw new Error('version rand_str not found'); if (!versionInfoEntry.randStr) throw new Error('version rand_str not found');
@@ -140,36 +162,14 @@ async function mainCmdHandler() {
}, },
rsp, rsp,
}; };
if (isLatestWrote === false) {
if ( await saveResult(
(await Bun.file(path.join(filePathBase, 'latest.json')).exists()) === false || ['akEndfield', 'launcher', 'game_resources', channelStr],
JSON.stringify(await Bun.file(path.join(filePathBase, 'latest.json')).json()) !== JSON.stringify(prettyRsp) versionInfoEntry.version,
) { prettyRsp,
await Bun.write(path.join(filePathBase, 'latest.json'), JSON.stringify(prettyRsp, null, 2)); !isLatestWrote,
} );
isLatestWrote = true; isLatestWrote = true;
}
for (const filePath of [path.join(filePathBase, `v${versionInfoEntry.version}.json`)]) {
if (
(await Bun.file(filePath).exists()) === false ||
JSON.stringify(await Bun.file(filePath).json()) !== JSON.stringify(prettyRsp)
) {
await Bun.write(filePath, JSON.stringify(prettyRsp, null, 2));
}
}
await (async () => {
let needWrite: boolean = true;
const tmp: ({ updatedAt: string } & typeof prettyRsp)[] = await Bun.file(
path.join(filePathBase, 'all.json'),
).json();
for (const dataStr of tmp.map((e) => JSON.stringify({ req: e.req, rsp: e.rsp }))) {
if (dataStr === JSON.stringify(prettyRsp)) needWrite = false;
}
if (needWrite) {
tmp.push({ updatedAt: DateTime.now().toISO(), ...prettyRsp });
await Bun.write(path.join(filePathBase, 'all.json'), JSON.stringify(tmp, null, 2));
}
})();
} }
})(); })();
@@ -194,40 +194,12 @@ async function mainCmdHandler() {
}, },
rsp, rsp,
}; };
const filePathBase = path.join(
argvUtils.getArgv()['outputDir'], await saveResult(
'akEndfield', ['akEndfield', 'launcher', 'launcher', launcherTargetAppEntry, channelStr],
'launcher', rsp.version,
'launcher', prettyRsp,
launcherTargetAppEntry,
String(cfg.channel.osWinRel),
); );
for (const filePath of [
path.join(filePathBase, 'latest.json'),
path.join(filePathBase, `v${rsp.version}.json`),
]) {
if (
(await Bun.file(filePath).exists()) === false ||
JSON.stringify(await Bun.file(filePath).json()) !== JSON.stringify(prettyRsp)
) {
await Bun.write(filePath, JSON.stringify(prettyRsp, null, 2));
}
}
await (async () => {
let needWrite: boolean = true;
const tmp: ({ updatedAt: string } & typeof prettyRsp)[] = await Bun.file(
path.join(filePathBase, 'all.json'),
).json();
for (const dataStr of tmp.map((e) => JSON.stringify({ req: e.req, rsp: e.rsp }))) {
if (dataStr === JSON.stringify(prettyRsp)) {
needWrite = false;
}
}
if (needWrite) {
tmp.push({ updatedAt: DateTime.now().toISO(), ...prettyRsp });
await Bun.write(path.join(filePathBase, 'all.json'), JSON.stringify(tmp, null, 2));
}
})();
} }
})(); })();
} }