Track matching architecture
Aurral matches tracks with native JavaScript rules. The matcher needs no Python runtime, external service, or audio fingerprints. A source adapter supplies only the evidence that its provider really exposes. A missing artist, duration, or recording ID never counts as a match.
Decision path
Section titled “Decision path”trackIdentity.jsbuilds the requested recording.candidateNormalizer.jsand the source adapters turn search results into comparable candidates.nativeMatcher.jsapplies one versioned policy. It checks contradictions, ranks candidates, checks release fit, and assigns files one to one.decisionEngine.jsadds provider evidence and returnsaccept,verify,review, orrejectfor each result.
After a download, postDownloadValidator.js runs the same matcher on the original file tags. Aurral writes its own tags only after this check passes.
- A strong title score cannot override a known conflict in the recording ID, version, artist, or duration.
- A recording ID tag counts only when it holds a MusicBrainz ID. Some rip tools write Spotify IDs there. An ID that MusicBrainz merged into the requested recording, which files tagged before the merge still carry, counts as the same recording.
- Missing evidence does not count as agreement.
- Editions of one recording differ by a few seconds of mastering, fade, or silence, so a file whose original title and artist tags match exactly is imported within 10 seconds of the requested length, as in Lidarr. A partly matching title needs to be within 2 seconds. Otherwise a file that matches except for its length goes to review. A Soulseek or yt-dlp file waits while the job tries its remaining candidates and the other download sources. It goes to review only when none of them verifies, and keeps its own source details, so denying it blocks that file.
- A credit such as “Kendrick Lamar, Drake” or “Blue Swede & Björn Skifs” names each of its artists, and a leading “The” does not change an artist.
- A clean, edited, or censored copy contradicts a request that does not ask for one. An “explicit” label does not.
- A file without usable identity tags is not imported automatically.
- A track number that points at another track of the requested album is a conflict only when the file comes from that album. A single, a compilation, or another album has its own numbering, and a later disc numbers its tracks from 1 again.
- Aurral takes a recording ID only from MusicBrainz release data, never from Last.fm. The expected length comes from the matched MusicBrainz release track; a Last.fm length, often a radio edit, only fills a missing one.
- A “Various Artists” credit is not artist evidence. A compilation’s jobs keep “Various Artists” as their artist and name each track’s own artist, with that artist’s other names from MusicBrainz, as aliases for matching and searching. Each file is tagged with its own artist and “Various Artists” as the album artist, so media servers group the album, and the Library keeps each track’s own artist.
Titles and scripts
Section titled “Titles and scripts”A title in a file name keeps its dash-separated version suffix. A remaster can match the original recording, but a radio edit must match the requested version. When the part before the dash names more than the artist, as in Artist [Album] 08 - Title, the part after it counts if it is closer to the requested title.
Matching removes Latin accents and treats equivalent Unicode spellings as equal. If either core title contains non-Latin letters, two different normalized titles are a contradiction, even when the artist, duration, or recording ID agrees. This rule also applies to file names and to album file assignment. A transliteration or spelling difference in such a title needs the user to choose.
yt-dlp files
Section titled “yt-dlp files”yt-dlp names files by video ID, so the file name is not title evidence. yt-dlp writes YouTube’s track and artist into the file when YouTube has them. Otherwise it splits a title of the form Artist - Title at the first dash, or names the uploader as the artist.
Aurral reads a video title the same way before and after the download. It removes upload wording such as “Official Music Video”, “(Audio)”, “Audio Oficial”, or “| Album”. The part of the title that names the requested artist is the artist, whether it comes first, last, or before 「Title」, and the part closest to the requested title is the title. A channel’s name counts as the artist only when it is the artist’s own channel, such as “Fleetwood Mac - Topic” or “DaftPunkVEVO”.
An upload on the artist’s channel that is not a music video is the release audio: the “- Topic” uploads, “(Audio)” uploads, lyric videos, and visualizers. Aurral downloads those first and gives them the 10-second length window. A music video, which is often cut differently, or an upload on another channel needs to be within 2 seconds, because re-uploads are often re-timed. A YouTube title must match exactly: uploader words such as “Concept” or “Reworked” send the file to review.
Manual selections
Section titled “Manual selections”When a user chooses a result in a manual search, the choice decides the identity. The validator still requires readable audio with a known quality tier. It accepts tiers that the quality profile turns off. It does not apply the title, artist, album, duration, or version rules. Aurral downloads only the chosen result and does not fall back to another result or source.
Policy version
Section titled “Policy version”MATCH_POLICY.version in nativeMatcher.js is stored with each matcher decision and returned by the health response. Change the policy in one place. Then run the fixture evaluation and the cross-source regression tests.
Album release grabs
Section titled “Album release grabs”An Aurral album request keeps one job for each missing track. When Soulseek, Usenet, or deemix is enabled, the first pending job reserves the other jobs for one release attempt:
- Usenet submits one NZB.
- Soulseek submits one folder batch.
- deemix submits one album URL.
Like a Lidarr import, the attempt matches against every release in the album’s release group, not only the release that Aurral stored when you requested the album. Each file is checked against the release whose tracklist fits the downloaded files best, so another edition’s numbering does not reject it.
For Soulseek, every folder that fits is a usable copy. Equal fits are usually the same rip shared by several people, so Aurral ranks them by completeness, quality profile tier, fit, free upload slot, queue length, and speed instead of abstaining. A listing without track lengths fits when exact titles sit at their positions. The post-download check still compares the real durations.
Aurral assigns the finished files to the reserved jobs and never uses one file twice. Each assigned file must pass its own post-download check before it moves into the Library. When the attempt leaves two or more tracks unfilled, Aurral tries the next ranked folder or release for them. It blocks the attempted release for every track it did not fill, so neither the next attempt nor a per-track search takes it again. Tracks that remain go through the per-track fallback. If the attempt ends early, for example because the first job is removed, the reserved jobs also return to per-track search.
The release attempt follows the configured source priority. yt-dlp stays a per-track source. Lidarr albums go through Lidarr. Cancellation removes only work that belongs to the album request. Queued pipeline state resumes after a worker restart.
Pipeline steps
Section titled “Pipeline steps”The download pipeline runs one step at a time, and each step holds its owner’s download step lock. A step therefore makes one provider call: it starts a search, polls a running search once, runs one Prowlarr query, or moves a download forward. Soulseek and Usenet results stay in a 15-minute cache keyed by query, so a restart repeats only the queries whose results it lost. The download worker hands a job to the pipeline only while fewer jobs than its concurrency are searching.
Add a source
Section titled “Add a source”- Declare the evidence that the source provides in
candidateNormalizer.js. - Map provider results through
buildSourceCandidates(). Keep provider-specific availability checks in the adapter. - Run the shared post-download validator before you write tags or import files.
- For whole-release downloads, pass the finished file paths and the payload fields to clear for the next candidate to
finishAlbumGrab(), and test partial and failed downloads. - Keep each pipeline step to one provider call, and block a file or release that fails its checks with
recordDeniedSource().
Verification
Section titled “Verification”.tests/track-matching/fixtures/ holds development and acceptance cases built from CC0 MusicBrainz data. The two sets share no identities. To get correct, wrong, abstained, contradicted, and yield counts for each flow, run:
node .tests/track-matching/native-evaluation.mjsThe held-out acceptance run is a release gate. Tune rules against the development set only. The cross-source and download tests cover provider mapping, real audio tags, album imports, partial failures, cancellation, and fallback.
Metadata cannot tell apart two recordings with identical visible evidence. Aurral does not use audio fingerprints. If that case matters, review the downloaded file before import, or choose the file with a manual search.