Highlights
- Transcoding works out of the box.
streamnow honorsformatandmaxBitRatewithout needing a per-user profile, so clients like Symfonium can pick a bitrate per-network with zero server-side setup. Admins can also configure per-format defaults from a new admin UI section. For legacy clients like Sonus, use the existing but now renamed "per-client overrides" section - Seeking works in transcoded streams. Cached transcodes are served with proper HTTP Range support, so scrubbing through an opus transcode now behaves like scrubbing through a normal file. For cache misses (first time streaming)
timeOffsetandestimateContentLengthare now supported - Track play counts are returned on individual tracks (#459), so scrobble counts sync correctly across devices
- Richer artist metadata: track contributors, performer roles, and per-relationship credit names are scanned and exposed.
displayArtistnow usesARTIST_CREDIT - More scanned tags: ISRCs, record labels, and per-track year tags are now picked up and returned to clients that support them
- Portable m3u playlists use relative paths, so they survive moves between machines or library roots (#537, #529)
- Bounded cover art cache with configurable size and eviction interval, useful on smaller disks (#687)
- Security: playlist ownership is now enforced - one user can no longer fetch or delete another user's playlists
Upgrade notes
- A full ("slow") scan is recommended after upgrading to v0.21.0 to pick up the newly scanned fields (contributors, ISRCs, record labels, per-track years,
ARTIST_CREDIT)
⚠ BREAKING CHANGES
- deps: bump to go1.26
Features
- add cache size and eject interval for cover art cache (#687) (b25bf3c)
- ci: update golangci-lint (be36fb4)
- db: refactor artist and album level artist roles (1edd175)
- db: update log format (3793d48)
- docs: add Music Assistant to list of tested applications (#676) (f5eecae)
- gonic: add genre-tree option to expand genre hierarchies (be4e137)
- gonic: scan and return per-relationship credit names (731c07a)
- gonic: use more efficient job polling (9b4a0e3)
- lastfm: retry when artist image fetch fails (4eef4df)
- playlist: use relative paths in m3u playlists (798e7f8), closes #537 #529
- podcast: ensure that any error path out of doPodcastDownload sets status (#672) (192ee10)
- scan and return track contributors (f9b6e27)
- scanner: also read multi vorbis singular tags (896b0dd), closes #659
- scanner: skip macOS resource fork files (e2dabd2), closes #657
- subsonic: add configurable per format transcoding defaults (b0e2c94)
- subsonic: don't render track contributors for DSub (3ae3177)
- subsonic: honor stream format/maxBitRate without a configured profile (9d888c0)
- subsonic: make error codes match Open Subsonic spec (#671) (1b770c9)
- subsonic: return alternate performance name artists from getSimilarArtists (a7bbf55)
- subsonic: return artist roles field (d5ef198)
- subsonic: return band member name artists from getSimilarArtists (c2a11a2)
- subsonic: return consistent shapes (72418cd)
- subsonic: scan and return ISRCs to child data (#688) (52e0fa1)
- subsonic: scan and return record labels (36fe025)
- subsonic: serve cached transcodes directly for Range support (58a2d06)
- subsonic: sort genres alphabetically by default (bf8469c)
- subsonic: support estimateContentLength on stream (2953d23)
- subsonic: support track level play counts (9f706b9), closes #459
- subsonic: use ARTIST_CREDIT for displayArtist fields (44c2d79)
- support track level year tags (#661) (5e916d0)
Bug Fixes
- cmd: don't panic on context.Canceled during shutdown (03a9d06)
- lastfm: don't replace cached artist image with empty on refresh (ec457fb)
- listenbrainz: disable post-quantum TLS to avoid connection reset errors (b2674f8)
- podcast: don't try to rm the podcast directory when deleting an episode (8a860dd)
- podcast: fix crash if itunes extensions are missing (#668) (9473ec7)
- scanner: reduce sqlite lock contention during scans (5daf95c), closes #678
- scanner: reset batch timer on fsnotify Remove events (65c4674), closes #637
- scanner: set track created_at from file birth/mod time (5a5308b), closes #693
- subsonic: allow no podcast id for getPodcasts (737c7f1), closes #686
- subsonic: always report scrobblingEnabled true (a2db490), closes #644
- subsonic: contain playlist paths to prevent cross-user access (0824bed)
- subsonic: enforce playlist ownership on getPlaylist/deletePlaylist (6dd71e6)
- subsonic: provide uncompressed file on /download (#679) (3e436aa)
- subsonic: return artist as track artist in TrackChild (9407450), closes #654
- subsonic: return averageRating as float (0f98064), closes #677
- subsonic: unambiguate all columns (dec4000)
- subsonic: update homepage URL casing (e535e78), closes #664
Miscellaneous Chores
- deps: bump to go1.26 (f55cc3f)
Richer artist metadata demo
with airsonic-refix (fork) (Changes hopefully to be upstreamed soon)
20260515_192059.mp4