Copy Genius Lyrics

Adds a button to copy lyrics from Genius.com

// ==UserScript==
// @name         Copy Genius Lyrics
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Adds a button to copy lyrics from Genius.com
// @match        https://genius.com/*
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    /** Error logging */
    const logError = (error, context) => console.error(`[Copy Genius Lyrics] Error in ${context}:`, error);

    /** Copies lyrics to clipboard */
    const copyLyrics = () => {
        try {
            const lyrics = [...document.querySelectorAll('[data-lyrics-container="true"]')]
            .map(container => container.innerText.trim())
            .join('\n\n');

            if (!lyrics) {
                showNotification('No lyrics found.');
                return;
            }

            navigator.clipboard.writeText(lyrics)
                .then(() => showNotification('Lyrics copied!'))
                .catch(error => {
                logError(error, 'copyLyrics (clipboard)');
                showNotification('Failed to copy.');
            });

        } catch (error) {
            logError(error, 'copyLyrics');
            showNotification('An error occurred.');
        }
    };

    /** Displays a notification message */
    const showNotification = (message) => {
        try {
            const notification = document.createElement('div');
            notification.className = 'copy-lyrics-notification';
            notification.textContent = message;
            document.body.appendChild(notification);

            setTimeout(() => {
                notification.style.opacity = '0';
                setTimeout(() => notification.remove(), 500);
            }, 2000);
        } catch (error) {
            logError(error, 'showNotification');
        }
    };

    /** Initializes the copy button and injects it into the DOM */
    const initCopyButton = () => {
        try {
            const headerContainer = document.querySelector('div[class*="LyricsHeader__Container"]');
            if (!headerContainer) {
                logError('Target container not found (LyricsHeader__Container)', 'DOM initialization');
                return;
            }

            if (document.querySelector('#copy-lyrics-button')) return; // Avoid duplicate buttons

            const button = document.createElement('button');
            button.id = 'copy-lyrics-button';
            button.textContent = 'Copy Lyrics';
            button.addEventListener('click', copyLyrics);
            headerContainer.appendChild(button);
        } catch (error) {
            logError(error, 'initCopyButton');
        }
    };

    /** Injects custom styles for the button and notification */
    const injectStyles = () => {
        GM_addStyle(`
            #copy-lyrics-button {
                margin-left: 10px;
                padding: 8px 15px;
                font-size: 14px;
                background-color: #1db954;
                color: white;
                border: none;
                border-radius: 5px;
                box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
                cursor: pointer;
                transition: background-color 0.2s ease-in-out;
                order: -1;
            }

            #copy-lyrics-button:hover {
                background-color: #1ed760;
            }

            .copy-lyrics-notification {
                position: fixed;
                bottom: 20px;
                right: 20px;
                padding: 10px 20px;
                background-color: #1db954;
                color: white;
                font-size: 14px;
                border-radius: 5px;
                opacity: 0;
                animation: fadeInOut 2.5s forwards;
                z-index: 1000;
            }

            @keyframes fadeInOut {
                0% { opacity: 0; transform: translateY(20px); }
                10% { opacity: 1; transform: translateY(0); }
                90% { opacity: 1; transform: translateY(0); }
                100% { opacity: 0; transform: translateY(20px); }
            }
        `);
    };

    /** Initializes the script */
    const init = () => {
        injectStyles();
        initCopyButton();
    };

    // Run script after page load
    window.addEventListener('load', init);
})();