Skip to content

Instantly share code, notes, and snippets.

@olphil99
Forked from sk22/lastfm-remove-duplicates.js
Last active August 12, 2019 04:20
Show Gist options
  • Save olphil99/161cd24cba9db74fc945f3ebf167a54a to your computer and use it in GitHub Desktop.
Save olphil99/161cd24cba9db74fc945f3ebf167a54a to your computer and use it in GitHub Desktop.
Last.fm duplicate scrobble deleter
let elements = Array.from(document.querySelectorAll('.chartlist-row'));
let mapp = new Map();
elements.forEach(function(elem, i, elems) {
let today = new Date(Date.now());
let elemArr = new Array(2);
let nameElement = elem.querySelector('.chartlist-name');
let timeStamp = elem.querySelector('.chartlist-timestamp');
if (timeStamp && timeStamp.textContent.includes('ago')) {
let time = timeStamp.textContent.match(/\d/g)[0];
// change agos to dates
switch (timeStamp.textContent.match(/((\w+)[^0-9]) /g)[0]) {
case "seconds ": {
timeStamp = new Date(today.getTime() - time * 1000).toString();
break;
}
case "minutes ": {
timeStamp = new Date(Date.now() - time * 60000).toString();
break;
}
case "hours ": {
timeStamp = new Date(Date.now() - time * 3600000).toString();
break;
}
}
} else if (timeStamp) {
// turns DD Mon, TT:tt -> Mon DD yyyy TT:tt
timeStamp = (1900 + today.getYear()) + " " + timeStamp.textContent.match(/([A-Z])\w+/g) + " " +
timeStamp.textContent.replace(/([A-Z])\w+ /g, '').replace('am', ' am').replace('pm', ' pm').trim();
}
elemArr[0] = nameElement && nameElement.textContent.replace(/\s+/g, ' ').trim();
elemArr[1] = timeStamp;
mapp.set(i, elemArr);
});
mapp.forEach(function(arr, i) {
let name = arr[0];
let date = new Date(Date.parse(arr[1]));
if (name) {
let m;
// search through the rest of the elements in the map
for (m = mapp.size - 1; m > i; m--) {
// make sure mapp[m] exists
if (mapp.get(m)) {
let otherName = mapp.get(m)[0];
let otherDate = new Date(Date.parse(mapp.get(m)[1]));
// check if they have the same name and if they happen within the same half hour
// note: the entries are going to be in reverse chronological order
if (name === otherName && (date.getTime() - otherDate.getTime()) / 60000 <= 30) {
// delete the extra scrobble and remove it from the map
var deleteButton = elements[m].querySelector('[data-ajax-form-sets-state="deleted"]');
if (deleteButton) deleteButton.click();
mapp.delete(m);
// reload the page
location.reload();
}
}
}
}
});

Last.fm duplicate scrobble deleter

This script serves to delete duplicate scrobbles (i.e. the same song scrobbled multiple times in a row) from your Last.fm library. To use it, paste the script into your browser's console (or the address bar, but prefix the script with javascript:) while logged in and in the own library.

Why would I need this?

Your scrobbler might just have decided to scrobble every song hundreds of times and you can't really remove those scrobbles efficiently. Or, if you're like me, you might have accidentally installed multiple scrobbler extensions at the same time - wondering why multiple scrobbles appear for every song played at a time - and you want to clear them after finding the issue.

Using this script still doesn't necessarily make the process quick, since Last.fm only shows a specific number of scrobbles which can be removed on each page in your library.

What's different in my fork?

I pretty much rewrote everything. My code will look through all of the rows on the screen and delete ANY entries with the same name that happened within the 30 minutes of each other. This is necessary because when my last.fm duplicates scrobbles, it will throw them all over the table, not right below one another.

How-to (create a bookmarklet)

  1. Copy the following script URL into your clipboard
javascript:let elements=Array.from(document.querySelectorAll(".js-link-block.js-focus-controls-container")),mapp=new Map;elements.forEach(function(e,t,a){let n=new Date(Date.now()),r=new Array(2),o=e.querySelector(".chartlist-name"),c=e.querySelector(".chartlist-timestamp");if(c&&c.textContent.includes("ago")){let e=c.textContent.match(/\d/g)[0];switch(c.textContent.match(/((\w+)[^0-9]) /g)[0]){case"seconds ":c=new Date(n.getTime()-1e3*e).toString();break;case"minutes ":c=new Date(Date.now()-6e4*e).toString();break;case"hours ":c=new Date(Date.now()-36e5*e).toString()}}else c&&(c=1900+n.getYear()+" "+c.textContent.match(/([A-Z])\w+/g)+" "+c.textContent.replace(/([A-Z])\w+ /g,"").replace("am"," am").replace("pm"," pm").trim());r[0]=o&&o.textContent.replace(/\s+/g," ").trim(),r[1]=c,mapp.set(t,r)}),mapp.forEach(function(e,t){let a=e[0],n=new Date(Date.parse(e[1]));if(a){let e;for(e=mapp.size-1;e>t;e--)if(mapp.get(e)){let t=mapp.get(e)[0],o=new Date(Date.parse(mapp.get(e)[1]));if(a===t&&(n.getTime()-o.getTime())/6e4<=30){var r=elements[e].querySelector('[data-ajax-form-sets-state="deleted"]');r&&r.click(),mapp.delete(e),location.reload()}}}});
  1. Right-click your browser's bookmark bar and click "Add page..."
  2. Give the bookmark a name, like "Remove duplicates"
  3. Paste the script you copied in step 1 into the bookmark's URL.
  4. Save the bookmark
  5. Open your Last.fm account's library while being logged in (https://www.last.fm/user/_/library).
  6. Opening your bookmark will trigger the script to execute.
  7. Repeat clicking the bookmark as long as there are no duplicates left.

