|
// ==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() |
|
})() |