"Copy Tracklist Markup" with MPA

Adds multiple primary artists unlike the original function + button accessible to Contributors

  1. // ==UserScript==
  2. // @name "Copy Tracklist Markup" with MPA
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.4
  5. // @description Adds multiple primary artists unlike the original function + button accessible to Contributors
  6. // @author thousandeyes
  7. // @match https://genius.com/albums/*
  8. // @grant none
  9. // @run-at document-end
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. function getTracklist() {
  16. const artistLinks = document.querySelectorAll('a.header_with_cover_art-primary_info-primary_artist');
  17. const albumTitle = document.querySelector('h1.header_with_cover_art-primary_info-title');
  18. const tracks = document.querySelectorAll('album-tracklist-row .chart_row-content');
  19.  
  20. if (!artistLinks.length || !albumTitle || tracks.length === 0) {
  21. console.log('');
  22. return;
  23. }
  24.  
  25. let artistNames = Array.from(artistLinks).map(link => `[${link.textContent.trim()}](${link.href})`);
  26. let formattedArtists = artistNames.length > 2
  27. ? artistNames.slice(0, -1).join(', ') + ' & ' + artistNames[artistNames.length - 1]
  28. : artistNames.join(' & ');
  29.  
  30. const albumName = albumTitle.textContent.trim();
  31. const albumUrl = window.location.href;
  32.  
  33. let tracklistText = `<b>${formattedArtists} - [*${albumName}*](${albumUrl}) Lyrics and Tracklist</b>\n\n`;
  34.  
  35. tracks.forEach((trackElement, index) => {
  36. const trackLink = trackElement.querySelector('a');
  37. if (!trackLink) return;
  38.  
  39. let rawTitle = trackLink.textContent.trim().replace(/\s*Lyrics$/, '');
  40. const trackUrl = trackLink.href;
  41.  
  42. let title = rawTitle;
  43. let featuredText = "";
  44.  
  45. const ftPattern = /[\(\s](ft\.?|feat\.?|Ft\.?)[\s\.](.+?)[\)]?$/i;
  46. const ftMatch = title.match(ftPattern);
  47. if (ftMatch) {
  48. featuredText = ftMatch[2].trim();
  49. title = title.replace(ftPattern, '').trim();
  50. }
  51.  
  52. let primaryArtists = [];
  53. const byPattern = /(.+?)\s+by\s+(.+)/i;
  54. const match = title.match(byPattern);
  55. if (match) {
  56. title = match[1].trim();
  57. primaryArtists = match[2]
  58. .split(/,\s*|\s*&\s*/)
  59. .map(artist => `[${artist}](${getArtistUrl(artist)})`);
  60. }
  61.  
  62. let trackText = `${index + 1}. `;
  63. if (primaryArtists.length > 0) {
  64. const joinedPrimary = primaryArtists.length > 2
  65. ? primaryArtists.slice(0, -1).join(', ') + ' & ' + primaryArtists[primaryArtists.length - 1]
  66. : primaryArtists.join(' & ');
  67. trackText += joinedPrimary + ' - ';
  68. }
  69. trackText += `[${title}](${trackUrl})`;
  70.  
  71. let featuredArtistsText = "";
  72. const featuredArtists = trackElement.querySelectorAll('.featured_artists a');
  73. if (featuredArtists.length > 0) {
  74. featuredArtistsText = Array.from(featuredArtists).map(artist => {
  75. const name = artist.textContent.trim();
  76. return `[${name}](${artist.href})`;
  77. }).join(', ');
  78. } else if (featuredText) {
  79. featuredArtistsText = featuredText;
  80. }
  81.  
  82. if (featuredArtistsText) {
  83. trackText += ` ft. ${featuredArtistsText}`;
  84. }
  85.  
  86. tracklistText += `${trackText}\n`;
  87. });
  88.  
  89. navigator.clipboard.writeText(tracklistText)
  90. .then(() => {
  91. const button = document.querySelector('.custom-copy-button');
  92. button.textContent = 'Copied to clipboard';
  93. setTimeout(() => {
  94. button.textContent = 'Copy Tracklist Markup';
  95. }, 2000);
  96. })
  97. .catch(err => console.log('Error: ' + err));
  98. }
  99.  
  100. function getArtistUrl(artistName) {
  101. return `https://genius.com/artists/${encodeURIComponent(artistName.trim().replace(/\s+/g, '-'))}`;
  102. }
  103.  
  104. function createCopyButton() {
  105. const button = document.createElement('div');
  106. button.className = 'square_button u-bottom_margin custom-copy-button';
  107. button.textContent = 'Copy Tracklist Markup';
  108. button.style.cursor = 'pointer';
  109. button.addEventListener('click', getTracklist);
  110.  
  111. const moreButton = document.querySelector('div.square_button.drop-target');
  112. if (moreButton) {
  113. moreButton.parentNode.insertBefore(button, moreButton.nextSibling);
  114. }
  115. }
  116.  
  117. window.addEventListener('load', createCopyButton);
  118. })();