Find a file
Deluan Quintão 52e47b896a
refactor: extract song-to-library matcher to core/matcher package (#5348)
* refactor: extract matchSongsToLibrary to core/matcher package

Move the song-to-library matching algorithm from core/external into its own
core/matcher package. The Matcher struct exposes a single public method
MatchSongsToLibrary that implements a multi-phase matching algorithm
(ID > MBID > ISRC > fuzzy title+artist). Includes pre-sanitization
optimization for the fuzzy matching loop.

No behavioral changes — the algorithm is identical to the version in
core/external/provider_matching.go.

* refactor: inject matcher.Matcher via Wire instead of creating it inline

Add *matcher.Matcher as a dependency of external.NewProvider, wired via
Google Wire. Update all provider test files to pass matcher.New(ds).
This eliminates tight coupling so future consumers can reuse the matcher
without depending on the external package.

* refactor: remove old provider_matching files

Delete core/external/provider_matching.go and its tests. All matching
logic now lives in core/matcher/.

* test(matcher): restore test coverage lost in extraction

Port back 23 specs that existed in the old provider_matching_test.go
but were dropped during the extraction. Covers specificity levels,
fuzzy matching thresholds, fuzzy album matching, duration matching,
and deduplication edge cases.

* test(matcher): extract matchFieldInAnd/matchFieldInEq helpers

The four inline mock.MatchedBy closures in setupAllPhaseExpectations
all followed the same squirrel.And -> squirrel.Eq -> field-name-check
pattern. Extract into two small helpers to reduce duplication and
make the setup functions read as a concise list of phase expectations.

* refactor(matcher): address PR #5348 review feedback

- sanitizedTrack now holds *model.MediaFile instead of a value copy. Since
  MediaFile is a large struct (~74 fields), this avoids the per-track copy
  into sanitized[] and a second copy when findBestMatch assigns the winner.
  loadTracksByTitleAndArtist updated to iterate by index and pass &tracks[i].

- loadTracksByISRC now sorts results (starred desc, rating desc, year asc,
  compilation asc) so that when multiple library tracks share an ISRC the
  most relevant one is picked deterministically, matching the sort order
  already used by loadTracksByTitleAndArtist.

- Restored the four worked examples (MBID Priority, ISRC Priority,
  Specificity Ranking, Fuzzy Title Matching) in the MatchSongsToLibrary
  godoc that were dropped during the extraction.

- matcher_test.go: tests now enforce expectations via AssertExpectations in
  a DeferCleanup. The old setupAllPhaseExpectations helper was replaced
  with per-phase helpers (expectIDPhase/expectMBIDPhase/expectISRCPhase +
  allowOtherPhases) so each test deterministically verifies which matching
  phases fire. This surfaced (and fixes) a latent issue copilot flagged:
  the old .Once() expectations were not actually asserted, so tests would
  silently pass even when phases short-circuited unexpectedly.
2026-04-12 16:47:22 -04:00
.devcontainer feat(scanner): upgrade TagLib to 2.2, with MKA/Matroska support (#5071) 2026-02-21 16:52:48 -05:00
.github chore(deps): bump nick-fields/retry from 3 to 4 in /.github/workflows (#5241) 2026-03-23 14:19:16 -04:00
adapters fix(scanner): map ORIGYEAR tag for VorbisComment and MP4 formats 2026-04-06 21:35:22 -04:00
cmd refactor: extract song-to-library matcher to core/matcher package (#5348) 2026-04-12 16:47:22 -04:00
conf refactor(configuration): improve error handling in configuration validation 2026-04-12 12:18:13 -04:00
consts feat(artwork): make max image upload size configurable (#5335) 2026-04-12 11:16:00 -04:00
contrib build: add packages for deb and rpm to release (#3202) 2024-10-26 13:31:45 -04:00
core refactor: extract song-to-library matcher to core/matcher package (#5348) 2026-04-12 16:47:22 -04:00
db fix(backup): surface real SQLite error when backup step fails 2026-04-11 21:14:52 -04:00
git feat(plugins): experimental support for plugins (#3998) 2025-06-22 20:45:38 -04:00
log feat(server): add syslog priority prefixes for systemd-journald (#5192) 2026-03-15 14:14:05 -04:00
model perf: reduce hot-path heap escapes from value-param pointer aliasing (#5342) 2026-04-10 21:59:49 -04:00
persistence fix(subsonic): always emit required created field on AlbumID3 (#5340) 2026-04-10 19:29:20 -04:00
plugins feat(plugins): add path to Scrobbler and Lyrics plugin TrackInfo (#5339) 2026-04-12 10:27:58 -04:00
release fix(transcoding): include ffprobe in MSI and fall back gracefully when absent (#5326) 2026-04-07 20:11:38 -04:00
resources fix(ui): add albumGain and trackGain translations in Brazilian Portuguese 2026-04-12 13:22:56 -04:00
scanner feat: add artist image uploads and image-folder artwork source (#5198) 2026-03-15 22:19:55 -04:00
scheduler test: increase FlakeAttempts for library directory tests and remove flaky job test 2026-03-23 11:59:11 -04:00
scripts build(worktree): add script for setting up git worktrees 2026-03-17 21:34:00 -04:00
server feat(artwork): make max image upload size configurable (#5335) 2026-04-12 11:16:00 -04:00
tests fix(transcoding): include ffprobe in MSI and fall back gracefully when absent (#5326) 2026-04-07 20:11:38 -04:00
ui fix(ui): update Russian translations and add missing gain keys (#5329) 2026-04-12 13:17:46 -04:00
utils refactor(shellquote): replace go-shellquote with custom shell quoting implementation 2026-03-14 10:23:45 -04:00
.dockerignore fix: add music.old to .dockerignore and .gitignore 2026-02-06 07:40:05 -05:00
.git-blame-ignore-revs Move project to Navidrome GitHub organization 2021-02-06 21:47:19 -05:00
.gitignore build(worktree): add script for setting up git worktrees 2026-03-17 21:34:00 -04:00
.golangci.yml chore(ui): regenerate package-lock.json to have integrity fields (#5276) 2026-04-05 11:37:50 -04:00
.nvmrc chore(deps): update all dependencies (#4618) 2025-10-25 17:05:16 -04:00
CODE_OF_CONDUCT.md Use Contributor Covenant v2.0 2020-07-21 14:40:21 -04:00
CONTRIBUTING.md docs: update commit message format in CONTRIBUTING.md 2026-02-20 11:00:34 -05:00
Dockerfile feat(server): implement FTS5-based full-text search (#5079) 2026-02-21 17:52:42 -05:00
go.mod fix(gotaglib): update go-taglib to fix issue with empty id3v2 frames 2026-04-07 15:30:21 -04:00
go.sum fix(gotaglib): update go-taglib to fix issue with empty id3v2 frames 2026-04-07 15:30:21 -04:00
LICENSE Change license to GPLv3 2020-01-22 14:48:38 -05:00
main.go feat(server): implement FTS5-based full-text search (#5079) 2026-02-21 17:52:42 -05:00
Makefile fix(artwork): address WebP performance regression on low-power hardware (#5286) 2026-04-04 15:17:01 -04:00
Procfile.dev chore(deps): upgrade to Go 1.24.1 (#3851) 2025-03-17 21:08:10 -04:00
README.md feat: add Navidrome Guru on Gurubase.io (#3491) 2024-11-23 17:29:00 -05:00
reflex.conf feat(server): implement FTS5-based full-text search (#5079) 2026-02-21 17:52:42 -05:00

Navidrome logo

Navidrome Music Server  Tweet

Last Release Build Downloads Docker Pulls Dev Chat Subreddit Contributor Covenant Gurubase

Navidrome is an open source web-based music collection server and streamer. It gives you freedom to listen to your music collection from any browser or mobile device. It's like your personal Spotify!

Note: The master branch may be in an unstable or even broken state during development. Please use releases instead of the master branch in order to get a stable set of binaries.

Check out our Live Demo!

Any feedback is welcome! If you need/want a new feature, find a bug or think of any way to improve Navidrome, please file a GitHub issue or join the discussion in our Subreddit. If you want to contribute to the project in any other way (ui/backend dev, translations, themes), please join the chat in our Discord server.

Installation

See instructions on the project's website

Cloud Hosting

PikaPods has partnered with us to offer you an officially supported, cloud-hosted solution. A share of the revenue helps fund the development of Navidrome at no additional cost for you.

PikaPods

Features

  • Handles very large music collections
  • Streams virtually any audio format available
  • Reads and uses all your beautifully curated metadata
  • Great support for compilations (Various Artists albums) and box sets (multi-disc albums)
  • Multi-user, each user has their own play counts, playlists, favourites, etc...
  • Very low resource usage
  • Multi-platform, runs on macOS, Linux and Windows. Docker images are also provided
  • Ready to use binaries for all major platforms, including Raspberry Pi
  • Automatically monitors your library for changes, importing new files and reloading new metadata
  • Themeable, modern and responsive Web interface based on Material UI
  • Compatible with all Subsonic/Madsonic/Airsonic clients
  • Transcoding on the fly. Can be set per user/player. Opus encoding is supported
  • Translated to various languages

Translations

Navidrome uses POEditor for translations, and we are always looking for more contributors

Documentation

All documentation can be found in the project's website: https://www.navidrome.org/docs. Here are some useful direct links:

Screenshots