From 40ab4c0354b7775bb653adaeacf64a1b6d787f02 Mon Sep 17 00:00:00 2001 From: Marvin Schenkel Date: Fri, 13 Feb 2026 13:25:51 +0100 Subject: [PATCH] Fix for Spotify returning endless tracks from playlist (#3155) * Fix for Spotify returning endless tracks from playlist * Auto cleanup cache for Spotify --- music_assistant/controllers/cache.py | 19 +++++++++++++------ music_assistant/providers/spotify/provider.py | 5 +++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/music_assistant/controllers/cache.py b/music_assistant/controllers/cache.py index da8e174b..9afb82d3 100644 --- a/music_assistant/controllers/cache.py +++ b/music_assistant/controllers/cache.py @@ -31,7 +31,7 @@ if TYPE_CHECKING: LOGGER = logging.getLogger(f"{MASS_LOGGER_NAME}.cache") CONF_CLEAR_CACHE = "clear_cache" DEFAULT_CACHE_EXPIRATION = 86400 * 30 # 30 days -DB_SCHEMA_VERSION = 6 +DB_SCHEMA_VERSION = 7 BYPASS_CACHE: ContextVar[bool] = ContextVar("BYPASS_CACHE", default=False) @@ -281,12 +281,11 @@ class CacheController(CoreController): prev_version, DB_SCHEMA_VERSION, ) - - if prev_version < DB_SCHEMA_VERSION: - # for now just keep it simple and just recreate the table(s) + try: + await self.__migrate_database(prev_version) + except Exception as err: + LOGGER.warning("Cache database migration failed: %s, resetting cache", err) await self.database.execute(f"DROP TABLE IF EXISTS {DB_TABLE_CACHE}") - - # recreate missing table(s) await self.__create_database_tables() # store current schema version @@ -362,6 +361,14 @@ class CacheController(CoreController): ) await self.database.commit() + async def __migrate_database(self, prev_version: int) -> None: + """Perform a database migration.""" + assert self.database is not None + if prev_version <= 6: + # clear spotify cache entries to fix bloated cache from playlist pagination bug + await self.database.delete(DB_TABLE_CACHE, query="WHERE provider LIKE '%spotify%'") + await self.database.commit() + def __schedule_cleanup_task(self) -> None: """Schedule the cleanup task.""" self.mass.create_task(self.auto_cleanup()) diff --git a/music_assistant/providers/spotify/provider.py b/music_assistant/providers/spotify/provider.py index bc1ddeb4..61afd664 100644 --- a/music_assistant/providers/spotify/provider.py +++ b/music_assistant/providers/spotify/provider.py @@ -610,7 +610,12 @@ class SpotifyProvider(MusicProvider): spotify_result = await self._get_data_with_caching( uri, cache_checksum, limit=page_size, offset=offset, use_global_session=use_global ) + total = spotify_result.get("total", 0) for index, item in enumerate(spotify_result["items"], 1): + # Spotify wraps/recycles items for offsets beyond the playlist size, + # so we need to break when we've reached the total. + if (offset + index) > total: + break if not (item and item["track"] and item["track"]["id"]): continue track = parse_track(item["track"], self) -- 2.34.1