Fix Last.fm radios mirrored under wrong source
Two-part fix for Last.fm Radio playlists showing up in the ListenBrainz group of the Auto-Sync manager + Mirrored tab instead of their own Last.fm group: 1. **Mirror-creation hook** (sync-services.js): the ``_mirrorListenBrainzAfterDiscovery`` helper hardcoded ``source='listenbrainz'`` on every auto-mirror call, even for Last.fm Radio playlists (which share the same MB-track shape + discovery worker but should land under ``source='lastfm'``). ``save_lastfm_radio_playlist`` always prefixes the playlist name with "Last.fm Radio: <seed>", so the helper now keys on that prefix to pick the right mirror source + owner fallback. Going forward, new Last.fm radios mirror correctly the moment discovery completes. 2. **Backfill** (listenbrainz_manager.py): legacy mirror rows created before the fix above are stuck under ``source='listenbrainz'``. Added ``_retag_misrouted_lastfm_radio_mirrors`` to ``_cleanup_old_playlists`` so the next LB refresh re-tags any row whose name starts with "Last.fm Radio:" but is still on ``source='listenbrainz'``. Idempotent — UPDATE only matches misrouted rows.
This commit is contained in:
parent
bbc950d325
commit
e8ee8576a0
2 changed files with 45 additions and 4 deletions
|
|
@ -326,11 +326,43 @@ class ListenBrainzManager:
|
||||||
covers_found = sum(1 for t in track_data_list if t.get('album_cover_url'))
|
covers_found = sum(1 for t in track_data_list if t.get('album_cover_url'))
|
||||||
logger.info(f"Fetched {covers_found}/{len(track_data_list)} cover art URLs")
|
logger.info(f"Fetched {covers_found}/{len(track_data_list)} cover art URLs")
|
||||||
|
|
||||||
|
def _retag_misrouted_lastfm_radio_mirrors(self, cursor):
|
||||||
|
"""Re-tag mirrored_playlists rows that should be 'lastfm' but
|
||||||
|
were inserted as 'listenbrainz'.
|
||||||
|
|
||||||
|
Backfill for the Phase 1c.1 bug where the auto-mirror helper
|
||||||
|
hardcoded ``source='listenbrainz'`` regardless of playlist
|
||||||
|
origin. Last.fm Radio playlists carry a consistent
|
||||||
|
"Last.fm Radio: <seed>" title prefix from
|
||||||
|
``save_lastfm_radio_playlist``, so any mirror row matching
|
||||||
|
that prefix should sit under the Last.fm group instead of
|
||||||
|
the ListenBrainz one. Idempotent — only updates rows that
|
||||||
|
are still misrouted."""
|
||||||
|
try:
|
||||||
|
cursor.execute(
|
||||||
|
"""
|
||||||
|
UPDATE mirrored_playlists
|
||||||
|
SET source = 'lastfm'
|
||||||
|
WHERE source = 'listenbrainz'
|
||||||
|
AND name LIKE 'Last.fm Radio:%'
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
if cursor.rowcount:
|
||||||
|
logger.info(
|
||||||
|
f"Re-tagged {cursor.rowcount} Last.fm Radio mirror rows "
|
||||||
|
"from source='listenbrainz' to source='lastfm'"
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
logger.debug(f"Last.fm radio mirror retag skipped: {exc}")
|
||||||
|
|
||||||
def _cleanup_old_playlists(self):
|
def _cleanup_old_playlists(self):
|
||||||
"""Remove old playlists, keeping only the 25 most recent per type"""
|
"""Remove old playlists, keeping only the 25 most recent per type"""
|
||||||
conn = self._get_db_connection()
|
conn = self._get_db_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# One-shot backfill for legacy misrouting (see method docstring).
|
||||||
|
self._retag_misrouted_lastfm_radio_mirrors(cursor)
|
||||||
|
|
||||||
# For each playlist type, keep only the N most recent
|
# For each playlist type, keep only the N most recent
|
||||||
# lastfm_radio keeps fewer since they're auto-regenerated weekly
|
# lastfm_radio keeps fewer since they're auto-regenerated weekly
|
||||||
playlist_type_limits = {
|
playlist_type_limits = {
|
||||||
|
|
|
||||||
|
|
@ -10855,18 +10855,27 @@ function _mirrorListenBrainzAfterDiscovery(playlistMbid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Last.fm Radio playlists live in the same listenbrainz_playlists
|
||||||
|
// table but are persisted by ``save_lastfm_radio_playlist`` with
|
||||||
|
// a "Last.fm Radio: <seed>" title prefix and ``playlist_type='lastfm_radio'``.
|
||||||
|
// Route them to ``source='lastfm'`` so the Auto-Sync manager
|
||||||
|
// groups them under the Last.fm Radio section + the cascade-
|
||||||
|
// delete hook targets the right mirror source.
|
||||||
|
const title = state.playlist.name || 'ListenBrainz Playlist';
|
||||||
|
const mirrorSource = title.startsWith('Last.fm Radio:') ? 'lastfm' : 'listenbrainz';
|
||||||
|
const ownerFallback = mirrorSource === 'lastfm' ? 'Last.fm' : 'ListenBrainz';
|
||||||
mirrorPlaylist(
|
mirrorPlaylist(
|
||||||
'listenbrainz',
|
mirrorSource,
|
||||||
playlistMbid,
|
playlistMbid,
|
||||||
state.playlist.name || 'ListenBrainz Playlist',
|
title,
|
||||||
tracks,
|
tracks,
|
||||||
{
|
{
|
||||||
owner: state.playlist.creator || 'ListenBrainz',
|
owner: state.playlist.creator || ownerFallback,
|
||||||
description: state.playlist.description || '',
|
description: state.playlist.description || '',
|
||||||
image_url: state.playlist.image_url || '',
|
image_url: state.playlist.image_url || '',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
console.log(`🪞 [LB Mirror] Mirrored '${state.playlist.name}' with ${tracks.length} matched tracks`);
|
console.log(`🪞 [${mirrorSource} Mirror] Mirrored '${title}' with ${tracks.length} matched tracks`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('LB mirror-after-discovery failed:', err);
|
console.warn('LB mirror-after-discovery failed:', err);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue