fix(media): the series is the name before the marker; a sweep carries its own empty subfolders #95
No files matched your search
+14
-2
@@ -241,6 +241,11 @@ def sweep_targets(root, journal):
|
||||
journalled destination lives under it. A symlink anywhere inside disqualifies
|
||||
the whole subtree: this tool never follows a link, and deleting the folder
|
||||
that holds one would delete someone's mount point.
|
||||
|
||||
Proof carries downward: once a folder qualifies, every empty directory inside
|
||||
it qualifies too. A release's junk (``Screens/``, ``Sample/``) is never itself
|
||||
a move source, so without that rule it holds its emptied parent on disk
|
||||
forever — the parent can never be removed while the child stands.
|
||||
"""
|
||||
moves = [r for r in journal.records if r.get("op") == "move"]
|
||||
made = {r["dst"] for r in journal.records if r.get("op") == "mkdir"}
|
||||
@@ -268,8 +273,15 @@ def sweep_targets(root, journal):
|
||||
return False
|
||||
return True
|
||||
|
||||
return sorted((d for d in marked if removable(d)),
|
||||
key=lambda q: (-q.count(os.sep), q))
|
||||
roots = [d for d in marked if removable(d)]
|
||||
targets = set(roots)
|
||||
for d in roots:
|
||||
for dirpath, dirnames, _ in os.walk(d):
|
||||
for c in dirnames:
|
||||
p = os.path.join(dirpath, c)
|
||||
if removable(p):
|
||||
targets.add(p)
|
||||
return sorted(targets, key=lambda q: (-q.count(os.sep), q))
|
||||
|
||||
|
||||
def do_sweep(args, root, journal):
|
||||
|
||||
@@ -155,6 +155,10 @@ curl -s -K /tmp/jf.hdr -o /dev/null -w "jellyfin scan: %{http_code}\n" \
|
||||
inside disqualifies the subtree, because the thing behind a link is not this
|
||||
tool's to delete. Every removal is journalled as `rmdir` and `rollback`
|
||||
recreates the folder, so the sweep is undone by the same command as the moves.
|
||||
Proof carries downward: inside a folder the journal proves emptied, every
|
||||
empty directory goes with it. A release's `Screens/` or `Sample/` is never a
|
||||
move source itself, so 146 of them held their emptied parents on disk after
|
||||
the first sweep.
|
||||
- **An episode-shaped name marks a SERIES, not a film — and the series is the
|
||||
name BEFORE the marker.** `Monk - S05E03 - Mr. Monk and the Big Game` is series
|
||||
`Monk`. Keyed on the whole title instead, every episode became a group of one
|
||||
|
||||
@@ -408,6 +408,17 @@ PY
|
||||
[ -d "$LIB/A Empty Placeholder" ]
|
||||
}
|
||||
|
||||
@test "a swept folder carries the empty junk folders inside it" {
|
||||
mkdir -p "$LIB/AMERICAN POP/Screens" # screenshots, never a move source
|
||||
plan
|
||||
apply_plan
|
||||
run python3 "$APPLY" sweep --root "$LIB" --journal "$JOURNAL" --apply
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"0 left in place"* ]]
|
||||
[ ! -e "$LIB/AMERICAN POP/Screens" ]
|
||||
[ ! -e "$LIB/AMERICAN POP" ]
|
||||
}
|
||||
|
||||
@test "sweep without --apply reports the husks and changes nothing" {
|
||||
plan
|
||||
apply_plan
|
||||
|
||||
Reference in new issue
Block a user