Skip to content

Phone remote: media controls (now-playing, transport, album art)#42

Merged
starbrightlab merged 2 commits into
mainfrom
claude/remote-media-controls
Jun 22, 2026
Merged

Phone remote: media controls (now-playing, transport, album art)#42
starbrightlab merged 2 commits into
mainfrom
claude/remote-media-controls

Conversation

@starbrightlab

Copy link
Copy Markdown
Owner

Requested by a remote user: media controls from the phone. Adds a Now Playing tab — album art, title/artist, a scrubber, and play/pause/skip/seek — bridged onto the launcher's existing now-playing stack (NowPlayingHub / MediaSessionReader, the same session that drives the on-TV header mini-player). Works with any media app, across the device switcher, with no new permissions (rides the notification-listener access already held).

Backend

  • RemoteMediastateJson (now-playing → JSON), command (transport, dispatched on the main thread), artPng.
  • Album art prefers the in-memory session bitmap; otherwise resolves the metadata art URIcontent:///file:// via ContentResolver (device-local, the phone can't fetch it itself), http(s):// via a bounded fetch — downscaled and relayed. artVersion lets the phone cache the cover and refetch only on track change.
  • seek() added to NowPlayingHub/MediaSessionReader for the scrubber.
  • Routes: GET /remote/nowplaying (authed), GET /remote/art (open, like icons), POST /remote/media (authed; 409 when idle, 400 on bad action).

UI

A Media tab that polls only while visible and interpolates position between polls so the scrubber moves smoothly without hammering. Pauses polling when the page is backgrounded.

Verification (on the Portal+, against a live session)

There was real audio playing (Alexa/Falcon → Hamilton), so I tested the live path:

  • nowplaying returned full metadata; media toggled playing true↔false; art returned a real 600×600 PNG — and because it exceeded the in-memory bitmap cap, it came through the URI-resolution path, confirming that case end-to-end. Idle → graceful (active:false, 409, 404); bad action → 400. (Left their playback as found.)
  • Media tab UI rendered at phone width: art, title, artist—album, scrubber + times, ⏮/⏸/⏭.
  • RemoteMediaTest (pure serializer) + the rest of the remote suite pass.

🤖 Generated with Claude Code

starbrightlab and others added 2 commits June 22, 2026 12:07
Adds a Now Playing tab to the phone remote: album art, title/artist, a scrubber, and play/pause/skip/seek. Bridges onto the launcher's existing now-playing stack (NowPlayingHub / MediaSessionReader) — the same media session that drives the on-TV header mini-player — so it works with any media app and across the device switcher, with no new permissions.

- RemoteMedia: stateJson (now-playing as JSON), command (transport on the main thread), artPng. Art prefers the in-memory session bitmap; otherwise resolves the metadata art URI — content://file:// via ContentResolver (device-local, the phone can't fetch it), http(s) via a bounded fetch — downscaled and relayed. artVersion lets the phone cache the cover per-track.
- NowPlayingHub/MediaSessionReader: add seek() (transportControls.seekTo) for the scrubber.
- RemoteRoutes: GET /remote/nowplaying (authed), GET /remote/art (open like icons), POST /remote/media (authed; 409 when nothing's playing, 400 on bad action).
- RemoteHtml: a Media tab with the now-playing card; polls only while visible and interpolates position between polls for a smooth scrubber.
- RemoteMediaTest covers the pure serializer (active/paused/null, URI-art, artVersion stability).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The media controls used Unicode media symbols (▶ ⏸ ⏮ ⏭, U+25B6/23F8/23EE/23ED), which iOS Safari renders as colour emoji rather than glyphs. Replace them with inline monochrome SVG (fill=currentColor) for the prev/play-pause/next buttons — crisp and identical across platforms. Verified the rendered controls in a mobile viewport.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@starbrightlab starbrightlab merged commit cd4943c into main Jun 22, 2026
3 checks passed
@starbrightlab starbrightlab deleted the claude/remote-media-controls branch June 22, 2026 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant