From a7877e6e0b67e1e6eb82f3d4be6c8ead90bd9382 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Sun, 12 Apr 2026 10:55:06 -0700 Subject: [PATCH] Skip albums with placeholder track names in watchlist scanner Spotify lists unreleased albums with placeholder names like "Track 1", "Track 2" before the real tracklist is revealed. The scanner was trying to download these, searching Soulseek for "Track 1" by artist which matches random files. Now skips any album where more than half the tracks match the placeholder pattern. Covers both the watchlist scan and discovery pool paths. --- core/watchlist_scanner.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/core/watchlist_scanner.py b/core/watchlist_scanner.py index a841a71d..98c66c9d 100644 --- a/core/watchlist_scanner.py +++ b/core/watchlist_scanner.py @@ -807,6 +807,12 @@ class WatchlistScanner: logger.debug(f"Skipping {release_type}: {album_data.get('name', 'Unknown')} - user preference") continue + # Skip albums with placeholder track names (unreleased tracklist) + # Spotify uses "Track 1", "Track 2", etc. for unannounced tracks + if self._has_placeholder_tracks(tracks): + logger.info(f"Skipping album with placeholder tracks (unreleased tracklist): {album_data.get('name', 'Unknown')}") + continue + # Check each track for track in tracks: # Check content type filters (live, remix, acoustic, compilation) @@ -1349,6 +1355,22 @@ class WatchlistScanner: except Exception: return False # Error — assume released + def _has_placeholder_tracks(self, tracks: list) -> bool: + """Check if an album's tracks are mostly placeholders (unreleased/unannounced tracklist). + Spotify uses 'Track 1', 'Track 2', etc. for tracks whose names haven't been revealed.""" + if not tracks or len(tracks) == 0: + return False + import re + placeholder_count = 0 + for track in tracks: + name = track.get('name', '') if isinstance(track, dict) else getattr(track, 'name', '') + # Match "Track 1", "Track 2", ..., "Track 99" (case-insensitive) + if re.match(r'^track\s+\d+$', name.strip(), re.IGNORECASE): + placeholder_count += 1 + # If more than half the tracks are placeholders, skip the album + # (some albums legitimately have a track called "Track X" but not most of them) + return placeholder_count > len(tracks) / 2 + def _should_include_release(self, track_count: int, watchlist_artist: WatchlistArtist) -> bool: """ Check if a release should be included based on user's preferences. @@ -2128,6 +2150,11 @@ class WatchlistScanner: logger.debug(f" Album {album_idx}: {album_data.get('name', 'Unknown')} ({len(tracks)} tracks)") + # Skip albums with placeholder tracks (unreleased tracklist) + if self._has_placeholder_tracks(tracks): + logger.info(f" Skipping album with placeholder tracks: {album_data.get('name', 'Unknown')}") + continue + # Determine if this is a new release (within last 30 days) is_new = False try: