Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions PRIMER.md
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,7 @@ Automatic, from the show's location; there is no setting. `lib/units.js` reverse
| 0.33.282-master.2 | **Updates page on Master shows the Master updates you have.** Up to date on Master, What's new showed only GitHub Release notes, so the newest entry was the last release, not the Master update installed. `routes/updates.js` now, for a Master version that's up to date, finds the newest release older than the running version and lists the commits from that tag to this install's commit (new `updater.changesSince(tag, head)`: one compare request per pair, kept in the comparison cache, null when GitHub can't answer), keeps those whose version is `-master.N`, and puts them before the release notes. The earlier-updates fold from master.1 applies. Main only (the updater isn't in Lite). Checked: `node --check`; the status route run with the channel, version and GitHub answers stubbed from real data (release notes and the v0.33.281…main comparison): the list starts with 0.33.282-master.1, then 0.33.281 and earlier releases. |
| 0.33.282 | **Release: Updates page tidy-up (master.1, master.2); "Detect my delay" turned off; iPhone mic fix.** Bundles 0.33.282-master.1 and master.2. **"Detect my delay" is hidden on every device:** `LT_DETECT_ENABLED = false` in `rf-compat.js` makes `ltDetectOk` false, so the Audio timing sheet no longer shows the button. Why: it could never work on Android (opening the mic in Chrome switches the phone to call audio and silences the player), and the maintainer's rule is that a feature that can't work on every phone stays out; the native app's own calibrator covers it. All the code stays; flip the constant to bring it back. Also adds the iPhone "Detect my delay" fix first shipped as 0.33.280-beta.4: reported in PR #71 by jddocea — on iPhone Safari the mic failed with "audio session category is not compatible with audio capture", because the player keeps the iOS audio session on `'playback'` (so it ignores the mute switch) and that mode doesn't allow recording. `ltGetMic()` now switches `navigator.audioSession.type` to `'play-and-record'` just before `getUserMedia`; `ltDetect()` already sets it back to `'playback'` when the mic closes (success and error paths). The PR's version changed all four `'playback'` assignments, which would have kept every iPhone listener in record mode and cancelled the reset after measuring, so only the mic path changes. The mic fix stays in the code for when the button returns. Player cache-buster 153 (beta used 152). Checked: `node --check`. Credit: jddocea (diagnosis and first fix). |
| 0.33.283 | **iPhone: Measure sync and Compare devices can use the microphone.** Why: after 0.33.282 an operator with Settings → Debug → Microphone sync measurement turned on got "Measurement failed: AudioSession category is not compatible with audio capture" from **🎤 Measure sync** on iPhone Safari. 0.33.282 only fixed `ltGetMic()` (Detect my delay); `micMeasure()` and `compareRun()` call `getUserMedia` themselves. New helpers `micSessionRecord()` / `micSessionDone()`: switch `navigator.audioSession.type` to `'play-and-record'` just before `getUserMedia`, and in `finally` set it back to `'playback'` and run `ltRestoreAudio()` (same engine rebuild Detect my delay uses). Only when `navigator.audioSession` exists (Safari); desktop and Android unchanged. Player cache-buster 154. Checked: `node --check`. Main only (audio player). |
| 0.33.284-master.1 | **Show directory admin page.** Why: the maintainer needed a way to remove shows from the app's directory and to diagnose shows that don't appear. In `tools/install-counter` (the directory server, not the ShowPilot app): new `/admin` page (`admin/index.html`), off unless the counter runs with `ADMIN_KEY`; the page sends the key as a Bearer header to `/api/admin/*` (timing-safe compare; 20 wrong keys in 15 min locks the admin API, counted globally since the counter never looks at IPs). `directory.js`: new `shows_blocked` table (blocked check-ins get 403 with a message the owner sees as "Not listed: …" in Settings → ShowPilot App) and `shows_rejects` (latest refused check-in per install with reason and repeat count; cleared on the next good check-in, purged after 30 days); `shows.verify_error` records a failed re-verification the grace period let through. Admin API: overview (every show with live / online / not checking in / dropped status), live Check (show-info + listing ID, viewer page, `/api/now-playing-audio` at the listed pin; re-verifies on success), Remove (comes back on next check-in if still listed), Block / Unblock, Dismiss. The page also runs the public `/nearby` and `/directory` endpoints for any point ("What a phone sees here"). `fetchShowInfo` generalized to `fetchFromShow` (same private-address refusal). Deploy: copy the folder to the counter host and restart with `ADMIN_KEY`. Checked: `node --check` on both files and the page script; ran the counter against a fake show (accepted, mismatched-ID and private-address check-ins, block → 403, show-info down) and screenshotted the page at desktop and phone width. Main only (directory server isn't in Lite). |

**Plugin version history (this session):**
| Version | Change |
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "showpilot",
"version": "0.33.283",
"version": "0.33.284-master.1",
"description": "Self-hosted light show viewer control server. Falcon Player (FPP) plugin compatible. Replaces Remote Falcon for self-hosters.",
"main": "server.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion public/admin/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2112,7 +2112,7 @@ <h1>ShowPilot <span class="login-brand-sub">Admin</span></h1>
<rect class="lp" x="8" y="-3" width="5" height="5" rx="1"/>
</svg>
<span class="app-brand-text">ShowPilot</span>
<span class="app-version">v0.33.283</span>
<span class="app-version">v0.33.284-master.1</span>
</span>
<span id="modePill" class="mode-pill off">OFF</span>
<span class="header-spacer"></span>
Expand Down
33 changes: 33 additions & 0 deletions tools/install-counter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ Then in Cloudflare:
Optional: make the stats page private by starting it with `STATS_KEY=yourkey`
and opening `/?key=yourkey`.

Directory admin page: start it with `ADMIN_KEY=<long random value>` (for
example `openssl rand -hex 24`) and open `/admin`. Without `ADMIN_KEY` the
page and its API answer 404. With pm2:
`ADMIN_KEY=… pm2 restart showpilot-install-counter --update-env && pm2 save`.

## Endpoints

| Path | What |
Expand All @@ -60,6 +65,10 @@ and opening `/?key=yourkey`.
| `POST /api/shows/checkin` | Listed show's once-a-minute check-in (directory) |
| `POST /api/shows/remove` | Show whose owner turned listing off (directory) |
| `GET /api/shows/nearby?lat=&lng=&radius_mi=` | Phone app: listed shows near a point (directory) |
| `GET /api/shows/directory?lat=&lng=&radius_mi=` | Phone app: Directory of Shows map (directory) |
| `GET /admin` | Directory admin page (needs `ADMIN_KEY`) |
| `GET /api/admin/directory` | Admin: every show, refused check-ins, blocked shows |
| `POST /api/admin/directory/check` `remove` `block` `unblock` `dismiss` | Admin actions, body `{ "idHash": "…" }` (`block` also takes `reason`) |

"Running" means checked in within the last 30 days. Daily totals are saved
for the trend line.
Expand Down Expand Up @@ -129,3 +138,27 @@ to `https://<counter host>/api/shows/…` (`DEFAULT_URL` in

Testing only: `VERIFY_REWRITE_TO=http://127.0.0.1:3100` sends the ownership
check to a local server instead of the show's real address.

## Directory admin

`/admin` (with `ADMIN_KEY` set; the page asks for the key once per browser
tab and sends it as `Authorization: Bearer …`, never in the URL):

- **Shows:** every show on record with its state — *Live*, *Online* (checking
in, not playing), *Not checking in* (quiet 2.5 min – 1 day: still in the
app, shown as not live), *Dropped* (quiet over a day: out of the app,
deleted after 30 days) — plus version, pin, listing ID and a flag when the
daily ownership check is failing but the 2-day grace keeps it listed.
- **Check:** runs live against the show: its `show-info` and listing ID, the
viewer page, and `/api/now-playing-audio` at its pin. Passing re-verifies the
listing.
- **Remove:** takes it out now. If the owner still has listing on, it comes
back on its next check-in (about a minute).
- **Block:** keeps it out. Its check-ins get `403` and the owner's ShowPilot
shows "Not listed: this show was removed from the ShowPilot app directory…".
**Unblock** lets it back on its next check-in.
- **Refused check-ins:** the latest refusal per install and why (bad web
address, ownership mismatch, show-info unreachable…), so "my show isn't in
the app" can be answered. Cleared when that install's check-in works.
- **What a phone sees here:** runs `/nearby` and `/directory` for any point
(or a show's own pin with *Test here*).
Loading
Loading