Skip to content

Instantly share code, notes, and snippets.

@yodaluca23
Last active June 27, 2025 01:42
Show Gist options
  • Save yodaluca23/7df187d91904b8b8f8679fc4eb10db70 to your computer and use it in GitHub Desktop.
Save yodaluca23/7df187d91904b8b8f8679fc4eb10db70 to your computer and use it in GitHub Desktop.
Amend Scrobbles on Last.FM for free
Just to not have `.env.example` show first lol.
LASTFM_API_KEY=your_lastfm_api_key_here
LASTFM_API_SECRET=your_lastfm_api_secret_here

Notes

As of now I only got it working with the first 200 tracks, this means if your errored tracks are further than that or if some of them are in the 200 and some are not, you'll only be able to amend the first 200, and will not be able to use the bulk delete feature, as the ones past the first 200 will not have been amended...

Requirements:

  • Python (tested on 3.11.9).
  • pip install pylast
  • Last.FM API credentials (Can obtain for free here).

Steps:

  1. Download scrobbleAmender.py and .env.example.
  2. Replace the example trackReplacements object at the top of scrobbleAmender.py with your search and replacements.
  3. Rename the .env.example to .env and make sure it's in the same folder.
  4. Replace the feilds in your .env file with your API credentials.
  5. Open your terminal of choice and run python "/path/to/scrobbleAmender.py".
  6. It will ask you to authenticate your account, and then it should start running.

IMPORTANT after it runs go to your Last.FM profile select the original (now amended) track > Three Dots > "Go to track in library" Click the "Delete track from library" button. This will delete the original (now amended) tracks from your library and Scrobble history.

import pylast
from time import sleep
# Example track replacements
trackReplacements = [
{
"artist": "Neuro-sama",
"title": "BOOM - Evil",
"artistReplacement": "Evil Neuro",
"titleReplacement": "BOOM",
"duration": 205
}
]
def authLastFm():
global lastfm_network
import os
import time
import webbrowser
from dotenv import load_dotenv
load_dotenv()
SESSION_KEY_FILE = os.path.join("lastfm_session_key.txt")
lastfm_network = pylast.LastFMNetwork(
api_key=os.getenv("LASTFM_API_KEY"),
api_secret=os.getenv("LASTFM_API_SECRET")
)
if not os.path.exists(SESSION_KEY_FILE):
skg = pylast.SessionKeyGenerator(lastfm_network)
url = skg.get_web_auth_url()
print(f"Please authorize this script to access your account: {url}\n")
webbrowser.open(url)
while True:
try:
#session_key = skg.get_web_auth_session_key(url)
session_key, username = skg.get_web_auth_session_key_username(url)
with open(SESSION_KEY_FILE, "w") as f:
f.write(session_key + "\n" + username)
break
except pylast.WSError:
time.sleep(60)
else:
with open(SESSION_KEY_FILE, "r") as f:
session_key = f.readline().strip()
username = f.readline().strip()
lastfm_network.session_key = session_key
lastfm_network.username = username # Add the recived username to this instance
return lastfm_network
lastfm_network = authLastFm()
replacementArtists = [replacement["artist"] for replacement in trackReplacements]
recentTracks = lastfm_network.get_authenticated_user().get_recent_tracks(limit=200)
for playedTrack in recentTracks:
try:
timestamp = playedTrack.timestamp
track = playedTrack.track
artist = playedTrack.track.artist.name
title = playedTrack.track.title
print(f"Processing track: {artist} - {title} (Timestamp: {timestamp})")
if artist in replacementArtists:
for replacement in trackReplacements:
if artist == replacement["artist"] and title == replacement["title"]:
print(f"Found track: {artist} - {title} (Timestamp: {timestamp}). Replacing scrobble...")
lastfm_network.scrobble(
artist=replacement["artistReplacement"],
title=replacement["titleReplacement"],
duration=replacement["duration"],
timestamp=timestamp
)
sleep(1)
except Exception as e:
print(f"Error processing track: {e}")
continue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment