Deezer Album Metadata Enhancer

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

Version vom 26.09.2025. Aktuellste Version

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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();
    }
})();