Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scott-joe/3146db1c946d83fc86ca324677f93fc5 to your computer and use it in GitHub Desktop.
Save scott-joe/3146db1c946d83fc86ca324677f93fc5 to your computer and use it in GitHub Desktop.
TamperMonkey Script

Gather the Top 500 Albums from Rolling Stone

A TamperMonkey Script

About

I'm trying to listen to a new album every day, or at least 365 by the end of a year. To help figure out what to listen to, I thought I could use this list as a source. But their site is slow and riddled with riddled with ad-bloat.

Format

Screenshot 2023-03-20 at 10 54 59

Using

  1. Add a TamperMonkey userscript and refresh the page.
  2. Push the button to save the first 50 albums,
  3. Navigate to the next 50
  4. Repeat steps 2-3 until you have all 500
  5. Open the console and copy the Object
  6. Paste the Object here https://konklone.io/json/
  7. Save the CSV
  8. Import it into Excel, Google Sheets, Notion, etc.
  9. Enjoy!
// ==UserScript==
// @name Gather the Top 500 Albums from Rolling Stone
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Collect the Rolling Stone Top 500 Albums list
// @author Scott Williams
// @match https://www.rollingstone.com/music/music-lists/best-albums-of-all-time-1062063/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=rollingstone.com
// @grant none
// ==/UserScript==
(function () {
'use strict'
const storeName = 'records'
const buttonText = () => `Collect Records<br/><span style="${subStyles}">Records so far: ${records.size}</span>`
const subStyles = `font-size: 13px; display: block; margin-top: 0px;`
const defaultStyles = `height: 105px;
width: 300px;
text-align: center;
background: rgb(124,0,0);
background: linear-gradient(0deg, rgba(124,0,0,1) 0%, rgba(219,0,0,1) 100%);
color: white;
border: 1px solid black;
margin: 50px auto;
position: fixed;
z-index: 555;
top: 70px;
left: 0px;
right: 0px;
padding: 30px;
filter: drop-shadow(rgb(100, 100, 100) 0px 0px 5px);
font-size: 20px;`
const successStyles = `${defaultStyles} background: rgb(20,124,0); background: linear-gradient(0deg, rgba(20,124,0,1) 0%, rgba(17,219,0,1) 100%);`
const mapToJson = (map) => Array.from(map, ([number, record]) => record)
const jsonToMap = (json) => new Map(json.map((record) => [record.number, record]))
const getStore = () => {
try {
// Grab the serialized LS data or initialize with an empty array
const data = localStorage.getItem(storeName) || '[]'
// Deserialize the JSON and convert it into a Map
return jsonToMap(JSON.parse(data))
} catch (err) { console.log(err) }
}
const setStore = () => {
try {
// Convert the Map to JSON then serialize it for storage
const data = JSON.stringify(mapToJson(records))
// Store that in LS
localStorage.setItem(storeName, data)
} catch (err) { console.log(err) }
}
const addButton = () => {
// Get reference to main content node
const container = document.querySelectorAll('#main-wrapper')[0]
// Create the Button element
const button = document.createElement('a')
button.id = 'collect-records'
button.innerHTML = buttonText()
button.style = defaultStyles
button.href = '#'
// Create the Button's wrapper element
const buttonWrapper = document.createElement('div')
buttonWrapper.id = 'collect-records-wrapper'
// Add new records on button click
buttonWrapper.onclick = addRecords
// Append the new elements
buttonWrapper.appendChild(button)
container.appendChild(buttonWrapper)
}
const addRecords = () => {
try {
// Get all the album nodes
const nodes = document.querySelectorAll('.c-gallery-vertical-album')
// Iterate over all the nodes
for (const node of nodes) {
// Get the important data out of the DOM node
const record = parseNode(node)
// If it's not already in the Map, add it with the index of the Album's Number in the list
if (!records.get(record.number)) { records.set(record.number, record) }
}
// Update LS
setStore(records)
// Update the Button's color and text
success(records.length)
} catch (err) { console.log(err) }
}
const parseNode = (node) => {
// Get the line of text that includes both the Artist and Album names
const albumData = node.querySelectorAll('.c-gallery-vertical-album__title')[0].innerHTML.split(',')
// Get the line of text that includes both the Publisher and published year
const publishData = node.querySelectorAll('.c-gallery-vertical-album__subtitle-1')[0].innerHTML.split(',')
// Extract and clean up the data, returning it in a new Object
return {
number: Number(node.querySelectorAll('.c-gallery-vertical-album__number')[0].innerHTML.trim()),
album: albumData[1].replace(/[‘’]+/g, '').trim(),
artist: albumData[0].trim(),
label: publishData[0].trim(),
year: Number(publishData[1].trim()),
desc: node.querySelectorAll('.c-gallery-vertical-album__description')[0].innerText
}
}
const success = () => {
try {
// Get a reference to our custom button
const button = document.querySelectorAll('#collect-records')[0]
// Set it's background to green!
button.style = successStyles
// Update the record count
button.innerHTML = buttonText()
console.clear()
// Spit the data out as JSON to later convert to CSV
console.log(mapToJson(records))
} catch (err) { console.log(err) }
}
// Get the data from LocalStorage and leave it as a global
const records = getStore()
// Add the button to the page
addButton()
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment