Tag writer: stop downgrading full release dates to just the year (#824)
Files tagged with a full date (e.g. 2023-11-03) were overwritten with only the year on every enrichment/retag: the tag reader pulls the full TDRC/date string, but the library DB stores `year` as an INTEGER, and the writer wrote str(year) back unconditionally — truncating 2023-11-03 → 2023 (Tacobell444 #824). Fix: new _date_to_write(existing, year) keeps the file's existing, more-specific date when its year already matches what we'd write (the full date is correct and consistent); it only writes the bare year when the file has no date or the year genuinely differs (a real correction). Wired into the ID3 (TDRC), Vorbis (date) and MP4 (©day) writers. build_tag_diff no longer flags the year as "changed" when the years match, so the preview stops showing a phantom 2023-11-03 → 2023. Tests: diff doesn't flag same-year full dates (but does flag a different year); end-to-end write preserves 2023-11-03 against DB year 2023, and still corrects a wrong year. 339 tag/retag tests pass. NOTE (not fixed here): manually entering a NEW full date still can't persist — the library albums/tracks tables store `year` as INT, so a yyyy-mm-dd entry is truncated at the DB layer. Supporting manual full dates + enrichment fetching full dates needs a release_date column (follow-up).
This commit is contained in:
parent
e6bf7c26de
commit
319e90dead
2 changed files with 61 additions and 3 deletions
|
|
@ -214,6 +214,12 @@ def build_tag_diff(file_tags: Dict[str, Any], db_data: Dict[str, Any]) -> List[D
|
|||
if db_key == 'year' and db_val is not None:
|
||||
db_str = str(db_val)
|
||||
db_val = str(db_val)
|
||||
# Don't flag a full file date (2023-11-03) → year (2023) as a change
|
||||
# when the years already match: the writer preserves the full date,
|
||||
# so it isn't actually changing (#824). Only a different year is a
|
||||
# real change.
|
||||
if file_str and file_str[:4] == db_str:
|
||||
file_str = db_str
|
||||
|
||||
# Only mark as changed if DB has a value AND it differs from file
|
||||
# (writer skips fields where DB value is empty, so don't show them as diffs)
|
||||
|
|
@ -442,6 +448,20 @@ def _multi_artist_write_enabled() -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def _date_to_write(existing: Optional[str], year) -> str:
|
||||
"""Value to write for the date/year tag. Writes the DB year, BUT keeps an
|
||||
existing, MORE-specific file date (e.g. ``2023-11-03``) when its year already
|
||||
matches — so enrichment/retag never downgrades a real full release date to
|
||||
just the year (#824). When the years differ (a genuine correction) or the
|
||||
file has no date, the year is written as before."""
|
||||
year_str = str(year)
|
||||
if existing:
|
||||
existing = str(existing).strip()
|
||||
if len(existing) > 4 and existing[:4] == year_str:
|
||||
return existing
|
||||
return year_str
|
||||
|
||||
|
||||
def _write_id3(audio, title, artist, album_artist, album, year, genre,
|
||||
track_num, total_tracks, disc_num, bpm,
|
||||
artists_list: Optional[List[str]] = None) -> List[str]:
|
||||
|
|
@ -473,8 +493,9 @@ def _write_id3(audio, title, artist, album_artist, album, year, genre,
|
|||
audio.tags.add(TALB(encoding=3, text=[album]))
|
||||
written.append('album')
|
||||
if year is not None:
|
||||
existing_date = _id3_text(audio.tags, 'TDRC')
|
||||
audio.tags.delall('TDRC')
|
||||
audio.tags.add(TDRC(encoding=3, text=[str(year)]))
|
||||
audio.tags.add(TDRC(encoding=3, text=[_date_to_write(existing_date, year)]))
|
||||
written.append('year')
|
||||
if genre:
|
||||
audio.tags.delall('TCON')
|
||||
|
|
@ -520,7 +541,7 @@ def _write_vorbis(audio, title, artist, album_artist, album, year, genre,
|
|||
audio['album'] = [album]
|
||||
written.append('album')
|
||||
if year is not None:
|
||||
audio['date'] = [str(year)]
|
||||
audio['date'] = [_date_to_write(_vorbis_first(audio, 'date'), year)]
|
||||
written.append('year')
|
||||
if genre:
|
||||
audio['genre'] = [genre]
|
||||
|
|
@ -564,7 +585,7 @@ def _write_mp4(audio, title, artist, album_artist, album, year, genre,
|
|||
audio['\xa9alb'] = [album]
|
||||
written.append('album')
|
||||
if year is not None:
|
||||
audio['\xa9day'] = [str(year)]
|
||||
audio['\xa9day'] = [_date_to_write(_mp4_first(audio, '\xa9day'), year)]
|
||||
written.append('year')
|
||||
if genre:
|
||||
audio['\xa9gen'] = [genre]
|
||||
|
|
|
|||
|
|
@ -141,3 +141,40 @@ def test_write_real_value_still_overwrites(flac_path):
|
|||
result = write_tags_to_file(flac_path, {'artist_name': 'Coldplay'}, embed_cover=False)
|
||||
assert result['success'] is True
|
||||
assert FLAC(flac_path).get('artist') == ['Coldplay']
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# #824 — full release dates must not be downgraded to just the year
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_diff_full_date_same_year_not_flagged():
|
||||
# File has the full date 2023-11-03; DB has year 2023. Same year → the writer
|
||||
# keeps the full date, so it must NOT show as a change.
|
||||
diff = {d['field']: d for d in build_tag_diff({'year': '2023-11-03'}, {'year': 2023})}
|
||||
assert diff['Year']['changed'] is False
|
||||
|
||||
|
||||
def test_diff_different_year_still_flagged():
|
||||
# A genuinely different year is still a real change.
|
||||
diff = {d['field']: d for d in build_tag_diff({'year': '2022-11-03'}, {'year': 2023})}
|
||||
assert diff['Year']['changed'] is True
|
||||
|
||||
|
||||
def test_write_preserves_full_date_when_year_matches(flac_path):
|
||||
audio = FLAC(flac_path)
|
||||
audio['date'] = ['2023-11-03'] # file already has the full release date
|
||||
audio.save()
|
||||
|
||||
write_tags_to_file(flac_path, {'year': 2023}, embed_cover=False) # DB knows only the year
|
||||
|
||||
assert FLAC(flac_path).get('date') == ['2023-11-03'] # full date preserved, NOT downgraded
|
||||
|
||||
|
||||
def test_write_corrects_year_when_it_actually_differs(flac_path):
|
||||
audio = FLAC(flac_path)
|
||||
audio['date'] = ['2022']
|
||||
audio.save()
|
||||
|
||||
write_tags_to_file(flac_path, {'year': 2023}, embed_cover=False)
|
||||
|
||||
assert FLAC(flac_path).get('date') == ['2023'] # wrong year still corrected
|
||||
|
|
|
|||
Loading…
Reference in a new issue