Conversation
Auto mode now arms a timer for the exact next dark/light boundary instead of polling hourly, flipping the theme as it passes and re-checking on visibilitychange (timers don't survive suspend). Gated behind a new 'Switch while running' setting, separate from the startup-only auto choice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Hover highlights stick after a tap on a touchscreen. Every :hover rule is now guarded by :global(html:not(.no-hover)), and the new touch-friendly setting puts that class on <html> to switch them all off at once. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds a 1x-4x scale slider to Settings > Kiosk, applied as CSS zoom on <html> so the layout reflows instead of just being magnified. Clickable 1x/2x/4x markers under the track, and the slider snaps to them when dragged close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Gonic streams a server-side transcode chunked, with no Content-Length or Accept-Ranges, so the stream has no seekable ranges. Assigning currentTime anyway left WebKitGTK stuck in a seek that never completes, taking play/pause with it. - 'Original' now sends format=raw, which the server serves with real range support (verified: 206 + Accept-Ranges), so scrubbing works as intended. - canSeekTo() gates every seek on the element's seekable ranges, so an unseekable stream is left alone instead of wedging playback. - A failed play() now resyncs the playing store, so the button can't lie. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Wifi power save parks the radio between beacons; the latency spikes starve the 200ms ALSA buffer and come out as crackle, even on a strong signal (the test Pi sits at -13 dBm and still drained to a single period). The installer now warns when it detects this and fixes it with --fix-wifi, persisting via a NetworkManager drop-in and applying it live with iw. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
format=raw fixed seeking for 'Original', but the 320/192/128 kbps options are still delivered chunked and unseekable. Gonic honours timeOffset on audio, so a seek on an unseekable stream now re-requests it starting at the target. - planSeek() picks between seeking the element and reloading at an offset. - PlayerBar tracks streamOffset as the loaded stream's time base, so position, duration and scrobble thresholds stay in track time. - Track loading is keyed on track id rather than the src URL, so re-requesting the same track at an offset doesn't count as a track change. - awaitingLoad stops the store->element sync from reloading in a loop while a new src still reports a stale currentTime and empty seekable ranges. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked branch covering five open issues.
#107 — Auto dark/light mode changes
automode re-checked the clock once an hour, so a boundary could pass up to 59 minutes before the theme moved, and there was no way to opt out of mid-session switching.msUntilNextSwitch()(pure, tested) computes the exact ms to the next boundary;theme.jsarms asetTimeoutfor it, flips, and re-arms — no polling.visibilitychange, since timers don't survive suspend.Test: Theme → Auto, set "Dark from" a minute or two ahead, leave the app open — it should flip on the dot. Turn the new toggle off and it should sit still until restart.
#106 — Touch friendly mode
:hoverrule (39 of them) is now written:global(html:not(.no-hover)) …:hover.no-hoveron<html>, switching them all off at once.Test: toggle it on, tap around on the touchscreen — no highlight should stick after a tap.
#103 — Kiosk interface scale
zoomon<html>, so the layout reflows rather than being magnified.Test: drag the slider on the kiosk, check the layout at 2× and 4× and that it survives a restart.
#105 — Scrubbing breaks playback on kiosk
Root cause, and it's server-side. Gonic has a transcode profile bound to the client name
tonearm. Measured against your server:c=tonearm200,audio/mpeg, chunked, noContent-Length/Accept-Ranges— unseekablec=DSub(or any other name)206,audio/flac,Accept-Ranges: bytes— seekableThe app's stream URL never changed — it's been bare
{id}since the first commit — so scrubbing worked until that profile was added on the server. With no seekable ranges, assigningcurrentTimeleft WebKitGTK stuck in a seek that never completes, which took play/pause down with it.Scrubbing now works in every configuration:
format=raw, which overrides the profile: verified206+Accept-Ranges+ realContent-Length, and the Pi's system GStreamer decodes the resulting FLAC.timeOffset. Gonic honours it for audio despite the spec calling it video-only — verified on the exact URL shape the app sends:timeOffset=120returns precisely 120s fewer bytes.planSeek()picks between seeking the element and re-requesting the stream at an offset.streamOffsetas the loaded stream's time base, so position, duration and scrobble thresholds stay in track time; track loading is keyed on track id so an offset reload isn't mistaken for a track change; andawaitingLoadstops the store→element sync from reloading in a loop while a newsrcstill reports a stalecurrentTime.play()resyncs theplayingstore (ignoring the expectedAbortErroron src change), so the button can't lie.Test: scrub around, forwards and backwards, then hit play/pause — at Original and at a transcoded bitrate. Note "Original" now streams raw files (FLAC, ~26MB/track vs ~4MB) — the Pi pulled one in 1.2s over wifi, so it's comfortable, but worth a listen. If you'd rather not stream raw, removing the
tonearmtranscode profile in Gonic gets you seekable streams too.#104 — Kiosk audio crackle
The Pi had wifi power save on, parking the radio between beacons. Those latency spikes starve the 200ms ALSA buffer, which comes out as crackle — despite an excellent signal (-13 dBm, 433 Mbit/s). The playback buffer had drained to a single 10ms period.
--fix-wifiturns it off via a NetworkManager drop-in plus a liveiwapply (no reconnect).Test: play for a while and listen. Two independent causes were addressed, so if crackle persists, say so — that rules one out.
🤖 Generated with Claude Code