Go back to the hardlink deduplicator (1da0132), keeping backups

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>
This commit is contained in:
cdnutterandClaude Opus 5.5 committed 2026-09-30 10:43:29 -07:00
1 parent 7b180e26db
commit e0617047f7
44 files changed
+103 -10456

No files matched your search

-19
View File
@@ -287,11 +287,6 @@ func (e *Engine) scan(ctx context.Context, j *Job, pairID int64, trigger string)
_ = e.st.FinishScan(ctx, pairID, started.Unix(), err.Error(), nil)
return err
}
if l.pair.AutoOrganize != "" && l.pair.AutoOrganize != "off" {
if err := e.autoOrganize(ctx, j, l); err != nil {
e.log.Warn("auto-organize failed", "pair", l.pair.Name, "err", err)
}
}
warns := layoutWarnings(l)
j.phase("Indexing master library", 0)
@@ -309,15 +304,6 @@ func (e *Engine) scan(ctx context.Context, j *Job, pairID int64, trigger string)
return err
}
ix := buildIndex(masterFiles, l.pair)
// The same file (hardlink) can sit at another path, e.g. after one library
// was organized; it is recognised as linked rather than unmatched.
byInode := map[[2]uint64]string{}
for _, rel := range sortedKeys(masterFiles) {
in := masterFiles[rel]
if _, dup := byInode[[2]uint64{in.Dev, in.Ino}]; !dup {
byInode[[2]uint64{in.Dev, in.Ino}] = rel
}
}
if ix.approx != nil {
ix.verify = e.artistVerifier(ctx, l)
}
@@ -336,11 +322,6 @@ func (e *Engine) scan(ctx context.Context, j *Job, pairID int64, trigger string)
si := slaveFiles[rel]
m := store.Match{PairID: pairID, RelSlave: rel}
m.RelMaster, m.Kind, m.Reason = ix.find(rel)
if m.Kind != store.KindPath {
if mrel, ok := byInode[[2]uint64{si.Dev, si.Ino}]; ok {
m.RelMaster, m.Kind, m.Reason = mrel, store.KindInode, ""
}
}
var pm *store.Match
if p, ok := prev[rel]; ok {
pm = &p