Skip to content

戦績 API 直叩き(ブラウザレス取得)

最終更新: 2026-06-13

戦績データ(battle_list / battle_detail / season 系)を Playwright のページ駆動なしに HTTP で直接取得する仕組みの設計ドキュメント。ログインは引き続きブラウザで行い、取得だけをブラウザレス化する「ハイブリッド方式」。

関連: Browser Automation Data(従来のページ駆動・傍受方式) / Electron Main


1. 背景:なぜ直叩きするか

従来は SPA(xzysteam.shengtiangames.com/gamerecords)をブラウザで開き、SPA が投げる API レスポンスを page.on('response')傍受していた。試合終了のたびにブラウザを駆動するため重く・不安定だった。

裏 API は token ヘッダ 1 本のみ(Cookie 不要・署名不要)で叩けることを実機検証済みのため、ログイン済みブラウザから抜いたトークンで直接 fetch すれば、取得ホットパスからブラウザを外せる。


2. API 仕様(実機検証 2026-06-12)

  • ホスト: https://xzy.shengtiangames.com/mini-game/xzy/battle-record/<endpoint>
    • SPA ホスト xzysteam.shengtiangames.com とは別ドメイン
  • 認証: HTTP ヘッダ token: <値> のみ
    • Cookie 不要・署名(signed)不要
    • ヘッダ名は厳密に tokenAuthorization / Bearer は不可)
  • 失効時: { code: 401, msg: "not login", data: "...未获取到token..." }

エンドポイント

エンドポイントクエリ用途
battle_listseason_code match_type time_start time_end page role_id戦績一覧(ページング)
battle_detail2v2id=<BattleId>試合詳細(Winner/Loser Details)
battle_seasonsummaryrole_id season_codeシーズンサマリー(T1/T2 スコア)
season_showseason_code role_idScoreMap / TopRoleList を含む詳細
season_list(なし)シーズン一覧(Code/StartTime/EndTime)

レスポンスは全て { code: 0, msg: "success", data: ... } 形式。battle_detail2v2data は従来の傍受方式と同一構造のため、既存の変換関数 battleDetailFromResponse がそのまま使える。


3. トークンの在り処と供給

トークンはログイン済みブラウザの localStorage(origin xzysteam.shengtiangames.com)の token キーに入る。role_id は同 localStorage の selected_role_id

Playwright の storageState.jsonorigins[].localStorage)にも保存されるため、ブラウザ未起動でもファイルから読める。

  • storageState 実パス: %APPDATA%/streaming-overlay-manager/browser-automation/storageState.json

CredentialResolver(live → file)

electron/services/battleRecordApi/credentialsProvider.ts

トークンは次の優先順で解決する:

  1. live: ブラウザ起動中なら BrowserAutomationService.getLiveCredentials()page.evaluate で最新の localStorage を読む(storageState の 60s 保存遅延を回避)
  2. file: 未起動なら readCredentialsFromFile(storageState.json)

BattleRecordApiClient は同期 getter を期待するため、IPC 呼び出しの先頭で refresh() を await してキャッシュし、以降は get() で同期参照する。


4. モジュール構成

electron/services/battleRecordApi/

ファイル役割
BattleRecordApiClient.ts各エンドポイントを token ヘッダ付きで叩く。fetchImpl 差し替えでテスト可能。401/not login は TokenExpiredError、その他非 0 は BattleRecordApiError
tokenStore.tsstorageState から token / role_id を抽出(extractCredentials 純関数 + readCredentialsFromFile
credentialsProvider.tsCredentialResolver(live→file 解決+キャッシュ)
seasonResolver.tsseason_list から現シーズン(Code/StartTime/EndTime)を動的解決(pickCurrentSeason 純関数 + キャッシュ付き SeasonResolver
seasonConverter.tsbattle_seasonsummary / season_showdata → DB 保存型の純変換
directWorkflows.ts取得ワークフロー本体(後述)
errors.tsTokenExpiredError / BattleRecordApiError
types.tsApiEnvelope / BattleRecordCredentials / BattleListParams

DB 保存(saveBattleListItems / saveBattleDetails / saveSeason*)・matchId 解決(findMatchBy*)・battleDetailFromResponse既存の DB / 変換関数を再利用する(ブラウザ非依存)。


5. ワークフロー(directWorkflows)

関数取得対象概要
directMatchEndWorkflowbattle_list(1p) → battle_detail2v2試合終了直後。最新試合の詳細を保存
directFullWorkflowbattle_list(全ページ) → battle_detail2v2ページ送りで全件取得。スクロール制御が不要に
directSeasonOnlybattle_seasonsummary + season_showシーズン統計のみ
directBattleListWithSeasonbattle_list(1p) + season軽量な一覧+シーズン

season_code / 取得期間の決定

battle_list 等は season_code と期間が必須。SeasonResolverseason_list API を権威として、現在時刻が属するシーズンの Code / StartTime / EndTime を動的に決める(ハードコードしない)。


6. IPC 配線(直叩き主・ブラウザ保険)

electron/ipc/BrowserAutomationHandlers.ts

4 つの workflow IPC(browser-automation-execute-match-end-workflow / -execute-full-workflow / -fetch-season-only / -fetch-battle-list-with-season)は次の方針で動く:

creds = await CredentialResolver.refresh()    // live→file
outcome = runDirectWorkflow(!!creds, 直叩き)
  ├─ login-required (creds 無 / TokenExpiredError)
  │     → handleLoginStatusUpdate({loggedIn:false})  // 再ログイン導線 + OS 通知
  ├─ ok        → 成功
  └─ fallback  → ブラウザ起動中のみ従来のページ駆動 workflow へ

runDirectWorkflow は実行結果を login-required / ok / fallback に分類する純粋ヘルパー(単体テスト可能)。

最大の利点: match-endブラウザ未起動でも storageState のトークンがあれば取得できる。

401 → 再ログイン導線

TokenExpiredErrorcode:401 / not login)を検知したら handleLoginStatusUpdate({ loggedIn:false }) を呼び、renderer の LoginRequiredDialog 表示+OS 通知でブラウザログインを促す。ログイン後は最新トークンが live/file から取得され、自動的に直叩きが復活する。


7. ビルド時の注意(重要)

electron メインのビルド後処理(scripts/build/build-electron.cjs の「require パス修正」)は、ディレクトリ barrel(index.ts)への import を解決できない

  • import { ... } from '../services/battleRecordApi'
    • bundle 後に require('../services/battleRecordApi.cjs') へ化け、起動時に Cannot find moduleウィンドウが開かず e2e スモークが落ちる(tsc / unit は通るので気付きにくい)
  • import { BattleRecordApiClient } from '../services/battleRecordApi/BattleRecordApiClient'
    • 個別ファイルから import する

barrel index.ts はテスト・型参照用に残すが、electron メインのランタイム import では使わないこと。


8. テスト

種別対象
UnittokenStore / BattleRecordApiClient(fetch モック)/ seasonResolver / seasonConverter / directWorkflows(DB モック)/ credentialsProvider / runDirectWorkflow
Integrationモック HTTP サーバ(directWorkflows.integration.test.ts)で「API → client → workflow」の結線(URL / token ヘッダ / パース)を検証
E2E スモークtests/e2e/scenarios/startup.e2e.ts が起動を担保(直叩き配線が dist 起動を壊さないこと)

UI 出力は不変(内部データ経路の置換)のため、専用の Playwright E2E は追加していない。


9. 今後(Phase F)

直叩きが安定稼働したら、従来のページ駆動 fetch を fallback 専用に縮退、api_responses 生保存の要否を再評価する。