From 501868d9c9db6b506c3d4b4dda623960ee410ad3 Mon Sep 17 00:00:00 2001 From: dev Date: Sun, 14 Jun 2026 23:12:04 +0200 Subject: [PATCH] fix(quality-scanner): resolve library paths + surface unprobeable files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The unified scanner must READ each file to judge real bit depth/sample rate (extension alone can't tell 16-bit from 24-bit FLAC). If the stored library path doesn't resolve to a readable file in this container, every probe returns None and — since an unprobeable file can't be judged — the whole library passes silently ("scans nothing"). Now: resolve the path via docker_resolve_path before probing, and count + log unprobeable files (first 5 paths at WARNING, plus an end-of-scan summary "N/M tracks could not be probed"). This makes a systematic path/mount mismatch visible instead of an empty result. Co-Authored-By: Claude Opus 4.8 --- core/discovery/quality_scanner.py | 36 ++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/core/discovery/quality_scanner.py b/core/discovery/quality_scanner.py index 1df9a890..728fec3e 100644 --- a/core/discovery/quality_scanner.py +++ b/core/discovery/quality_scanner.py @@ -418,6 +418,10 @@ def run_quality_scanner(scope='watchlist', profile_id=1, deps: QualityScannerDep if add_to_wishlist is None: raise AttributeError("Wishlist service does not expose an add-to-wishlist method") + # Count tracks whose file couldn't be probed — surfaces a systematic + # path/access problem (e.g. the library mount differs in this container). + probe_failed_count = 0 + # Scan each track for idx, track_row in enumerate(tracks_to_scan, 1): # Check for stop request @@ -430,12 +434,30 @@ def run_quality_scanner(scope='watchlist', profile_id=1, deps: QualityScannerDep # Probe the REAL audio quality (bit depth / sample rate / bitrate) # and check it against the ranked targets — same core as the - # download guard. Extension tier is only a fallback label when the - # file can't be probed. - aq = deps.probe_audio_quality(file_path) if deps.probe_audio_quality else None + # download guard. The library path may be a Windows/host path that + # needs Docker resolution before mutagen can open it. + resolved_path = file_path + try: + from core.imports.paths import docker_resolve_path + resolved_path = docker_resolve_path(file_path) if file_path else file_path + except Exception: + resolved_path = file_path + + aq = deps.probe_audio_quality(resolved_path) if deps.probe_audio_quality else None if aq is not None: tier_name = aq.label() else: + # Probe failed — the file couldn't be read at resolved_path. + # Bit-depth/sample-rate can't be assessed without reading the + # file, so this track can't be judged. Count + log it so a + # systematic path problem is visible instead of silently + # passing the whole library. + probe_failed_count += 1 + if probe_failed_count <= 5: + logger.warning( + "[Quality Scanner] Could not probe audio quality (file not " + "readable?): db_path=%r resolved=%r", file_path, resolved_path, + ) tier_name = deps.get_quality_tier_from_extension(file_path)[0] # Update progress @@ -633,6 +655,14 @@ def run_quality_scanner(scope='watchlist', profile_id=1, deps: QualityScannerDep logger.error(f"[Quality Scanner] Error processing track: {track_error}") continue + if probe_failed_count: + logger.warning( + "[Quality Scanner] %d/%d tracks could not be probed (file unreadable) — " + "their quality could NOT be verified and they were left unflagged. If this " + "is most of the library, the stored file paths don't resolve to readable " + "files in this container.", probe_failed_count, total_tracks, + ) + # Scan complete (don't overwrite if already stopped by user) with deps.quality_scanner_lock: was_stopped = deps.quality_scanner_state["status"] != "running"