diff --git a/.gitignore b/.gitignore index 5616374..0b5fd7e 100644 --- a/.gitignore +++ b/.gitignore @@ -62,8 +62,12 @@ htmlcov/ logs/ *.log.* -# Runtime data -data/ +# Runtime data — anchor to repo root so nested package data dirs +# (server/src/ledgrab/data/prebuilt_sounds, game_adapters) are NOT ignored. +# An unanchored `data/` rule silently broke the v0.4.2 release by keeping +# shipped sound assets out of the CI tag checkout. +/data/ +/server/data/ *.db *.sqlite *.json.bak diff --git a/build/build-common.sh b/build/build-common.sh index fae9476..f60ee1e 100644 --- a/build/build-common.sh +++ b/build/build-common.sh @@ -69,6 +69,16 @@ copy_app_files() { # Clean up source maps and __pycache__ find "$APP_DIR" -name "*.map" -delete 2>/dev/null || true find "$APP_DIR" -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true + + # Patch the fallback version in the bundled __init__.py. Bundled installs + # strip ledgrab-*.dist-info from site-packages, so importlib.metadata + # falls back to this literal at runtime — and a stale literal is what + # silently shipped v0.4.2 reporting "0.3.0" in the WebUI. + local bundled_init="$APP_DIR/src/ledgrab/__init__.py" + if [ -f "$bundled_init" ] && [ -n "${VERSION_CLEAN:-}" ]; then + sed -i "s/_FALLBACK_VERSION = \"[^\"]*\"/_FALLBACK_VERSION = \"${VERSION_CLEAN}\"/" "$bundled_init" + echo " Patched _FALLBACK_VERSION -> ${VERSION_CLEAN}" + fi } # ── Site-packages cleanup ──────────────────────────────────── diff --git a/build/build-dist.ps1 b/build/build-dist.ps1 index 30ade02..d87749f 100644 --- a/build/build-dist.ps1 +++ b/build/build-dist.ps1 @@ -196,6 +196,17 @@ New-Item -ItemType Directory -Path (Join-Path $DistDir "logs") -Force | Out-Null Get-ChildItem -Path $srcDest -Recurse -Filter "*.map" | Remove-Item -Force -ErrorAction SilentlyContinue Get-ChildItem -Path $srcDest -Recurse -Directory -Filter "__pycache__" | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue +# Patch the fallback version in the bundled __init__.py so the WebUI always +# reports the release version — the installer strips ledgrab-*.dist-info from +# site-packages (above), so importlib.metadata falls back to this literal. +$bundledInit = Join-Path $srcDest "ledgrab\__init__.py" +if (Test-Path $bundledInit) { + $initContent = Get-Content $bundledInit -Raw + $patched = [regex]::Replace($initContent, '_FALLBACK_VERSION\s*=\s*"[^"]*"', "_FALLBACK_VERSION = `"$VersionClean`"") + Set-Content -Path $bundledInit -Value $patched -NoNewline + Write-Host " Patched _FALLBACK_VERSION -> $VersionClean" +} + # ── Create launcher ──────────────────────────────────────────── Write-Host "[8/8] Creating launcher..." diff --git a/server/src/ledgrab/__init__.py b/server/src/ledgrab/__init__.py index fafc649..ebdc781 100644 --- a/server/src/ledgrab/__init__.py +++ b/server/src/ledgrab/__init__.py @@ -2,10 +2,14 @@ from importlib.metadata import version, PackageNotFoundError -# Fallback version — kept in sync with pyproject.toml. +# Fallback version — kept in sync with pyproject.toml. MUST match the +# version declared there on every release. The Windows installer build +# (build/build-dist.ps1) also patches this literal to the resolved build +# version, so any drift here is corrected for bundled distributions. # Used when the package isn't pip-installed (e.g. embedded via Chaquopy -# on Android, where the source is included directly via source sets). -_FALLBACK_VERSION = "0.3.0" +# on Android, where the source is included directly via source sets, or +# in the Windows bundle where the installed dist-info is stripped). +_FALLBACK_VERSION = "0.4.2" try: __version__ = version("ledgrab") diff --git a/server/src/ledgrab/data/game_adapters/minecraft.yaml b/server/src/ledgrab/data/game_adapters/minecraft.yaml new file mode 100644 index 0000000..baff3be --- /dev/null +++ b/server/src/ledgrab/data/game_adapters/minecraft.yaml @@ -0,0 +1,78 @@ +# Minecraft community adapter +# Requires a server-side mod that sends game state via webhook +# (e.g., GameStateIntegration mod or custom Fabric/Forge mod) +# +# Configure your mod to POST JSON to: +# http://:8080/api/v1/game-integrations//event + +name: minecraft +game: Minecraft +protocol: webhook + +mappings: + - source_path: player.health + event: health + min: 0 + max: 20 + trigger: on_change + + - source_path: player.armor + event: armor + min: 0 + max: 20 + trigger: on_change + + - source_path: player.food_level + event: energy + min: 0 + max: 20 + trigger: on_change + + - source_path: player.experience_level + event: speed + min: 0 + max: 100 + trigger: on_change + + - source_path: player.deaths + event: death + trigger: on_increase + min: 0 + max: 100 + + - source_path: stats.kills + event: kill + trigger: on_increase + min: 0 + max: 100 + +auth: + type: header + header: X-Minecraft-Auth + +setup_instructions: | + ## Minecraft Integration Setup + + This adapter requires a server-side mod that sends game state data as JSON. + + **Recommended mods:** + - [GameStateIntegration](https://github.com/example/gsi-mod) (Fabric) + - Custom Forge mod using `PlayerTickEvent` + + **Expected JSON format:** + ```json + { + "player": { + "health": 20.0, + "armor": 10, + "food_level": 18, + "experience_level": 30 + }, + "stats": { + "kills": 5 + } + } + ``` + + Configure the mod to POST to the event endpoint with the auth token + in the `X-Minecraft-Auth` header. diff --git a/server/src/ledgrab/data/game_adapters/rocket_league.yaml b/server/src/ledgrab/data/game_adapters/rocket_league.yaml new file mode 100644 index 0000000..0ec671a --- /dev/null +++ b/server/src/ledgrab/data/game_adapters/rocket_league.yaml @@ -0,0 +1,99 @@ +# Rocket League community adapter +# Uses the SOS (Rocket League Overlay System) plugin +# https://gitlab.com/bakkesplugins/sos/sos-plugin +# +# SOS sends game state via WebSocket, but you can use a bridge +# to forward events as HTTP POST to: +# http://:8080/api/v1/game-integrations//event + +name: rocket_league +game: Rocket League +protocol: webhook + +mappings: + - source_path: player.boost + event: energy + min: 0 + max: 100 + trigger: on_change + + - source_path: player.speed + event: speed + min: 0 + max: 2300 + trigger: on_value + + - source_path: match.goals_scored + event: kill + trigger: on_increase + min: 0 + max: 20 + + - source_path: match.goals_conceded + event: death + trigger: on_increase + min: 0 + max: 20 + + - source_path: match.time_remaining + event: objective_progress + min: 0 + max: 300 + trigger: on_value + + - source_path: game.started + event: match_start + trigger: on_change + min: 0 + max: 1 + + - source_path: game.ended + event: match_end + trigger: on_change + min: 0 + max: 1 + + - source_path: team.score_blue + event: team_a + min: 0 + max: 10 + trigger: on_change + + - source_path: team.score_orange + event: team_b + min: 0 + max: 10 + trigger: on_change + +setup_instructions: | + ## Rocket League Integration Setup + + This adapter works with the SOS (Rocket League Overlay System) plugin. + + **Setup:** + 1. Install BakkesMod: https://bakkesmod.com + 2. Install the SOS plugin from the BakkesMod plugin manager + 3. Use a WebSocket-to-HTTP bridge to forward SOS events + + **Bridge tool:** + A small script that connects to SOS WebSocket (ws://localhost:49122) + and forwards events as HTTP POST to the WLED event endpoint. + + **Expected JSON format:** + ```json + { + "player": { + "boost": 75, + "speed": 1500 + }, + "match": { + "goals_scored": 2, + "goals_conceded": 1, + "time_remaining": 180 + }, + "team": { + "score_blue": 2, + "score_orange": 1 + } + } + ``` diff --git a/server/src/ledgrab/data/game_adapters/valorant.yaml b/server/src/ledgrab/data/game_adapters/valorant.yaml new file mode 100644 index 0000000..874a856 --- /dev/null +++ b/server/src/ledgrab/data/game_adapters/valorant.yaml @@ -0,0 +1,85 @@ +# Valorant community adapter +# Uses Overwolf/Insights API or third-party overlay tool +# that exposes game state via webhook +# +# Configure your overlay to POST JSON to: +# http://:8080/api/v1/game-integrations//event + +name: valorant +game: Valorant +protocol: webhook + +mappings: + - source_path: player.health + event: health + min: 0 + max: 100 + trigger: on_change + + - source_path: player.shield + event: shield + min: 0 + max: 50 + trigger: on_change + + - source_path: player.money + event: gold + min: 0 + max: 9000 + trigger: on_change + + - source_path: match.kills + event: kill + trigger: on_increase + min: 0 + max: 50 + + - source_path: match.deaths + event: death + trigger: on_increase + min: 0 + max: 50 + + - source_path: match.round_phase + event: round_start + trigger: on_change + min: 0 + max: 1 + + - source_path: match.spike_planted + event: objective_captured + trigger: on_change + min: 0 + max: 1 + +auth: + type: header + header: X-Valorant-Auth + +setup_instructions: | + ## Valorant Integration Setup + + Valorant does not have a native Game State Integration API. + You need a third-party tool to capture and forward game data. + + **Options:** + - Overwolf with a game events plugin + - Insights.gg capture API + - Custom screen-reading overlay + + **Expected JSON format:** + ```json + { + "player": { + "health": 100, + "shield": 50, + "money": 3900 + }, + "match": { + "kills": 12, + "deaths": 5, + "round_phase": 1, + "spike_planted": 0 + } + } + ``` diff --git a/server/src/ledgrab/data/prebuilt_sounds/alert.wav b/server/src/ledgrab/data/prebuilt_sounds/alert.wav new file mode 100644 index 0000000..94b648e Binary files /dev/null and b/server/src/ledgrab/data/prebuilt_sounds/alert.wav differ diff --git a/server/src/ledgrab/data/prebuilt_sounds/bell.wav b/server/src/ledgrab/data/prebuilt_sounds/bell.wav new file mode 100644 index 0000000..ca7149e Binary files /dev/null and b/server/src/ledgrab/data/prebuilt_sounds/bell.wav differ diff --git a/server/src/ledgrab/data/prebuilt_sounds/chime.wav b/server/src/ledgrab/data/prebuilt_sounds/chime.wav new file mode 100644 index 0000000..2c0e3a1 Binary files /dev/null and b/server/src/ledgrab/data/prebuilt_sounds/chime.wav differ diff --git a/server/src/ledgrab/data/prebuilt_sounds/ping.wav b/server/src/ledgrab/data/prebuilt_sounds/ping.wav new file mode 100644 index 0000000..72a7e74 Binary files /dev/null and b/server/src/ledgrab/data/prebuilt_sounds/ping.wav differ diff --git a/server/src/ledgrab/data/prebuilt_sounds/pop.wav b/server/src/ledgrab/data/prebuilt_sounds/pop.wav new file mode 100644 index 0000000..1e68abc Binary files /dev/null and b/server/src/ledgrab/data/prebuilt_sounds/pop.wav differ