GitHub - Vatroslav/spotify-auto-skipper: Auto-skip Spotify songs that you've recently scrobbled on Last.fm

3 min read Original article β†—

🎡 Spotify + Last.fm Auto-Skipper

A small Windows tray app that automatically skips songs on Spotify that you've already listened to recently β€” based on your Last.fm scrobble history.


πŸ’‘ What it does

  • Checks which song is currently playing on your Spotify account
  • Asks Last.fm when that same song was last scrobbled
  • If it was played within a configurable number of days (default: 60), it automatically skips it on Spotify
  • Runs quietly in the background with a system tray icon
  • Logs all activity to daily log files

βš™οΈ Configuration

Create a file named config.ini in the same folder as the .exe (or .py) file, with the following content:

[LastFM]
username = YOUR_LASTFM_USERNAME
api_key = YOUR_LASTFM_API_KEY

[Spotify]
client_id = YOUR_SPOTIFY_CLIENT_ID
client_secret = YOUR_SPOTIFY_CLIENT_SECRET
refresh_token = YOUR_SPOTIFY_REFRESH_TOKEN

[Settings]
skip_window_days = 60
poll_interval_seconds = 120

You can use config.ini.template by removing .template from the file name to leave it as just config.ini.

The template file holds advice how to gather the required data.

Important: Spotify API Scopes

When generating your Spotify refresh token, make sure to include these scopes:

  • user-read-currently-playing β€” to detect what's playing
  • user-read-playback-state β€” to check playback status
  • user-modify-playback-state β€” to skip tracks
  • user-library-read β€” required if you enable always_play_liked_songs (to check if a track is in your Liked Songs)

If you get an error like Insufficient client scope, you need to regenerate your refresh token with the correct scopes.

Notes

  • skip_window_days β†’ how many days back to check your scrobbles
  • poll_interval_seconds β†’ how often to check what's currently playing (minimum 5 seconds to avoid rate limiting)
  • never_skip_artist_ids β†’ comma-separated list of Spotify artist IDs that should never be skipped. To find an artist's Spotify ID, go to the artist's Spotify page, click Share β†’ Copy link to artist. The ID is the last part of the URL (e.g., spotify.com/artist/3WrFJ7ztbogyGnTHbHJFl2)
  • The app reads this config only at startup, so restart the app after changes.

πŸš€ Running the app

Option 1: Run as Python script

python spotify_skip_recently_played_song.py

Option 2: Build as EXE

You can compile it into a self-contained Windows .exe using PyInstaller:

pyinstaller --noconsole --onefile spotify_skip_recently_played_song.py

Then place your config.ini next to the generated .exe.


πŸͺŸ System tray controls

When the app is running:

  • 🟒 Green Spotify-like icon appears in your tray

  • Right-click β†’

    • ⏯️ Pause Skipping β†’ pauses ALL skipping (toggle to resume)
    • 🎡 Don't skip this song β†’ pauses skipping for the current song only (automatically resumes when next song plays)
    • πŸ“ Open Logs β†’ opens the log folder
    • ❌ Exit β†’ stops the app

πŸ—Ύ Logs

Logs are stored in a logs subfolder next to the .exe, for example:

C:\Users\<yourname>\Tools\Spotify skip recently scrobbled song\logs\2025-10-24.txt

Each line includes a timestamp for easy tracking.

Automatic Log Cleanup

The app automatically purges log files older than 30 days on every startup to prevent storage bloat. You can customize the retention period in config.ini:

[Settings]
log_retention_days = 30

The purge operation is logged to the day's log file at startup, showing which files were deleted (or any errors encountered).


🚱 Preventing multiple instances

The app uses a Windows mutex (SpotifyAutoSkipperMutex) to ensure that only one instance runs at a time.

If you try to start it again, it will show a small info popup and immediately exit.


🧠 Tech details

  • Spotify API β†’ used for current track detection + skip command
  • Last.fm API β†’ used for fetching last scrobble time
  • Token refresh β†’ handled automatically using your permanent refresh_token
  • Built with β†’ requests, pystray, Pillow, ctypes, configparser

πŸ‘¨β€πŸ’» Credits

Created by Vatroslav Mileusnić

Code + comments co-written with ChatGPT 5