A Javascript Oneliner

How to Delete Old Scrobbles from Last.fm

Like most reading this now, I am currently riding out the storm of coronavirus. Luckily I have my two cats to keep me company. Please, everyone, wash your hands! /PSA

I was listening to some new music, when I remembered I had an old last.fm account with some data that would be better left forgotten. For those unaware, last.fm is a proprietary service that tracks your music listening habits to give you back data and recommendations. It can integrate with many different music players to continually upload what you listen to (each song is called a scrobble) to the world wide web. For anyone who cares, there are two (lackluster) FLOSS alternatives: Libre.fm and ListenBrainz.

With a seemingly simple problem to solve, delete all my scrobbles while keeping my account if I ever need it later, I logged in and did what any reasonable person would do: go to the settings page. Yet, there was no one-click option. I found that I would need to manually click to delete each one from my history. Yikes! There has to be a better way, and there is.


The dev-tools were my next stop. I found that each scrobble in the library page has its own <form> element with all the data required to make a POST to delete it.

The first thing I need to do is get all those <form>s. That is a pretty simple by using document.querySelectorAll. The action attributes each end with "/library/delete", so I will search for that:

let forms = document.querySelectorAll('form[action$="/library/delete"]')

Now that we have a NodeList, we can submit each form:

forms.forEach(fm => fm.submit())

Alright, all done! Wait, what did you say? It doesn’t work? This solution may seem correct, but it refreshes the page after only submitting the first form. We want to do it for all of them at once.

Enter: window.fetch

The fetch api is really a treat. Compared to the ugly old XMLHttpRequest (shortened to XHR), fetch is much more developer friendly. Changing from .submit() to fetch is not much effort. The new code looks like:

forms.forEach(fm => fetch(`${window.location}/delete`, { method: 'POST', body: new FormData(fm) }))

The delete endpoint is POSTed to with the parameters from the form. There are fifty scrobbles per page, so after waiting a few seconds, refresh to see the scrobble count be subtracted by fifty. Just past the code in again, and repeat.


To delete scrobbles from you last.fm library do the following: (1) Go to your library page. (2) Run the following code in the console. (3) Refresh the page and repeat step two until all scrobbles are gone.

document.querySelectorAll('form[action$="/library/delete"]').forEach(fm => fetch(`${window.location}/delete`, { method: 'POST', body: new FormData(fm) }))

Thanks for sticking around! This was my first ever technical blog post, so feedback is much appreciated. Comment on Lobsters.