Fix: ID gate missed Deezer-track-id-only rows

The original gate baked into `_select_discovery_tracks` only checked
Spotify + iTunes:

    AND (spotify_track_id IS NOT NULL OR itunes_track_id IS NOT NULL)

For Deezer-primary users, discovery_pool rows have populated
`deezer_track_id` but NULL Spotify + NULL iTunes IDs. The gate
filtered every row out — Time Machine, Genre Browser, Hidden Gems,
Discovery Shuffle, Popular Picks all rendered "no tracks found" for
every tab on every Deezer-primary install.

Extended the gate to include `deezer_track_id` and added that column
to the standard SELECT column tuple. `_build_track_dict` already
exposed `deezer_track_id` in its output shape, so frontend rendering
needed no changes.

Regression pinned via new test
`test_discovery_helper_accepts_deezer_only_id_rows` — inserts a row
with NULL Spotify + NULL iTunes but a populated `deezer_track_id`
and asserts it survives the gate.

2220/2220 full suite green.
This commit is contained in:
Broque Thomas 2026-05-08 07:46:09 -07:00
parent 959562f6b0
commit d123581a39
2 changed files with 26 additions and 2 deletions

View file

@ -111,6 +111,7 @@ class PersonalizedPlaylistsService:
_STANDARD_DISCOVERY_COLUMNS: Tuple[str, ...] = (
'spotify_track_id',
'itunes_track_id',
'deezer_track_id',
'track_name',
'artist_name',
'album_name',
@ -141,7 +142,7 @@ class PersonalizedPlaylistsService:
The WHERE clause always includes:
source = ?
AND (spotify_track_id IS NOT NULL OR itunes_track_id IS NOT NULL)
AND (spotify_track_id IS NOT NULL OR itunes_track_id IS NOT NULL OR deezer_track_id IS NOT NULL)
AND LOWER(artist_name) NOT IN
(SELECT LOWER(artist_name) FROM discovery_artist_blacklist)
@ -181,7 +182,7 @@ class PersonalizedPlaylistsService:
{select_cols}
FROM discovery_pool
WHERE source = ?
AND (spotify_track_id IS NOT NULL OR itunes_track_id IS NOT NULL)
AND (spotify_track_id IS NOT NULL OR itunes_track_id IS NOT NULL OR deezer_track_id IS NOT NULL)
AND LOWER(artist_name) NOT IN (SELECT LOWER(artist_name) FROM discovery_artist_blacklist)
{extra_where}
ORDER BY {order_by}

View file

@ -135,6 +135,29 @@ def test_discovery_helper_filters_null_id_rows(service):
assert names == ['Has Spotify ID', 'Has iTunes ID']
def test_discovery_helper_accepts_deezer_only_id_rows(service):
"""Discovery pool rows with NULL spotify + NULL itunes but a populated
deezer_track_id MUST pass the gate. Regression test early version
of the gate only checked Spotify + iTunes, which silently filtered
out every row for Deezer-primary users (entire Time Machine /
Genre / Hidden Gems / Shuffle / Popular Picks rendered empty)."""
svc, db = service
db.insert_discovery_track(
source='deezer', deezer_track_id='dz1',
spotify_track_id=None, itunes_track_id=None,
track_name='Deezer Only', artist_name='A', album_name='X',
popularity=50, release_date='2024-01-01',
)
with patch.object(svc, '_get_active_source', return_value='deezer'):
tracks = svc._select_discovery_tracks(
source='deezer',
order_by='track_name',
fetch_limit=100,
)
assert [t['track_name'] for t in tracks] == ['Deezer Only']
assert tracks[0]['deezer_track_id'] == 'dz1'
def test_discovery_helper_filters_blacklisted_artists(service):
svc, db = service
db.insert_discovery_track(