From c033656fdfdea3efa9b83fcb26701a49d5195b97 Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Thu, 25 Jun 2026 16:30:52 -0700 Subject: [PATCH] Popular Picks: fix empty result for deezer (popularity threshold scale mismatch) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The discovery pool synthesizes deezer popularity onto a 0-100 score (base 45 + bonuses, capped at 100), but _get_popularity_thresholds had deezer on the raw-rank scale (500000/100000). So Popular Picks' 'popularity >= 500000' matched nothing — empty for every deezer-primary user — while Hidden Gems' '< 100000' caught the whole pool. Deezer thresholds now sit on the 0-100 scale (60/50, like Spotify's 60/40). Tested. --- core/personalized_playlists.py | 7 ++++-- tests/test_popularity_thresholds.py | 37 +++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 tests/test_popularity_thresholds.py diff --git a/core/personalized_playlists.py b/core/personalized_playlists.py index 1f395eea..7b7b4738 100644 --- a/core/personalized_playlists.py +++ b/core/personalized_playlists.py @@ -111,7 +111,10 @@ class PersonalizedPlaylistsService: Either value can be None to skip that filter for that source. - Spotify: 60 / 40 (the existing 0-100 popularity scale) - - Deezer: 500000 / 100000 (rank values — ballpark from real data) + - Deezer: 60 / 50 (ALSO 0-100 — the discovery pool SYNTHESIZES deezer popularity to a + 0-100 score at scan time, capped at 100; it is NOT Deezer's raw rank. The old + 500000/100000 rank thresholds matched nothing, so Popular Picks came back empty for + deezer users while Hidden Gems' < 100000 caught the whole pool.) - iTunes / others: None / None (no popularity data; fall back to no threshold filter, just diversity-on-random) @@ -121,7 +124,7 @@ class PersonalizedPlaylistsService: if normalized == 'spotify': return 60, 40 if normalized == 'deezer': - return 500_000, 100_000 + return 60, 50 # iTunes, hydrabase, anything else — no usable popularity data return None, None diff --git a/tests/test_popularity_thresholds.py b/tests/test_popularity_thresholds.py new file mode 100644 index 00000000..c9842d01 --- /dev/null +++ b/tests/test_popularity_thresholds.py @@ -0,0 +1,37 @@ +"""Popular Picks was empty for deezer users — wrong popularity-threshold scale. + +The discovery pool synthesizes deezer popularity onto a 0-100 score (base 45 + bonuses, capped +at 100), but _get_popularity_thresholds had deezer on the raw-rank scale (500000/100000). So +`popularity >= 500000` matched nothing (Popular Picks empty) while `< 100000` matched the whole +pool (Hidden Gems caught everything). Thresholds must stay on the 0-100 scale. +""" + +from __future__ import annotations + +from core.personalized_playlists import PersonalizedPlaylistsService + + +def _svc(): + return PersonalizedPlaylistsService(database=None) + + +def test_deezer_thresholds_are_on_the_0_100_scale(): + popular_min, hidden_max = _svc()._get_popularity_thresholds('deezer') + assert (popular_min, hidden_max) == (60, 50) # was (500000, 100000) — unreachable + assert 0 < popular_min <= 100 and 0 < hidden_max <= 100 + assert popular_min > hidden_max # popular tier sits above the hidden tier + + +def test_spotify_thresholds_unchanged(): + assert _svc()._get_popularity_thresholds('spotify') == (60, 40) + + +def test_case_insensitive(): + assert _svc()._get_popularity_thresholds('Deezer') == (60, 50) + assert _svc()._get_popularity_thresholds('SPOTIFY') == (60, 40) + + +def test_sources_without_popularity_skip_the_filter(): + assert _svc()._get_popularity_thresholds('itunes') == (None, None) + assert _svc()._get_popularity_thresholds('musicbrainz') == (None, None) + assert _svc()._get_popularity_thresholds('') == (None, None)