Tighten legacy logging output
- collapse old multi-line debug bursts into single structured rows - remove leftover DEBUG-style prefixes from message text - keep the app log readable without losing useful trace detail
This commit is contained in:
parent
01d118daa6
commit
71e114b6fe
8 changed files with 221 additions and 113 deletions
|
|
@ -930,10 +930,16 @@ class DatabaseUpdateWorker:
|
|||
if (db_track.title != current_title or
|
||||
db_track.artist_name != current_artist or
|
||||
db_track.album_title != current_album):
|
||||
logger.debug(f"Metadata change detected for track ID {track_id}:")
|
||||
logger.debug(f" Title: '{db_track.title}' → '{current_title}'")
|
||||
logger.debug(f" Artist: '{db_track.artist_name}' → '{current_artist}'")
|
||||
logger.debug(f" Album: '{db_track.album_title}' → '{current_album}'")
|
||||
logger.debug(
|
||||
"Metadata change detected for track %s: title=%r→%r artist=%r→%r album=%r→%r",
|
||||
track_id,
|
||||
db_track.title,
|
||||
current_title,
|
||||
db_track.artist_name,
|
||||
current_artist,
|
||||
db_track.album_title,
|
||||
current_album,
|
||||
)
|
||||
changes_detected += 1
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -61,10 +61,12 @@ class DownloadOrchestrator:
|
|||
|
||||
logger.info(f"Download Orchestrator initialized - Mode: {self.mode}")
|
||||
if self.mode == 'hybrid':
|
||||
if self.hybrid_order:
|
||||
logger.info(f" Source priority: {' → '.join(self.hybrid_order)}")
|
||||
else:
|
||||
logger.info(f" Primary: {self.hybrid_primary}, Fallback: {self.hybrid_secondary}")
|
||||
logger.info(
|
||||
"Hybrid source order: order=%s primary=%s secondary=%s",
|
||||
" → ".join(self.hybrid_order) if self.hybrid_order else "default",
|
||||
self.hybrid_primary,
|
||||
self.hybrid_secondary,
|
||||
)
|
||||
|
||||
def _safe_init(self, name, cls):
|
||||
"""Initialize a download client, returning None on failure instead of crashing."""
|
||||
|
|
@ -154,8 +156,10 @@ class DownloadOrchestrator:
|
|||
except Exception:
|
||||
results[source] = False
|
||||
|
||||
status_parts = [f"{s}: {'' if ok else ''}" for s, ok in results.items()]
|
||||
logger.info(f" {' | '.join(status_parts)}")
|
||||
logger.info(
|
||||
"Hybrid connection check: %s",
|
||||
" | ".join(f"{source}={'ok' if ok else 'fail'}" for source, ok in results.items()),
|
||||
)
|
||||
|
||||
return any(results.values())
|
||||
|
||||
|
|
|
|||
|
|
@ -1633,14 +1633,14 @@ class JellyfinClient:
|
|||
def is_library_scanning(self, library_name: str = "Music") -> bool:
|
||||
"""Check if Jellyfin library is currently scanning"""
|
||||
if not self.ensure_connection():
|
||||
logger.debug("DEBUG: Not connected to Jellyfin, cannot check scan status")
|
||||
logger.debug("Not connected to Jellyfin, cannot check scan status")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Check scheduled tasks for library scan activities
|
||||
response = self._make_request('/ScheduledTasks')
|
||||
if not response:
|
||||
logger.debug("DEBUG: Could not get scheduled tasks")
|
||||
logger.debug("Could not get scheduled tasks")
|
||||
return False
|
||||
|
||||
for task in response:
|
||||
|
|
@ -1650,10 +1650,14 @@ class JellyfinClient:
|
|||
# Look for library scan related tasks that are running
|
||||
if ('scan' in task_name or 'refresh' in task_name or 'library' in task_name):
|
||||
if task_state in ['Running', 'Cancelling']:
|
||||
logger.debug(f"DEBUG: Found running scan task: {task.get('Name')} (State: {task_state})")
|
||||
logger.debug(
|
||||
"Found running scan task: name=%s state=%s",
|
||||
task.get('Name'),
|
||||
task_state,
|
||||
)
|
||||
return True
|
||||
|
||||
logger.debug("DEBUG: No active scan tasks detected")
|
||||
logger.debug("No active scan tasks detected")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -1088,7 +1088,14 @@ def check_album_completion(
|
|||
else:
|
||||
status = "missing"
|
||||
|
||||
logger.debug(f" Result: {owned_tracks}/{expected_tracks or total_tracks} tracks ({completion_percentage:.1f}%) - {status}")
|
||||
logger.debug(
|
||||
"Album completion result: owned=%s expected=%s total=%s completion=%.1f status=%s",
|
||||
owned_tracks,
|
||||
expected_tracks or total_tracks,
|
||||
total_tracks,
|
||||
completion_percentage,
|
||||
status,
|
||||
)
|
||||
|
||||
return {
|
||||
"id": album_id,
|
||||
|
|
@ -1137,7 +1144,12 @@ def check_single_completion(
|
|||
if total_tracks == 0:
|
||||
total_tracks = _resolve_completion_track_total(single_data, source_chain) or 1
|
||||
|
||||
logger.debug(f"Checking {album_type}: '{single_name}' ({total_tracks} tracks)")
|
||||
logger.debug(
|
||||
"Checking %s: name=%r tracks=%s",
|
||||
album_type,
|
||||
single_name,
|
||||
total_tracks,
|
||||
)
|
||||
|
||||
if album_type == 'ep' or total_tracks > 1:
|
||||
try:
|
||||
|
|
@ -1167,7 +1179,14 @@ def check_single_completion(
|
|||
else:
|
||||
status = "missing"
|
||||
|
||||
logger.debug(f" EP Result: {owned_tracks}/{expected_tracks or total_tracks} tracks ({completion_percentage:.1f}%) - {status}")
|
||||
logger.debug(
|
||||
"EP completion result: owned=%s expected=%s total=%s completion=%.1f status=%s",
|
||||
owned_tracks,
|
||||
expected_tracks or total_tracks,
|
||||
total_tracks,
|
||||
completion_percentage,
|
||||
status,
|
||||
)
|
||||
|
||||
return {
|
||||
"id": single_id,
|
||||
|
|
@ -1208,7 +1227,12 @@ def check_single_completion(
|
|||
elif ext:
|
||||
formats = [ext]
|
||||
|
||||
logger.debug(f" Single Result: {owned_tracks}/1 tracks ({completion_percentage:.1f}%) - {status}")
|
||||
logger.debug(
|
||||
"Single completion result: owned=%s expected=1 completion=%.1f status=%s",
|
||||
owned_tracks,
|
||||
completion_percentage,
|
||||
status,
|
||||
)
|
||||
|
||||
return {
|
||||
"id": single_id,
|
||||
|
|
|
|||
|
|
@ -937,7 +937,7 @@ class PlexClient:
|
|||
def is_library_scanning(self, library_name: str = "Music") -> bool:
|
||||
"""Check if Plex library is currently scanning"""
|
||||
if not self.ensure_connection():
|
||||
logger.debug(f"DEBUG: Not connected to Plex, cannot check scan status")
|
||||
logger.debug("Not connected to Plex, cannot check scan status")
|
||||
return False
|
||||
|
||||
try:
|
||||
|
|
@ -946,31 +946,31 @@ class PlexClient:
|
|||
# Check if library has a scanning attribute or is refreshing
|
||||
# The Plex API exposes this through the library's refreshing property
|
||||
refreshing = hasattr(library, 'refreshing') and library.refreshing
|
||||
logger.debug(f"DEBUG: Library.refreshing = {refreshing}")
|
||||
logger.debug("Library.refreshing = %s", refreshing)
|
||||
|
||||
if refreshing:
|
||||
logger.debug(f"DEBUG: Library is refreshing")
|
||||
logger.debug("Library is refreshing")
|
||||
return True
|
||||
|
||||
# Alternative method: Check server activities for scanning
|
||||
try:
|
||||
activities = self.server.activities()
|
||||
logger.debug(f"DEBUG: Found {len(activities)} server activities")
|
||||
logger.debug("Found %s server activities", len(activities))
|
||||
|
||||
for activity in activities:
|
||||
# Look for library scan activities
|
||||
activity_type = getattr(activity, 'type', 'unknown')
|
||||
activity_title = getattr(activity, 'title', 'unknown')
|
||||
logger.debug(f"DEBUG: Activity - type: {activity_type}, title: {activity_title}")
|
||||
logger.debug("Activity - type=%s title=%s", activity_type, activity_title)
|
||||
|
||||
if (activity_type in ['library.scan', 'library.refresh'] and
|
||||
library_name.lower() in activity_title.lower()):
|
||||
logger.debug(f"DEBUG: Found matching scan activity: {activity_title}")
|
||||
logger.debug("Found matching scan activity: %s", activity_title)
|
||||
return True
|
||||
except Exception as activities_error:
|
||||
logger.debug(f"Could not check server activities: {activities_error}")
|
||||
|
||||
logger.debug(f"DEBUG: No scan activity detected")
|
||||
logger.debug("No scan activity detected")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -455,11 +455,23 @@ class SoulIDWorker:
|
|||
matching.normalize_string(db_name)
|
||||
)
|
||||
if score >= self.album_match_threshold:
|
||||
logger.debug(f" {source_name}: matched '{artist.name}' via album '{api_name}' ↔ '{db_name}' (score={score:.2f})")
|
||||
logger.debug(
|
||||
"%s matched artist=%r via album api=%r db=%r score=%.2f",
|
||||
source_name,
|
||||
artist.name,
|
||||
api_name,
|
||||
db_name,
|
||||
score,
|
||||
)
|
||||
return discog
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f" {source_name}: discography fetch failed for '{artist.name}': {e}")
|
||||
logger.debug(
|
||||
"%s discography fetch failed for artist=%r: %s",
|
||||
source_name,
|
||||
artist.name,
|
||||
e,
|
||||
)
|
||||
continue
|
||||
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -311,15 +311,17 @@ class WishlistService:
|
|||
def _spotify_track_object_to_dict(self, spotify_track) -> Dict[str, Any]:
|
||||
"""Convert a Spotify track object or TrackResult object to a dictionary"""
|
||||
try:
|
||||
# Add debug logging to see what we're dealing with
|
||||
logger.info(f"DEBUG: Converting track object to dict. Type: {type(spotify_track)}")
|
||||
logger.info(f"DEBUG: Has 'title' attribute: {hasattr(spotify_track, 'title')}")
|
||||
logger.info(f"DEBUG: Has 'artist' attribute: {hasattr(spotify_track, 'artist')}")
|
||||
logger.info(f"DEBUG: Has 'id' attribute: {hasattr(spotify_track, 'id')}")
|
||||
logger.debug(
|
||||
"Converting track object to dict: type=%s has_title=%s has_artist=%s has_id=%s",
|
||||
type(spotify_track),
|
||||
hasattr(spotify_track, 'title'),
|
||||
hasattr(spotify_track, 'artist'),
|
||||
hasattr(spotify_track, 'id'),
|
||||
)
|
||||
|
||||
# Check if this is a TrackResult object (has title/artist but no id)
|
||||
if hasattr(spotify_track, 'title') and hasattr(spotify_track, 'artist') and not hasattr(spotify_track, 'id'):
|
||||
logger.info("DEBUG: Detected TrackResult object, converting...")
|
||||
logger.debug("Detected TrackResult object, converting")
|
||||
# Handle TrackResult objects - these don't have Spotify IDs
|
||||
album_name = getattr(spotify_track, 'album', '') or getattr(spotify_track, 'title', 'Unknown Album')
|
||||
result = {
|
||||
|
|
@ -333,19 +335,23 @@ class WishlistService:
|
|||
'popularity': 0,
|
||||
'source': 'trackresult'
|
||||
}
|
||||
logger.info(f"DEBUG: TrackResult converted successfully: {result['name']} by {result['artists'][0]['name']}")
|
||||
logger.debug(
|
||||
"TrackResult converted successfully: name=%s artist=%s",
|
||||
result['name'],
|
||||
result['artists'][0]['name'],
|
||||
)
|
||||
return result
|
||||
|
||||
# Handle regular Spotify Track objects
|
||||
logger.info("DEBUG: Processing as Spotify Track object")
|
||||
logger.debug("Processing as Spotify Track object")
|
||||
|
||||
# Handle artists list carefully to avoid TrackResult serialization issues
|
||||
artists_list = []
|
||||
raw_artists = getattr(spotify_track, 'artists', [])
|
||||
logger.info(f"DEBUG: Raw artists: {raw_artists}, type: {type(raw_artists)}")
|
||||
logger.debug("Raw artists: %r (type=%s)", raw_artists, type(raw_artists))
|
||||
|
||||
for artist in raw_artists:
|
||||
logger.info(f"DEBUG: Processing artist: {artist}, type: {type(artist)}")
|
||||
logger.debug("Processing artist: %r (type=%s)", artist, type(artist))
|
||||
if hasattr(artist, 'name'):
|
||||
artists_list.append({'name': artist.name})
|
||||
elif isinstance(artist, str):
|
||||
|
|
@ -375,16 +381,20 @@ class WishlistService:
|
|||
'disc_number': getattr(spotify_track, 'disc_number', 1)
|
||||
}
|
||||
|
||||
logger.info(f"DEBUG: Spotify Track converted: {result['name']} by {[a['name'] for a in result['artists']]}")
|
||||
logger.debug(
|
||||
"Spotify Track converted: name=%s artists=%s",
|
||||
result['name'],
|
||||
[a['name'] for a in result['artists']],
|
||||
)
|
||||
|
||||
# Test JSON serialization before returning to catch any remaining issues
|
||||
try:
|
||||
import json
|
||||
json.dumps(result)
|
||||
logger.info("DEBUG: Conversion result is JSON serializable")
|
||||
logger.debug("Conversion result is JSON serializable")
|
||||
except Exception as json_error:
|
||||
logger.error(f"DEBUG: Conversion result is NOT JSON serializable: {json_error}")
|
||||
logger.error(f"DEBUG: Result content: {result}")
|
||||
logger.error("Conversion result is NOT JSON serializable: %s", json_error)
|
||||
logger.error("Conversion result content: %r", result)
|
||||
# Return a safe fallback
|
||||
return {
|
||||
'id': f"fallback_{hash(str(spotify_track))}",
|
||||
|
|
|
|||
188
web_server.py
188
web_server.py
|
|
@ -8206,14 +8206,9 @@ def get_beatport_hero_tracks():
|
|||
# SMART FILTERING - Remove duplicates and invalid tracks
|
||||
valid_tracks = []
|
||||
seen_urls = set()
|
||||
|
||||
logger.debug(f"Processing {len(tracks)} raw tracks from scraper (SMART FILTERING)...")
|
||||
filtered_reasons = collections.Counter()
|
||||
|
||||
for i, track in enumerate(tracks):
|
||||
logger.debug(f" Track {i+1}: {track.get('title', 'NO_TITLE')} - {track.get('artist', 'NO_ARTIST')}")
|
||||
logger.debug(f" URL: {track.get('url', 'NO_URL')}")
|
||||
logger.debug(f" Image: {'YES' if track.get('image_url') else 'NO'}")
|
||||
|
||||
# Extract and clean basic data
|
||||
title = track.get('title', '').strip()
|
||||
artist = track.get('artist', '').strip()
|
||||
|
|
@ -8258,7 +8253,7 @@ def get_beatport_hero_tracks():
|
|||
skip_reasons.append("Duplicate URL")
|
||||
|
||||
if not is_valid:
|
||||
logger.debug(f" Track {i+1} filtered out: {', '.join(skip_reasons)}")
|
||||
filtered_reasons.update(skip_reasons)
|
||||
continue
|
||||
|
||||
# Mark URL as seen for deduplication
|
||||
|
|
@ -8301,7 +8296,16 @@ def get_beatport_hero_tracks():
|
|||
break
|
||||
|
||||
valid_tracks.append(track_data)
|
||||
logger.debug(f" Track {i+1} added: {title} - {artist}")
|
||||
|
||||
sample_titles = [f"{t['title']} - {t['artist']}" for t in valid_tracks[:3]]
|
||||
logger.debug(
|
||||
"Beatport smart filter summary: raw=%s valid=%s filtered=%s reasons=%s sample=%s",
|
||||
len(tracks),
|
||||
len(valid_tracks),
|
||||
len(tracks) - len(valid_tracks),
|
||||
dict(filtered_reasons),
|
||||
sample_titles,
|
||||
)
|
||||
|
||||
logger.info(f"Retrieved {len(valid_tracks)} valid unique Beatport tracks (SMART FILTERING)")
|
||||
|
||||
|
|
@ -16257,10 +16261,14 @@ def _start_enhanced_album_download(enhanced_tracks, unmatched_tracks, spotify_ar
|
|||
"has_full_spotify_metadata": True # Flag for robust processing
|
||||
}
|
||||
|
||||
logger.info(f"Queued matched track: '{spotify_track['name']}' (track #{spotify_track['track_number']})")
|
||||
logger.info(
|
||||
"Queued matched track: title=%r track_number=%s",
|
||||
spotify_track['name'],
|
||||
spotify_track['track_number'],
|
||||
)
|
||||
started_count += 1
|
||||
else:
|
||||
logger.error(f"Failed to queue track: {filename}")
|
||||
logger.error("Failed to queue track: filename=%s", filename)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing matched track: {e}")
|
||||
|
|
@ -16399,10 +16407,14 @@ def _start_album_download_tasks(album_result, spotify_artist, spotify_album):
|
|||
"original_search_result": enhanced_context, # Contains corrected data + clean title
|
||||
"is_album_download": True
|
||||
}
|
||||
logger.info(f" + Queued track: {filename} (Matched to: '{corrected_meta.get('title')}')")
|
||||
logger.info(
|
||||
"Queued track: filename=%s matched_title=%r",
|
||||
filename,
|
||||
corrected_meta.get('title'),
|
||||
)
|
||||
started_count += 1
|
||||
else:
|
||||
logger.error(f" - Failed to queue track: {filename}")
|
||||
logger.error("Failed to queue track: filename=%s", filename)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing track in album batch: {track_data.get('filename')}: {e}")
|
||||
|
|
@ -16804,35 +16816,44 @@ def _detect_album_info_web(context: dict, artist: dict) -> dict:
|
|||
try:
|
||||
# Log available data for debugging (GUI PARITY)
|
||||
original_search = context.get("original_search_result", {})
|
||||
logger.info(f"\n[Album Detection] Starting for track: '{original_search.get('title', 'Unknown')}'")
|
||||
logger.info(f"[Data Available]:")
|
||||
logger.info(f" - Clean Spotify title: '{original_search.get('spotify_clean_title', 'None')}'")
|
||||
logger.info(f" - Clean Spotify album: '{original_search.get('spotify_clean_album', 'None')}'")
|
||||
logger.info(f" - Filename album: '{original_search.get('album', 'None')}'")
|
||||
logger.info(f" - Artist: '{artist.get('name', 'Unknown')}'")
|
||||
logger.info(f" - Context has clean data: {context.get('has_clean_spotify_data', False)}")
|
||||
logger.info(f" - Is album download: {context.get('is_album_download', False)}")
|
||||
logger.info(
|
||||
"[Album Detection] start: track=%r clean_spotify_title=%r clean_spotify_album=%r "
|
||||
"filename_album=%r artist=%r clean_data=%s album_download=%s",
|
||||
original_search.get('title', 'Unknown'),
|
||||
original_search.get('spotify_clean_title', 'None'),
|
||||
original_search.get('spotify_clean_album', 'None'),
|
||||
original_search.get('album', 'None'),
|
||||
artist.get('name', 'Unknown'),
|
||||
context.get('has_clean_spotify_data', False),
|
||||
context.get('is_album_download', False),
|
||||
)
|
||||
spotify_album_context = context.get("spotify_album")
|
||||
is_album_download = context.get("is_album_download", False)
|
||||
artist_name = artist['name']
|
||||
|
||||
logger.info(f"Album detection for '{original_search.get('title', 'Unknown')}' by '{artist_name}':")
|
||||
logger.info(f" Has album attr: {bool(original_search.get('album'))}")
|
||||
if original_search.get('album'):
|
||||
logger.info(f" Album value: '{original_search.get('album')}'")
|
||||
logger.info(
|
||||
"[Album Detection] track=%r artist=%r has_album_attr=%s album=%r",
|
||||
original_search.get('title', 'Unknown'),
|
||||
artist_name,
|
||||
bool(original_search.get('album')),
|
||||
original_search.get('album'),
|
||||
)
|
||||
|
||||
# --- THIS IS THE CRITICAL FIX ---
|
||||
# If this is part of a matched album download, we TRUST the context data completely.
|
||||
# This is the exact logic from downloads.py.
|
||||
if is_album_download and spotify_album_context:
|
||||
logger.info("Matched Album context found. Prioritizing pre-matched Spotify data.")
|
||||
|
||||
# We exclusively use the track number and title that were matched
|
||||
# *before* the download started. We do not try to re-parse the filename.
|
||||
track_number = original_search.get('track_number', 1)
|
||||
clean_track_name = original_search.get('title', 'Unknown Track')
|
||||
|
||||
logger.info(f" -> Using pre-matched Track #{track_number} and Title '{clean_track_name}'")
|
||||
logger.info(
|
||||
"[Album Detection] using matched context: track_number=%s title=%r album=%r",
|
||||
track_number,
|
||||
clean_track_name,
|
||||
spotify_album_context['name'],
|
||||
)
|
||||
|
||||
return {
|
||||
'is_album': True,
|
||||
|
|
@ -21333,11 +21354,12 @@ def _post_process_matched_download(context_key, context, file_path):
|
|||
clean_track_name = original_search.get('spotify_clean_title', 'Unknown Track')
|
||||
clean_album_name = original_search.get('spotify_clean_album', 'Unknown Album')
|
||||
|
||||
# DEBUG: Check what's in original_search
|
||||
logger.debug("Path 1 - Clean Spotify data path:")
|
||||
logger.info(f" original_search keys: {list(original_search.keys())}")
|
||||
logger.info(f" track_number in original_search: {'track_number' in original_search}")
|
||||
logger.info(f" track_number value: {original_search.get('track_number', 'NOT_FOUND')}")
|
||||
logger.debug(
|
||||
"Path 1 - Clean Spotify data path: keys=%s has_track_number=%s track_number=%s",
|
||||
list(original_search.keys()),
|
||||
'track_number' in original_search,
|
||||
original_search.get('track_number', 'NOT_FOUND'),
|
||||
)
|
||||
|
||||
album_info = {
|
||||
'is_album': True,
|
||||
|
|
@ -21358,12 +21380,13 @@ def _post_process_matched_download(context_key, context, file_path):
|
|||
spotify_album = context.get("spotify_album", {})
|
||||
clean_track_name = original_search.get('spotify_clean_title') or original_search.get('title', 'Unknown Track')
|
||||
|
||||
# DEBUG: Check what's in original_search for path 2
|
||||
logger.debug("Path 2 - Enhanced fallback album context path:")
|
||||
logger.info(f" original_search keys: {list(original_search.keys())}")
|
||||
logger.info(f" track_number in original_search: {'track_number' in original_search}")
|
||||
logger.info(f" track_number value: {original_search.get('track_number', 'NOT_FOUND')}")
|
||||
logger.info(f" spotify_album name: {spotify_album.get('name', 'NOT_FOUND')}")
|
||||
logger.debug(
|
||||
"Path 2 - Enhanced fallback album context path: keys=%s has_track_number=%s track_number=%s spotify_album=%s",
|
||||
list(original_search.keys()),
|
||||
'track_number' in original_search,
|
||||
original_search.get('track_number', 'NOT_FOUND'),
|
||||
spotify_album.get('name', 'NOT_FOUND'),
|
||||
)
|
||||
|
||||
# ENHANCEMENT: Use spotify_clean_album if available for consistency
|
||||
album_name = (original_search.get('spotify_clean_album') or
|
||||
|
|
@ -21391,8 +21414,11 @@ def _post_process_matched_download(context_key, context, file_path):
|
|||
# Explicit album downloads already have the correct Spotify album name —
|
||||
# re-grouping would mangle names like "(Reworked and Remastered)" into "(Deluxe Edition)".
|
||||
if album_info and album_info['is_album'] and not is_album_download:
|
||||
logger.info(f"\nSMART ALBUM GROUPING for track: '{album_info.get('clean_track_name', 'Unknown')}'")
|
||||
logger.info(f" Original album: '{album_info.get('album_name', 'None')}'")
|
||||
logger.info(
|
||||
"SMART ALBUM GROUPING for track=%r original_album=%r",
|
||||
album_info.get('clean_track_name', 'Unknown'),
|
||||
album_info.get('album_name', 'None'),
|
||||
)
|
||||
|
||||
# Get original album name from context if available
|
||||
original_album = None
|
||||
|
|
@ -21403,11 +21429,12 @@ def _post_process_matched_download(context_key, context, file_path):
|
|||
consistent_album_name = _resolve_album_group(spotify_artist, album_info, original_album)
|
||||
album_info['album_name'] = consistent_album_name
|
||||
|
||||
logger.info(f" Final album name: '{consistent_album_name}'")
|
||||
logger.info(f"Album grouping complete!\n")
|
||||
logger.info("Album grouping complete: final_album=%r", consistent_album_name)
|
||||
elif album_info and album_info['is_album'] and is_album_download:
|
||||
logger.info(f"\nEXPLICIT ALBUM DOWNLOAD - preserving Spotify album name: '{album_info.get('album_name', 'None')}'")
|
||||
logger.info(f" Skipping smart grouping (not needed for explicit album downloads)\n")
|
||||
logger.info(
|
||||
"EXPLICIT ALBUM DOWNLOAD - preserving Spotify album name=%r; skipping smart grouping",
|
||||
album_info.get('album_name', 'None'),
|
||||
)
|
||||
|
||||
# 1. Get transfer path (directory creation handled by _build_final_path_for_track)
|
||||
file_ext = os.path.splitext(file_path)[1]
|
||||
|
|
@ -21443,17 +21470,21 @@ def _post_process_matched_download(context_key, context, file_path):
|
|||
final_track_name_sanitized = _sanitize_filename(clean_track_name)
|
||||
track_number = album_info['track_number']
|
||||
|
||||
# DEBUG: Check final track_number values
|
||||
logger.debug("Final track_number processing:")
|
||||
logger.info(f" album_info source: {album_info.get('source', 'unknown')}")
|
||||
logger.info(f" album_info track_number: {album_info.get('track_number', 'NOT_FOUND')}")
|
||||
logger.info(f" track_number variable: {track_number}")
|
||||
logger.debug(
|
||||
"Final track_number processing: source=%s album_info_track_number=%s track_number=%s",
|
||||
album_info.get('source', 'unknown'),
|
||||
album_info.get('track_number', 'NOT_FOUND'),
|
||||
track_number,
|
||||
)
|
||||
|
||||
# Fix: Handle None track_number
|
||||
if track_number is None:
|
||||
logger.info(f"Track number is None, extracting from filename: {os.path.basename(file_path)}")
|
||||
track_number = _extract_track_number_from_filename(file_path)
|
||||
logger.info(f" -> Extracted track number: {track_number}")
|
||||
logger.info(
|
||||
"Track number was None; extracted from filename=%r -> %s",
|
||||
os.path.basename(file_path),
|
||||
track_number,
|
||||
)
|
||||
|
||||
# Ensure track_number is valid
|
||||
if not isinstance(track_number, int) or track_number < 1:
|
||||
|
|
@ -29288,9 +29319,12 @@ def _run_post_processing_worker(task_id, batch_id):
|
|||
|
||||
# If no track number in context, extract from filename
|
||||
if track_number == 1 and found_file:
|
||||
logger.warning(f"[Verification] No track_number in context, extracting from filename: {os.path.basename(found_file)}")
|
||||
track_number = _extract_track_number_from_filename(found_file)
|
||||
logger.info(f" -> Extracted track number: {track_number}")
|
||||
logger.warning(
|
||||
"[Verification] missing track_number; extracted from filename=%r -> %s",
|
||||
os.path.basename(found_file),
|
||||
track_number,
|
||||
)
|
||||
|
||||
# Ensure track_number is valid
|
||||
if not isinstance(track_number, int) or track_number < 1:
|
||||
|
|
@ -32990,24 +33024,37 @@ def get_spotify_playlists():
|
|||
# Handle snapshot_id safely - may not exist in core Playlist class
|
||||
playlist_snapshot = getattr(p, 'snapshot_id', '')
|
||||
|
||||
logger.info(f"Processing playlist: {p.name} (ID: {p.id})")
|
||||
logger.info(f" - Playlist snapshot: '{playlist_snapshot}'")
|
||||
logger.info(f" - Status info: {status_info}")
|
||||
|
||||
if 'last_synced' in status_info:
|
||||
stored_snapshot = status_info.get('snapshot_id')
|
||||
last_sync_time = datetime.fromisoformat(status_info['last_synced']).strftime('%b %d, %H:%M')
|
||||
logger.info(f" - Stored snapshot: '{stored_snapshot}'")
|
||||
logger.info(f" - Snapshots match: {playlist_snapshot == stored_snapshot}")
|
||||
|
||||
if playlist_snapshot != stored_snapshot:
|
||||
sync_status = f"Last Sync: {last_sync_time}"
|
||||
logger.info(f" - Result: Needs Sync (showing: {sync_status})")
|
||||
logger.info(
|
||||
"Playlist sync status: name=%s id=%s snapshot=%r stored_snapshot=%r result=Needs Sync display=%s",
|
||||
p.name,
|
||||
p.id,
|
||||
playlist_snapshot,
|
||||
stored_snapshot,
|
||||
sync_status,
|
||||
)
|
||||
else:
|
||||
sync_status = f"Synced: {last_sync_time}"
|
||||
logger.info(f" - Result: {sync_status}")
|
||||
logger.info(
|
||||
"Playlist sync status: name=%s id=%s snapshot=%r stored_snapshot=%r result=Synced display=%s",
|
||||
p.name,
|
||||
p.id,
|
||||
playlist_snapshot,
|
||||
stored_snapshot,
|
||||
sync_status,
|
||||
)
|
||||
else:
|
||||
logger.warning(f" - No last_synced found - Never Synced")
|
||||
logger.warning(
|
||||
"Playlist sync status: name=%s id=%s snapshot=%r result=Never Synced display=%s",
|
||||
p.name,
|
||||
p.id,
|
||||
playlist_snapshot,
|
||||
sync_status,
|
||||
)
|
||||
|
||||
playlist_data.append({
|
||||
"id": p.id, "name": p.name, "owner": p.owner,
|
||||
|
|
@ -46872,18 +46919,19 @@ def start_metadata_update():
|
|||
add_activity_item("", "Metadata Update", "Plex client not available", "Now")
|
||||
return jsonify({"success": False, "error": "Plex client not available"}), 400
|
||||
|
||||
# DEBUG: Check Plex connection details
|
||||
logger.debug(f"Active server: {active_server}")
|
||||
logger.debug(f"Plex client: {media_client}")
|
||||
logger.debug("Plex connection details: active_server=%s client=%s", active_server, media_client)
|
||||
if hasattr(media_client, 'server') and media_client.server:
|
||||
logger.debug(f"Plex server URL: {getattr(media_client.server, '_baseurl', 'NO_URL')}")
|
||||
logger.debug(f"Plex server name: {getattr(media_client.server, 'friendlyName', 'NO_NAME')}")
|
||||
logger.debug(
|
||||
"Plex server details: url=%s name=%s",
|
||||
getattr(media_client.server, '_baseurl', 'NO_URL'),
|
||||
getattr(media_client.server, 'friendlyName', 'NO_NAME'),
|
||||
)
|
||||
# Check available libraries
|
||||
try:
|
||||
sections = media_client.server.library.sections()
|
||||
logger.debug(f"Available Plex libraries: {[(s.title, s.type) for s in sections]}")
|
||||
logger.debug("Available Plex libraries: %s", [(s.title, s.type) for s in sections])
|
||||
except Exception as e:
|
||||
logger.debug(f"Error getting Plex libraries: {e}")
|
||||
logger.debug("Error getting Plex libraries: %s", e)
|
||||
else:
|
||||
logger.debug("Plex server is NOT connected!")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue