From 06e32d84c36971830aae755acb10cada88371fc8 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Tue, 7 Apr 2026 13:31:15 -0700 Subject: [PATCH] Skip future/unreleased albums in watchlist scanner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Albums announced but not yet released have no real audio available, causing Soulseek to match random tracks with similar names. Both discography methods (Spotify and generic client) now filter out albums with release dates in the future. Skipped albums are not marked as processed — they will be picked up on the first scan after their release date passes. --- core/watchlist_scanner.py | 44 +++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/core/watchlist_scanner.py b/core/watchlist_scanner.py index c18c3794..89f744f1 100644 --- a/core/watchlist_scanner.py +++ b/core/watchlist_scanner.py @@ -900,10 +900,15 @@ class WatchlistScanner: filtered_albums.append(album) logger.info(f"Filtered {len(albums)} albums to {len(filtered_albums)} released after {cutoff_timestamp}") - return filtered_albums + albums = filtered_albums - # Return all albums if no cutoff (lookback_period = 'all') - return albums + # Skip future/unreleased albums — no real audio available yet + now = datetime.now(timezone.utc) + released = [a for a in albums if not self._is_future_release(a, now)] + skipped = len(albums) - len(released) + if skipped: + logger.info(f"Skipped {skipped} future/unreleased albums (will be picked up after release)") + return released except Exception as e: logger.error(f"Error getting discography for artist {spotify_artist_id}: {e}") @@ -982,10 +987,15 @@ class WatchlistScanner: filtered_albums.append(album) logger.info(f"Filtered {len(albums)} albums to {len(filtered_albums)} released after {cutoff_timestamp}") - return filtered_albums + albums = filtered_albums - # Return all albums if no cutoff (lookback_period = 'all') - return albums + # Skip future/unreleased albums — no real audio available yet + now = datetime.now(timezone.utc) + released = [a for a in albums if not self._is_future_release(a, now)] + skipped = len(albums) - len(released) + if skipped: + logger.info(f"Skipped {skipped} future/unreleased albums (will be picked up after release)") + return released except Exception as e: logger.error(f"Error getting discography for artist {artist_id}: {e}") @@ -1285,6 +1295,28 @@ class WatchlistScanner: logger.warning(f"Error comparing album date {album.release_date} with timestamp {timestamp}: {e}") return True # Include if we can't determine + def _is_future_release(self, album, now: datetime) -> bool: + """Check if an album's release date is in the future. Returns False for unknown dates (safe default).""" + try: + if not album.release_date: + return False # Unknown date — assume released + release_date_str = album.release_date + if len(release_date_str) == 4: + album_date = datetime(int(release_date_str), 1, 1, tzinfo=timezone.utc) + elif len(release_date_str) == 7: + year, month = release_date_str.split('-') + album_date = datetime(int(year), int(month), 1, tzinfo=timezone.utc) + elif len(release_date_str) == 10: + album_date = datetime.strptime(release_date_str, "%Y-%m-%d").replace(tzinfo=timezone.utc) + elif 'T' in release_date_str: + date_part = release_date_str.split('T')[0] + album_date = datetime.strptime(date_part, "%Y-%m-%d").replace(tzinfo=timezone.utc) + else: + return False # Can't parse — assume released + return album_date > now + except Exception: + return False # Error — assume released + def _should_include_release(self, track_count: int, watchlist_artist: WatchlistArtist) -> bool: """ Check if a release should be included based on user's preferences.