The new Cleanup tab lists the top-most folders in either library that
contain no music file (per the pair's extensions). Removing them needs
confirmation, plus an explicit acknowledgement when they still hold
files; each folder is re-checked for music and moved into the
quarantine (undoable from History, purged after the retention period).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Restores the code of 1da0132 ("Add a setting to hide the quarantine from
Plex") and removes everything added after it: the tag editor, album art,
organizing/naming, the step-by-step tune-up and library types.
Kept:
- Database backups (Settings -> Backups): scheduled, manual, download,
restore, and the optional backup before every action.
- The .env-driven docker-compose.yml for Arcane.
Databases that already ran the later migrations keep working: migrations
6-10 stay in the list (they only add columns) so numbering never goes
backwards, and Undo refuses History entries of removed features instead
of treating them as links.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each pair is a Music (Artist/Album/01 Title) or Soundtracks (Album/01 Title)
library. The new Fixer tab takes the master, then the slave, through four
reviewed steps: folder structure, album tags (optional MusicBrainz lookup;
the slave reuses the fixed master's tags), folder names and file names,
then links the two libraries. Every fix is an undoable operation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Search iTunes, Deezer, MusicBrainz, DuckDuckGo and Google for square covers,
embed them and/or save cover.jpg, auto-match covers for albums, and edit an
album's shared tags and track list in one place.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Naming: separate artist folder, album folder, track and multi-disc track
formats with presets, Lidarr-style tokens ({Artist Name}, {Artist
NameThe}, {Artist CleanName}, {Artist NameFirstCharacter}, {Album
Title}, {Album TitleThe}, {Album CleanTitle}, {Release Year},
{track:00}, {medium:00}, {Medium Format}, {Track Title}, {Track
CleanTitle}, {Track ArtistName}, {Genre}) with Lidarr's word-separator
and case variants, colon replacement modes and replace/remove for other
illegal characters. Empty brackets and separators left by missing values
are cleaned up. Defaults to Artist/Album/01 Title with Disc 01 folders
for multi-disc albums; earlier pattern/disc settings are converted.
Examples are now rendered by the server with the same code as real
renames, fixing the settings page showing paths that differed from what
would happen (e.g. disc 1 of a multi-disc album outside its Disc folder).
"Rename now..." checks one or both libraries, then lists every change
grouped by destination folder with per-file and per-folder selection,
skipped files with reasons and a Fix tags button, and warnings; applying
re-checks each file, renames, and rescans. The pre-action backup runs
first when enabled. Migration 9 stores the naming as JSON.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Disc numbers: the organizer writes two-digit disc numbers by default
(Disc 01, 01-04 Title, {disc}), with an option for the plain style
(Disc 2, 2-04). Migration 8 adds the per-pair setting.
Backups (Settings -> Backups), similar to Sonarr:
- A backup is a zip with a consistent snapshot of the database (VACUUM
INTO, safe while running) and backup.json. Configurable folder,
schedule (off/1/3/7/14 days) and retention for scheduled backups;
manual backups are kept until deleted. List, download, delete.
- Restore from a listed backup or an uploaded zip: validated first
(integrity check, playlink tables, not a newer schema), staged next to
the live database, then the server restarts; at startup the staged
database is swapped in and the previous one kept as
playlink.db.pre-restore-<time>. Refused while a job runs. Backup names
are validated, so downloads/deletes cannot reach other files.
- Optional backup before every action in live mode: once per action the
user starts (link, promote, bulk, build/remove, tag edit, folder
renames, undo, purge) and before scans auto-link or auto-organize,
never per file and never in dry run. If the backup fails the action
does not run. The newest 10 action backups are kept.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The preview/apply flow on the Organize tab did not work as expected, so
it is removed along with its backend: the stored per-pair preview, the
/organize/preview, /organize/plan and /organize/apply endpoints and
their UI and types.
The File naming card stays, and renaming now happens only through
"Organize automatically" during scans, which keeps the underlying
planning/moving code (now internal), undo, crash recovery and dry run.
The rename-folders warning is unchanged. Tests now drive the kept
planning and moving code directly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new Organize tab renames audio files from their tags into a per-pair
naming pattern, by default {artist}/{album}/{track} {title} (album
artist, falling back to artist). Multi-disc albums get a disc prefix
(2-04) or a Disc N folder; names are made safe for Windows/SMB shares.
- Preview first: every rename, files already organized, and files
skipped with the reason (missing tags, with a button into the tag
editor; two files resolving to the same name; an existing file).
- Applying re-checks each file against the preview, moves it within its
library (hardlinks and contents untouched, case-only renames via a
temporary name, completed on startup after a crash), carries .lrc
lyrics and folder cover art along, and removes emptied folders. Each
move is an operation that can be undone; the library is rescanned.
- Optional automatic organizing of the slave, master or both during
scans (off by default). Dry run applies.
- Scans now recognise a slave file that is a hardlink of a master file
at a different path as linked ("same file, other path") instead of
unmatched.
Migration 7 adds the per-pair naming settings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Settings -> Media servers -> "Hide quarantine from Plex" writes a
.plexignore into every pair's quarantine folder (.playlink-trash by
default), with patterns for every folder depth quarantined files live
at. Quarantine folders opened later get the file automatically.
The file carries a marker line: turning the option off removes only
playlink's own file, and an existing .plexignore written by someone else
is never overwritten or deleted (reported instead). Writes go through a
temporary file and a rename.
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>
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>
A singles library naturally has artists and songs the albums library
lacks, so "only N of M top-level folders exist in the master" and "N of M
slave files have no counterpart" were false alarms.
Layout warnings now only flag real layout problems:
- Folders that are the same but named differently (case, punctuation,
accents, "&"/"and", leading/trailing "The"), at the top level and one
level down inside shared folders, with examples.
- Songs found in both libraries that mostly live in a different folder in
the master (e.g. Artist/Song vs Artist/Album/Song). Slave-only songs are
ignored, as are singles/EPs/compilations matched to their album version.
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>