Skip to content

feat: add similar songs functionality in agents, and Instant Mix (song-based) to UI#4919

Merged
deluan merged 25 commits intomasterfrom
similar-songs
Jan 25, 2026
Merged

feat: add similar songs functionality in agents, and Instant Mix (song-based) to UI#4919
deluan merged 25 commits intomasterfrom
similar-songs

Conversation

@deluan
Copy link
Member

@deluan deluan commented Jan 21, 2026

Description

This PR implements similar songs functionality in Navidrome, allowing users to discover songs similar to a given track, album, or artist. The implementation leverages external music services (like Last.fm) to retrieve song similarity data and matches them against the user's music library.

Key Features

  • Song-level similarity: Get similar songs based on a specific track with enhanced matching using title, artist, and album metadata
  • Enhanced matching algorithm: Implements a multi-level matching strategy prioritizing MBID, then title+artist+album, then title+artist, and finally title-only matches
  • Comprehensive test coverage: Added extensive unit tests covering all matching scenarios and edge cases
  • Code quality improvements: Refactored complex functions to reduce cyclomatic complexity

New Agent Interfaces

Three new agent interfaces were added to core/agents/interfaces.go:

  1. SimilarSongsByTrackRetriever - Get similar songs based on a specific track

    • GetSimilarSongsByTrack(ctx, id, name, artist, mbid, count) returns songs similar to the given track
  2. SimilarSongsByAlbumRetriever - Get similar songs based on an album

    • GetSimilarSongsByAlbum(ctx, id, name, artist, mbid, count) returns songs similar to tracks on the given album
  3. SimilarSongsByArtistRetriever - Get similar songs based on an artist

    • GetSimilarSongsByArtist(ctx, id, name, mbid, count) returns songs similar to the artist's catalog

Enhanced Song Struct

The agents.Song struct was extended with additional metadata fields to enable better matching:

type Song struct {
    ID         string
    Name       string
    MBID       string
    Artist     string    // NEW
    ArtistMBID string    // NEW
    Album      string    // NEW
    AlbumMBID  string    // NEW
}

Agents Implementation

The Agents meta-agent now implements all three new interfaces:

  • Tries each enabled agent in order until one returns valid data
  • Over-fetches results (using DevExternalArtistFetchMultiplier) since some returned songs may not exist in the local database
  • Properly handles special cases (Unknown Artist, Various Artists)

Last.fm Integration

Added track.getSimilar API support to the Last.fm agent:

  • New GetSimilarSongsByTrack method calls the Last.fm API
  • New response types: SimilarTracks, SimilarTrack, SimilarTrackArtist, SimilarAttr
  • Returns artist name and MBID along with track info for better matching

Smart Matching Algorithm

The new provider_matching.go file contains sophisticated matching logic:

  1. ID matching: Direct match by local media file ID
  2. MBID matching: Match by MusicBrainz recording ID
  3. Title + metadata matching: Multi-level fallback:
    • Title + ArtistMBID + AlbumMBID (most specific)
    • Title + ArtistMBID + Album name
    • Title + Artist name + Album name
    • Title + ArtistMBID
    • Title + Artist name
    • Title only (least specific)

Results are sorted by: starred status, rating, year (ascending), compilation status

Refactoring

  • Renamed ArtistRadio to SimilarSongs for clarity and consistency
  • Extracted song matching functionality into dedicated provider_matching.go file
  • Reduced cyclomatic complexity by breaking down large functions into smaller, focused helpers

Type of Change

  • New feature
  • Bug fix
  • Documentation update
  • Refactor
  • Other (please describe):

Checklist

  • My code follows the project's coding style
  • I have tested the changes locally
  • I have added or updated documentation as needed
  • I have added tests that prove my fix/feature works
  • All existing and new tests pass

How to Test

  1. Configure Navidrome with Last.fm API credentials
  2. Use the Subsonic API endpoint getSimilarSongs2 with a song ID
  3. Verify that similar songs are returned and correctly matched to your library
  4. Check that the matching prioritizes exact metadata matches over fuzzy matches
  5. Run the test suite: make test

