On Linux the API (/api/now-playing) and tray showed nothing playing while music played, and quitting from the tray left the app running.
Root causes and fixes
Empty now-playing: current YouTube Music layouts render no ytmusic-player-bar / #play-pause-button, so the scraper's selectors matched nothing. The scraper now reads the Media Session API first (now-playing.js) and falls back to the legacy DOM scrape. Artist is also clean (no "• views • likes" suffix).
Quit hang:ws's close() waits for every client to disconnect, so quitting with an overlay open never finished. stop() now terminates connected clients first.
Tray icon: the embedded PNG had a bad IDAT CRC and decoded to an empty image in Electron. Replaced with a valid PNG (tray-icon.js).
Tray race: state arriving before the tray existed was dropped. The tray is now created before the window.
Version bumped to 1.0.1.
Testing
npm test: 14/14 pass. New tests cover the Media Session and fallback scrape, stop() with a connected client, and PNG chunk validity. The stop and scrape tests were written failing first.
Ran the full app under Xvfb: track data flowed scraper -> IPC -> /api/now-playing.
Not covered by automated tests: the tray creation order (needs Electron). Not verified on a signed-in session with a real tray host.
## Problem
On Linux the API (`/api/now-playing`) and tray showed nothing playing while music played, and quitting from the tray left the app running.
## Root causes and fixes
- **Empty now-playing:** current YouTube Music layouts render no `ytmusic-player-bar` / `#play-pause-button`, so the scraper's selectors matched nothing. The scraper now reads the Media Session API first (`now-playing.js`) and falls back to the legacy DOM scrape. Artist is also clean (no "• views • likes" suffix).
- **Quit hang:** `ws`'s `close()` waits for every client to disconnect, so quitting with an overlay open never finished. `stop()` now terminates connected clients first.
- **Tray icon:** the embedded PNG had a bad IDAT CRC and decoded to an empty image in Electron. Replaced with a valid PNG (`tray-icon.js`).
- **Tray race:** state arriving before the tray existed was dropped. The tray is now created before the window.
- Version bumped to 1.0.1.
## Testing
- `npm test`: 14/14 pass. New tests cover the Media Session and fallback scrape, `stop()` with a connected client, and PNG chunk validity. The stop and scrape tests were written failing first.
- Ran the full app under Xvfb: track data flowed scraper -> IPC -> `/api/now-playing`.
- Not covered by automated tests: the tray creation order (needs Electron). Not verified on a signed-in session with a real tray host.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- Read the track from the Media Session API, falling back to the legacy
ytmusic-player-bar scrape. Current YT Music layouts render no player bar,
so the API and tray stayed empty while music played. Artist is also clean
now (no "• views • likes" suffix).
- Terminate connected WebSocket clients before closing the server. ws's
close() waits for every client to disconnect, so quitting with an overlay
open hung forever, leaving the window playing and the port bound.
- Replace the tray icon with a valid PNG (the old one had a bad IDAT CRC and
decoded to an empty image) and test that its chunks are well formed.
- Create the tray before the window so early state updates are not dropped.
- Bump version to 1.0.1.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
jknapp
merged commit 0e5b20498a into main2026-10-04 18:37:51 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
On Linux the API (
/api/now-playing) and tray showed nothing playing while music played, and quitting from the tray left the app running.Root causes and fixes
ytmusic-player-bar/#play-pause-button, so the scraper's selectors matched nothing. The scraper now reads the Media Session API first (now-playing.js) and falls back to the legacy DOM scrape. Artist is also clean (no "• views • likes" suffix).ws'sclose()waits for every client to disconnect, so quitting with an overlay open never finished.stop()now terminates connected clients first.tray-icon.js).Testing
npm test: 14/14 pass. New tests cover the Media Session and fallback scrape,stop()with a connected client, and PNG chunk validity. The stop and scrape tests were written failing first./api/now-playing.🤖 Generated with Claude Code