Add China Bilibili channel

This commit is contained in:
daydreamer-json
2026-02-24 18:23:02 +09:00
parent 3e16ae7986
commit 0932c7db19
23 changed files with 1434 additions and 27 deletions

View File

@@ -186,7 +186,7 @@ async function generateGameListMd(target: GameTarget) {
return (await Bun.file(localJsonPath).json()) as MirrorFileEntry[];
})();
mdTexts.push(`# Game Packages (${target.name})\n`);
mdTexts.push(`# Game Packages (${target.region === 'cn' ? 'China' : 'Global'}, ${target.name})\n`);
// TOC
for (const e of gameAllJson) {
@@ -251,7 +251,7 @@ async function generatePatchListMd(target: GameTarget) {
return (await Bun.file(localJsonPath).json()) as MirrorFileEntry[];
})();
mdTexts.push(`# Game Patch Packages (${target.name})\n`);
mdTexts.push(`# Game Patch Packages (${target.region === 'cn' ? 'China' : 'Global'}, ${target.name})\n`);
// TOC
for (const e of patchAllJson) {
@@ -322,7 +322,11 @@ async function generatePatchListMd(target: GameTarget) {
async function generateResourceListMd(gameTargets: GameTarget[]) {
const sanitizedGameTargets = [
...new Set(gameTargets.map((e) => JSON.stringify({ region: e.region, appCode: e.appCode, channel: e.channel }))),
...new Set(
gameTargets
.filter((e) => [appConfig.network.api.akEndfield.channel.cnWinRelBilibili].includes(e.channel) === false)
.map((e) => JSON.stringify({ region: e.region, appCode: e.appCode, channel: e.channel })),
),
].map((e) => JSON.parse(e)) as { region: 'os' | 'cn'; appCode: string; channel: number }[];
const platforms = ['Windows', 'Android', 'iOS', 'PlayStation'] as const;
@@ -612,7 +616,11 @@ async function fetchAndSaveLatestGameResources(gameTargets: GameTarget[]) {
const platforms = ['Windows', 'Android', 'iOS', 'PlayStation'] as const;
const sanitizedGameTargets = [
...new Set(gameTargets.map((e) => JSON.stringify({ region: e.region, appCode: e.appCode, channel: e.channel }))),
...new Set(
gameTargets
.filter((e) => [appConfig.network.api.akEndfield.channel.cnWinRelBilibili].includes(e.channel) === false)
.map((e) => JSON.stringify({ region: e.region, appCode: e.appCode, channel: e.channel })),
),
].map((e) => JSON.parse(e)) as { region: 'os' | 'cn'; appCode: string; channel: number }[];
const needDlRawFileBase: string[] = [];
@@ -683,7 +691,11 @@ async function fetchAndSaveAllGameResRawData(gameTargets: GameTarget[]) {
const platforms = ['Windows', 'Android', 'iOS', 'PlayStation'] as const;
const sanitizedGameTargets = [
...new Set(gameTargets.map((e) => JSON.stringify({ region: e.region, appCode: e.appCode, channel: e.channel }))),
...new Set(
gameTargets
.filter((e) => [appConfig.network.api.akEndfield.channel.cnWinRelBilibili].includes(e.channel) === false)
.map((e) => JSON.stringify({ region: e.region, appCode: e.appCode, channel: e.channel })),
),
].map((e) => JSON.parse(e)) as { region: 'os' | 'cn'; appCode: string; channel: number }[];
const queue = new PQueue({ concurrency: appConfig.threadCount.network });
const needDlRawFileBase: string[] = [];
@@ -822,6 +834,16 @@ async function mainCmdHandler() {
launcherSubChannel: cfg.subChannel.cnWinRel,
dirName: String(cfg.channel.cnWinRel),
},
{
name: 'Bilibili',
region: 'cn',
appCode: cfg.appCode.game.cnWinRel,
launcherAppCode: cfg.appCode.launcher.cnWinRel,
channel: cfg.channel.cnWinRelBilibili,
subChannel: cfg.subChannel.cnWinRelBilibili,
launcherSubChannel: cfg.subChannel.cnWinRelBilibili,
dirName: String(cfg.channel.cnWinRelBilibili),
},
];
const launcherTargets: LauncherTarget[] = [

View File

@@ -19,14 +19,14 @@ async function mainCmdHandler() {
if (!('token' in argvUtils.getArgv()) || !argvUtils.getArgv()['token']) {
const tokenUserRsp: string = await (async () => {
logger.warn('Gryphline account service token has not been specified. Requesting ...');
const onCancelFn = () => {
const onCancel = () => {
logger.error('Aborted');
exitUtils.exit(1, null, false);
};
return (
await prompts(
{ name: 'value', type: 'password', message: 'Enter Gryphline account service token' },
{ onCancel: onCancelFn },
{ onCancel },
)
).value;
})();
@@ -53,8 +53,8 @@ async function mainCmdHandler() {
}
}
if (needRetrieveToken) {
await (async () => {
const onCancelFn = () => {
{
const onCancel = () => {
logger.error('Aborted');
exitUtils.exit(1, null, false);
};
@@ -66,7 +66,7 @@ async function mainCmdHandler() {
...{ name: 'value', type: 'text', message: 'Enter Gryphline account email' },
validate: (value) => (Boolean(value) ? true : 'Invalid value'),
},
{ onCancel: onCancelFn },
{ onCancel },
)
).value;
argvUtils.setArgv({ ...argvUtils.getArgv(), email: emailRsp });
@@ -79,12 +79,12 @@ async function mainCmdHandler() {
...{ name: 'value', type: 'password', message: 'Enter Gryphline account password' },
validate: (value) => (Boolean(value) ? true : 'Invalid value'),
},
{ onCancel: onCancelFn },
{ onCancel },
)
).value;
argvUtils.setArgv({ ...argvUtils.getArgv(), password: pwdRsp });
}
})();
}
logger.debug('Retrieving account service token ...');
const accSrvTokenRsp = await apiUtils.akEndfield.accountService.user.auth.v1.tokenByEmailPassword(
argvUtils.getArgv()['email'],
@@ -101,6 +101,11 @@ async function mainCmdHandler() {
argvUtils.getArgv()['token'],
)
: oauth2TokenPreRsp;
const oauth2TokenSkportRsp = await apiUtils.akEndfield.accountService.user.oauth2.v2.grant(
cfg.appCode.accountService.skport,
argvUtils.getArgv()['token'],
0,
);
const oauth2TokenBindRsp = await apiUtils.akEndfield.accountService.user.oauth2.v2.grant(
cfg.appCode.accountService.binding,
argvUtils.getArgv()['token'],
@@ -112,8 +117,13 @@ async function mainCmdHandler() {
cfg.channel.osWinRel,
oauth2TokenRsp.data.code,
);
logger.debug('Retrieving SKPort credential ...');
const skPortCredRsp = await apiUtils.akEndfield.zonai.web.v1.user.auth.generateCredByCode(
oauth2TokenSkportRsp.data.code,
1,
);
// logger.debug('Retrieving u8 OAuth 2.0 code ...');
// const u8OAuth2Rsp = await apiUtils.apiAkEndfield.u8.user.auth.v2.grant(u8TokenRsp.data.token);
// const u8OAuth2Rsp = await apiUtils.akEndfield.u8.user.auth.v2.grant(u8TokenRsp.data.token);
logger.info('Authentication successful!');
logger.info('Retrieving user information data ...');
@@ -129,6 +139,46 @@ async function mainCmdHandler() {
oauth2TokenBindRsp.data.token,
);
logger.debug('Retrieving SKPort binding data ...');
const skPortBindingRsp = await apiUtils.akEndfield.zonai.api.v1.game.player.binding(
skPortCredRsp.data.cred,
skPortCredRsp.data.token,
);
const skPortGameRoleStr = (() => {
const game = skPortBindingRsp.data.list.find((e) => e.appCode === 'endfield');
if (!game) throw new Error('SKPort game id not found for endfield');
return `${game.bindingList[0]?.gameId}_${game.bindingList[0]?.defaultRole.roleId}_${game.bindingList[0]?.defaultRole.serverId}`;
})();
logger.debug('Trying SKPort attendance ...');
await apiUtils.akEndfield.zonai.web.v1.game.endfield.attendance.record(
skPortCredRsp.data.cred,
skPortCredRsp.data.token,
skPortGameRoleStr,
);
const attendanceRsp = await apiUtils.akEndfield.zonai.web.v1.game.endfield.attendance.get(
skPortCredRsp.data.cred,
skPortCredRsp.data.token,
skPortGameRoleStr,
);
logger.debug(
'SKPort attendance status: ' + (attendanceRsp.data.hasToday ? chalk.red('Not complete') : chalk.green('Done')),
);
logger.debug('Testing redeem code flow ...');
const redeemRsp = await (async () => {
const game = skPortBindingRsp.data.list.find((e) => e.appCode === 'endfield');
if (!game || !game.bindingList[0]) throw new Error('SKPort game id not found for endfield');
return await apiUtils.akEndfield.gameHub.giftcode.redeem(
appConfig.network.api.akEndfield.channel.osWinRel,
parseInt(game.bindingList[0].defaultRole.serverId),
'Windows',
'RETURNOFALL',
u8TokenRsp.data.token,
);
})();
logger.debug(`Redeem result: ${JSON.stringify(redeemRsp)}`);
logger.debug('Retrieving gacha record ...');
const selectedServerId = await (async () => {
const selectedServerAccData = userGameBindingData.data.list