- Dart 92.5%
- CMake 4.4%
- C++ 2.7%
- C 0.3%
- Progress bar no longer sticks at full when a track repeats: a sustained overshoot on a still-playing track (HA leaves media_position pinned at the end) wraps and counts again, while a brief overshoot still shows full so normal track transitions look right. - Album/playlist/artist track rows now listen to the playback controller and highlight the currently playing track. Matching is by ratingKey from media_content_id with a title fallback, shared with the queue panel so duplicate titles don't both light up. - Unify the "now playing" indicator into a single PlayingArtThumb widget (art + animated equalizer overlay) used by every art-based row, so the playlist/search/queue views all match the album view instead of three divergent implementations. analyze clean, 13 tests passing, Linux build green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| android | ||
| lib | ||
| linux | ||
| test | ||
| .gitignore | ||
| .metadata | ||
| analysis_options.yaml | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| pubspec.lock | ||
| pubspec.yaml | ||
| README.md | ||
Plex Sonos Caster
A rich, animated Flutter music app (Linux + Android) that browses your Plex library and casts it to your Sonos speakers — a single speaker or every speaker at once — orchestrated through Home Assistant.
The app talks to your Plex Media Server directly for metadata and artwork, and uses Home Assistant to group Sonos speakers and drive playback.
Features
- Browse your music library: albums, artists, and playlists, with a recently-added shelf and disk-cached album art.
- Search across artists, albums, and songs with live results.
- Cast any album, artist, playlist, or track to a chosen speaker or to all Sonos at once (whole-home grouping). Non-Sonos HA media players (Google Cast / DLNA, e.g. an LG soundbar) are supported too.
- Full transport controls: play/pause, stop, next/previous, shuffle, repeat, seek, and group volume — each enabled per the target's reported capabilities.
- Now playing: album-art-driven gradient ambience, a live-ticking progress bar, and a persistent mini-player docked above the navigation.
- Up Next queue: see the tracks you cast and which one is playing.
- Ratings: Plex star ratings (5 stars, half-star precision) shown across the library and the player.
- Device picker that detects already-grouped Sonos zones.
How it works
┌──────────────┐ browse / search ┌──────────────────┐
│ │ ───────────────────▶ │ Plex Media │
│ Flutter app │ │ Server (direct) │
│ (this repo) │ └──────────────────┘
│ │ discover · group · play_media
│ │ ───────────────────▶ ┌──────────────────┐
└──────────────┘ │ Home Assistant │ ──▶ Sonos speakers
└──────────────────┘
- Discover Sonos speakers —
media_playerentities exposing agroup_membersattribute. - Group them into one coordinator via
media_player.join(when casting everywhere). - Cast a Plex item to the coordinator with
media_player.play_media, using aplex://<machineId>/<ratingKey>content id that HA's Plex integration resolves and streams to the whole group. - Poll the coordinator's
media_playerstate for the now-playing view.
Project layout
lib/
main.dart App entry; wires controllers + theme
src/
backends.dart Barrel export for the backend layer
config/ url + token value objects
services/
home_assistant_backend.dart REST client (states + service calls)
plex_backend.dart REST client (search / browse / artwork)
sonos_service.dart Discovery, grouping, casting, playback state
settings_service.dart On-device persistence (shared_preferences)
ui/
app_scope.dart Inherited access to the controllers
theme.dart Dark theme, colors, gradients, motion
navigation.dart Fade/slide page transitions
controllers/ connection · library · playback (ChangeNotifier)
screens/ root · settings · library · search · detail ·
now-playing · main shell
widgets/ album art · cards · track tile · mini player ·
device picker · queue sheet · stars · …
The backend layer (src/config, src/services) has no Flutter dependency —
plain Dart, independently unit-testable. The UI layer talks to it only through
the service classes.
Configuration
Two connections are entered in-app on first run and persisted locally:
| Setting | Example | Notes |
|---|---|---|
| Home Assistant URL | http://homeassistant.local:8123 |
|
| Home Assistant token | long-lived access token | Profile → Security |
| Plex URL | http://192.168.1.10:32400 |
|
| Plex token | X-Plex-Token | |
| Music library | chosen from a dropdown | pick Music vs. Audiobooks etc. |
Tap Test connections to verify reachability and load the list of music libraries. Local HTTP (cleartext) traffic is enabled in the Android manifest so on-network servers work without TLS.
Casting format: HA's Sonos integration resolves Plex media addressed as
plex://<plexMachineIdentifier>/<ratingKey>(seeSonosService.buildPlexContentId). A bare JSON payload returns HTTP 200 but plays nothing; aplex://{json}payload returns HTTP 500. The machine id is read from the Plex server viaPlexBackend.machineId().
Speakers
- Sonos is first-class: whole-home grouping ("Everywhere") and full transport.
- Google Cast / DLNA players (e.g. an LG soundbar) work as single targets.
HA's Cast integration resolves the same
plex://id, so casting works — but many Cast endpoints only expose play/pause/stop/seek/volume, not skip/shuffle/repeat. The app reads each player'ssupported_featuresand greys out controls a device can't do. Such players also often publish no artwork; the app recovers it from Plex.
Limitations
- Sonos/HA does not expose its live queue over REST, so "Up Next" reflects the collection you cast. For a shuffled cast the songs are correct but the displayed order is the original collection order, not HA's random order.
- Skip/shuffle/repeat on non-Sonos devices depend on what the player exposes to HA; many Cast devices don't expose them, and there is no client-side queue engine to work around that.
- Now-playing ratings are looked up from Plex by title, so they appear a moment after the track changes.
Development
flutter pub get
flutter run -d linux # desktop
flutter run -d <android-device> # Android
flutter analyze
flutter test
Acknowledgements
The Home Assistant and Plex REST clients are adapted from angela-dart.