slim-embedded-art: hash the audio region from mutagen own tag parse
A tagger that writes a non-standard size field puts the header claim and the real tag end in different places. mutagen preserves audio from where it parsed the tag to end; the guard hashed from where the header claimed, and refused good rewrites across a whole album. Both hashes now use the same authority. Failed files stay untouched and a re-run picks them up.
This commit is contained in:
@@ -41,16 +41,29 @@ EMBED_TARGET = 80_000
|
||||
PROCESS_OVER = 100_000
|
||||
|
||||
|
||||
def audio_region_hash(path):
|
||||
"""SHA-256 of everything after the ID3v2 tag - the audio, byte-for-byte."""
|
||||
def audio_region_hash(path, offset=None):
|
||||
"""SHA-256 of everything after the ID3v2 tag - the audio, byte-for-byte.
|
||||
|
||||
The offset comes from mutagen's OWN parse of the tag when available. Reading the header's
|
||||
syncsafe size field ourselves disagreed with mutagen on files whose tagger wrote a
|
||||
non-standard size (Shamrocks and Shenanigans, 2026-08-29): mutagen preserved the audio from
|
||||
where IT parsed the tag to end, our hash read from where the header claimed, and the guard
|
||||
refused a perfectly good rewrite.
|
||||
"""
|
||||
if offset is None:
|
||||
try:
|
||||
offset = ID3(path).size
|
||||
except Exception:
|
||||
offset = 0
|
||||
if not offset:
|
||||
with open(path, "rb") as f:
|
||||
head = f.read(10)
|
||||
if head[:3] == b"ID3":
|
||||
offset = 10 + ((head[6] << 21) | (head[7] << 14) | (head[8] << 7) | head[9])
|
||||
if head[5] & 0x10: # v2.4 footer
|
||||
offset += 10
|
||||
with open(path, "rb") as f:
|
||||
head = f.read(10)
|
||||
off = 0
|
||||
if head[:3] == b"ID3":
|
||||
off = 10 + ((head[6] << 21) | (head[7] << 14) | (head[8] << 7) | head[9])
|
||||
if head[5] & 0x10: # v2.4 footer
|
||||
off += 10
|
||||
f.seek(off)
|
||||
f.seek(offset)
|
||||
h = hashlib.sha256()
|
||||
while chunk := f.read(1 << 20):
|
||||
h.update(chunk)
|
||||
|
||||
Reference in New Issue
Block a user