From 6820e2d4e3aabd2da62d6e268b995f3efa41a8bd Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Wed, 25 Mar 2026 15:59:22 -0700 Subject: [PATCH] Enforce FLAC bit depth preference and prioritize audio quality in sorting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes to the Soulseek quality filter: 1. Sort candidates by effective bitrate first, peer quality second. Previously a 16-bit FLAC from a fast peer could beat a 24-bit FLAC from a slower peer. Now highest audio quality always wins within the same format tier, with peer speed as tiebreaker. 2. Enforce the FLAC bit depth UI preference (Any/16-bit/24-bit) that was previously cosmetic-only. Uses effective bitrate threshold of 1450 kbps to distinguish 16-bit (<1411 kbps theoretical) from 24-bit (>2116 kbps theoretical). Respects the bit_depth_fallback toggle — when enabled, gracefully accepts any FLAC if preferred depth is unavailable. When disabled, strictly rejects non-matching depth. Default bit_depth="any" — zero behavior change for existing users. --- core/soulseek_client.py | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/core/soulseek_client.py b/core/soulseek_client.py index 2ccc57e..c548140 100644 --- a/core/soulseek_client.py +++ b/core/soulseek_client.py @@ -1617,14 +1617,49 @@ class SoulseekClient: else: logger.debug(f"Quality Filter: {quality_key} rejected via size fallback - {file_size_mb:.1f} MB outside {size_min}-{size_max} MB safety limits") - # Sort each bucket by quality score and effective bitrate + # Sort each bucket: effective bitrate first (prefer highest audio quality), + # then peer quality score as tiebreaker (prefer fastest peer at same quality) for bucket in quality_buckets.values(): - bucket.sort(key=lambda x: (x.quality_score, self._calculate_effective_kbps(x.size, x.duration) or 0), reverse=True) + bucket.sort(key=lambda x: (self._calculate_effective_kbps(x.size, x.duration) or 0, x.quality_score), reverse=True) + + # Enforce FLAC bit depth preference from quality profile + flac_config = profile['qualities'].get('flac', {}) + bit_depth_pref = flac_config.get('bit_depth', 'any') + bit_depth_fallback = flac_config.get('bit_depth_fallback', True) + + if bit_depth_pref != 'any' and quality_buckets['flac']: + # 16-bit/44.1kHz FLAC theoretical max is 1411 kbps; 24-bit starts at ~2116 kbps + # Real-world compressed: 16-bit = 800-1400 kbps, 24-bit = 1500+ kbps + DEPTH_THRESHOLD = 1450 + + if bit_depth_pref == '24': + hi_res = [c for c in quality_buckets['flac'] + if (self._calculate_effective_kbps(c.size, c.duration) or 0) > DEPTH_THRESHOLD] + if hi_res: + logger.info(f"Quality Filter: Bit depth 24-bit preference — {len(hi_res)}/{len(quality_buckets['flac'])} FLAC candidates are hi-res") + quality_buckets['flac'] = hi_res + elif not bit_depth_fallback: + logger.info(f"Quality Filter: No 24-bit FLAC found and fallback disabled — rejecting all FLAC") + quality_buckets['flac'] = [] + else: + logger.info(f"Quality Filter: No 24-bit FLAC found — falling back to 16-bit") + + elif bit_depth_pref == '16': + lo_res = [c for c in quality_buckets['flac'] + if (self._calculate_effective_kbps(c.size, c.duration) or 0) <= DEPTH_THRESHOLD] + if lo_res: + logger.info(f"Quality Filter: Bit depth 16-bit preference — {len(lo_res)}/{len(quality_buckets['flac'])} FLAC candidates are standard") + quality_buckets['flac'] = lo_res + elif not bit_depth_fallback: + logger.info(f"Quality Filter: No 16-bit FLAC found and fallback disabled — rejecting all FLAC") + quality_buckets['flac'] = [] + else: + logger.info(f"Quality Filter: No 16-bit FLAC found — falling back to 24-bit") # Debug logging for quality, bucket in quality_buckets.items(): if bucket: - logger.debug(f"Quality Filter: Found {len(bucket)} '{quality}' candidates (after bitrate filtering)") + logger.debug(f"Quality Filter: Found {len(bucket)} '{quality}' candidates (after bitrate + bit depth filtering)") # Waterfall priority logic: try qualities in priority order # Build priority list from enabled qualities