Prune stems whose source song was removed or replaced
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5b7fadb7f7
commit
0fc35b13e8
7 files changed
+133
-3
No files matched your search
@@ -12,6 +12,7 @@ import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import time
|
||||
import unicodedata
|
||||
|
||||
import numpy as np
|
||||
import soundfile as sf
|
||||
@@ -105,3 +106,49 @@ def write_track(dest, stems, meta):
|
||||
for name in [s["file"] for s in written] + [MARKER]:
|
||||
os.replace(os.path.join(part, name), os.path.join(dest, name))
|
||||
os.rmdir(part)
|
||||
|
||||
|
||||
def _norm(path):
|
||||
return unicodedata.normalize("NFC", os.path.normpath(path)).casefold()
|
||||
|
||||
|
||||
def find_stale(src, dst):
|
||||
"""Stems folders that no longer match the library.
|
||||
|
||||
Returns (orphans, changed): orphans have no source track any more (removed, renamed or
|
||||
moved); changed still have one, but its size or mtime differs from the marker's, so the
|
||||
stems are of an older version of the song.
|
||||
"""
|
||||
expected = {_norm(d): p for p, d in iter_tracks(src, dst)}
|
||||
orphans, changed = [], []
|
||||
for root, dirs, files in os.walk(dst):
|
||||
dirs[:] = [d for d in dirs if not d.startswith(".")]
|
||||
if MARKER not in files:
|
||||
continue
|
||||
dirs[:] = []
|
||||
source = expected.get(_norm(root))
|
||||
if source is None:
|
||||
orphans.append(root)
|
||||
continue
|
||||
try:
|
||||
with open(os.path.join(root, MARKER)) as f:
|
||||
m = json.load(f)
|
||||
if [m["size"], m["mtime_ns"]] != signature(source):
|
||||
changed.append(root)
|
||||
except (OSError, ValueError, KeyError):
|
||||
pass # unreadable marker or source: leave it alone
|
||||
return sorted(orphans), sorted(changed)
|
||||
|
||||
|
||||
def remove_stems(dst, folders):
|
||||
"""Delete stems folders, then any parent folders left empty (never dst itself)."""
|
||||
dst = os.path.realpath(dst)
|
||||
for folder in folders:
|
||||
shutil.rmtree(folder)
|
||||
parent = os.path.dirname(os.path.realpath(folder))
|
||||
while parent != dst and parent.startswith(dst + os.sep):
|
||||
try:
|
||||
os.rmdir(parent)
|
||||
except OSError:
|
||||
break
|
||||
parent = os.path.dirname(parent)
|
||||
Reference in new issue
Block a user