Fix staging files bypassing path template

_try_staging_match() built a minimal context missing spotify_artist,
spotify_album, is_album_download, and has_clean_spotify_data. Post-
processing returned early at the missing-spotify_artist guard and the
copied file was left at the transfer root with its original filename.

Now mirrors the sync modal worker's context-building: uses
_explicit_album_context/_explicit_artist_context when available
(artist-page album downloads), falls back to track.album/track.artists
for playlists and sync modal. track_number and disc_number are also
forwarded so multi-disc albums land in the correct Disc N/ subfolder.
pull/301/head
Broque Thomas 1 week ago
parent ab9064d3f6
commit 61c6b6f3f9

@ -28732,13 +28732,100 @@ def _try_staging_match(task_id, batch_id, track):
context_key = f"staging_{task_id}"
with tasks_lock:
track_info = download_tasks.get(task_id, {}).get('track_info', {})
if not isinstance(track_info, dict):
track_info = {}
# Build spotify_artist / spotify_album context so post-processing can apply
# the path template. Without these, _post_process_matched_download returns
# early and the file stays at the transfer root with its original filename.
# Mirror the context-building logic from the sync modal worker.
has_explicit_context = track_info.get('_is_explicit_album_download', False)
if has_explicit_context:
explicit_artist = track_info.get('_explicit_artist_context', {})
if isinstance(explicit_artist, str):
explicit_artist = {'name': explicit_artist}
elif not isinstance(explicit_artist, dict):
explicit_artist = {}
spotify_artist_ctx = {
'id': explicit_artist.get('id', 'staging'),
'name': explicit_artist.get('name', track_artist),
'genres': explicit_artist.get('genres', [])
}
explicit_album = track_info.get('_explicit_album_context', {})
if not isinstance(explicit_album, dict):
explicit_album = {}
_album_image_url = explicit_album.get('image_url')
if not _album_image_url and explicit_album.get('images'):
_imgs = explicit_album['images']
if isinstance(_imgs, list) and _imgs:
_album_image_url = _imgs[0].get('url') if isinstance(_imgs[0], dict) else None
spotify_album_ctx = {
'id': explicit_album.get('id', 'staging'),
'name': explicit_album.get('name', getattr(track, 'album', '') or ''),
'release_date': explicit_album.get('release_date', ''),
'image_url': _album_image_url,
'album_type': explicit_album.get('album_type', 'album'),
'total_tracks': explicit_album.get('total_tracks', 0),
'total_discs': explicit_album.get('total_discs', 1),
'artists': explicit_album.get('artists', [{'name': spotify_artist_ctx.get('name', '')}])
}
is_album_ctx = True
has_clean_data = True
else:
fallback_album = track_info.get('album', {})
if isinstance(fallback_album, str):
fallback_album = {'name': fallback_album}
elif not isinstance(fallback_album, dict):
fallback_album = {}
track_album_name = getattr(track, 'album', '') or fallback_album.get('name', '') or ''
spotify_artist_ctx = {
'id': 'staging',
'name': track_artist or 'Unknown',
'genres': []
}
spotify_album_ctx = {
'id': 'staging',
'name': track_album_name,
'release_date': fallback_album.get('release_date', ''),
'image_url': fallback_album.get('image_url'),
'album_type': fallback_album.get('album_type', 'album'),
'total_tracks': fallback_album.get('total_tracks', 0),
'total_discs': fallback_album.get('total_discs', 1),
'artists': [{'name': track_artist}] if track_artist else []
}
is_album_ctx = bool(
track_album_name and
track_album_name.strip() and
track_album_name.lower() not in ('unknown album', '') and
track_album_name.lower() != track_title.lower()
)
has_clean_data = bool(track_title and track_artist and track_album_name)
track_number = (
track_info.get('track_number', 0) or
getattr(track, 'track_number', 0) or 0
)
disc_number = (
track_info.get('disc_number', 1) or
getattr(track, 'disc_number', 1) or 1
)
context = {
'track_info': track_info,
'spotify_artist': spotify_artist_ctx,
'spotify_album': spotify_album_ctx,
'original_search_result': {
'title': track_title,
'artist': track_artist,
'spotify_clean_title': track_title,
'spotify_clean_album': spotify_album_ctx.get('name', ''),
'spotify_clean_artist': track_artist,
'track_number': track_number,
'disc_number': disc_number,
},
'is_album_download': is_album_ctx,
'has_clean_spotify_data': has_clean_data,
'staging_source': True,
}

@ -3600,6 +3600,10 @@ function closeHelperSearch() {
const WHATS_NEW = {
'2.2': [
// --- April 14, 2026 ---
{ date: 'April 14, 2026' },
{ title: 'Fix Staging Files Ignoring Path Template', desc: 'Files matched from the Staging folder were copied to the transfer root with their original filename instead of applying the configured path template. Post-processing now receives full artist/album context for staging matches' },
// --- April 4, 2026 ---
{ date: 'April 4, 2026' },
{ title: 'Artist Map — Visualize Your Music Universe', desc: 'Three interactive canvas modes: Watchlist Constellation (your artists + similar), Genre Map (browse by genre with sidebar), and Artist Explorer (deep-dive any artist). Offscreen buffer rendering handles 1000+ nodes', page: 'discover' },

Loading…
Cancel
Save