Save Amazon Music playlist as JSON file

This script adds an export button at Amazon Music playlist pages

  1. // ==UserScript==
  2. // @name Save Amazon Music playlist as JSON file
  3. // @name:fr Save Amazon Music playlist as JSON file
  4. // @name:de Save Amazon Music playlist as JSON file
  5. // @name:it Save Amazon Music playlist as JSON file
  6. // @name:es Save Amazon Music playlist as JSON file
  7. // @name:ja Save Amazon Music playlist as JSON file
  8. // @name:pt-BR Save Amazon Music playlist as JSON file
  9. // @namespace https://github.com/projecteurlumiere/save-amazon-music-playlist
  10. // @version 2024-05-15
  11. // @description This script adds an export button at Amazon Music playlist pages
  12. // @description:fr This script adds an export button at Amazon Music playlist pages
  13. // @description:de This script adds an export button at Amazon Music playlist pages
  14. // @description:it This script adds an export button at Amazon Music playlist pages
  15. // @description:es This script adds an export button at Amazon Music playlist pages
  16. // @description:ja This script adds an export button at Amazon Music playlist pages
  17. // @description:pt-BR This script adds an export button at Amazon Music playlist pages
  18. // @author projecteurlumiere
  19. // @match https://music.amazon.com/*
  20. // @match https://music.amazon.co.uk/*
  21. // @match https://music.amazon.fr/*
  22. // @match https://music.amazon.de/*
  23. // @match https://music.amazon.it/*
  24. // @match https://music.amazon.es/*
  25. // @match https://music.amazon.co.jp/*
  26. // @match https://music.amazon.ca/*
  27. // @match https://music.amazon.com.au/*
  28. // @match https://music.amazon.com.mx/*
  29. // @match https://music.amazon.com.br/*
  30. // @match https://music.amazon.in/*
  31. // @grant none
  32. // @license MIT
  33. // ==/UserScript==
  34.  
  35. (function() {
  36. 'use strict';
  37.  
  38. whenPlaylistAvailable("music-container music-image-row").then(() => { insertButtons(); })
  39.  
  40. async function whenPlaylistAvailable(selector) {
  41. while (document.querySelectorAll(selector).length === 0) {
  42. console.log("waiting for playlist");
  43. await new Promise(r => setTimeout(r, 1000));
  44. }
  45. }
  46.  
  47. function insertButtons() {
  48. console.log("inserting buttons");
  49.  
  50. document.querySelector("body").insertAdjacentHTML('beforeend', `
  51. <style>
  52. #download-playlist-via-script {
  53. position: fixed !important;
  54. left: 45%; top: 75px;
  55. }
  56.  
  57. #download-playlist-via-script button {
  58. padding: 15px 30px;
  59. background-color: rgb(168, 237, 240);
  60. }
  61. </style>
  62. <div id="download-playlist-via-script">
  63. <button>Download playlist</button>
  64. <button>Scroll ↓</button>
  65. <button>Scroll ↑</button>
  66. </div>
  67. `.trim()
  68. )
  69.  
  70. const firstButton = "#download-playlist-via-script button:nth-child(1)"
  71. const secondButton = "#download-playlist-via-script button:nth-child(2)"
  72. const thirdButton = "#download-playlist-via-script button:nth-child(3)"
  73.  
  74. document.querySelector(firstButton).addEventListener("click", () => {
  75. try {
  76. getPlaylist()
  77. }
  78. catch {
  79. if (window.location.href.includes("playlist")) {
  80. alert("Error! Perhaps, your viewport is not wide enough: " +
  81. "try to maximize your window and make sure album names are positioned next to song durations, and not below song titles")
  82. }
  83. else {
  84. alert("Error! Make sure you're on the playlist page you want to export (albums are not supported)");
  85. }
  86. }
  87. })
  88.  
  89. document.querySelector(secondButton).addEventListener("click", () => {
  90. window.scrollTo(0, document.body.scrollHeight);
  91. })
  92.  
  93. document.querySelector(thirdButton).addEventListener("click", () => {
  94. window.scrollTo(0, 0);
  95. })
  96. }
  97.  
  98. function getPlaylist() {
  99. const entries =
  100. Array.from(document.querySelectorAll("music-container music-image-row"));
  101.  
  102. let playlist = [];
  103. let n_total = 0;
  104.  
  105. entries.forEach((e) => {
  106. playlist.push({
  107. index: parseInt(e.querySelector(".index").innerText),
  108. title: e.querySelector(".col1 > music-link").title,
  109. artist: e.querySelector(".col2 > music-link").title,
  110. album: e.querySelector(".col3 > music-link").title,
  111. duration: e.querySelector(".col4 > music-link").title
  112. })
  113. n_total += 1
  114. })
  115.  
  116. const n_first = playlist[0].index
  117. const n_last = playlist[playlist.length - 1].index
  118.  
  119. let pretty_json = JSON.stringify(playlist, null, 2);
  120. download(pretty_json, "application/json", composeName(n_first, n_last, n_total));
  121. }
  122.  
  123. function download(content, mimeType, filename) {
  124. const a = document.createElement('a') // Create "a" element
  125. const blob = new Blob([content], {type: mimeType}) // Create a blob (file-like object)
  126. const url = URL.createObjectURL(blob) // Create an object URL from blob
  127. a.setAttribute('href', url) // Set "a" element link
  128. a.setAttribute('download', filename) // Set download filename
  129. a.click() // Start downloading
  130. a.remove()
  131. }
  132.  
  133. function composeName(n_first, n_last, n_total) {
  134. const header = document.querySelector("music-detail-header[label]").shadowRoot;
  135. const playlistType =
  136. capitalize(header.querySelector(".label").innerText.toLowerCase());
  137. const playlistTitle =
  138. header.querySelector("[title]").innerText
  139.  
  140. if (n_first != 1) {
  141. alert("The first song(s) has/have not been exported. Try to scroll to the top of the page and retry exporting" +
  142. "(this way the song(s) on the top of the page should become visible for exporting)")
  143. }
  144.  
  145. if (n_last % 500 === 0) {
  146. alert("Your playlist may be incomplete: scroll to the bottom of the page until you get the entire playlist")
  147. }
  148.  
  149. return `${playlistType} - ${playlistTitle} - ${n_total} song(s) in total - from ${n_first} to ${n_last}`
  150. }
  151.  
  152. function capitalize(str) {
  153. return str.charAt(0).toUpperCase() + str.slice(1)
  154. }
  155. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址