* 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>
* refactor: rename ArtistRadio to SimilarSongs for clarity and consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement GetSimilarSongsByTrack and related functionality for song similarity retrieval
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance GetSimilarSongsByTrack to include artist and album details and update tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance song matching by implementing title and artist filtering in loadTracksByTitleAndArtist
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add unit tests for song matching functionality in provider
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: extract song matching functionality into its own file
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: clarify similarSongsFallback function description in provider.go
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: initialize result slice for songs with capacity based on response length
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify agent method calls for retrieving images and similar songs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify agent method calls for retrieving images and similar songs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove outdated comments in GetSimilarSongs methods
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: use composite key for song matches to handle duplicates by title and artist
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: consolidate expectations setup for similar songs tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add instant mix action to song context menu and update translations
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(provider): handle unknown entity types in GetSimilarSongs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: move playSimilar action to playbackActions and streamline song processing
Signed-off-by: Deluan <deluan@navidrome.org>
* format
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance instant mix functionality with loading notification and shuffle option
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement fuzzy matching for similar songs based on configurable threshold
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: implement track matching with multiple specificity levels
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: enhance track matching by implementing unified scoring with specificity levels
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance deezer top tracks result with album
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance track matching with fuzzy album similarity for improved scoring
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: document multi-phase song matching algorithm with detailed scoring and prioritization
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): use stock array renderer for plugins config form
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): enforce minimum user tokens and require users field
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): simplify error handling in control state hook
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): remove "None" MenuItem from OutlinedEnumControl
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): enhance error handling by returning field info and path in validation errors
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): update OutlinedEnumControl to handle empty values and remove "None" option when required
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(db): Include items with no annotation for starred=false, handle has_rating=false
* hardcode starred instead
* test: ensure albums and artists without annotations are included in starred and has_rating filters
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: replace starred and has_rating filters with annotationBoolFilter for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update annotationBoolFilter to handle boolean values correctly in SQL expressions
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* feat(subsonic): add averageRating to API responses
Add averageRating attribute to Subsonic API responses for artists,
albums, and songs. The average is calculated across all user ratings.
* perf(db): add index for average rating queries
Add composite index on (item_id, item_type, rating) to optimize
the correlated subquery used for calculating average ratings.
Signed-off-by: Terry Raimondo <terry.raimondo@gmail.com>
* test: add tests for averageRating feature
Add tests for:
- Album.AverageRating calculation in persistence layer
- MediaFile.AverageRating calculation in persistence layer
- AverageRating mapping in subsonic response helpers
Signed-off-by: Terry Raimondo <terry.raimondo@gmail.com>
* test: improve averageRating rounding test with 3 users
Add third test user to fixtures and update rounding test to use
3 ratings (5 + 4 + 4) / 3 = 4.33 for proper decimal rounding coverage.
Signed-off-by: Terry Raimondo <terry.raimondo@gmail.com>
* perf: store avg_rating on entity tables instead of using subquery
- Add avg_rating column to album, media_file, and artist tables
- Update SetRating() to recalculate and store average when ratings change
- Read avg_rating directly from entity table in withAnnotation()
- Remove old annotation index migration (no longer needed)
This trades write-time computation for read-time performance by
pre-computing the average rating instead of using a correlated
subquery on every read.
* feat: add Subsonic.EnableAverageRating config option (default true)
Allow administrators to disable exposing averageRating in Subsonic API
responses if they don't want to expose other users' rating data.
The avg_rating column is still updated internally when users rate items,
but the value is only included in API responses when this option is enabled.
* address PR comments
- Use structs:"avg_rating" with db:"avg_rating" tag instead of SQL alias
- Remove avg_rating indexes (not needed)
- Populate avg_rating columns from existing ratings in migration
* Woops
* rename avg_rating column to average_rating
---------
Signed-off-by: Terry Raimondo <terry.raimondo@gmail.com>
* feat(ui): Add composer field to datatables
In order to make the UI a bit more useful for classical music, where the
recorded artist isn't the composer of the work, add the composer field
to the song and album datatables.
To not affect existing users, the field is default off.
* Fix typo
* Remove composer field for albums
Albums can have more than one composer. Showing all or just one of them
in a list doesn't really make sense.
* Format code