mirror of
https://github.com/daydreamer-json/ak-endfield-api-archive.git
synced 2026-03-22 15:22:28 +01:00
feat: integrate game patch data processing
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import chalk from 'chalk';
|
||||
import CliTable3 from 'cli-table3';
|
||||
import { HTTPError } from 'ky';
|
||||
import { DateTime } from 'luxon';
|
||||
import prompts from 'prompts';
|
||||
import apiUtils from '../utils/api.js';
|
||||
import argvUtils from '../utils/argv.js';
|
||||
@@ -35,8 +36,10 @@ async function mainCmdHandler() {
|
||||
argvUtils.setArgv({ ...argvUtils.getArgv(), token: tokenUserRsp });
|
||||
}
|
||||
}
|
||||
logger.info('Authorization in progress ...');
|
||||
if (needRetrieveToken === false) {
|
||||
try {
|
||||
logger.debug('Retrieving account service OAuth 2.0 code ...');
|
||||
oauth2TokenPreRsp = await apiUtils.apiAkEndfield.accountService.user.oauth2.v2.grant(
|
||||
cfg.appCode.accountService.osWinRel,
|
||||
argvUtils.getArgv()['token'],
|
||||
@@ -82,7 +85,7 @@ async function mainCmdHandler() {
|
||||
argvUtils.setArgv({ ...argvUtils.getArgv(), password: pwdRsp });
|
||||
}
|
||||
})();
|
||||
logger.info('Retrieving account service token ...');
|
||||
logger.debug('Retrieving account service token ...');
|
||||
const accSrvTokenRsp = await apiUtils.apiAkEndfield.accountService.user.auth.v1.tokenByEmailPassword(
|
||||
argvUtils.getArgv()['email'],
|
||||
argvUtils.getArgv()['password'],
|
||||
@@ -90,37 +93,116 @@ async function mainCmdHandler() {
|
||||
argvUtils.setArgv({ ...argvUtils.getArgv(), token: accSrvTokenRsp.data.token });
|
||||
}
|
||||
|
||||
logger.info('Retrieving account service OAuth 2.0 token ...');
|
||||
const oauth2TokenRsp = await apiUtils.apiAkEndfield.accountService.user.oauth2.v2.grant(
|
||||
cfg.appCode.accountService.osWinRel,
|
||||
oauth2TokenPreRsp === null ? logger.debug('Retrieving account service OAuth 2.0 code ...') : undefined;
|
||||
const oauth2TokenRsp =
|
||||
oauth2TokenPreRsp === null
|
||||
? await apiUtils.apiAkEndfield.accountService.user.oauth2.v2.grant(
|
||||
cfg.appCode.accountService.osWinRel,
|
||||
argvUtils.getArgv()['token'],
|
||||
)
|
||||
: oauth2TokenPreRsp;
|
||||
const oauth2TokenBindRsp = await apiUtils.apiAkEndfield.accountService.user.oauth2.v2.grant(
|
||||
cfg.appCode.accountService.binding,
|
||||
argvUtils.getArgv()['token'],
|
||||
1,
|
||||
);
|
||||
logger.info('Retrieving u8 access token ...');
|
||||
logger.debug('Retrieving u8 access token ...');
|
||||
const u8TokenRsp = await apiUtils.apiAkEndfield.u8.user.auth.v2.tokenByChToken(
|
||||
cfg.appCode.u8.osWinRel,
|
||||
cfg.channel.osWinRel,
|
||||
oauth2TokenRsp.data.code,
|
||||
);
|
||||
// logger.debug('Retrieving u8 OAuth 2.0 code ...');
|
||||
// const u8OAuth2Rsp = await apiUtils.apiAkEndfield.u8.user.auth.v2.grant(u8TokenRsp.data.token);
|
||||
logger.info('Authentication successful!');
|
||||
|
||||
logger.info('Retrieving user account data ...');
|
||||
logger.info('Retrieving user information data ...');
|
||||
|
||||
logger.debug('Retrieving user account data ...');
|
||||
const userAccData = await apiUtils.apiAkEndfield.accountService.user.info.v1.basic(
|
||||
cfg.appCode.accountService.osWinRel,
|
||||
argvUtils.getArgv()['token'],
|
||||
);
|
||||
logger.info('Retrieving user game server data ...');
|
||||
logger.debug('Retrieving user game server data ...');
|
||||
const userGameData = await apiUtils.apiAkEndfield.u8.game.server.v1.serverList(u8TokenRsp.data.token);
|
||||
const userGameBindingData = await apiUtils.apiAkEndfield.binding.account.binding.v1.bindingList(
|
||||
oauth2TokenBindRsp.data.token,
|
||||
);
|
||||
|
||||
logger.debug('Retrieving gacha record ...');
|
||||
const selectedServerId = await (async () => {
|
||||
const selectedServerAccData = userGameBindingData.data.list
|
||||
.find((f) => f.appCode === 'endfield')!
|
||||
.bindingList[0]!.roles.filter((e) => e.isBanned === false)
|
||||
.sort((a, b) => b.level - a.level)[0];
|
||||
if (!selectedServerAccData) throw new Error('Game account not found');
|
||||
const id = selectedServerAccData.serverId;
|
||||
logger.debug('Confirming server availability ...');
|
||||
const confirmServerRsp = await apiUtils.apiAkEndfield.u8.game.role.v1.confirmServer(
|
||||
u8TokenRsp.data.token,
|
||||
parseInt(id),
|
||||
);
|
||||
if (confirmServerRsp.status !== 0)
|
||||
throw new Error('Game server availability error: ' + JSON.stringify(confirmServerRsp));
|
||||
return id;
|
||||
})();
|
||||
const gachaRecordRsp = await (async () => {
|
||||
const overallRsp = await (async () => {
|
||||
const poolTypeList = [
|
||||
'E_CharacterGachaPoolType_Standard',
|
||||
'E_CharacterGachaPoolType_Beginner',
|
||||
'E_CharacterGachaPoolType_Special',
|
||||
] as const;
|
||||
const recordArr = [];
|
||||
for (const poolTypeEntry of poolTypeList) {
|
||||
let seqId: string | null = null;
|
||||
while (true) {
|
||||
const rsp = await apiUtils.apiAkEndfield.webview.record.char(
|
||||
u8TokenRsp.data.token,
|
||||
parseInt(selectedServerId),
|
||||
poolTypeEntry,
|
||||
seqId,
|
||||
);
|
||||
recordArr.push(...rsp.data.list.map((e) => ({ poolType: poolTypeEntry, ...e })));
|
||||
logger.trace(`Loaded: ${poolTypeEntry}, ${recordArr.length} entries, hasMore=${rsp.data.hasMore}`);
|
||||
if (rsp.data.hasMore === false) break;
|
||||
if (!rsp.data.list.at(-1)) break;
|
||||
seqId = rsp.data.list.at(-1)!.seqId;
|
||||
}
|
||||
}
|
||||
return recordArr;
|
||||
})();
|
||||
return overallRsp.toReversed();
|
||||
})();
|
||||
const gachaPoolInfoList = await (async () => {
|
||||
logger.debug('Retrieving gacha pool info ...');
|
||||
const arr = [];
|
||||
const poolIdList = [...new Set(gachaRecordRsp.map((e) => e.poolId))];
|
||||
for (const poolId of poolIdList) {
|
||||
const rsp = await apiUtils.apiAkEndfield.webview.content(parseInt(selectedServerId), poolId, 'ja-jp');
|
||||
arr.push({ poolId, ...rsp.data.pool });
|
||||
}
|
||||
return arr;
|
||||
})();
|
||||
logger.info('Data retrieval completed!');
|
||||
|
||||
(() => {
|
||||
const table = new CliTable3(termPrettyUtils.cliTableConfig.rounded);
|
||||
table.push(
|
||||
// [{ colSpan: 2, hAlign: 'center', content: chalk.bold('Account Info') }],
|
||||
...[
|
||||
['Account ID', userAccData.data.hgId],
|
||||
['Hypergryph ID', userAccData.data.hgId],
|
||||
['OAuth Grant ID', oauth2TokenRsp.data.uid],
|
||||
['Game Overall UID', userGameBindingData.data.list.find((e) => e.appCode === 'endfield')!.bindingList[0]!.uid],
|
||||
['Email', userAccData.data.realEmail],
|
||||
['Nickname', userAccData.data.nickName === '' ? chalk.dim('(none)') : userAccData.data.nickName],
|
||||
['Age Region', userAccData.data.ageGate.regionInfo['en-us']],
|
||||
[
|
||||
'Registered',
|
||||
DateTime.fromSeconds(
|
||||
userGameBindingData.data.list.find((e) => e.appCode === 'endfield')!.bindingList[0]!.registerTs,
|
||||
).toFormat('yyyy/MM/dd HH:mm:ss'),
|
||||
],
|
||||
].map((e) => [chalk.dim(e[0]), e[1]]),
|
||||
);
|
||||
console.log(table.toString());
|
||||
@@ -147,17 +229,108 @@ async function mainCmdHandler() {
|
||||
const table = new CliTable3(termPrettyUtils.cliTableConfig.rounded);
|
||||
table.push(
|
||||
...[
|
||||
['ID', 'UID', 'Level', 'Default'].map((e) => chalk.dim(e)),
|
||||
['ID', 'UID', 'Lv', 'Found', 'Default', 'Nickname', 'Registered'].map((e) => chalk.dim(e)),
|
||||
...userGameData.data.serverList.map((e) => [
|
||||
e.serverId,
|
||||
e.roleId,
|
||||
{ hAlign: 'right' as const, content: e.level },
|
||||
Boolean(
|
||||
userGameBindingData.data.list
|
||||
.find((f) => f.appCode === 'endfield')!
|
||||
.bindingList[0]!.roles.find((f) => f.serverId === e.serverId),
|
||||
),
|
||||
e.defaultChoose,
|
||||
userGameBindingData.data.list
|
||||
.find((f) => f.appCode === 'endfield')!
|
||||
.bindingList[0]!.roles.find((f) => f.serverId === e.serverId)?.nickName,
|
||||
userGameBindingData.data.list
|
||||
.find((f) => f.appCode === 'endfield')!
|
||||
.bindingList[0]!.roles.find((f) => f.serverId === e.serverId)?.registerTs
|
||||
? DateTime.fromSeconds(
|
||||
userGameBindingData.data.list
|
||||
.find((f) => f.appCode === 'endfield')!
|
||||
.bindingList[0]!.roles.find((f) => f.serverId === e.serverId)?.registerTs!,
|
||||
).toFormat('yyyy/MM/dd HH:mm:ss')
|
||||
: '',
|
||||
]),
|
||||
],
|
||||
);
|
||||
console.log(table.toString());
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const table = new CliTable3(termPrettyUtils.cliTableConfig.rounded);
|
||||
table.push(
|
||||
...[
|
||||
['Pool ID', 'Pool Name', 'Pulls', '*6', '*5', '*4', 'Pity *6', '*5', 'Latest'].map((e) => chalk.dim(e)),
|
||||
...gachaPoolInfoList.map((e) => [
|
||||
e.poolId,
|
||||
e.pool_name,
|
||||
...[
|
||||
gachaRecordRsp.filter((f) => f.poolId === e.poolId).length,
|
||||
gachaRecordRsp.filter((f) => f.poolId === e.poolId && f.rarity === 6).length,
|
||||
gachaRecordRsp.filter((f) => f.poolId === e.poolId && f.rarity === 5).length,
|
||||
gachaRecordRsp.filter((f) => f.poolId === e.poolId && f.rarity === 4).length,
|
||||
(() => {
|
||||
let counter = 0;
|
||||
for (const pullEntry of gachaRecordRsp.filter((f) => f.poolId === e.poolId).toReversed()) {
|
||||
if (pullEntry.rarity >= 6) break;
|
||||
counter++;
|
||||
}
|
||||
return String(counter);
|
||||
})(),
|
||||
(() => {
|
||||
let counter = 0;
|
||||
for (const pullEntry of gachaRecordRsp.filter((f) => f.poolId === e.poolId).toReversed()) {
|
||||
if (pullEntry.rarity >= 5) break;
|
||||
counter++;
|
||||
}
|
||||
return String(counter);
|
||||
})(),
|
||||
].map((f) => ({ hAlign: 'right' as const, content: f })),
|
||||
(() => {
|
||||
const latestRecord = gachaRecordRsp.filter((f) => f.poolId === e.poolId).at(-1)!;
|
||||
const color = latestRecord.rarity === 6 ? chalk.yellow : chalk.magenta;
|
||||
return color(`*${latestRecord.rarity} ${latestRecord.charName}`);
|
||||
})(),
|
||||
]),
|
||||
],
|
||||
);
|
||||
console.log(table.toString());
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const tableData: (string | number)[][] = [];
|
||||
tableData.push(['Pool ID', 'Pool Name', 'Pulled', 'Pity', 'Character'].map((e) => chalk.dim(e)));
|
||||
for (const [gachaPoolInfoIndex, gachaPoolInfoEntry] of Object.entries(gachaPoolInfoList)) {
|
||||
const records = gachaRecordRsp.filter((e) => e.poolId === gachaPoolInfoEntry.poolId);
|
||||
const tableSubData: typeof tableData = [];
|
||||
let pityR6: number = 0;
|
||||
let pityR5: number = 0;
|
||||
for (const record of records) {
|
||||
pityR6++;
|
||||
pityR5++;
|
||||
if (record.rarity >= 5) {
|
||||
tableSubData.push([
|
||||
gachaPoolInfoEntry.poolId,
|
||||
gachaPoolInfoEntry.pool_name,
|
||||
DateTime.fromMillis(parseInt(record.gachaTs)).toFormat('yyyy/MM/dd hh:mm:ss'),
|
||||
record.rarity === 6 ? pityR6 : pityR5,
|
||||
record.rarity === 6
|
||||
? chalk.yellow(`*${record.rarity} ${record.charName}`)
|
||||
: chalk.magenta(`*${record.rarity} ${record.charName}`),
|
||||
]);
|
||||
if (record.rarity === 6) pityR6 = 0;
|
||||
pityR5 = 0;
|
||||
}
|
||||
}
|
||||
tableData.push(...tableSubData.toReversed());
|
||||
if (parseInt(gachaPoolInfoIndex) < gachaPoolInfoList.length - 1) tableData.push(Array(4).fill(''));
|
||||
}
|
||||
const table = new CliTable3(termPrettyUtils.cliTableConfig.rounded);
|
||||
table.push(...tableData);
|
||||
console.log(table.toString());
|
||||
})();
|
||||
}
|
||||
|
||||
export default mainCmdHandler;
|
||||
|
||||
Reference in New Issue
Block a user