Auto merge dev → main (#1332)

* feat(tssbot): build_match_logs + match_logs persistence

* feat(tssbot): create match_logs table and write logs at ingest

* feat(tssbot): one-time match_logs backfill script

* feat(srebot): persist chat/battle logs to match_logs (parity, no backfill)

* feat(tssbot): Battle/Chat Log buttons on Discord scoreboards
This commit is contained in:
NotSoToothless
2026-06-18 01:02:59 -07:00
committed by GitHub
parent 53e3db9159
commit 32e747212f
6 changed files with 370 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
"""Backfill match_logs from on-disk TSS replays (one-time).
Usage: python TSSBOT/scripts/backfill_match_logs.py [--dry-run]
"""
import asyncio
import gzip
import json
import os
import sys
import pathlib
ROOT = pathlib.Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(ROOT.parent / "SHARED"))
from BOT.match_logs import build_match_logs, upsert_match_logs, MATCH_LOGS_SQL
from BOT.storage import TSS_BATTLES_DB_PATH
REPLAYS = pathlib.Path(os.environ["STORAGE_VOL_PATH"]) / "REPLAYS" / "TSS"
async def main(dry_run: bool) -> None:
import aiosqlite
files = sorted(REPLAYS.glob("*/replay_data.json.gz"))
print(f"Found {len(files)} replays under {REPLAYS}")
async with aiosqlite.connect(TSS_BATTLES_DB_PATH) as conn:
await conn.execute(MATCH_LOGS_SQL)
await conn.commit()
done = 0
for f in files:
sid = f.parent.name
try:
with gzip.open(f, "rb") as fh:
game = json.loads(fh.read().decode("utf-8"))
except Exception as exc:
print(f" skip {sid}: {exc}")
continue
chat, battle = build_match_logs(game)
if dry_run:
print(f" {sid}: chat={len(chat)} battle={len(battle)}")
else:
await upsert_match_logs(TSS_BATTLES_DB_PATH, sid, chat, battle)
done += 1
print(f"{'Would backfill' if dry_run else 'Backfilled'} "
f"{len(files) if dry_run else done} sessions")
if __name__ == "__main__":
asyncio.run(main("--dry-run" in sys.argv))