Deezer Album Metadata Enhancer

Add label, UPC, and release dates to Deezer album pages

// ==UserScript==
// @name         Deezer Album Metadata Enhancer
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Add label, UPC, and release dates to Deezer album pages
// @author       waiter7
// @match        https://www.deezer.com/*/album/*
// @license      MIT
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    function waitForElement(selector, timeout = 10000) {
        return new Promise((resolve, reject) => {
            const element = document.querySelector(selector);
            if (element) {
                resolve(element);
                return;
            }

            const observer = new MutationObserver((mutations, obs) => {
                const element = document.querySelector(selector);
                if (element) {
                    obs.disconnect();
                    resolve(element);
                }
            });

            observer.observe(document.body, {
                childList: true,
                subtree: true
            });

            setTimeout(() => {
                observer.disconnect();
                reject(new Error('Element not found within timeout'));
            }, timeout);
        });
    }

    function formatDate(dateString) {
        if (!dateString) return 'N/A';
        try {
            const date = new Date(dateString);
            return date.toLocaleDateString('en-US', {
                year: 'numeric',
                month: '2-digit',
                day: '2-digit'
            });
        } catch (e) {
            return dateString;
        }
    }

    function extractAlbumId() {
        const path = window.location.pathname;
        const match = path.match(/\/album\/(\d+)/);
        return match ? match[1] : null;
    }

    function addMetadata() {
        try {
            // Get the album data from the global state
            const appState = window.__DZR_APP_STATE__;
            if (!appState || !appState.DATA) {
                console.log('No app state found, retrying...');
                return false;
            }

            const albumData = appState.DATA;
            const albumId = extractAlbumId();

            if (!albumId) {
                console.log('Could not extract album ID from URL');
                return false;
            }

            // Extract metadata
            const label = albumData.LABEL_NAME || 'N/A';
            const upc = albumData.UPC || 'N/A';
            const digitalReleaseDate = formatDate(albumData.DIGITAL_RELEASE_DATE);
            const physicalReleaseDate = formatDate(albumData.PHYSICAL_RELEASE_DATE);
            const originalReleaseDate = formatDate(albumData.ORIGINAL_RELEASE_DATE);

            console.log('Album metadata:', {
                label,
                upc,
                digitalReleaseDate,
                physicalReleaseDate,
                originalReleaseDate
            });

            // Find the existing metadata list (tracks/minutes/date/fans)
            const metadataList = document.querySelector('ul.css-1s16397');
            if (!metadataList) {
                console.log('Metadata list not found');
                return false;
            }

            // Check if our metadata is already added
            if (document.querySelector('.custom-metadata-table')) {
                console.log('Metadata already added');
                return true;
            }

            // Create a clean table for metadata
            const tableContainer = document.createElement('div');
            tableContainer.className = 'custom-metadata-table';
            tableContainer.style.cssText = `
                margin-top: 16px;
                background: #f8f9fa;
                border-radius: 8px;
                padding: 16px;
                border: 1px solid #e9ecef;
            `;

            const table = document.createElement('table');
            table.style.cssText = `
                width: 100%;
                border-collapse: separate;
                border-spacing: 0;
                font-size: 13px;
                color: #495057;
            `;

            // Create table header
            const thead = document.createElement('thead');
            const headerRow = document.createElement('tr');
            headerRow.style.borderBottom = '2px solid #dee2e6';

            const headers = ['Label', 'UPC', 'Digital Release', 'Physical Release', 'Original Release', 'API'];
            headers.forEach(headerText => {
                const th = document.createElement('th');
                th.textContent = headerText;
                th.style.cssText = `
                    text-align: left;
                    padding: 8px 12px;
                    font-weight: 600;
                    color: #343a40;
                    background: #e9ecef;
                    border-right: 1px solid #dee2e6;
                `;
                if (headerText === 'API') {
                    th.style.borderRight = 'none';
                }
                headerRow.appendChild(th);
            });
            thead.appendChild(headerRow);
            table.appendChild(thead);

            // Create table body
            const tbody = document.createElement('tbody');
            const dataRow = document.createElement('tr');
            dataRow.style.backgroundColor = '#ffffff';

            const values = [label, upc, digitalReleaseDate, physicalReleaseDate, originalReleaseDate];

            // Add data cells
            values.forEach((value, index) => {
                const td = document.createElement('td');
                td.textContent = value || 'N/A';
                td.style.cssText = `
                    padding: 12px;
                    border-right: 1px solid #dee2e6;
                    vertical-align: top;
                    background: #ffffff;
                `;
                if (index === values.length - 1) {
                    td.style.borderRight = 'none';
                }
                dataRow.appendChild(td);
            });

            // Add API link cell
            const apiTd = document.createElement('td');
            apiTd.style.cssText = `
                padding: 12px;
                vertical-align: top;
                background: #ffffff;
                text-align: center;
            `;
            const apiLink = document.createElement('a');
            apiLink.href = `https://api.deezer.com/album/${albumId}`;
            apiLink.target = '_blank';
            apiLink.textContent = 'View API';
            apiLink.style.cssText = `
                color: #a238ff;
                text-decoration: none;
                font-weight: 500;
                padding: 4px 8px;
                border-radius: 4px;
                background: #f8f5ff;
                border: 1px solid #a238ff;
                display: inline-block;
                transition: all 0.2s ease;
            `;
            apiLink.addEventListener('mouseenter', () => {
                apiLink.style.background = '#a238ff';
                apiLink.style.color = '#ffffff';
            });
            apiLink.addEventListener('mouseleave', () => {
                apiLink.style.background = '#f8f5ff';
                apiLink.style.color = '#a238ff';
            });
            apiTd.appendChild(apiLink);
            dataRow.appendChild(apiTd);

            tbody.appendChild(dataRow);
            table.appendChild(tbody);
            tableContainer.appendChild(table);

            // Insert the table after the existing metadata list
            metadataList.parentNode.insertBefore(tableContainer, metadataList.nextSibling);

            console.log('Metadata added successfully');
            return true;

        } catch (error) {
            console.error('Error adding metadata:', error);
            return false;
        }
    }

    function init() {
        console.log('Deezer Album Metadata Enhancer: Starting...');

        // Wait for the page to load and the metadata list to be available
        waitForElement('ul.css-1s16397')
            .then(() => {
                console.log('Metadata list found, attempting to add custom metadata...');

                // Try to add metadata immediately
                if (!addMetadata()) {
                    // If it fails, wait a bit for the app state to load
                    setTimeout(() => {
                        addMetadata();
                    }, 2000);
                }
            })
            .catch(error => {
                console.error('Failed to find metadata list:', error);
            });

        // Also listen for navigation changes (for SPA navigation)
        let lastUrl = location.href;
        new MutationObserver(() => {
            const url = location.href;
            if (url !== lastUrl) {
                lastUrl = url;
                if (url.includes('/album/')) {
                    console.log('Navigation detected, re-initializing...');
                    setTimeout(init, 1000);
                }
            }
        }).observe(document, { subtree: true, childList: true });
    }

    // Start when DOM is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();

QingJ © 2025

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