From 93321ce45bf0f3c168110182ea24dab0a2ede993 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 12 Nov 2026 20:20:23 -0600 Subject: [PATCH 1/2] =?UTF-8?q?v0.33.282=20=E2=80=94=20iPhone=20microphone?= =?UTF-8?q?=20timing=20check=20works=20again,=20tidier=20Updates=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bug fix: On iPhone Safari, "Detect my delay" in the player's timing settings failed with "audio session category is not compatible with audio capture". The player now switches iPhone audio into record-capable mode only while the microphone is measuring, then back to normal playback, so everyday listening is unchanged. - Bug fix: On the Master channel, the Updates page showed the last release's notes as "Recent updates" even after you'd installed newer Master updates. It now starts with the Master updates you have since the last release, then the earlier releases. - Feature update: On the Updates page, earlier releases are now folded behind a "Show earlier updates" button, so only your current version's notes show until you ask for more. Main only (audio). Source: #71 Co-authored-by: jddocea πŸ€– Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01PJcoKLr2bhdUTsNw524TXK --- PRIMER.md | 1 + lib/viewer-renderer.js | 2 +- package.json | 2 +- public/admin/index.html | 2 +- public/rf-compat.js | 6 ++++++ 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/PRIMER.md b/PRIMER.md index a4a7fa6..9e673db 100644 --- a/PRIMER.md +++ b/PRIMER.md @@ -819,6 +819,7 @@ Automatic, from the show's location; there is no setting. `lib/units.js` reverse | 0.33.281 | **Listen Only gets its own template section (issue #70, suggested by @jddocea).** In Listen Only the page kept the last mode's song list, so whether the voting or jukebox list showed depended on the previous mode, and 0.33.280's "Keep the song list" setting only added a switch on top. New `{listen-only-dynamic-container}` (`data-showpilot-container="listenonly"`, visible only in Listen Only) and `{show-on-dynamic-container}` (`"showon"`, every mode except Off). When a template has the Listen Only section, Listen Only shows it and hides the voting and jukebox sections (renderer `shownMode` 'NONE' via `hasListenSection`; rf-compat checks for the element live). Templates without it keep the last mode's list, so Remote Falcon templates are unchanged. The 0.33.280 setting is removed from Settings, the config allow-list and `/api/state`; the `listen_show_list` column stays in the schema (unused) so databases and backups stay valid. New "Listen Only" block (one per page) with a title and a message that can include `{LISTEN_BUTTON}`. Template reference documents both sections. `rf-compat.js?v=150`. Checked: `node --check` on changed files and admin inline scripts; headless test on a fresh install switching Voting β†’ Listen only β†’ Off β†’ Jukebox β†’ Listen only, live and after reload, for a template with the Listen Only section (Listen only shows it plus show-on, hides voting/jukebox; Off shows only after-hours) and one without (Listen only keeps the last mode's list); admin loads without errors and lists the new block. | | 0.33.282-master.1 | **Updates page: earlier updates fold behind one button.** When up to date, the What's new box listed every earlier release under an "Earlier updates" heading, which looked busy. Now only your version's notes show, followed by a "Show earlier updates (N)" button (`details.whats-new-earlier`, label switches to "Hide earlier updates" when open). The list of updates waiting to install (not up to date) is unchanged. Main only: ShowPilot-Lite has no Updates page (it updates through FPP's Plugin Manager). Checked: `node --check` on the admin inline scripts; headless render of the Updates page with six releases of notes, closed and open. | | 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) plus iPhone mic fix.** Bundles 0.33.282-master.1 and master.2, and 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. Player cache-buster 153 (beta used 152). Checked: `node --check`. Credit: jddocea (diagnosis and first fix). | **Plugin version history (this session):** | Version | Change | diff --git a/lib/viewer-renderer.js b/lib/viewer-renderer.js index 18e6bea..ea5e3a6 100644 --- a/lib/viewer-renderer.js +++ b/lib/viewer-renderer.js @@ -1383,7 +1383,7 @@ ${visitorMessages.BOX_CSS}${showButtons.CSS} ${cfg.debug_mic_measure === 1 ? '' : ''} - + `; if (html.includes('')) { html = html.replace('', injection + ''); diff --git a/package.json b/package.json index 0790342..9a9671b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "showpilot", - "version": "0.33.282-master.2", + "version": "0.33.282", "description": "Self-hosted light show viewer control server. Falcon Player (FPP) plugin compatible. Replaces Remote Falcon for self-hosters.", "main": "server.js", "scripts": { diff --git a/public/admin/index.html b/public/admin/index.html index aa0559c..ae82b11 100644 --- a/public/admin/index.html +++ b/public/admin/index.html @@ -2112,7 +2112,7 @@

ShowPilot

