Skip to content

ブラウザ自動化 取得データ・DB保存設計

最終更新: 2026-02-25


1. キャプチャ対象レスポンス

BrowserAutomationService は、起動中のページで発生する xhr / fetch レスポンスのうち以下の条件を満たすものを取得します。

  • HTTP ステータスが 200
  • リソースタイプが xhr または fetch
  • URL に以下のいずれかのキーワードを含む(CONFIG.targetApiKeywords
キーワードエンドポイント概要
battle_list戦績一覧
battle_detail試合詳細
battle_seasonsummaryシーズンサマリー統計
season_showシーズン詳細データ(ScoreMap含む)
login認証レスポンス

キャプチャデータ構造

ts
interface FetchResponseData {
  url: string;         // リクエストURL
  status: number;      // HTTPステータス
  body: string;        // レスポンス本文(text)
  timestamp: string;   // 取得時刻(ISO 8601)
  contentType: string; // Content-Type
}

2. ワークフロー別の取得フロー

2.1 試合終了ワークフロー(executeMatchEndWorkflow

試合完了を検知した際に自動実行。

取得対象: battle_listbattle_detail

battle_list 取得
  ↓ BattleId を抽出
battle_detail 取得(BattleId 単位)

DB 保存(saveBattleListItems + saveBattleDetails)

2.2 シーズン付き一覧取得(fetchBattleListWithSeason

取得対象: battle_list + battle_seasonsummary + season_show

battle_list 取得
battle_seasonsummary 取得  ← 並行
season_show 取得           ← 並行

DB 保存(saveBattleListItems + saveSeasonSummary + saveSeasonShow)

2.3 シーズンのみ取得(fetchSeasonOnly

取得対象: battle_seasonsummary + season_show

battle_seasonsummary 取得
season_show 取得

DB 保存(saveSeasonSummary + saveSeasonShow)

2.4 全試合取得(executeFullWorkflow

取得対象: battle_list + battle_detail(全件)+ battle_seasonsummary + season_show


3. API レスポンスの DB 保存設計

3.1 api_responses テーブル(生レスポンス保存)

全キャプチャレスポンスを saveApiResponse() で保存。

スキーマ:

sql
CREATE TABLE IF NOT EXISTS api_responses (
  id           INTEGER PRIMARY KEY AUTOINCREMENT,
  url          TEXT NOT NULL,
  status       INTEGER NOT NULL,
  content_type TEXT NOT NULL,
  timestamp    TEXT NOT NULL,
  endpoint     TEXT,               -- URLの最後のパスセグメント(例: "battle_list")
  body         TEXT NOT NULL,      -- レスポンス本文(生JSONテキスト)
  is_json      INTEGER NOT NULL DEFAULT 0,
  json_code    INTEGER,            -- レスポンスの .code フィールド
  json_msg     TEXT,               -- レスポンスの .msg フィールド
  created_at   TEXT DEFAULT CURRENT_TIMESTAMP
);

取得 API:

ts
db.getApiResponses({
  endpoint: 'battle_list',  // エンドポイントで絞り込み
  status: 200,              // ステータスで絞り込み
  uids: ['1046101022'],     // URLまたはbody内のUIDで絞り込み
  limit: 200,               // 件数制限(デフォルト200)
})

3.2 season_summaries テーブル

battle_seasonsummary のレスポンスをパースして保存。

スキーマ:

sql
CREATE TABLE IF NOT EXISTS season_summaries (
  id              INTEGER PRIMARY KEY AUTOINCREMENT,
  captured_at     TEXT NOT NULL,       -- 取得時刻(ISO 8601)
  captured_date   TEXT NOT NULL,       -- 日付(YYYY-MM-DD)← ユニークキー
  t1_arena_score  INTEGER,
  t1_grade_dan_id INTEGER,
  t1_mvp_cnt      INTEGER,
  t1_total_cnt    INTEGER,
  t1_win_rate     TEXT,
  t2_arena_score  INTEGER,
  t2_grade_dan_id INTEGER,
  t2_mvp_cnt      INTEGER,
  t2_total_cnt    INTEGER,
  t2_win_rate     TEXT,
  raw_json        TEXT
);
CREATE INDEX IF NOT EXISTS idx_season_summaries_date ON season_summaries(captured_date);

保存ロジック(saveSeasonSummary):

条件動作
同日レコードが存在しないINSERT
同日レコードが存在するUPDATE(全フィールドを最新値で上書き)

APIレスポンスからのマッピング:

DBカラムJSONパス
t1_arena_scoredata.T1.ArenaScore
t1_grade_dan_iddata.T1.GradeDanId
t1_mvp_cntdata.T1.MvpCnt
t1_total_cntdata.T1.TotalCnt
t1_win_ratedata.T1.WinRate
t2_*data.T2.*(同上)

3.3 season_shows テーブル

season_show のレスポンスをパースして保存。ScoreMapTopRoleList を含む詳細データ。

スキーマ:

sql
CREATE TABLE IF NOT EXISTS season_shows (
  id              INTEGER PRIMARY KEY AUTOINCREMENT,
  captured_at     TEXT NOT NULL,       -- 取得時刻(ISO 8601)
  captured_date   TEXT NOT NULL,       -- 日付(YYYY-MM-DD)← ユニークキー
  t1_max_score    INTEGER,
  t1_arena_score  INTEGER,
  t1_total_cnt    INTEGER,
  t1_win_cnt      INTEGER,
  t1_win_rate     TEXT,
  t1_score_map    TEXT,                -- JSON文字列 { "YYYYMMDD": score, ... }
  t2_max_score    INTEGER,
  t2_arena_score  INTEGER,
  t2_total_cnt    INTEGER,
  t2_win_cnt      INTEGER,
  t2_win_rate     TEXT,
  t2_score_map    TEXT,                -- JSON文字列 { "YYYYMMDD": score, ... }
  top_role_list   TEXT,                -- JSON文字列(TopRoleListの配列)
  raw_json        TEXT
);
CREATE INDEX IF NOT EXISTS idx_season_shows_date ON season_shows(captured_date);

保存ロジック(saveSeasonShow):

条件動作
同日レコードが存在しないINSERT
同日レコードが存在するUPDATE(全フィールドを最新値で上書き)

APIレスポンスからのマッピング:

DBカラムJSONパス
t1_max_scoredata.T1.MaxScore
t1_arena_scoredata.T1.ArenaScore
t1_total_cntdata.T1.TotalCnt
t1_win_cntdata.T1.WinCnt
t1_win_ratedata.T1.WinRate
t1_score_mapJSON.stringify(data.T1.ScoreMap)
t2_*data.T2.*(同上)
top_role_listJSON.stringify(data.TopRoleList)

ScoreMap のデータ形式:

json
{
  "20260101": 5200,
  "20260102": 5314,
  "20260103": 5489
}

キー: YYYYMMDD(8桁日付文字列)、値: その日のスコア(integer)

TopRoleList の要素形式:

json
[
  {
    "TotalCnt": 42,
    "WinCnt": 25,
    "WinRate": "0.5952",
    "Role": {
      "english_name": "haruka",
      "name_jp": "ハルカ"
    }
  }
]

WinRate0.0 〜 1.0 の小数文字列。画面表示時は parseFloat * 100 で % 変換。


4. テーブル間の関係

api_responses          ← 全レスポンスの生テキストを保持(監査・デバッグ用)
season_summaries       ← battle_seasonsummary を正規化して保持(1日1件)
season_shows           ← season_show を正規化して保持(1日1件)

season_summaries / season_showsapi_responses のサブセットをパースして格納した派生テーブル。raw_json に元の全レスポンスも保持しているため、カラム追加なしに後からデータを参照可能。


5. UI での表示(SeasonAnalyticsPanel)

season_showsseason_summaries のデータは PlayerDashboardTabシーズン解析 パネルに表示される。

UI要素データソース
日別スコア推移チャートt1_score_map / t2_score_mapJSON.parse
勝率推移チャートseason_summaries.t1_win_rate の時系列
スコア推移(Arena/Max)season_summaries.t1_arena_score + season_shows.t1_max_score
最新サマリーカードseason_shows(最新1件)+ season_summaries(最新1件)
キャラ別勝率横棒グラフtop_role_listJSON.parse(TotalCnt 降順)

6. レスポンスファイル保存(ResponseStorage)

レスポンス本文をファイル保存する場合(任意機能)、メタデータとして以下を保持:

フィールド説明
id連番
urlリクエストURL
timestamp取得時刻(ISO 8601)
fileName保存ファイル名
fileSizeファイルサイズ(bytes)
saveReasonauto / manual
memo任意メモ
apiEndpointURLから推定したエンドポイント名

7. ログイン状態テスト(未ログイン / 別アカウント)

7.1 セッション保存の仕様

  • ブラウザ自動化のログインセッションは storageState.json で永続化される
  • 保存先は app.getPath('userData')/browser-automation/storageState.json
  • Windows 例:
    • C:\Users\<ユーザー名>\AppData\Roaming\streaming-overlay-manager\browser-automation\storageState.json
  • アプリ内の「プロファイル」(UID/プレイヤー名/ログDir)は、ブラウザログインセッションとは別管理

7.2 未ログイン状態の再現手順

  1. ブラウザ自動化を停止する
  2. storageState.json を削除または退避する
  3. リアルタイム解析タブでブラウザ自動化を起動する
  4. ゲームサイトにログインせず、ログイン状態バナーを確認する

期待結果:

  • ⚠️ ログインが確認できませんでした。... が表示される

7.3 別アカウントでのテスト手順

  1. ブラウザ自動化を停止する
  2. storageState.json を削除して既存セッションを初期化する
  3. ブラウザ自動化を起動し、テスト対象の別アカウントでログインする
  4. ログイン状態バナーとワークフロー(テスト実行 / 全試合取得)を確認する

期待結果:

  • ✅ ログイン済みです。 が表示される
  • その後のAPI取得ワークフローが通常どおり実行できる