slim-embedded-art: drop junk lyrics frames over 50 KB

The 49 files the art pass left behind were fat with USLT, not APIC -
the worst held the complete text of Angela's Ashes (1.5 MB of Frank
McCourt) in an Eels track, some tagger malfunction. AVPlayer pages
through the whole tag before the first audio frame regardless of what
fills it, so absurd lyrics cost the same silence as absurd art. No
song has 50 KB of lyrics; anything past it is junk and is removed.
This commit is contained in:
2026-08-29 07:48:07 +01:00
parent 76d7ce6ccd
commit f17a88be9a
+25 -8
View File
@@ -39,6 +39,10 @@ from PIL import Image
ROOT = os.path.expanduser("~/Music")
EMBED_TARGET = 80_000
PROCESS_OVER = 100_000
# No song has 50 KB of lyrics. The frame that set this limit held the complete text of Frank
# McCourt's "Angela's Ashes" - 1.5 MB of memoir in an Eels track's USLT, courtesy of some tagger
# malfunction - and AVPlayer pages through ALL of it before the first audio frame, art or not.
LYRICS_SANE = 50_000
def audio_region_hash(path, offset=None):
@@ -120,22 +124,33 @@ def process(path, apply):
return None
pics = pictures(tag)
total = sum(len(p.data) for p in pics)
if total <= PROCESS_OVER:
junk_lyrics = [f for f in tag.getall("USLT") if len(f.text or "") > LYRICS_SANE]
if total <= PROCESS_OVER and not junk_lyrics:
return None
largest = max(pics, key=lambda p: len(p.data))
largest = max(pics, key=lambda p: len(p.data)) if pics else None
if not apply:
return f"would slim {total // 1024} KB of art"
parts = []
if total > PROCESS_OVER: parts.append(f"{total // 1024} KB of art")
if junk_lyrics: parts.append(f"{sum(len(f.text) for f in junk_lyrics) // 1024} KB of junk lyrics")
return "would slim " + " + ".join(parts)
before = audio_region_hash(path)
tmp = path + ".slimtmp"
shutil.copy2(path, tmp)
try:
rescued = rescue_cover(os.path.dirname(path), largest.data)
jpeg, note = compress_cover(largest.data)
note = "art untouched"
t = ID3(tmp)
t.delall("APIC")
t.delall("PIC")
t.add(APIC(encoding=0, mime="image/jpeg", type=3, desc="", data=jpeg))
if largest is not None and total > PROCESS_OVER:
rescued = rescue_cover(os.path.dirname(path), largest.data)
jpeg, note = compress_cover(largest.data)
t.delall("APIC")
t.delall("PIC")
t.add(APIC(encoding=0, mime="image/jpeg", type=3, desc="", data=jpeg))
else:
rescued = False
jpeg = b""
for f in junk_lyrics:
t.delall(f.HashKey)
v2 = 4 if tag.version >= (2, 4, 0) else 3
# v1=0 REMOVES any trailing ID3v1 tag: it is a 128-byte legacy appendix fully redundant
# with the v2 frames, and keeping it in sync is what tripped the audio guard before the
@@ -145,6 +160,8 @@ def process(path, apply):
raise RuntimeError("audio bytes changed - keeping original")
os.replace(tmp, path)
note_out = f"{total // 1024} KB -> {len(jpeg) // 1024} KB ({note})"
if junk_lyrics:
note_out += f" -{sum(len(f.text) for f in junk_lyrics) // 1024} KB junk lyrics"
return note_out + (" +rescued cover.jpg" if rescued else "")
except Exception as e:
if os.path.exists(tmp):