diff --git a/src/api/splatnet3-types.ts b/src/api/splatnet3-types.ts index db29234..37a7da8 100644 --- a/src/api/splatnet3-types.ts +++ b/src/api/splatnet3-types.ts @@ -244,6 +244,51 @@ export interface CurrentFestResult { /** c1553ac75de0a3ea497cdbafaa93e95b BankaraBattleHistoriesQuery */ export type BankaraBattleHistoriesResult = unknown; +/** 817618ce39bcf5570f52a97d73301b30 CoopHistoryQuery */ +export interface CoopHistoryResult { + coopResult: { + historyGroups: { + nodes: CoopHistoryGroup[]; + }; + historyGroupsOnlyFirst: unknown; + monthlyGear: unknown; + pointCard: unknown; + regularAverageClearWave: unknown; + regularGrade: unknown; + regularGradePoint: unknown; + scale: unknown; + } +} +interface CoopHistoryGroup { + historyDetails: { + nodes: CoopHistoryDetail[]; + }; +} +interface CoopHistoryDetail { + afterGrade: unknown; + afterGradePoint: unknown; + bossResult: unknown; + coopStage: unknown; + gradePointDiff: unknown; + id: string; + memberResults: unknown; + myResult: unknown; + nextHistoryDetail: { + id: string; + } | null; + previousHistoryDetail: { + id: string; + } | null; + resultWave: unknown; + waveResults: unknown; + weapons: unknown; +} + +/** f3799a033f0a7ad4b1b396f9a3bafb1e CoopHistoryDetailQuery */ +export interface CoopHistoryDetailResult { + coopHistoryDetail: unknown; +} + /** 7d8b560e31617e981cf7c8aa1ca13a00 LatestBattleHistoriesQuery */ export interface LatestBattleHistoriesResult { latestBattleHistories: { diff --git a/src/api/splatnet3.ts b/src/api/splatnet3.ts index 26c2f1b..cbda764 100644 --- a/src/api/splatnet3.ts +++ b/src/api/splatnet3.ts @@ -5,7 +5,7 @@ import { NintendoAccountUser } from './na.js'; import { defineResponse, ErrorResponse } from './util.js'; import CoralApi from './coral.js'; import { timeoutSignal } from '../util/misc.js'; -import { BankaraBattleHistoriesResult, BattleHistoryCurrentPlayerResult, BulletToken, CurrentFestResult, FriendListResult, GraphQLRequest, GraphQLResponse, HistoryRecordResult, HomeResult, LatestBattleHistoriesResult, PrivateBattleHistoriesResult, RegularBattleHistoriesResult, RequestId, SettingResult, StageScheduleResult, VsHistoryDetailResult } from './splatnet3-types.js'; +import { BankaraBattleHistoriesResult, BattleHistoryCurrentPlayerResult, BulletToken, CurrentFestResult, FriendListResult, GraphQLRequest, GraphQLResponse, HistoryRecordResult, HomeResult, LatestBattleHistoriesResult, PrivateBattleHistoriesResult, RegularBattleHistoriesResult, RequestId, SettingResult, StageScheduleResult, VsHistoryDetailResult, CoopHistoryResult, CoopHistoryDetailResult } from './splatnet3-types.js'; const debug = createDebug('nxapi:api:splatnet3'); @@ -143,7 +143,13 @@ export default class SplatNet3Api { } async getCoopHistory() { - return this.persistedQuery(RequestId.CoopHistoryQuery, {}); + return this.persistedQuery(RequestId.CoopHistoryQuery, {}); + } + + async getCoopHistoryDetail(id: string) { + return this.persistedQuery(RequestId.CoopHistoryDetailQuery, { + coopHistoryDetailId: id + }); } static async createWithCoral(nso: CoralApi, user: NintendoAccountUser) { diff --git a/src/cli/splatnet3/dump-results.ts b/src/cli/splatnet3/dump-results.ts index 2f5a9e6..e3bbb38 100644 --- a/src/cli/splatnet3/dump-results.ts +++ b/src/cli/splatnet3/dump-results.ts @@ -28,7 +28,7 @@ export function builder(yargs: Argv) { type: 'boolean', default: true, }).option('coop', { - describe: 'Include coop (Salmon Run) results', + describe: 'Include coop (salmon run) results', type: 'boolean', default: true, }); @@ -51,9 +51,9 @@ export async function handler(argv: ArgumentsCamelCase) { if (argv.battles) { await dumpResults(splatnet, directory); } - // if (argv.coop) { - // await dumpCoopResults(splatnet, directory); - // } + if (argv.coop) { + await dumpCoopResults(splatnet, directory); + } } export async function dumpResults( @@ -97,3 +97,37 @@ export async function dumpResults( else debug('Skipped %d battle results, files already exist', skipped.length); } } + +export async function dumpCoopResults(splatnet: SplatNet3Api, directory: string) { + debug('Fetching coop results'); + const results = await splatnet.getCoopHistory(); + + const skipped = []; + + // Reverse coop history order so oldest records are downloaded first + for (const group of results.data.coopResult.historyGroups.nodes.reverse()) { + for (const item of group.historyDetails.nodes.reverse()) { + const id_str = Buffer.from(item.id, 'base64').toString() || item.id; + + const filename = 'splatnet3-coopHistory-' + id_str + '.json'; + const file = path.join(directory, filename); + + try { + await fs.stat(file); + skipped.push(item.id); + } catch (err) { + debug('Fetching co-op history %s', id_str); + const result = await splatnet.getCoopHistoryDetail(item.id); + + debug('Writing %s', filename); + await fs.writeFile(file, JSON.stringify({ + result: result.data.coopHistoryDetail, + }, null, 4) + '\n', 'utf-8'); + } + } + } + + if (skipped.length) { + debug('Skipped %d co-op history, files already exist', skipped.length); + } +}