#915: redownload pulls full album_data from the primary source for iTunes/Deezer too
Second leak of the same class: redownload_start built full album_data (release_date/album_type/
total_tracks) only in the Spotify branch. The iTunes and Deezer branches set just track/disc number
and left album_data lean ({'name': ...}), so single-track redownloads on those sources dropped the
$year — same symptom as #915 in the add/download path.
Fix: both branches now fetch the album via get_album_for_source (cached, source-aware) and build
album_data through the shared _album_data_from_source helper, mirroring the Spotify branch. Falls
back to the lean default if the fetch returns nothing (no regression). get_album is cached on both
iTunes and Deezer, so no extra API cost.
Tests: _album_data_from_source (full build, image-url fallback, defaults). 694 library+downloads
tests green.
This commit is contained in:
parent
2b17ed8451
commit
d4e80fdaa0
2 changed files with 80 additions and 6 deletions
|
|
@ -16,6 +16,7 @@ from core.runtime_state import (
|
|||
download_tasks,
|
||||
tasks_lock,
|
||||
)
|
||||
from core.metadata.album_tracks import get_album_for_source
|
||||
from core.metadata.registry import (
|
||||
get_deezer_client,
|
||||
get_itunes_client,
|
||||
|
|
@ -26,6 +27,27 @@ from database.music_database import get_database
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _album_data_from_source(full: dict, album_id: str, fallback_name: str) -> dict:
|
||||
"""Build the redownload `album_data` from a primary-source get_album result (#915).
|
||||
|
||||
Mirrors the Spotify branch's album_data shape so iTunes/Deezer redownloads carry the
|
||||
real release_date / album_type / total_tracks — instead of a lean {'name': ...} that
|
||||
drops the $year and forces a manual reorganize afterwards."""
|
||||
images = full.get('images') or []
|
||||
image_url = full.get('image_url') or ''
|
||||
if not image_url and images and isinstance(images[0], dict):
|
||||
image_url = images[0].get('url', '')
|
||||
return {
|
||||
'id': str(full.get('id') or album_id),
|
||||
'name': full.get('name') or fallback_name,
|
||||
'release_date': full.get('release_date', ''),
|
||||
'album_type': full.get('album_type', 'album'),
|
||||
'total_tracks': full.get('total_tracks', 0),
|
||||
'images': images,
|
||||
'image_url': image_url,
|
||||
}
|
||||
|
||||
|
||||
def _get_itunes_client():
|
||||
"""Mirror of web_server._get_itunes_client — delegates to registry."""
|
||||
return get_itunes_client()
|
||||
|
|
@ -141,12 +163,26 @@ def redownload_start(track_id):
|
|||
'images': album_images,
|
||||
'image_url': album_images[0]['url'] if album_images else '',
|
||||
}
|
||||
elif meta_source == 'itunes':
|
||||
track_number = full_track_details.get('trackNumber')
|
||||
disc_number = full_track_details.get('discNumber', 1)
|
||||
elif meta_source == 'deezer':
|
||||
track_number = full_track_details.get('track_position')
|
||||
disc_number = full_track_details.get('disk_number', 1)
|
||||
elif meta_source in ('itunes', 'deezer'):
|
||||
# #915: parity with the Spotify branch + Reorganize — pull the full album from
|
||||
# the primary source so album_data carries release_date/album_type/total_tracks
|
||||
# (was lean {'name': ...}, which dropped the $year on iTunes/Deezer redownloads).
|
||||
if meta_source == 'itunes':
|
||||
track_number = full_track_details.get('trackNumber')
|
||||
disc_number = full_track_details.get('discNumber', 1)
|
||||
_alb_id = full_track_details.get('collectionId')
|
||||
else:
|
||||
track_number = full_track_details.get('track_position')
|
||||
disc_number = full_track_details.get('disk_number', 1)
|
||||
_alb_id = (full_track_details.get('album') or {}).get('id')
|
||||
if _alb_id:
|
||||
try:
|
||||
_full_album = get_album_for_source(meta_source, str(_alb_id))
|
||||
except Exception as _alb_err: # noqa: BLE001 — never let metadata break redownload
|
||||
logger.debug("[Redownload] %s album fetch failed: %s", meta_source, _alb_err)
|
||||
_full_album = None
|
||||
if isinstance(_full_album, dict):
|
||||
album_data = _album_data_from_source(_full_album, str(_alb_id), metadata.get('album', ''))
|
||||
|
||||
track_data = {
|
||||
'id': meta_id,
|
||||
|
|
|
|||
38
tests/library/test_redownload_album_data.py
Normal file
38
tests/library/test_redownload_album_data.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
"""Redownload builds full album_data from the primary source (#915).
|
||||
|
||||
iTunes/Deezer single-track redownloads used to carry a lean album_data ({'name': ...}),
|
||||
dropping the $year folder. _album_data_from_source mirrors the Spotify branch so the real
|
||||
release_date / album_type / total_tracks come through.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from core.library.redownload import _album_data_from_source
|
||||
|
||||
|
||||
def test_builds_full_album_data_from_source():
|
||||
full = {'id': 'it-1', 'name': 'Big OST', 'release_date': '2024-04-17',
|
||||
'album_type': 'album', 'total_tracks': 70, 'image_url': 'http://x/cover.jpg'}
|
||||
out = _album_data_from_source(full, 'it-1', 'fallback')
|
||||
assert out['release_date'] == '2024-04-17' # real date, not YYYY-01-01
|
||||
assert out['album_type'] == 'album'
|
||||
assert out['total_tracks'] == 70
|
||||
assert out['id'] == 'it-1'
|
||||
assert out['name'] == 'Big OST'
|
||||
assert out['image_url'] == 'http://x/cover.jpg'
|
||||
|
||||
|
||||
def test_image_url_falls_back_to_images_array():
|
||||
full = {'name': 'A', 'release_date': '2020-01-01', 'images': [{'url': 'http://x/img.jpg'}]}
|
||||
out = _album_data_from_source(full, 'a1', 'fb')
|
||||
assert out['image_url'] == 'http://x/img.jpg'
|
||||
|
||||
|
||||
def test_defaults_when_fields_missing():
|
||||
out = _album_data_from_source({}, 'a1', 'Fallback Album')
|
||||
assert out['id'] == 'a1' # falls back to the queried id
|
||||
assert out['name'] == 'Fallback Album'
|
||||
assert out['album_type'] == 'album' # default
|
||||
assert out['total_tracks'] == 0
|
||||
assert out['release_date'] == ''
|
||||
assert out['image_url'] == ''
|
||||
Loading…
Reference in a new issue