From ceebc2edb44e18cc815639f7c1e1352bf4509c9c Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Thu, 12 Feb 2026 08:40:03 -0600 Subject: [PATCH 1/5] Generalize welcome message This will be helpful in preparation for the next step: Timeout on idle. --- src/App.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index dc97a78..d1944ec 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -56,7 +56,7 @@ function App() { const [album, setAlbum] = useState(null); const [buffer, setBuffer] = useState([]); const [nowPlaying, play] = useState(0); - const [searching, setSearching] = useState(false); + const [displayText, setDisplayText] = useState("Scan an album to begin."); const [paused, setPaused] = useState(true); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); @@ -129,7 +129,7 @@ function App() { console.log("empty barcode; ignoring"); return; } - setSearching(true); + setDisplayText("Searching…"); console.log("Scanned barcode:", barcode); var mbRelease: IRelease | IReleaseMatch; if (barcode.startsWith("mbid:")) { @@ -145,8 +145,8 @@ function App() { inc: ['artist-credits', 'release-groups', 'genres'], // TODO }); if (searchResponse.count === 0) { - console.log("No album found for barcode:", barcode); // TODO: some kind of toast? - setSearching(false); + setDisplayText("No album found for barcode: " + barcode); + setTimeout(() => setDisplayText("Scan an album to begin."), 3000); return; } mbRelease = searchResponse.releases[0]; @@ -179,7 +179,6 @@ function App() { // # …and play! play(0); setPaused(false); - setSearching(false); } else { // Not found in Navidrome; populate with MusicBrainz data instead const fullMbRelease = await mbApi.lookup('release', mbRelease.id, ['recordings', 'artist-credits', 'release-groups']); const tracks: Track[] = fullMbRelease.media[0].tracks.map((t: ITrack) => ({ // TODO: handle multi-disc albums @@ -196,7 +195,6 @@ function App() { coverArtLink: await getCoverArtSrcURL(fullMbRelease.id, fullMbRelease['release-group']?.id || '') || '', }) console.log(album); - setSearching(false); } } @@ -231,10 +229,8 @@ function App() { {player} ) - } else if (searching) { - return (
Searching…
); } else { - return (
Scan an album to begin.
); + return (
{displayText}
); } } From 0614fa1460168d372807a7b56270e91ad42c7cd5 Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Wed, 18 Feb 2026 20:35:22 -0600 Subject: [PATCH 2/5] Extract out WELCOME_TEXT --- src/App.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index d1944ec..ee182cb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -52,11 +52,12 @@ function navidromeURL(path: string, params: Record): string { }).toString(); } +const WELCOME_TEXT = "Scan an album to begin."; function App() { const [album, setAlbum] = useState(null); const [buffer, setBuffer] = useState([]); const [nowPlaying, play] = useState(0); - const [displayText, setDisplayText] = useState("Scan an album to begin."); + const [displayText, setDisplayText] = useState(WELCOME_TEXT); const [paused, setPaused] = useState(true); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); @@ -146,7 +147,7 @@ function App() { }); if (searchResponse.count === 0) { setDisplayText("No album found for barcode: " + barcode); - setTimeout(() => setDisplayText("Scan an album to begin."), 3000); + setTimeout(() => setDisplayText(WELCOME_TEXT), 3000); return; } mbRelease = searchResponse.releases[0]; From 31d0bddc380d1863ae13e8cab68e8013c521d4f6 Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Wed, 18 Feb 2026 20:36:39 -0600 Subject: [PATCH 3/5] Reset on album end --- src/App.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/App.tsx b/src/App.tsx index ee182cb..21fe836 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -67,6 +67,9 @@ function App() { if ((album?.tracks?.length ?? 0) > nowPlaying + 1) { // if there's a next track play(nowPlaying + 1); setPaused(false); + } else { + setAlbum(null); + setDisplayText(WELCOME_TEXT); // Either I could always be diligent about resetting it elsewhere…or I can just do it here! } }; From 9bb7f8d1471bf5cbc4fc99245e520f468a37f31d Mon Sep 17 00:00:00 2001 From: Chandler Swift Date: Wed, 18 Feb 2026 20:37:13 -0600 Subject: [PATCH 4/5] Turn off barcode reader after 15m timeout A future enhancement would be to make sure it only times out 15m after an album is done playing (possibly by ignoring signals while an album is playing, and then at the end of the album set the timer again?) but that wasn't something I've implemented yet. --- src/App.tsx | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 21fe836..37db27c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -62,6 +62,22 @@ function App() { const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); const audioRef = useRef(null); + const [lastClicked, setLastClicked] = useState(new Date); + + const click = () => setLastClicked(new Date); + + useEffect(() => { + const IDLE_TIMEOUT_MS = 15 * 60 * 1000; // 15 minutes + window.setTimeout(() => { + setDisplayText("Asleep. Tap screen to scan."); + fetch('/api/reader/auto', { method: 'POST' }); + }, lastClicked.getTime() + IDLE_TIMEOUT_MS - new Date().getTime()); + + return () => { + setDisplayText(WELCOME_TEXT); + fetch('/api/reader/on', { method: 'POST' }); + } + }, [lastClicked]); const handleEnded = () => { if ((album?.tracks?.length ?? 0) > nowPlaying + 1) { // if there's a next track @@ -216,7 +232,7 @@ function App() {

This album cannot be played, as Chandler doesn't own a copy.

); return ( -
+