Files Changed

  • core/agents/interfaces.go - New interfaces and extended Song struct
  • core/agents/agents.go - Meta-agent implementations for new interfaces
  • core/agents/agents_test.go - Tests for new agent methods
  • adapters/lastfm/agent.go - Last.fm GetSimilarSongsByTrack implementation
  • adapters/lastfm/client.go - Last.fm API client for track.getSimilar
  • adapters/lastfm/responses.go - Response types for similar tracks
  • adapters/lastfm/*_test.go - Tests for Last.fm changes
  • core/external/provider.go - SimilarSongs method (renamed from ArtistRadio)
  • core/external/provider_matching.go - Extracted matching logic
  • core/external/provider_matching_test.go - Tests for matching logic
  • core/external/provider_similarsongs_test.go - Tests for SimilarSongs
  • server/subsonic/browsing.go - Updated to use renamed method
  • tests/fixtures/lastfm.track.getsimilar*.json - Test fixtures

…song similarity retrieval

Signed-off-by: Deluan <deluan@navidrome.org>
…ils and update tests

Signed-off-by: Deluan <deluan@navidrome.org>
…g in loadTracksByTitleAndArtist

Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @deluan, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant new capability to Navidrome, allowing users to discover music similar to a specific track, album, or artist from their library. It intelligently integrates with external music services to retrieve similarity data and then applies a sophisticated, multi-criteria matching process to find corresponding songs within the user's local collection. This enhancement aims to provide a richer and more dynamic music discovery experience.

Highlights

  • Similar Songs Functionality: Introduced a new feature to find similar songs based on a given track, album, or artist, leveraging external music services like Last.fm.
  • Enhanced Matching Algorithm: Implemented a multi-level matching strategy to accurately link external similar song data with the user's local music library. This prioritizes matches by MusicBrainz ID (MBID), then title+artist+album, then title+artist, and finally title-only.
  • Last.fm Integration: Added new methods to the Last.fm agent to fetch similar track data, including new API client calls and response structures.
  • Core Agent Updates: The core Agents meta-agent now includes new retriever interfaces and methods (GetSimilarSongsByTrack, GetSimilarSongsByAlbum, GetSimilarSongsByArtist) to aggregate similar song results from various configured agents.
  • Refactored External Provider: The external provider has been refactored to dispatch similar song requests based on the entity type (track, album, or artist) and includes a fallback mechanism to the existing artist-based radio algorithm if entity-specific similarity data is not found.
  • Comprehensive Testing: Extensive unit tests have been added for the new Last.fm agent methods, the core Agents dispatch logic, and the complex song matching algorithm to ensure robustness and correctness.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a significant and well-implemented feature for finding similar songs. The changes are well-structured, separating the Last.fm adapter logic, agent aggregation, and the new provider-level song matching logic. The hierarchical matching algorithm is a robust approach to finding songs in the user's library. The code is also accompanied by comprehensive tests. I've identified a potential logic bug in the new matching implementation and a couple of opportunities for code improvement, which are detailed in the review comments. Overall, this is an excellent contribution.

…sponse length

Signed-off-by: Deluan <deluan@navidrome.org>
…ar songs

Signed-off-by: Deluan <deluan@navidrome.org>
…ar songs

Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
@deluan deluan marked this pull request as ready for review January 22, 2026 00:05
Copilot AI review requested due to automatic review settings January 22, 2026 00:05
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 977915252e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a similar songs feature for Navidrome, allowing users to discover songs similar to a given track, album, or artist. The implementation leverages external music services (like Last.fm) to retrieve similarity data and matches them against the user's local library using an enhanced multi-level matching algorithm.

Changes:

  • Added three new agent interfaces for track-level, album-level, and artist-level similar song retrieval
  • Extended the agents.Song struct with artist and album metadata fields for improved matching accuracy
  • Implemented a sophisticated matching algorithm that prioritizes matches by ID, MBID, and progressively less specific metadata combinations
  • Renamed ArtistRadio to SimilarSongs for clarity and added entity-type dispatching with fallback to the existing algorithm

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.

Show a summary per file
File Description
core/agents/interfaces.go Added three new retriever interfaces and extended Song struct with artist/album metadata fields
core/agents/agents.go Implemented meta-agent methods for new interfaces with refactored helper functions to reduce duplication
core/agents/agents_test.go Added comprehensive test coverage for all three new similar songs methods
adapters/lastfm/agent.go Implemented GetSimilarSongsByTrack using Last.fm's track.getSimilar API
adapters/lastfm/client.go Added trackGetSimilar client method for Last.fm API integration
adapters/lastfm/responses.go Added response types for similar tracks API
adapters/lastfm/client_test.go Added tests for track.getSimilar client method
adapters/lastfm/agent_test.go Added tests for GetSimilarSongsByTrack agent method
core/external/provider.go Renamed ArtistRadio to SimilarSongs, added entity-type dispatching with fallback, refactored to use shared matching logic
core/external/provider_matching.go Extracted sophisticated multi-level matching algorithm into dedicated file
core/external/provider_matching_test.go Added comprehensive tests for matching algorithm covering all priority levels
core/external/provider_similarsongs_test.go Added tests for SimilarSongs method covering all entity types and fallback scenarios
core/external/provider_artistradio_test.go Removed old test file (functionality moved to provider_similarsongs_test.go)
core/external/extdata_helper_test.go Added mock implementations for new similar songs interfaces
server/subsonic/browsing.go Updated to call renamed SimilarSongs method
tests/fixtures/lastfm.track.getsimilar.json Added test fixture with sample Last.fm similar tracks response
tests/fixtures/lastfm.track.getsimilar.unknown.json Added test fixture for unknown track scenario

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

… and artist

Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
@deluan deluan changed the title feat: Add similar songs functionality feat: add similar songs functionality in agents Jan 22, 2026
…ions

Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
…ong processing

Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
… shuffle option

Signed-off-by: Deluan <deluan@navidrome.org>
…e threshold

Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
… specificity levels

Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
… scoring

Signed-off-by: Deluan <deluan@navidrome.org>
…ing and prioritization

Signed-off-by: Deluan <deluan@navidrome.org>
@deluan deluan changed the title feat: add similar songs functionality in agents feat: add similar songs functionality in agents, and Instant Mix (song-based) to UI Jan 25, 2026
@deluan deluan merged commit 772d1f3 into master Jan 25, 2026
8 of 11 checks passed
@deluan deluan deleted the similar-songs branch January 25, 2026 21:16
alexlebens pushed a commit to alexlebens/infrastructure that referenced this pull request Feb 3, 2026
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [deluan/navidrome](https://github.com/navidrome/navidrome) | minor | `0.59.0` → `0.60.0` |

---

### Release Notes

<details>
<summary>navidrome/navidrome (deluan/navidrome)</summary>

### [`v0.60.0`](https://github.com/navidrome/navidrome/releases/tag/v0.60.0)

[Compare Source](navidrome/navidrome@v0.59.0...v0.60.0)

#### Plugins

This release introduces a major rewrite of the experimental **Plugin System**, now with multi-language PDK support, enabling developers to extend Navidrome's functionality using WebAssembly-based plugins written in Go, Rust, Python or JavaScript. Plugins run in a secure sandbox and can provide additional metadata sources, custom integrations, and server-side enhancements. Users can now easily configure plugins directly from the UI through a new JSONForms-based configuration interface.

A couple of working plugins are already available:

- [AudioMuse-AI integration](https://github.com/NeptuneHub/AudioMuse-AI-NV-plugin)
- [ListenBrainz Daily Playlist Importer](https://github.com/kgarner7/navidrome-listenbrainz-daily-playlist)
- [Discord Rich Presence](https://github.com/navidrome/discord-rich-presence-plugin)

For more plugins, keep an eye on the tag [navidrome-plugins](https://github.com/topics/navidrome-plugin) in GitHub.

More details and instructions on how to use and manage plugins can be found in our [documentation](https://www.navidrome.org/docs/usage/features/plugins/).
New documentation will soon be added with details on how to create new plugins.

#### Metadata Extraction

Additionally, this version includes a **pure-Go metadata extractor** built on top of the new `go-taglib` library. This is a significant step toward removing the C++ TagLib dependency, which will simplify cross-platform builds and packaging in future releases. The new extractor is activated by default, but in case of any issues you can revert to the previous implementation by setting `Scanner.Extractor="legacy-taglib"` configuration option.

#### Instant Mix

The Instant Mix feature generates a playlist of similar songs based on a selected track. By default, it retrieves similar songs from Last.fm (if configured with an API key) or falls back to Deezer. It can also be configured to use external plugins, like [AudioMuse-AI](https://github.com/NeptuneHub/AudioMuse-AI-NV-plugin) for sonic analysis-based similarity recommendations.

#### New and Changed Configuration Options

##### Plugin System Options

| Option               | Default   | Description                                                   |
| -------------------- | --------- | ------------------------------------------------------------- |
| `Plugins.Enabled`    | `true`    | Enable/disable the plugin system                              |
| `Plugins.Folder`     | `""`      | Path to the plugins directory. Default: `$DataFolder/Plugins` |
| `Plugins.CacheSize`  | `"200MB"` | Maximum cache size for storing compiled plugin WASM modules   |
| `Plugins.AutoReload` | `false`   | Automatically detect new/changed/removed plugins              |
| `Plugins.LogLevel`   | `""`      | Override log level for plugin-related messages                |

##### Subsonic API Options

| Option                         | Default | Description                                                                                                                    |
| ------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `Subsonic.MinimalClients`      | `""`    | Comma-separated list of clients that receive reduced API responses (useful for resource-constrained devices like smartwatches) |
| `Subsonic.EnableAverageRating` | `true`  | Include average rating in API responses                                                                                        |

##### Metadata & Matching Options

| Option                       | Default | Description                                                                                        |
| ---------------------------- | ------- | -------------------------------------------------------------------------------------------------- |
| `SimilarSongsMatchThreshold` | `85`    | Minimum similarity score (0-100) for matching similar songs from external sources to local library |
| `LastFM.Language`            | `"en"`  | Now supports comma-separated list of languages (e.g., `"de,fr,en"`) for metadata fallback          |
| `Deezer.Language`            | `"en"`  | Now supports comma-separated list of languages for metadata fallback                               |

##### Renamed Options (Deprecation Notice)

The following options have been renamed. The old names still work but will be removed in a future release:

| Old Name                                      | New Name                   |
| --------------------------------------------- | -------------------------- |
| `HTTPSecurityHeaders.CustomFrameOptionsValue` | `HTTPHeaders.FrameOptions` |

#### Security

- Fix potential XSS vulnerability by sanitizing user-supplied data before rendering (GHSA-rh3r-8pxm-hg4w). ([d7ec735](navidrome/navidrome@d7ec7355c) by [@&#8203;AlexGustafsson](https://github.com/AlexGustafsson))
- Fix potential DoS vulnerability in cover art upscaling by clamping requested square size to original dimensions (GHSA-hrr4-3wgr-68x3). ([77367548](navidrome/navidrome@77367548f) by [@&#8203;deluan](https://github.com/deluan)). Thanks to [@&#8203;yunfachi](https://github.com/yunfachi)

#### Added

- Plugins:
  - Add new WebAssembly-based plugin system with multi-language PDK support (Go, Rust, Python). ([#&#8203;4833](navidrome/navidrome#4833) by [@&#8203;deluan](https://github.com/deluan))
  - Add JSONForms-based plugin configuration UI. ([#&#8203;4911](navidrome/navidrome#4911) by [@&#8203;deluan](https://github.com/deluan))
  - Add similar songs retrieval functions to plugins API. ([#&#8203;4933](navidrome/navidrome#4933) by [@&#8203;deluan](https://github.com/deluan))

- Server:
  - Add pure-Go metadata extractor (`go-taglib`) as alternative to FFmpeg-based extraction. ([#&#8203;4902](navidrome/navidrome#4902) by [@&#8203;deluan](https://github.com/deluan))
  - Add support for reading embedded images using the new taglib extractor by default. ([66474fc](navidrome/navidrome@66474fc9f) by [@&#8203;deluan](https://github.com/deluan))
  - Add Instant Mix (song-based Similar Songs) functionality with MBID, ISRC and Title/Artist fuzzy matching. ([#&#8203;4919](navidrome/navidrome#4919), [#&#8203;4946](navidrome/navidrome#4946) by [@&#8203;deluan](https://github.com/deluan))
  - Add support for multiple languages when fetching metadata from Last.fm and Deezer. ([#&#8203;4952](navidrome/navidrome#4952) by [@&#8203;deluan](https://github.com/deluan))
  - Add `Subsonic.MinimalClients` configuration option for improved compatibility with minimal Subsonic clients. Default list is `"SubMusic"` ([#&#8203;4850](navidrome/navidrome#4850) by [@&#8203;typhoon2099](https://github.com/typhoon2099))
  - Add support for public/private playlists in NSP import. ([c5447a6](navidrome/navidrome@c5447a637) by [@&#8203;deluan](https://github.com/deluan))
  - Add RISCV64 builds. ([#&#8203;4949](navidrome/navidrome#4949) by [@&#8203;MichaIng](https://github.com/MichaIng))

- UI Features:
  - Add composer field to table views. ([#&#8203;4857](navidrome/navidrome#4857) by [@&#8203;AlexGustafsson](https://github.com/AlexGustafsson))
  - Add prompt before closing window if music is playing. ([#&#8203;4899](navidrome/navidrome#4899) by [@&#8203;alannnna](https://github.com/alannnna))
  - Add Nautiline-like theme. ([#&#8203;4909](navidrome/navidrome#4909) by [@&#8203;borisrorsvort](https://github.com/borisrorsvort))
  - Add multiline support and resizing for playlist comment input. ([6fce30c](navidrome/navidrome@6fce30c13) by [@&#8203;deluan](https://github.com/deluan))

- Subsonic API:
  - Add `avgRating` field from Subsonic spec. ([#&#8203;4900](navidrome/navidrome#4900) by [@&#8203;terry90](https://github.com/terry90))

- Insights:
  - Add insights collection for Scanner.Extractor configuration to measure go-taglib usage. ([63517e9](navidrome/navidrome@63517e904) by [@&#8203;deluan](https://github.com/deluan))
  - Add file suffix counting to insights. ([0473c50](navidrome/navidrome@0473c50b4) by [@&#8203;deluan](https://github.com/deluan))

#### Changed

- Optimize cross-library move detection for single-library setups. ([#&#8203;4888](navidrome/navidrome#4888) by [@&#8203;deluan](https://github.com/deluan))
- Improve Deezer artist search ranking. ([a081569](navidrome/navidrome@a081569ed) by [@&#8203;deluan](https://github.com/deluan))
- Rename `HTTPSecurityHeaders.CustomFrameOptionsValue` to `HTTPHeaders.FrameOptions`. ([7ccf44b](navidrome/navidrome@7ccf44b8e) by [@&#8203;deluan](https://github.com/deluan))
- Update translations: Bulgarian, Catalan, German, Greek, Spanish, Finnish, French, Galician, Indonesian, Dutch, Polish, Russian, Slovenian, Swedish, Thai by [POEditor contributors](https://www.navidrome.org/docs/developers/translations/).
- Update Spanish translations. ([#&#8203;4904](navidrome/navidrome#4904) by [@&#8203;abrugues](https://github.com/abrugues))
- Update Basque translation. ([#&#8203;4815](navidrome/navidrome#4815) by [@&#8203;xabirequejo](https://github.com/xabirequejo))

#### Fixed

- Playlists:
  - Fix M3U playlist import failing for paths with different UTF/Unicode representations (NFC/NFD normalization). ([#&#8203;4890](navidrome/navidrome#4890) by [@&#8203;deluan](https://github.com/deluan))
  - Fix playlist name sorting to be case-insensitive. ([#&#8203;4845](navidrome/navidrome#4845) by [@&#8203;deluan](https://github.com/deluan))

- UI:
  - Fix various UI issues and improve styling coherence. ([#&#8203;4910](navidrome/navidrome#4910) by [@&#8203;borisrorsvort](https://github.com/borisrorsvort))
  - Fix AMusic theme player buttons and delete button color. ([#&#8203;4797](navidrome/navidrome#4797) by [@&#8203;dragonish](https://github.com/dragonish))
  - Fix export missing files showing only first 1000 results. ([017676c](navidrome/navidrome@017676c45) by [@&#8203;deluan](https://github.com/deluan))

- Scanner:
  - Fix `FullScanInProgress` not reflecting current scan request during interrupted scans. ([8c80be5](navidrome/navidrome@8c80be56d) by [@&#8203;deluan](https://github.com/deluan))
  - Fix "Expression tree is too large" error by executing GetFolderUpdateInfo in batches. ([cde5992](navidrome/navidrome@cde5992c4) by [@&#8203;deluan](https://github.com/deluan))
  - Fix stale role associations when artist role changes. ([2d7b716](navidrome/navidrome@2d7b71683) by [@&#8203;deluan](https://github.com/deluan))
  - Fix infinite recursion in PID configuration. ([1c4a7e8](navidrome/navidrome@1c4a7e855) by [@&#8203;deluan](https://github.com/deluan))
  - Fix default PIDs not being set for Album and Track. In some circumstances it could lead to empty PIDs ([71f549a](navidrome/navidrome@71f549afb) by [@&#8203;deluan](https://github.com/deluan))
  - Fix error when watcher detected too many folder changes, causing the scan to fail. ([9ed309a](navidrome/navidrome@9ed309ac8) by [@&#8203;deluan](https://github.com/deluan))
  - Show scan errors in the UI more consistently. ([ebbc31f](navidrome/navidrome@ebbc31f1a) by [@&#8203;deluan](https://github.com/deluan))

- Subsonic API:
  - Fix username parameter validation for `getUser` endpoint. ([6ed6524](navidrome/navidrome@6ed652475) by [@&#8203;deluan](https://github.com/deluan))
  - Fix `getNowPlaying` endpoint to always be enabled regardless of configuration. ([603cccd](navidrome/navidrome@603cccde1) by [@&#8203;deluan](https://github.com/deluan))

- Server:
  - Fix JWT-related errors being exposed on share page. ([#&#8203;4892](navidrome/navidrome#4892) by [@&#8203;AlexGustafsson](https://github.com/AlexGustafsson))
  - Fix user context not preserved in async NowPlaying dispatch. ([396eee4](navidrome/navidrome@396eee48c) by [@&#8203;deluan](https://github.com/deluan))
  - Fix environment variable configuration loading not being logged when no config file is found. ([51ca2de](navidrome/navidrome@51ca2dee6) by [@&#8203;deluan](https://github.com/deluan))
  - Fix items with no annotation not being included for `starred=false` filter, handle `has_rating=false`. ([#&#8203;4921](navidrome/navidrome#4921) by [@&#8203;kgarner7](https://github.com/kgarner7))
  - Last.fm's `scrobble` and `updateNowPlaying` methods should send parameters in request body. ([51026de](navidrome/navidrome@51026de80) by [@&#8203;deluan](https://github.com/deluan))

#### New Contributors

- [@&#8203;alannnna](https://github.com/alannnna) made their first contribution in [#&#8203;4899](navidrome/navidrome#4899)
- [@&#8203;abrugues](https://github.com/abrugues) made their first contribution in [#&#8203;4904](navidrome/navidrome#4904)
- [@&#8203;AlexGustafsson](https://github.com/AlexGustafsson) made their first contribution in [#&#8203;4857](navidrome/navidrome#4857)
- [@&#8203;borisrorsvort](https://github.com/borisrorsvort) made their first contribution in [#&#8203;4909](navidrome/navidrome#4909)
- [@&#8203;dragonish](https://github.com/dragonish) made their first contribution in [#&#8203;4797](navidrome/navidrome#4797)
- [@&#8203;MichaIng](https://github.com/MichaIng) made their first contribution in [#&#8203;4949](navidrome/navidrome#4949)
- [@&#8203;terry90](https://github.com/terry90) made their first contribution in [#&#8203;4900](navidrome/navidrome#4900)
- [@&#8203;typhoon2099](https://github.com/typhoon2099) made their first contribution in [#&#8203;4850](navidrome/navidrome#4850)

**Full Changelog**: <navidrome/navidrome@v0.59.0...v0.60.0>

#### Helping out

This release is only possible thanks to the support of some **awesome people**!

Want to be one of them?
You can [sponsor](https://github.com/sponsors/deluan), pay me a [Ko-fi](https://ko-fi.com/deluan),
or [contribute with code](https://www.navidrome.org/docs/developers/).

#### Where to go next?

- Read installation instructions on our [website](https://www.navidrome.org/docs/installation/).
- Host Navidrome on [PikaPods](https://www.pikapods.com/pods/navidrome) for a simple cloud solution.
- Reach out on [Discord](https://discord.gg/xh7j7yF), [Reddit](https://www.reddit.com/r/navidrome/)
  and [Twitter](https://twitter.com/navidrome)!

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4wLjIiLCJ1cGRhdGVkSW5WZXIiOiI0My4wLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbImltYWdlIl19-->

Reviewed-on: https://gitea.alexlebens.dev/alexlebens/infrastructure/pulls/3687
Co-authored-by: Renovate Bot <renovate-bot@alexlebens.net>
Co-committed-by: Renovate Bot <renovate-bot@alexlebens.net>
renovate bot added a commit to sdwilsh/ansible-playbooks that referenced this pull request Feb 9, 2026
##### [\`0.60.0\`](https://github.com/navidrome/navidrome/releases/tag/v0.60.0)

##### Plugins

This release introduces a major rewrite of the experimental **Plugin System**, now with multi-language PDK support, enabling developers to extend Navidrome's functionality using WebAssembly-based plugins written in Go, Rust, Python or JavaScript. Plugins run in a secure sandbox and can provide additional metadata sources, custom integrations, and server-side enhancements. Users can now easily configure plugins directly from the UI through a new JSONForms-based configuration interface.

A couple of working plugins are already available:

- [AudioMuse-AI integration](https://github.com/NeptuneHub/AudioMuse-AI-NV-plugin)
- [ListenBrainz Daily Playlist Importer](https://github.com/kgarner7/navidrome-listenbrainz-daily-playlist)
- [Discord Rich Presence](https://github.com/navidrome/discord-rich-presence-plugin)

For more plugins, keep an eye on the tag [navidrome-plugins](https://github.com/topics/navidrome-plugin) in GitHub.

More details and instructions on how to use and manage plugins can be found in our [documentation](https://www.navidrome.org/docs/usage/features/plugins/).
New documentation will soon be added with details on how to create new plugins.

##### Metadata Extraction

Additionally, this version includes a **pure-Go metadata extractor** built on top of the new `go-taglib` library. This is a significant step toward removing the C++ TagLib dependency, which will simplify cross-platform builds and packaging in future releases. The new extractor is activated by default, but in case of any issues you can revert to the previous implementation by setting `Scanner.Extractor="legacy-taglib"` configuration option.

##### Instant Mix

The Instant Mix feature generates a playlist of similar songs based on a selected track. By default, it retrieves similar songs from Last.fm (if configured with an API key) or falls back to Deezer. It can also be configured to use external plugins, like [AudioMuse-AI](https://github.com/NeptuneHub/AudioMuse-AI-NV-plugin) for sonic analysis-based similarity recommendations.

##### New and Changed Configuration Options

##### Plugin System Options

| Option               | Default   | Description                                                   |
| -------------------- | --------- | ------------------------------------------------------------- |
| `Plugins.Enabled`    | `true`    | Enable/disable the plugin system                              |
| `Plugins.Folder`     | `""`      | Path to the plugins directory. Default: `$DataFolder/Plugins` |
| `Plugins.CacheSize`  | `"200MB"` | Maximum cache size for storing compiled plugin WASM modules   |
| `Plugins.AutoReload` | `false`   | Automatically detect new/changed/removed plugins              |
| `Plugins.LogLevel`   | `""`      | Override log level for plugin-related messages                |

##### Subsonic API Options

| Option                         | Default | Description                                                                                                                    |
| ------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `Subsonic.MinimalClients`      | `""`    | Comma-separated list of clients that receive reduced API responses (useful for resource-constrained devices like smartwatches) |
| `Subsonic.EnableAverageRating` | `true`  | Include average rating in API responses                                                                                        |

##### Metadata & Matching Options

| Option                       | Default | Description                                                                                        |
| ---------------------------- | ------- | -------------------------------------------------------------------------------------------------- |
| `SimilarSongsMatchThreshold` | `85`    | Minimum similarity score (0-100) for matching similar songs from external sources to local library |
| `LastFM.Language`            | `"en"`  | Now supports comma-separated list of languages (e.g., `"de,fr,en"`) for metadata fallback          |
| `Deezer.Language`            | `"en"`  | Now supports comma-separated list of languages for metadata fallback                               |

##### Renamed Options (Deprecation Notice)

The following options have been renamed. The old names still work but will be removed in a future release:

| Old Name                                      | New Name                   |
| --------------------------------------------- | -------------------------- |
| `HTTPSecurityHeaders.CustomFrameOptionsValue` | `HTTPHeaders.FrameOptions` |

##### Security

- Fix potential XSS vulnerability by sanitizing user-supplied data before rendering ([GHSA-rh3r-8pxm-hg4w](GHSA-rh3r-8pxm-hg4w)). ([d7ec735](navidrome/navidrome@d7ec7355c) by [@AlexGustafsson](https://github.com/AlexGustafsson))
- Fix potential DoS vulnerability in cover art upscaling by clamping requested square size to original dimensions ([GHSA-hrr4-3wgr-68x3](GHSA-hrr4-3wgr-68x3)). ([77367548](navidrome/navidrome@77367548f) by [@deluan](https://github.com/deluan)). Thanks to [@yunfachi](https://github.com/yunfachi)

##### Added

- Plugins:
  - Add new WebAssembly-based plugin system with multi-language PDK support (Go, Rust, Python). ([#4833](navidrome/navidrome#4833) by [@deluan](https://github.com/deluan))
  - Add JSONForms-based plugin configuration UI. ([#4911](navidrome/navidrome#4911) by [@deluan](https://github.com/deluan))
  - Add similar songs retrieval functions to plugins API. ([#4933](navidrome/navidrome#4933) by [@deluan](https://github.com/deluan))

- Server:
  - Add pure-Go metadata extractor (`go-taglib`) as alternative to FFmpeg-based extraction. ([#4902](navidrome/navidrome#4902) by [@deluan](https://github.com/deluan))
  - Add support for reading embedded images using the new taglib extractor by default. ([66474fc](navidrome/navidrome@66474fc9f) by [@deluan](https://github.com/deluan))
  - Add Instant Mix (song-based Similar Songs) functionality with MBID, ISRC and Title/Artist fuzzy matching. ([#4919](navidrome/navidrome#4919), [#4946](navidrome/navidrome#4946) by [@deluan](https://github.com/deluan))
  - Add support for multiple languages when fetching metadata from Last.fm and Deezer. ([#4952](navidrome/navidrome#4952) by [@deluan](https://github.com/deluan))
  - Add `Subsonic.MinimalClients` configuration option for improved compatibility with minimal Subsonic clients. Default list is `"SubMusic"` ([#4850](navidrome/navidrome#4850) by [@typhoon2099](https://github.com/typhoon2099))
  - Add support for public/private playlists in NSP import. ([c5447a6](navidrome/navidrome@c5447a637) by [@deluan](https://github.com/deluan))
  - Add RISCV64 builds. ([#4949](navidrome/navidrome#4949) by [@MichaIng](https://github.com/MichaIng))

- UI Features:
  - Add composer field to table views. ([#4857](navidrome/navidrome#4857) by [@AlexGustafsson](https://github.com/AlexGustafsson))
  - Add prompt before closing window if music is playing. ([#4899](navidrome/navidrome#4899) by [@alannnna](https://github.com/alannnna))
  - Add Nautiline-like theme. ([#4909](navidrome/navidrome#4909) by [@borisrorsvort](https://github.com/borisrorsvort))
  - Add multiline support and resizing for playlist comment input. ([6fce30c](navidrome/navidrome@6fce30c13) by [@deluan](https://github.com/deluan))

- Subsonic API:
  - Add `avgRating` field from Subsonic spec. ([#4900](navidrome/navidrome#4900) by [@terry90](https://github.com/terry90))

- Insights:
  - Add insights collection for Scanner.Extractor configuration to measure go-taglib usage. ([63517e9](navidrome/navidrome@63517e904) by [@deluan](https://github.com/deluan))
  - Add file suffix counting to insights. ([0473c50](navidrome/navidrome@0473c50b4) by [@deluan](https://github.com/deluan))

##### Changed

- Optimize cross-library move detection for single-library setups. ([#4888](navidrome/navidrome#4888) by [@deluan](https://github.com/deluan))
- Improve Deezer artist search ranking. ([a081569](navidrome/navidrome@a081569ed) by [@deluan](https://github.com/deluan))
- Rename `HTTPSecurityHeaders.CustomFrameOptionsValue` to `HTTPHeaders.FrameOptions`. ([7ccf44b](navidrome/navidrome@7ccf44b8e) by [@deluan](https://github.com/deluan))
- Update translations: Bulgarian, Catalan, German, Greek, Spanish, Finnish, French, Galician, Indonesian, Dutch, Polish, Russian, Slovenian, Swedish, Thai by [POEditor contributors](https://www.navidrome.org/docs/developers/translations/).
- Update Spanish translations. ([#4904](navidrome/navidrome#4904) by [@abrugues](https://github.com/abrugues))
- Update Basque translation. ([#4815](navidrome/navidrome#4815) by [@xabirequejo](https://github.com/xabirequejo))

##### Fixed

- Playlists:
  - Fix M3U playlist import failing for paths with different UTF/Unicode representations (NFC/NFD normalization). ([#4890](navidrome/navidrome#4890) by [@deluan](https://github.com/deluan))
  - Fix playlist name sorting to be case-insensitive. ([#4845](navidrome/navidrome#4845) by [@deluan](https://github.com/deluan))

- UI:
  - Fix various UI issues and improve styling coherence. ([#4910](navidrome/navidrome#4910) by [@borisrorsvort](https://github.com/borisrorsvort))
  - Fix AMusic theme player buttons and delete button color. ([#4797](navidrome/navidrome#4797) by [@dragonish](https://github.com/dragonish))
  - Fix export missing files showing only first 1000 results. ([017676c](navidrome/navidrome@017676c45) by [@deluan](https://github.com/deluan))

- Scanner:
  - Fix `FullScanInProgress` not reflecting current scan request during interrupted scans. ([8c80be5](navidrome/navidrome@8c80be56d) by [@deluan](https://github.com/deluan))
  - Fix "Expression tree is too large" error by executing GetFolderUpdateInfo in batches. ([cde5992](navidrome/navidrome@cde5992c4) by [@deluan](https://github.com/deluan))
  - Fix stale role associations when artist role changes. ([2d7b716](navidrome/navidrome@2d7b71683) by [@deluan](https://github.com/deluan))
  - Fix infinite recursion in PID configuration. ([1c4a7e8](navidrome/navidrome@1c4a7e855) by [@deluan](https://github.com/deluan))
  - Fix default PIDs not being set for Album and Track. In some circumstances it could lead to empty PIDs ([71f549a](navidrome/navidrome@71f549afb) by [@deluan](https://github.com/deluan))
  - Fix error when watcher detected too many folder changes, causing the scan to fail. ([9ed309a](navidrome/navidrome@9ed309ac8) by [@deluan](https://github.com/deluan))
  - Show scan errors in the UI more consistently. ([ebbc31f](navidrome/navidrome@ebbc31f1a) by [@deluan](https://github.com/deluan))

- Subsonic API:
  - Fix username parameter validation for `getUser` endpoint. ([6ed6524](navidrome/navidrome@6ed652475) by [@deluan](https://github.com/deluan))
  - Fix `getNowPlaying` endpoint to always be enabled regardless of configuration. ([603cccd](navidrome/navidrome@603cccde1) by [@deluan](https://github.com/deluan))

- Server:
  - Fix JWT-related errors being exposed on share page. ([#4892](navidrome/navidrome#4892) by [@AlexGustafsson](https://github.com/AlexGustafsson))
  - Fix user context not preserved in async NowPlaying dispatch. ([396eee4](navidrome/navidrome@396eee48c) by [@deluan](https://github.com/deluan))
  - Fix environment variable configuration loading not being logged when no config file is found. ([51ca2de](navidrome/navidrome@51ca2dee6) by [@deluan](https://github.com/deluan))
  - Fix items with no annotation not being included for `starred=false` filter, handle `has_rating=false`. ([#4921](navidrome/navidrome#4921) by [@kgarner7](https://github.com/kgarner7))
  - Last.fm's `scrobble` and `updateNowPlaying` methods should send parameters in request body. ([51026de](navidrome/navidrome@51026de80) by [@deluan](https://github.com/deluan))

##### New Contributors

- [@alannnna](https://github.com/alannnna) made their first contribution in [#4899](navidrome/navidrome#4899)
- [@abrugues](https://github.com/abrugues) made their first contribution in [#4904](navidrome/navidrome#4904)
- [@AlexGustafsson](https://github.com/AlexGustafsson) made their first contribution in [#4857](navidrome/navidrome#4857)
- [@borisrorsvort](https://github.com/borisrorsvort) made their first contribution in [#4909](navidrome/navidrome#4909)
- [@dragonish](https://github.com/dragonish) made their first contribution in [#4797](navidrome/navidrome#4797)
- [@MichaIng](https://github.com/MichaIng) made their first contribution in [#4949](navidrome/navidrome#4949)
- [@terry90](https://github.com/terry90) made their first contribution in [#4900](navidrome/navidrome#4900)
- [@typhoon2099](https://github.com/typhoon2099) made their first contribution in [#4850](navidrome/navidrome#4850)

**Full Changelog**: <navidrome/navidrome@v0.59.0...v0.60.0>

##### Helping out

This release is only possible thanks to the support of some **awesome people**!

Want to be one of them?
You can [sponsor](https://github.com/sponsors/deluan), pay me a [Ko-fi](https://ko-fi.com/deluan), or [contribute with code](https://www.navidrome.org/docs/developers/).

##### Where to go next?

- Read installation instructions on our [website](https://www.navidrome.org/docs/installation/).
- Host Navidrome on [PikaPods](https://www.pikapods.com/pods/navidrome) for a simple cloud solution.
- Reach out on [Discord](https://discord.gg/xh7j7yF), [Reddit](https://www.reddit.com/r/navidrome/) and [Twitter](https://twitter.com/navidrome)!
renovate bot added a commit to sdwilsh/ansible-playbooks that referenced this pull request Feb 9, 2026
##### [\`0.60.0\`](https://github.com/navidrome/navidrome/releases/tag/v0.60.0)

##### Plugins

This release introduces a major rewrite of the experimental **Plugin System**, now with multi-language PDK support, enabling developers to extend Navidrome's functionality using WebAssembly-based plugins written in Go, Rust, Python or JavaScript. Plugins run in a secure sandbox and can provide additional metadata sources, custom integrations, and server-side enhancements. Users can now easily configure plugins directly from the UI through a new JSONForms-based configuration interface.

A couple of working plugins are already available:

- [AudioMuse-AI integration](https://github.com/NeptuneHub/AudioMuse-AI-NV-plugin)
- [ListenBrainz Daily Playlist Importer](https://github.com/kgarner7/navidrome-listenbrainz-daily-playlist)
- [Discord Rich Presence](https://github.com/navidrome/discord-rich-presence-plugin)

For more plugins, keep an eye on the tag [navidrome-plugins](https://github.com/topics/navidrome-plugin) in GitHub.

More details and instructions on how to use and manage plugins can be found in our [documentation](https://www.navidrome.org/docs/usage/features/plugins/).
New documentation will soon be added with details on how to create new plugins.

##### Metadata Extraction

Additionally, this version includes a **pure-Go metadata extractor** built on top of the new `go-taglib` library. This is a significant step toward removing the C++ TagLib dependency, which will simplify cross-platform builds and packaging in future releases. The new extractor is activated by default, but in case of any issues you can revert to the previous implementation by setting `Scanner.Extractor="legacy-taglib"` configuration option.

##### Instant Mix

The Instant Mix feature generates a playlist of similar songs based on a selected track. By default, it retrieves similar songs from Last.fm (if configured with an API key) or falls back to Deezer. It can also be configured to use external plugins, like [AudioMuse-AI](https://github.com/NeptuneHub/AudioMuse-AI-NV-plugin) for sonic analysis-based similarity recommendations.

##### New and Changed Configuration Options

##### Plugin System Options

| Option               | Default   | Description                                                   |
| -------------------- | --------- | ------------------------------------------------------------- |
| `Plugins.Enabled`    | `true`    | Enable/disable the plugin system                              |
| `Plugins.Folder`     | `""`      | Path to the plugins directory. Default: `$DataFolder/Plugins` |
| `Plugins.CacheSize`  | `"200MB"` | Maximum cache size for storing compiled plugin WASM modules   |
| `Plugins.AutoReload` | `false`   | Automatically detect new/changed/removed plugins              |
| `Plugins.LogLevel`   | `""`      | Override log level for plugin-related messages                |

##### Subsonic API Options

| Option                         | Default | Description                                                                                                                    |
| ------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `Subsonic.MinimalClients`      | `""`    | Comma-separated list of clients that receive reduced API responses (useful for resource-constrained devices like smartwatches) |
| `Subsonic.EnableAverageRating` | `true`  | Include average rating in API responses                                                                                        |

##### Metadata & Matching Options

| Option                       | Default | Description                                                                                        |
| ---------------------------- | ------- | -------------------------------------------------------------------------------------------------- |
| `SimilarSongsMatchThreshold` | `85`    | Minimum similarity score (0-100) for matching similar songs from external sources to local library |
| `LastFM.Language`            | `"en"`  | Now supports comma-separated list of languages (e.g., `"de,fr,en"`) for metadata fallback          |
| `Deezer.Language`            | `"en"`  | Now supports comma-separated list of languages for metadata fallback                               |

##### Renamed Options (Deprecation Notice)

The following options have been renamed. The old names still work but will be removed in a future release:

| Old Name                                      | New Name                   |
| --------------------------------------------- | -------------------------- |
| `HTTPSecurityHeaders.CustomFrameOptionsValue` | `HTTPHeaders.FrameOptions` |

##### Security

- Fix potential XSS vulnerability by sanitizing user-supplied data before rendering ([GHSA-rh3r-8pxm-hg4w](GHSA-rh3r-8pxm-hg4w)). ([d7ec735](navidrome/navidrome@d7ec7355c) by [@AlexGustafsson](https://github.com/AlexGustafsson))
- Fix potential DoS vulnerability in cover art upscaling by clamping requested square size to original dimensions ([GHSA-hrr4-3wgr-68x3](GHSA-hrr4-3wgr-68x3)). ([77367548](navidrome/navidrome@77367548f) by [@deluan](https://github.com/deluan)). Thanks to [@yunfachi](https://github.com/yunfachi)

##### Added

- Plugins:
  - Add new WebAssembly-based plugin system with multi-language PDK support (Go, Rust, Python). ([#4833](navidrome/navidrome#4833) by [@deluan](https://github.com/deluan))
  - Add JSONForms-based plugin configuration UI. ([#4911](navidrome/navidrome#4911) by [@deluan](https://github.com/deluan))
  - Add similar songs retrieval functions to plugins API. ([#4933](navidrome/navidrome#4933) by [@deluan](https://github.com/deluan))

- Server:
  - Add pure-Go metadata extractor (`go-taglib`) as alternative to FFmpeg-based extraction. ([#4902](navidrome/navidrome#4902) by [@deluan](https://github.com/deluan))
  - Add support for reading embedded images using the new taglib extractor by default. ([66474fc](navidrome/navidrome@66474fc9f) by [@deluan](https://github.com/deluan))
  - Add Instant Mix (song-based Similar Songs) functionality with MBID, ISRC and Title/Artist fuzzy matching. ([#4919](navidrome/navidrome#4919), [#4946](navidrome/navidrome#4946) by [@deluan](https://github.com/deluan))
  - Add support for multiple languages when fetching metadata from Last.fm and Deezer. ([#4952](navidrome/navidrome#4952) by [@deluan](https://github.com/deluan))
  - Add `Subsonic.MinimalClients` configuration option for improved compatibility with minimal Subsonic clients. Default list is `"SubMusic"` ([#4850](navidrome/navidrome#4850) by [@typhoon2099](https://github.com/typhoon2099))
  - Add support for public/private playlists in NSP import. ([c5447a6](navidrome/navidrome@c5447a637) by [@deluan](https://github.com/deluan))
  - Add RISCV64 builds. ([#4949](navidrome/navidrome#4949) by [@MichaIng](https://github.com/MichaIng))

- UI Features:
  - Add composer field to table views. ([#4857](navidrome/navidrome#4857) by [@AlexGustafsson](https://github.com/AlexGustafsson))
  - Add prompt before closing window if music is playing. ([#4899](navidrome/navidrome#4899) by [@alannnna](https://github.com/alannnna))
  - Add Nautiline-like theme. ([#4909](navidrome/navidrome#4909) by [@borisrorsvort](https://github.com/borisrorsvort))
  - Add multiline support and resizing for playlist comment input. ([6fce30c](navidrome/navidrome@6fce30c13) by [@deluan](https://github.com/deluan))

- Subsonic API:
  - Add `avgRating` field from Subsonic spec. ([#4900](navidrome/navidrome#4900) by [@terry90](https://github.com/terry90))

- Insights:
  - Add insights collection for Scanner.Extractor configuration to measure go-taglib usage. ([63517e9](navidrome/navidrome@63517e904) by [@deluan](https://github.com/deluan))
  - Add file suffix counting to insights. ([0473c50](navidrome/navidrome@0473c50b4) by [@deluan](https://github.com/deluan))

##### Changed

- Optimize cross-library move detection for single-library setups. ([#4888](navidrome/navidrome#4888) by [@deluan](https://github.com/deluan))
- Improve Deezer artist search ranking. ([a081569](navidrome/navidrome@a081569ed) by [@deluan](https://github.com/deluan))
- Rename `HTTPSecurityHeaders.CustomFrameOptionsValue` to `HTTPHeaders.FrameOptions`. ([7ccf44b](navidrome/navidrome@7ccf44b8e) by [@deluan](https://github.com/deluan))
- Update translations: Bulgarian, Catalan, German, Greek, Spanish, Finnish, French, Galician, Indonesian, Dutch, Polish, Russian, Slovenian, Swedish, Thai by [POEditor contributors](https://www.navidrome.org/docs/developers/translations/).
- Update Spanish translations. ([#4904](navidrome/navidrome#4904) by [@abrugues](https://github.com/abrugues))
- Update Basque translation. ([#4815](navidrome/navidrome#4815) by [@xabirequejo](https://github.com/xabirequejo))

##### Fixed

- Playlists:
  - Fix M3U playlist import failing for paths with different UTF/Unicode representations (NFC/NFD normalization). ([#4890](navidrome/navidrome#4890) by [@deluan](https://github.com/deluan))
  - Fix playlist name sorting to be case-insensitive. ([#4845](navidrome/navidrome#4845) by [@deluan](https://github.com/deluan))

- UI:
  - Fix various UI issues and improve styling coherence. ([#4910](navidrome/navidrome#4910) by [@borisrorsvort](https://github.com/borisrorsvort))
  - Fix AMusic theme player buttons and delete button color. ([#4797](navidrome/navidrome#4797) by [@dragonish](https://github.com/dragonish))
  - Fix export missing files showing only first 1000 results. ([017676c](navidrome/navidrome@017676c45) by [@deluan](https://github.com/deluan))

- Scanner:
  - Fix `FullScanInProgress` not reflecting current scan request during interrupted scans. ([8c80be5](navidrome/navidrome@8c80be56d) by [@deluan](https://github.com/deluan))
  - Fix "Expression tree is too large" error by executing GetFolderUpdateInfo in batches. ([cde5992](navidrome/navidrome@cde5992c4) by [@deluan](https://github.com/deluan))
  - Fix stale role associations when artist role changes. ([2d7b716](navidrome/navidrome@2d7b71683) by [@deluan](https://github.com/deluan))
  - Fix infinite recursion in PID configuration. ([1c4a7e8](navidrome/navidrome@1c4a7e855) by [@deluan](https://github.com/deluan))
  - Fix default PIDs not being set for Album and Track. In some circumstances it could lead to empty PIDs ([71f549a](navidrome/navidrome@71f549afb) by [@deluan](https://github.com/deluan))
  - Fix error when watcher detected too many folder changes, causing the scan to fail. ([9ed309a](navidrome/navidrome@9ed309ac8) by [@deluan](https://github.com/deluan))
  - Show scan errors in the UI more consistently. ([ebbc31f](navidrome/navidrome@ebbc31f1a) by [@deluan](https://github.com/deluan))

- Subsonic API:
  - Fix username parameter validation for `getUser` endpoint. ([6ed6524](navidrome/navidrome@6ed652475) by [@deluan](https://github.com/deluan))
  - Fix `getNowPlaying` endpoint to always be enabled regardless of configuration. ([603cccd](navidrome/navidrome@603cccde1) by [@deluan](https://github.com/deluan))

- Server:
  - Fix JWT-related errors being exposed on share page. ([#4892](navidrome/navidrome#4892) by [@AlexGustafsson](https://github.com/AlexGustafsson))
  - Fix user context not preserved in async NowPlaying dispatch. ([396eee4](navidrome/navidrome@396eee48c) by [@deluan](https://github.com/deluan))
  - Fix environment variable configuration loading not being logged when no config file is found. ([51ca2de](navidrome/navidrome@51ca2dee6) by [@deluan](https://github.com/deluan))
  - Fix items with no annotation not being included for `starred=false` filter, handle `has_rating=false`. ([#4921](navidrome/navidrome#4921) by [@kgarner7](https://github.com/kgarner7))
  - Last.fm's `scrobble` and `updateNowPlaying` methods should send parameters in request body. ([51026de](navidrome/navidrome@51026de80) by [@deluan](https://github.com/deluan))

##### New Contributors

- [@alannnna](https://github.com/alannnna) made their first contribution in [#4899](navidrome/navidrome#4899)
- [@abrugues](https://github.com/abrugues) made their first contribution in [#4904](navidrome/navidrome#4904)
- [@AlexGustafsson](https://github.com/AlexGustafsson) made their first contribution in [#4857](navidrome/navidrome#4857)
- [@borisrorsvort](https://github.com/borisrorsvort) made their first contribution in [#4909](navidrome/navidrome#4909)
- [@dragonish](https://github.com/dragonish) made their first contribution in [#4797](navidrome/navidrome#4797)
- [@MichaIng](https://github.com/MichaIng) made their first contribution in [#4949](navidrome/navidrome#4949)
- [@terry90](https://github.com/terry90) made their first contribution in [#4900](navidrome/navidrome#4900)
- [@typhoon2099](https://github.com/typhoon2099) made their first contribution in [#4850](navidrome/navidrome#4850)

**Full Changelog**: <navidrome/navidrome@v0.59.0...v0.60.0>

##### Helping out

This release is only possible thanks to the support of some **awesome people**!

Want to be one of them?
You can [sponsor](https://github.com/sponsors/deluan), pay me a [Ko-fi](https://ko-fi.com/deluan), or [contribute with code](https://www.navidrome.org/docs/developers/).

##### Where to go next?

- Read installation instructions on our [website](https://www.navidrome.org/docs/installation/).
- Host Navidrome on [PikaPods](https://www.pikapods.com/pods/navidrome) for a simple cloud solution.
- Reach out on [Discord](https://discord.gg/xh7j7yF), [Reddit](https://www.reddit.com/r/navidrome/) and [Twitter](https://twitter.com/navidrome)!
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.

2 participants