// Script to extract track names and artists from your current playlist page and export them in CSV format. // This script is intended for personal use to manage playlists efficiently. // Any misuse of this script is not the responsibility of the author. (async function() { // Map to store tracks using `aria-rowindex` as the key const tracksMap = new Map(); // Adjust these parameters if needed const scrollDelay = 800; // Delay between scrolls in milliseconds const scrollAmount = 300; // Scroll increment in pixels const maxScrollAttempts = 1000; // Maximum number of scroll attempts to prevent infinite loops // Target the identified scrollable container const scrollableElement = document.querySelector('div.main-view-container [data-overlayscrollbars-viewport]'); if (!scrollableElement) { console.error('Scrollable container not found.'); return; } // Helper function to pause execution const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); // Scroll and collect tracks for (let attempt = 0; attempt < maxScrollAttempts; attempt++) { // Scroll down by the specified amount scrollableElement.scrollBy(0, scrollAmount); // Wait for the DOM to update await sleep(scrollDelay); // Extract tracks currently in the DOM const trackRows = scrollableElement.querySelectorAll('div[role="row"]'); trackRows.forEach(row => { row.querySelector('[data-testid="tracklist-row"]'); const ariaRowIndex = row.getAttribute('aria-rowindex'); if (ariaRowIndex && !tracksMap.has(ariaRowIndex)) { // Extract the song title const songTitleElement = row.querySelector('a[data-testid="internal-track-link"] div[data-encore-id="text"]'); const songTitle = songTitleElement ? songTitleElement.textContent.trim() : 'Unknown Title'; // Extract the artist names const artistElements = row.querySelectorAll('span.encore-text-body-small a'); const artistNames = artistElements.length > 0 ? Array.from(artistElements).map(artist => artist.textContent.trim()).join(', ') : 'Unknown Artist'; tracksMap.set(ariaRowIndex, { title: songTitle, artist: artistNames }); } }); // Log progress console.log(`Collected ${tracksMap.size} tracks so far...`); // Check if all tracks are collected (stop scrolling) // Assuming we know the total track count, break if collected all const totalTracks = 336; // Replace with actual total if available if (tracksMap.size >= totalTracks) { console.log('All tracks have been collected.'); break; } } // Convert the collected data to an array and sort by track index const tracksArray = Array.from(tracksMap.entries()) .sort((a, b) => a[0] - b[0]) // Sort by track index .map(entry => entry[1]); // Extract the track details // Output the collected tracks console.table(tracksArray); // Optional: Export the data to a CSV file with UTF-8 BOM encoding const exportToCSV = true; // Set to true if you want to export the data if (exportToCSV) { // Add BOM (Byte Order Mark) for UTF-8 encoding to handle special characters const BOM = '\uFEFF'; let csvContent = 'Index,Title,Artist\n' + Array.from(tracksMap.entries()) .sort((a, b) => a[0] - b[0]) .map(entry => `${entry[0]},"${entry[1].title.replace(/"/g, '""')}","${entry[1].artist.replace(/"/g, '""')}"`) .join('\n'); // Create Blob with UTF-8 BOM let blob = new Blob([BOM + csvContent], { type: 'text/csv;charset=utf-8;' }); let url = URL.createObjectURL(blob); let link = document.createElement('a'); link.setAttribute('href', url); link.setAttribute('download', 'spotify_playlist.csv'); document.body.appendChild(link); link.click(); document.body.removeChild(link); console.log('CSV file has been downloaded.'); } })();