How-to (alternative, one-time way)

  1. Copy the script
let elements=Array.from(document.querySelectorAll(".js-link-block.js-focus-controls-container")),mapp=new Map;elements.forEach(function(e,t,a){let n=new Date(Date.now()),r=new Array(2),o=e.querySelector(".chartlist-name"),c=e.querySelector(".chartlist-timestamp");if(c&&c.textContent.includes("ago")){let e=c.textContent.match(/\d/g)[0];switch(c.textContent.match(/((\w+)[^0-9]) /g)[0]){case"seconds ":c=new Date(n.getTime()-1e3*e).toString();break;case"minutes ":c=new Date(Date.now()-6e4*e).toString();break;case"hours ":c=new Date(Date.now()-36e5*e).toString()}}else c&&(c=1900+n.getYear()+" "+c.textContent.match(/([A-Z])\w+/g)+" "+c.textContent.replace(/([A-Z])\w+ /g,"").replace("am"," am").replace("pm"," pm").trim());r[0]=o&&o.textContent.replace(/\s+/g," ").trim(),r[1]=c,mapp.set(t,r)}),mapp.forEach(function(e,t){let a=e[0],n=new Date(Date.parse(e[1]));if(a){let e;for(e=mapp.size-1;e>t;e--)if(mapp.get(e)){let t=mapp.get(e)[0],o=new Date(Date.parse(mapp.get(e)[1]));if(a===t&&(n.getTime()-o.getTime())/6e4<=30){var r=elements[e].querySelector('[data-ajax-form-sets-state="deleted"]');r&&r.click(),mapp.delete(e),location.reload()}}}});
  1. Open your Last.fm account's library while being logged in (https://www.last.fm/user/_/library).
  2. Type javascript: into the address bar and paste the script directly after it. Or, open the dev tools and paste the script into the console.
  3. Press enter. This will remove all duplicates on the current page.
  4. Let the site reload (invoked by the script).
  5. Repeat pasting the script and pressing enter if more duplicates appear at the bottom.
  6. If needed, go to the next page of your library repeat the steps as of step 3.

Why do I need to repeat executing the script?

The script will only remove what's visible on the current library page. After entries were deleted, more duplicates may appear at the bottom. This might happen multiple times. Once one page is finally duplicate-free, the process can be repeated for next pages.

let elements=Array.from(document.querySelectorAll(".chartlist-row")),mapp=new Map;elements.forEach(function(e,t,a){let n=new Date(Date.now()),r=new Array(2),o=e.querySelector(".chartlist-name"),c=e.querySelector(".chartlist-timestamp");if(c&&c.textContent.includes("ago")){let e=c.textContent.match(/\d/g)[0];switch(c.textContent.match(/((\w+)[^0-9]) /g)[0]){case"seconds ":c=new Date(n.getTime()-1e3*e).toString();break;case"minutes ":c=new Date(Date.now()-6e4*e).toString();break;case"hours ":c=new Date(Date.now()-36e5*e).toString()}}else c&&(c=1900+n.getYear()+" "+c.textContent.match(/([A-Z])\w+/g)+" "+c.textContent.replace(/([A-Z])\w+ /g,"").replace("am"," am").replace("pm"," pm").trim());r[0]=o&&o.textContent.replace(/\s+/g," ").trim(),r[1]=c,mapp.set(t,r)}),mapp.forEach(function(e,t){let a=e[0],n=new Date(Date.parse(e[1]));if(a){let e;for(e=mapp.size-1;e>t;e--)if(mapp.get(e)){let t=mapp.get(e)[0],o=new Date(Date.parse(mapp.get(e)[1]));if(a===t&&(n.getTime()-o.getTime())/6e4<=30){var r=elements[e].querySelector('[data-ajax-form-sets-state="deleted"]');r&&r.click(),mapp.delete(e),location.reload()}}}});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment