fix: keep the mirror stable across Lidarr upgrades and renames
Build and publish container / build (pull_request) Canceled after 6m18s
Build and publish container / build (pull_request) Canceled after 6m18s
Three defects in how the mirror tracked its source, all of which show up on a library that something else reorganises. Pruning probed the source tree for a mirror file's original name, trying each known extension in turn. A source saved as .FLAC was never found, so its mirror file was deleted as an orphan and re-encoded on the next pass, for ever. Pruning now works from the set of paths the pass actually accounted for, which cannot disagree with the walk over letter case or extension coverage. Two sources could also claim one mirror path -- 01 Song.flac beside a leftover 01 Song.mp3, which is what an interrupted upgrade leaves behind. Both encoded to the same destination, whichever finished last won the race, and every later pass found the other one stale. The best-quality source now wins, ties break on path, and the loser is logged. The source mtime was read after encoding rather than before. A file still being written when the pass reached it would be stamped with its final mtime while holding truncated audio, and would never be revisited. Adds regression tests for all three, plus the format-upgrade, album-rename and whole-library-deletion cases, each verified to fail before the change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
82c9da6d62
commit
7a57e03c7b
@@ -28,6 +28,29 @@ mtime, so a file is stale exactly when the two differ. There is no database to
|
||||
fall out of step with the library, which matters when something else — Lidarr,
|
||||
in this case — is the thing that owns and reorganises it.
|
||||
|
||||
### What that means for Lidarr
|
||||
|
||||
| Lidarr does this | The mirror does this |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Replaces a file with a better rip | Re-encodes in place. Same path in, same path out, so no duplicate |
|
||||
| Upgrades MP3 to FLAC | Both map to the same `.mp3` mirror path, so the old one is overwritten |
|
||||
| Renames a track, album or artist folder | Old path pruned, new path encoded. Correct, but it re-encodes rather than moving |
|
||||
| Deletes an album or artist | Every orphaned mirror file is deleted and the emptied directories go too |
|
||||
|
||||
Pruning is driven by what the pass actually found, not by guessing source
|
||||
filenames from mirror ones: a `.FLAC` source would not be found by a search for
|
||||
`.flac`, and the mirror file would be deleted and rebuilt on alternate passes
|
||||
for ever.
|
||||
|
||||
If two sources want the same mirror path — a `01 Song.flac` next to a leftover
|
||||
`01 Song.mp3`, which is what an interrupted upgrade leaves — the better format
|
||||
wins, ties break on path, and the loser is logged. Without that rule both
|
||||
encode to the same destination and every pass finds one of them stale.
|
||||
|
||||
The mtime is read _before_ encoding rather than after. A file still being
|
||||
written when the pass reaches it would otherwise be stamped with its final
|
||||
mtime while holding truncated audio, and never be revisited.
|
||||
|
||||
Encodes are written to a temporary file and renamed into place, so an
|
||||
interrupted run cannot leave a truncated MP3 that the next run mistakes for
|
||||
finished work. A lock file in the mirror root stops two passes overlapping.
|
||||
|
||||
Reference in New Issue
Block a user