ShowPilot - v0.33.282-master.2 + v0.33.282 OFF diff --git a/public/rf-compat.js b/public/rf-compat.js index 5d9e7bb..bfe7723 100644 --- a/public/rf-compat.js +++ b/public/rf-compat.js @@ -4113,6 +4113,12 @@ } async function ltGetMic() { const base = { echoCancellation: false, noiseSuppression: false, autoGainControl: false }; + // iOS Safari refuses the mic while the audio session is 'playback' + // ("audio session category is not compatible with audio capture"). + // Switch to play-and-record only for the measurement; ltDetect() puts + // it back to 'playback' when the mic closes, so normal listening is + // unchanged. Feature-detected: a no-op outside Safari. (Thanks jddocea, #71) + try { if (navigator.audioSession) navigator.audioSession.type = 'play-and-record'; } catch (_) {} let stream = await navigator.mediaDevices.getUserMedia({ audio: base }); let devices = []; try { From ef8d45d8401c87f5d7fa185a71abf73893381f5b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 12 Nov 2026 20:21:23 -0600 Subject: [PATCH 2/2] =?UTF-8?q?v0.33.282=20=E2=80=94=20"Detect=20my=20dela?= =?UTF-8?q?y"=20turned=20off,=20tidier=20Updates=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Feature update: The "Detect my delay" microphone button is no longer shown in the player's Audio timing settings. It couldn't work on Android phones, so it's turned off everywhere for now. The manual timing buttons, slider and presets are unchanged. - Bug fix: On iPhone Safari, the microphone timing check failed with "audio session category is not compatible with audio capture". The fix is in place for if the button comes back, and only affects the moment the microphone is in use. - Bug fix: On the Master channel, the Updates page showed the last release's notes as "Recent updates" even after you'd installed newer Master updates. It now starts with the Master updates you have since the last release, then the earlier releases. - Feature update: On the Updates page, earlier releases are now folded behind a "Show earlier updates" button, so only your current version's notes show until you ask for more. Main only (audio). Source: #71 Co-authored-by: jddocea πŸ€– Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01PJcoKLr2bhdUTsNw524TXK --- PRIMER.md | 2 +- public/rf-compat.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/PRIMER.md b/PRIMER.md index 9e673db..057f079 100644 --- a/PRIMER.md +++ b/PRIMER.md @@ -819,7 +819,7 @@ Automatic, from the show's location; there is no setting. `lib/units.js` reverse | 0.33.281 | **Listen Only gets its own template section (issue #70, suggested by @jddocea).** In Listen Only the page kept the last mode's song list, so whether the voting or jukebox list showed depended on the previous mode, and 0.33.280's "Keep the song list" setting only added a switch on top. New `{listen-only-dynamic-container}` (`data-showpilot-container="listenonly"`, visible only in Listen Only) and `{show-on-dynamic-container}` (`"showon"`, every mode except Off). When a template has the Listen Only section, Listen Only shows it and hides the voting and jukebox sections (renderer `shownMode` 'NONE' via `hasListenSection`; rf-compat checks for the element live). Templates without it keep the last mode's list, so Remote Falcon templates are unchanged. The 0.33.280 setting is removed from Settings, the config allow-list and `/api/state`; the `listen_show_list` column stays in the schema (unused) so databases and backups stay valid. New "Listen Only" block (one per page) with a title and a message that can include `{LISTEN_BUTTON}`. Template reference documents both sections. `rf-compat.js?v=150`. Checked: `node --check` on changed files and admin inline scripts; headless test on a fresh install switching Voting β†’ Listen only β†’ Off β†’ Jukebox β†’ Listen only, live and after reload, for a template with the Listen Only section (Listen only shows it plus show-on, hides voting/jukebox; Off shows only after-hours) and one without (Listen only keeps the last mode's list); admin loads without errors and lists the new block. | | 0.33.282-master.1 | **Updates page: earlier updates fold behind one button.** When up to date, the What's new box listed every earlier release under an "Earlier updates" heading, which looked busy. Now only your version's notes show, followed by a "Show earlier updates (N)" button (`details.whats-new-earlier`, label switches to "Hide earlier updates" when open). The list of updates waiting to install (not up to date) is unchanged. Main only: ShowPilot-Lite has no Updates page (it updates through FPP's Plugin Manager). Checked: `node --check` on the admin inline scripts; headless render of the Updates page with six releases of notes, closed and open. | | 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) plus iPhone mic fix.** Bundles 0.33.282-master.1 and master.2, and 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. Player cache-buster 153 (beta used 152). Checked: `node --check`. Credit: jddocea (diagnosis and first fix). | +| 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). | **Plugin version history (this session):** | Version | Change | diff --git a/public/rf-compat.js b/public/rf-compat.js index bfe7723..4e4d8a9 100644 --- a/public/rf-compat.js +++ b/public/rf-compat.js @@ -4093,7 +4093,11 @@ // call audio the moment a page opens the mic, which silenced the player // in the first real test β€” a browser can't play and listen at once there. // That measurement needs a native app. - const ltDetectOk = !!(window.isSecureContext && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) && + // Turned off everywhere in v0.33.282: a feature that can't work on every + // phone stays out of the web player. The code is kept; set this to true + // to bring the button back. + const LT_DETECT_ENABLED = false; + const ltDetectOk = LT_DETECT_ENABLED && !!(window.isSecureContext && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) && !/Android/i.test(navigator.userAgent || ''); let ltDetectBusy = false, ltDetectLast = null; function ltDetectMsg(html) {