Fix Invalid ID3TimeStamp error when writing date tags
Strip non-timestamp characters (BOM, invisible chars) from date/year values both when reading existing tags in metadata_resolver and when writing in executor. Also harden the EasyID3 except block to not wipe existing tags when adding a missing ID3 header, and add per-field try/except in MP3 tag writing so one bad field doesn't abort the entire track. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d91eb36007
commit
460b92aab3
2 changed files with 23 additions and 5 deletions
22
executor.py
22
executor.py
|
|
@ -73,7 +73,10 @@ def write_tags(path: Path, proposal: TrackProposal, album_proposal: AlbumProposa
|
||||||
if proposal.disc_number:
|
if proposal.disc_number:
|
||||||
tags_to_write["discnumber"] = str(proposal.disc_number)
|
tags_to_write["discnumber"] = str(proposal.disc_number)
|
||||||
if album_proposal.date:
|
if album_proposal.date:
|
||||||
tags_to_write["date"] = album_proposal.date
|
# Strip everything except valid ID3 timestamp characters to prevent ID3TimeStamp errors
|
||||||
|
date_clean = re.sub(r"[^\d\-T:+Z]", "", str(album_proposal.date)).strip()
|
||||||
|
if date_clean:
|
||||||
|
tags_to_write["date"] = date_clean
|
||||||
if album_proposal.genre:
|
if album_proposal.genre:
|
||||||
tags_to_write["genre"] = album_proposal.genre
|
tags_to_write["genre"] = album_proposal.genre
|
||||||
if album_proposal.label:
|
if album_proposal.label:
|
||||||
|
|
@ -84,11 +87,22 @@ def write_tags(path: Path, proposal: TrackProposal, album_proposal: AlbumProposa
|
||||||
try:
|
try:
|
||||||
audio = EasyID3(str(path))
|
audio = EasyID3(str(path))
|
||||||
except Exception:
|
except Exception:
|
||||||
audio = EasyID3()
|
# File has no ID3 header — add one without wiping audio data
|
||||||
audio.save(str(path))
|
from mutagen.id3 import ID3NoHeaderError
|
||||||
|
try:
|
||||||
|
from mutagen.mp3 import MP3
|
||||||
|
full = MP3(str(path))
|
||||||
|
full.tags = None
|
||||||
|
full.add_tags()
|
||||||
|
full.save(str(path), v2_version=4)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
audio = EasyID3(str(path))
|
audio = EasyID3(str(path))
|
||||||
for k, v in tags_to_write.items():
|
for k, v in tags_to_write.items():
|
||||||
audio[k] = [v]
|
try:
|
||||||
|
audio[k] = [v]
|
||||||
|
except Exception as tag_err:
|
||||||
|
print(f" ⚠️ Tag-Feld '{k}' übersprungen ({path.name}): {tag_err}", file=sys.stderr)
|
||||||
audio.save(v2_version=4)
|
audio.save(v2_version=4)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -337,8 +337,12 @@ def resolve(
|
||||||
album = album or Counter(tag_albums).most_common(1)[0][0]
|
album = album or Counter(tag_albums).most_common(1)[0][0]
|
||||||
|
|
||||||
# Tag year/genre/label
|
# Tag year/genre/label
|
||||||
|
import re as _re
|
||||||
for t in hints.tracks:
|
for t in hints.tracks:
|
||||||
year = year or t.existing_tags.get("date") or t.existing_tags.get("year")
|
raw_year = t.existing_tags.get("date") or t.existing_tags.get("year")
|
||||||
|
if raw_year and not year:
|
||||||
|
# Strip invisible chars so ID3TimeStamp validation doesn't fail later
|
||||||
|
year = _re.sub(r"[^\d\-T:+Z]", "", str(raw_year)).strip()[:10] or None
|
||||||
genre = genre or t.existing_tags.get("genre")
|
genre = genre or t.existing_tags.get("genre")
|
||||||
label = label or t.existing_tags.get("label") or t.existing_tags.get("organization")
|
label = label or t.existing_tags.get("label") or t.existing_tags.get("organization")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue