A new Tags tab browses either library; songs can be edited one at a time
or several at once (e.g. a whole album, where per-song fields are locked
and differing values are kept unless changed). Review's compare panel
links to the editor for either side.
Tags are read with ffprobe and written with ffmpeg (MP3/ID3, FLAC, M4A,
OGG, Opus). An existing tag is always written under the name the file
already uses, so edits replace values instead of duplicating them (e.g.
raw Vorbis ALBUMARTIST/TRACKNUMBER), totals follow the file's style
("3/12" or a separate TRACKTOTAL), stale alias tags (YEAR next to DATE)
are removed, other tags and cover art are kept, and no encoder tag is
added. Every written file is verified: values must read back and the
decoded audio must be bit-identical.
Hardlinks are respected: a file used by one library is replaced
atomically (old file to quarantine); a file shared with the other
library is updated in place so the link survives, after a verified
backup copy goes to quarantine, with an option to edit only one
library's copy instead. Edits are operations (old -> new values shown in
History) that can be undone; an interrupted in-place edit is rolled back
on startup. Dry run applies. Migration 6 stores operation details.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The "N folders are named differently" warning now offers to rename the
slave folders to match the master, marked as the recommended first step
after a scan (also linked from the dashboard card).
- A preview lists each rename with the differing characters highlighted;
renames are selectable, and conflicts (the slave already has a folder
with the master's name, symlinks, the quarantine) are skipped with a
reason.
- Only renames the server computes itself are applied; a request can
only narrow them down, never name arbitrary paths. Only slave folders
are renamed.
- Case-only renames go through a temporary name so they also work on
case-insensitive filesystems; a rename interrupted by a crash is
completed on startup (the folder is never removed).
- Renaming everything repeats until folders revealed inside renamed ones
(an album under a renamed artist) are fixed too, then rescans.
- Each rename is an operation in History that can be undone (which also
rescans). Dry run records renames as planned.
Also fixes the Review list not refreshing after a job that started and
finished between two status polls, and logs the new path of operations.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a match lives in another folder than the master (e.g. Game Rips/ vs
Video Games/), linking creates the new link at the master's path and then
removes the original. That removal re-checked the original's modification
time, which FUSE filesystems such as Unraid's /mnt/user can report
inconsistently; the check then failed after the link was already made,
leaving both files and a failed operation whose quarantine copy was hidden.
- Once the original is quarantined, verify it by identity (same inode as
the quarantine copy) instead of by timestamp. Identical files without a
quarantine copy keep the strict check, now with a detailed error.
- If the original still cannot be removed, roll back: remove the new link
and the unneeded quarantine copy so nothing changes. If the original was
swapped for another file mid-way, its quarantine copy is kept.
- Linking again when the master's path already holds a hardlink of the
master only retires the leftover original, which cleans up files left
by the old behaviour; undo then keeps that pre-existing link
(migration 5 records this).
- Promote gets the same identity check and rollback.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Warnings are now stored and served as structured data (title, detail,
slave/master items, total) and rendered as cards with a Slave -> Master
table: the first five rows, with "Show all" for the rest.
- Renamed folders highlight the characters that differ; non-ASCII
characters get their code point in a tooltip, so look-alikes such as
"-" (U+002D) and "‐" (U+2010) can be told apart.
- Songs in a different folder are grouped by folder pair with a song
count, most affected first, instead of two long examples.
- Folders that only differ by name are no longer also reported as
songs in a different folder.
- Warnings saved as plain text by earlier scans still display.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Review list can now be grouped by album (disc folders folded in),
showing per-album counts of upgrades, identical files, downgrades and
approximate matches. Whole albums or individual songs can be selected and
linked, promoted, ignored or un-ignored in one action.
Every bulk action is previewed server-side first: how many songs will be
processed, which are skipped and why, and warnings with examples for
downgrades, approximate matches, duration mismatches, folder moves and
renames. Downgrades are excluded unless explicitly included, and
replacing master files requires an acknowledgement. Link and promote run
as a background job that re-plans each song and uses the normal
single-item operation, so all preflight checks still apply. IDs from
another pair are refused and duplicates are ignored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Review tab gets an Export CSV menu: "This view" exports the current
status filter and search, "Entire scan" exports every scanned slave file.
Each row carries status, match type, a recommendation, slave/master paths,
the link target, the match reason, sizes, codec details for both sides,
the quality verdict, notes, errors and timestamps. Rows are streamed in
pages of 1000 so a large export never holds the database connection a
running scan needs. The file starts with a UTF-8 BOM for Excel, and cells
a spreadsheet would evaluate as formulas are prefixed with an apostrophe.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Matching:
- Prefer the studio album over singles, EPs and compilations when a song
exists on several releases, including when the master also has the
single at the slave's exact folder.
- Ignore release labels (Single Version, Remastered, Explicit, Deluxe)
inside brackets or a trailing " - ..." part; "Clean" stays a version.
- Treat live/acoustic/remix/... album folders as different recordings;
the strict top-folder fallback now respects this too.
- Add a last-resort library-wide search that only accepts candidates whose
artist tag agrees with the slave file.
Linking:
- Cross-folder matches now mirror the master's path in the slave (e.g. a
single moves into the album folder) and prune the emptied folder; a
"keep in current folder" option preserves the old behaviour. Undo
recreates and prunes folders accordingly.
- Operations record the match kind and reason, so undo (and promotes that
rename the master file) restore the correct pairing instead of leaving
the file unmatched until the next scan.
UI: rewrite the approximate matching description with Avenged Sevenfold
examples and clear safeguards, and show where linking will place a file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A per-pair "Approximate matching" setting adds a second pass for slave
files the strict rules could not place. It searches the same album with
disc folders (Disc 02, CD2, ...) ignored, then the top-level folder, and
scores titles by edit distance and word containment against a configurable
threshold (default 85%), with a small track-number bonus.
Guards against false matches: version words (live, remix, reprise,
instrumental, ...) must agree, near-tied candidates are left unmatched,
and approximate matches always go to manual review, never auto-link.
Each match records a human-readable reason.
Review now flags matches where the master copy is better as upgrades,
with an Upgrades filter and count and an "Upgrade to master copy" action.
The redundant "master is lossless" warning note is dropped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The two libraries are now "master" and "slave" everywhere: UI text, API
JSON fields (master_root, rel_master, master_size, ...), Go identifiers,
database columns, quality verdicts, quarantine subfolders and docs.
Existing databases are upgraded by a new migration that renames the
columns in place and rewrites stored "host" values, so pairs, history,
cached verdicts and restorable quarantine entries carry over. Network
"host" usages (SplitHostPort, the Origin/Host check) are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Matching has always been by relative path, so any folder layout works as
long as both libraries use the same one. Remove the depth and loose-root-file
warnings, which flagged valid layouts, and reword the UI and README to say
"same folder layout on both sides" with Artist/Album/Title.ext only as an
example. The "elsewhere" fallback is now described as same top-level folder,
different subfolder. Add a test covering flat and deeply nested layouts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Go backend (chi, SQLite) with an embedded React/TypeScript UI that finds
songs present in both a host and a slave music library and replaces the
slave copy with a hardlink to the host copy.
- Path-first matching with format/title/album-folder fallbacks
- Auto-linking of byte-identical files, re-verified with cmp before linking
- Manual review with ffprobe quality comparison, downgrade guard and
promote-to-host override
- Build mode to populate an empty slave library from the host
- Dry run by default, atomic stage+rename replacement, quarantine with
retention, undo, path confinement and authenticated UI
- Dockerfile and compose file for Unraid
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>