* feat(subsonic): add OS readonly and validUntil properties
* remove duplicated test
* test: fix and enable disabled child smart playlist tests
Fixed the XContext("child smart playlists") tests that were disabled with
a TODO comment. The tests had several issues: nested playlists were missing
Public: true (required by InPlaylist criteria), the criteria matched no
test fixtures, the "not expired" test set EvaluatedAt on the parent too
(preventing it from refreshing at all), and the "expired" test dereferenced
a nil EvaluatedAt. Added proper cleanup with DeferCleanup and config
restoration via configtest.
* fix(subsonic): always include readonly field in JSON playlist responses
Removed omitempty from the JSON tag of the Readonly field in
OpenSubsonicPlaylist so that readonly: false is always serialized in
JSON responses, per the OpenSubsonic spec requirement that supported
fields must be returned with default values. Added a test case with an
empty OpenSubsonicPlaylist to verify the behavior.
---------
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
* fix(ui): use div for fragment, check lastfm url for artist page
* use span instead of div for better compat
* fix: implement isLastFmURL utility and add tests for URL validation
---------
Co-authored-by: Deluan <deluan@navidrome.org>
* Rework frontend code interacting directly with DOM
Rework frontend code that uses user-supplied data to render things like
comments and notes. In places where using React's built-in sanitization
is possible, the feature is used. In other places, where some markup
might be necessary, DOMPurify is used to sanitize the HTML before
rendering it.
Solves: GHSA-rh3r-8pxm-hg4w
* Remove test post DOM rework
* fixup! Rework frontend code interacting directly with DOM
* ci: add riscv64 builds
This requires at least Debian Trixie base systems, and a cross-taglib version with riscv64 release assets.
Signed-off-by: MichaIng <micha@dietpi.com>
* fix(makefile): add riscv64 to supported platforms and update cross-taglib version
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: MichaIng <micha@dietpi.com>
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* feat(lastfm): support multiple languages for album and artist info retrieval
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(lastfm): improve content validation for album and artist descriptions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(lastfm): remove single language test and clarify languages field in configuration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(deezer): support multiple languages for artist bio retrieval
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(lastfm): rename ignoredBiographies to ignoredContent for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add ISRC support to similar songs matching and plugin interface
Add ISRC (International Standard Recording Code) as a high-priority
identifier in the provider matching algorithm, alongside MBID. The
matching pipeline now uses four strategies in priority order:
ID > MBID > ISRC > Title+Artist fuzzy match.
- Add ISRC field to agents.Song struct
- Add ISRC field to plugin capability SongRef (Go, Rust PDKs)
- Add loadTracksByISRC using json_tree query on tags column
- Integrate ISRC into matchSongsToLibrary, selectBestMatchingSongs,
and buildTitleQueries
https://claude.ai/code/session_01Dd4mTq1VQZag4RNjCVusiF
* chore: regenerate plugin schema after ISRC addition
Run `make gen` to update the generated YAML schema for the
metadata agent capability with the new ISRC field on SongRef.
https://claude.ai/code/session_01Dd4mTq1VQZag4RNjCVusiF
* feat(mediafile): add GetAllByTags method to MediaFileRepository for tag-based retrieval
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(provider): speed up track matching by incorporating prior matches in ISRC and MBID lookups
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: integrate duration into matchScore instead of using pre-filter
Duration matching was handled as a binary pre-filter with fallback,
inconsistent with how title, specificity, and album are scored via the
matchScore system. Move duration into matchScore as a boolean field
ranked between title similarity and specificity level, making all
match criteria use the same hierarchical comparison.
https://claude.ai/code/session_01BWJ5aAzbQRvwjB7PvUcNYs
* refactor: remove findBestMatchInTracks function and integrate its logic into findBestMatch
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: use duration proximity score instead of boolean match
Replace the binary durationMatch bool with a continuous durationProximity
float64 (0.0-1.0) using 1/(1+diff). This removes the hard 3-second
tolerance cutoff, so closer durations are always preferred over farther
ones without an arbitrary cliff edge.
https://claude.ai/code/session_01BWJ5aAzbQRvwjB7PvUcNYs
* style: fix gofmt alignment in matchScore struct
https://claude.ai/code/session_01BWJ5aAzbQRvwjB7PvUcNYs
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add duration filtering for similar songs matching
Signed-off-by: Deluan <deluan@navidrome.org>
* test: refactor expectations for similar songs in provider matching tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add functions to retrieve similar songs by track, album, and artist
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): support uint32 in ndpgen
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update duration field to use seconds as float instead of milliseconds as uint32
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: add helper functions for Rust's skip_serializing_if with numeric types
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(provider): enhance track matching logic to fallback to title match when duration-filtered tracks fail
---------
Signed-off-by: Deluan <deluan@navidrome.org>