v0.5.0: send album art to the Chromecast
The device is on a TV, so it should show the cover. play_media now carries thumb=, which pychromecast folds into metadata["images"] — the field the receiver paints full-screen. Verified against the real device: it fetches both the audio and the artwork URL from us on every track change. Album art lives in the audio file's tags rather than as a file of its own, so TrackServer tokens now resolve to an _Asset that is either a path or a blob held in memory. Audio and art get separate eviction rings so a cover can't push out the previous track's audio while the device is still fetching it; Range and HEAD work on both. The image type is sniffed from the cover's magic bytes rather than trusted from the tag — ID3 APIC mimes are routinely wrong or blank, and the receiver silently drops an image whose declared type doesn't match its content. Anything unrecognized is treated as "no cover". Best-effort throughout: no art, junk where the art should be, or an unreadable file all just play without a cover rather than failing the load. Also sends albumArtist and trackNumber in the metadata. tests/test_round29.py: 74 tests; 447 pass overall. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -117,7 +117,12 @@ persistence) → GUI (Qt widgets that read the manager and connect to its signal
|
||||
file itself (bit-exact, no transcode). URLs carry an opaque random token, never
|
||||
a path, so traversal is structurally impossible; Range + HEAD are mandatory
|
||||
(the device seeks by re-requesting ranges and won't report a duration without
|
||||
them). `support.py` is the format gate — ALAC, AIFF and protected AAC are
|
||||
them). A token resolves to an `_Asset` that is either a file on disk (audio)
|
||||
or an in-memory blob (album art, which lives in tags rather than as its own
|
||||
file); the two have **separate eviction rings** so a cover can't push out the
|
||||
previous track's audio. Art is passed as `play_media(thumb=…)`, which
|
||||
pychromecast folds into `metadata["images"]` — that's what a TV paints
|
||||
full-screen. `support.py` is the format gate — ALAC, AIFF and protected AAC are
|
||||
refused and Player skips them with a status-bar message. `discovery.py` wraps
|
||||
`CastBrowser`; `sink.py` is the `PlaybackSink`; `controller.py` owns the
|
||||
session and its own `SleepInhibitor`. **pychromecast is imported lazily**, never
|
||||
|
||||
Reference in New Issue
Block a user