v0.13.0
This release is mostly about sources. Spotify arrives as a full streaming backend, and the cover-reference plumbing underneath every source finally gets finished off, which shook two real ID-mismatch bugs out of Subsonic and Jellyfin on the way.
Highlights
Spotify. A new media server option, built entirely on the public Web API. No reverse-engineered endpoints, no password. You create your own Spotify app, paste the Client ID into Settings > Media servers > Add > Spotify, and Kopuz does PKCE auth through a loopback listener on 127.0.0.1:8898, then refreshes the token itself from there on. You get saved tracks as favorites, saved albums as your library, browsable playlists, a Discover page (On repeat, Jump back in, All-time favorites), search, like/unlike, and scrobbling to Last.fm, Libre.fm and ListenBrainz like any other source.
Playback has two modes. By default Kopuz opens a small player tab in a supported browser (Chrome, Edge, Brave, Chromium, Vivaldi or Safari; Firefox is excluded because the SDK dies a few seconds in there) running Spotify's official Web Playback SDK. That tab does the actual playing, since DRM needs a real browser, but everything is driven from Kopuz: play/pause, seek, volume, next/previous, queue and system media keys. It closes itself when you quit. Or pick any Spotify Connect target from the new device button in the bottom bar, whether that's your phone, the desktop app, a speaker or a TV. Progress and play state stay in sync either way. Two settings on the Spotify row control which browser hosts the tab, and whether Kopuz adopts an already-playing Connect session on startup instead of yanking playback to itself (adopting is the default).
Premium is required for playback, though browsing works without it. Spotify's Development Mode caps a fresh app at five listed users, limits search to ten results per type, and hides editorial playlists. There are no downloads, tag editing, radio, EQ, crossfade or gapless on Spotify audio, because the browser owns that pipeline. Full setup walkthrough and troubleshooting are in the README (#533).
One place encodes a cover ref. #426 got the parsing side, this finishes the encoding side, which was still hand-rolled in about five places. Everything now goes through stored_item_ref + CoverRef::NO_COVER, and the per-service URL builders (jellyfin_image.rs, subsonic_image.rs) collapse into cover.rs, dispatching on the ref's own shape. Two bugs fell out of it. The Subsonic playlist mapper was emitting jellyfin: album ids, so those tracks could never match the subsonic: rows fetch_library writes. And a whole cover ref landing in a track's cover slot got pasted into ?tag= as if it were that track's image tag, instead of resolving as the ref it actually is. SubsonicItem.cover was also a String that existed only to be compared against "none", so it's a bool now (#558).
Local artwork is served untouched. The Optimize Local Artwork toggle and its size selector are gone, along with the render-size downscaling behind them. The implementation was broken enough not to be worth keeping. Local covers are now always served as the original file bytes (#558).
Subsonic playlists use their own cover. Playlists that report a coverArt id now resolve it through getCoverArt.view at 512 px instead of always falling back to a track thumbnail. Playlists without one keep the old fallback (#517).
Opus downloads. The downloader gains OPUS alongside Best Audio, MP3, FLAC, WAV and it respects the audio-quality setting like the other audio formats (#562).
Release years come from more tags. Album details now read the year from RecordingDate, Year, ReleaseDate or OriginalReleaseDate, whichever lands first, instead of Year alone, so Vorbis files that only carry a recording date stop showing nothing. The year also moves to the end of the meta line (Album, N songs, duration, year) and now appears in the album details modal.
Malayalam. A full docs/README-ML.md translation, linked from the main README (#547).
Fixes
- scrobble: local files are scrobbled to Libre.fm again.
ScrobbleOptions::LOCALhadinclude_librefm: false(#564).
What's Changed
- i18n: add malayalam translation by @kraken-503 in #547
- fix: enable librefm scrobbling for local files by @diggingforce in #564
- feat: add opus for downloads by @yofukashino in #562
- various: centralize cover-ref encoding in CoverRef by @temidaradev in #558
- various: Spotify integration (Public API) by @temidaradev in #533
- docs: update README by @faristonz in #559
New Contributors
- @kraken-503 made their first contribution in #547
- @diggingforce made their first contribution in #564
- @faristonz made their first contribution in #559
Full Changelog: v0.12.0...v0.13.0