Drawaria CHRISTMAS JUKEBOX 🎄

¡Escucha tus villancicos favoritos con este reproductor con temática navideña!

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Drawaria CHRISTMAS JUKEBOX 🎄
// @namespace    http://violentmonkey.com/
// @version      7.0
// @description  ¡Escucha tus villancicos favoritos con este reproductor con temática navideña!
// @match        https://drawaria.online/*
// @match        https://drawaria.online/test
// @match        https://n.drawaria.online/
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// @author       YouTubeDrawaria / Christmas Edit
// ==/UserScript==

(function() {
    'use strict';

    // --- ESTILOS NAVIDEÑOS (RED, GREEN, GOLD) ---
    const style = document.createElement('style');
    style.textContent = `
    #music-mod {
        position: fixed;
        top: 20px;
        right: 20px;
        width: 320px;
        max-height: 80vh;
        /* Fondo: Rojo de terciopelo oscuro */
        background: rgba(48, 8, 8, 0.95);
        /* Borde: Dorado */
        border: 1px solid #ffd700;
        border-radius: 12px;
        padding: 0;
        z-index: 9999;
        color: white;
        font-family: 'Segoe UI', sans-serif;
        /* Sombra: Roja festiva */
        box-shadow: 0 10px 25px rgba(255, 50, 50, 0.5);
        backdrop-filter: blur(8px);
        overflow: hidden;
        transition: all 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28);
    }

    #music-mod-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 15px;
        /* Fondo: Degradado de Rojo a Verde */
        background: linear-gradient(to right, #8b0000, #006400);
        cursor: move;
        user-select: none;
    }

    #music-mod-title {
        margin: 0;
        /* Color: Dorado brillante */
        color: #ffcc00;
        font-size: 18px;
        font-weight: 600;
        /* Sombra: Resplandor festivo */
        text-shadow: 0 0 10px rgba(255, 255, 200, 0.8);
    }

    #music-mod-controls {
        display: flex;
        gap: 8px;
    }

    .mod-btn-control {
        width: 24px;
        height: 24px;
        border: none;
        border-radius: 6px;
        /* Fondo: Rojo oscuro transparente */
        background: rgba(160, 0, 0, 0.4);
        /* Color: Blanco Nieve */
        color: #ffffff;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        transition: all 0.2s;
    }

    .mod-btn-control:hover {
        /* Fondo: Rojo brillante transparente */
        background: rgba(255, 50, 50, 0.6);
        transform: scale(1.1);
    }

    #music-mod-content {
        padding: 15px;
        overflow-y: auto;
        max-height: calc(80vh - 60px);
    }

    .mod-btn {
        width: 100%;
        padding: 12px 15px;
        margin: 8px 0;
        border: none;
        border-radius: 8px;
        /* Fondo: Degradado de Rojo Oscuro a Verde Oscuro */
        background: linear-gradient(135deg, #8b0000, #004d00);
        color: white;
        font-weight: 500;
        font-size: 14px;
        cursor: pointer;
        transition: all 0.3s;
        position: relative;
        overflow: hidden;
        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 8px;
    }

    .mod-btn::before {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        /* Efecto Nieve/Brillo */
        background: linear-gradient(135deg, rgba(255, 255, 255, 0.3), transparent);
        opacity: 0;
        transition: opacity 0.3s;
    }

    .mod-btn:hover {
        /* Fondo: Rojo Naranja a Verde Bosque */
        background: linear-gradient(135deg, #ff4500, #228b22);
        /* Sombra: Dorado */
        box-shadow: 0 6px 10px rgba(255, 215, 0, 0.5);
        transform: translateY(-2px);
    }

    .mod-btn:hover::before {
        opacity: 1;
    }

    .mod-btn:active {
        transform: translateY(0);
    }

    .mod-btn i {
        font-size: 16px;
    }

    .mod-section {
        margin: 15px 0;
        padding: 15px;
        /* Fondo de sección: Gris oscuro navideño */
        background: rgba(30, 0, 0, 0.6);
        border-radius: 10px;
        /* Borde: Dorado */
        border: 1px solid #ffd700;
    }

    .mod-section-title {
        margin: 0 0 12px 0;
        /* Color: Dorado brillante */
        color: #ffcc00;
        font-size: 14px;
        font-weight: 500;
        display: flex;
        align-items: center;
        gap: 8px;
    }

    /* Scrollbar con colores navideños */
    #music-mod-content::-webkit-scrollbar {
        width: 6px;
    }

    #music-mod-content::-webkit-scrollbar-track {
        background: rgba(50, 10, 10, 0.3);
        border-radius: 3px;
    }

    #music-mod-content::-webkit-scrollbar-thumb {
        /* Degradado de Rojo a Verde */
        background: linear-gradient(#a00000, #008000);
        border-radius: 3px;
    }

    /* Animación de pulso */
    @keyframes pulse {
        0% { box-shadow: 0 0 0 0 rgba(255, 215, 0, 0.4); } /* Dorado */
        70% { box-shadow: 0 0 0 12px rgba(255, 215, 0, 0); }
        100% { box-shadow: 0 0 0 0 rgba(255, 215, 0, 0); }
    }

    .playing {
        animation: pulse 2s infinite;
    }

    select, input[type="text"], input[type="range"] {
        width: 100%;
        padding: 8px;
        margin: 5px 0;
        /* Fondo: Rojo muy oscuro */
        background: rgba(60, 10, 10, 0.7);
        /* Borde: Dorado */
        border: 1px solid #ffd700;
        border-radius: 6px;
        color: white;
    }

    input[type="range"] {
        padding: 0;
        height: 6px;
        -webkit-appearance: none;
    }

    input[type="range"]::-webkit-slider-thumb {
        -webkit-appearance: none;
        width: 16px;
        height: 16px;
        /* Pulgar del slider: Dorado */
        background: #ffcc00;
        border-radius: 50%;
        cursor: pointer;
        box-shadow: 0 0 5px rgba(255, 215, 0, 0.5);
    }
    `;
    document.head.appendChild(style);

    // --- ESTRUCTURA HTML (Nuevos Títulos e Iconos) ---
    const mod = document.createElement('div');
    mod.id = 'music-mod';
    mod.innerHTML = `
    <div id="music-mod-header">
        <h3 id="music-mod-title">🎄 CHRISTMAS JUKEBOX 🎶</h3>
        <div id="music-mod-controls">
            <button id="collapse-btn" class="mod-btn-control">−</button>
            <button id="close-btn" class="mod-btn-control">×</button>
        </div>
    </div>
    <div id="music-mod-content">
        <div class="mod-section">
            <div class="mod-section-title">🔔 CAROL CONTROL</div>
            <button id="add-music-btn" class="mod-btn"><i>🎁</i> ADD CAROLS</button>
            <input type="file" id="file-input" accept=".mp3,audio/*" multiple style="display:none">
            <select id="song-list" size="4"></select>

            <div style="display:flex; gap:8px; margin-top:10px;">
                <button id="play-btn" class="mod-btn" style="flex:1;"><i>▶️</i> PLAY</button>
                <button id="stop-btn" class="mod-btn" style="flex:1;"><i>⏹</i> STOP</button>
            </div>

            <div style="display:flex; gap:8px;">
                <button id="prev-btn" class="mod-btn" style="flex:1;"><i>⏮</i> PREVIOUS</button>
                <button id="next-btn" class="mod-btn" style="flex:1;"><i>⏭</i> NEXT</button>
            </div>
        </div>

        <div class="mod-section">
            <div class="mod-section-title">✨ SETTINGS</div>
            <div style="margin:12px 0;">
                <div style="display:flex; justify-content:space-between; margin-bottom:5px;">
                    <span style="color:#ffcc00;">SPEED:</span>
                    <span id="speed-value" style="color:#ffffff;">1.0x</span>
                </div>
                <input type="range" id="speed-slider" min="0.5" max="2" step="0.1" value="1">
            </div>

            <div style="margin:12px 0;">
                <div style="display:flex; justify-content:space-between; margin-bottom:5px;">
                    <span style="color:#ffcc00;">VOLUME:</span>
                    <span id="volume-value" style="color:#ffffff;">70%</span>
                </div>
                <input type="range" id="volume-slider" min="0" max="1" step="0.1" value="0.7">
            </div>

            <div style="display:flex; gap:8px;">
                <button id="loop-btn" class="mod-btn" style="flex:1;"><i>🔁</i> LOOP</button>
                <button id="shuffle-btn" class="mod-btn" style="flex:1;"><i>🔀</i> SHUFFLE</button>
            </div>
        </div>

        <div class="mod-section">
            <div class="mod-section-title">🎅 PLAYLIST MANAGEMENT</div>
            <input type="text" id="playlist-name" placeholder="Playlist Name">
            <button id="save-playlist-btn" class="mod-btn"><i>💾</i> SAVE PRESENT</button>
            <select id="playlist-select"></select>
            <div style="display:flex; gap:8px;">
                <button id="load-playlist-btn" class="mod-btn" style="flex:1;"><i>🎄</i> OPEN PRESENT</button>
                <button id="delete-playlist-btn" class="mod-btn" style="flex:1;"><i>🗑️</i> DELETE SACK</button>
            </div>
        </div>
    </div>
    `;
    document.body.appendChild(mod);

    // --- LÓGICA DEL SCRIPT (Sin cambios funcionales mayores) ---
    // Initialize player
    const audio = new Audio();
    let songs = [];
    let currentSongIndex = 0;
    let isPlaying = false;
    let loopMode = true;
    let isShuffled = false;
    let originalPlaylist = [];

    // Get all elements
    const modElement = document.getElementById('music-mod');
    const header = document.getElementById('music-mod-header');
    const content = document.getElementById('music-mod-content');
    const collapseBtn = document.getElementById('collapse-btn');
    const closeBtn = document.getElementById('close-btn');
    const addBtn = document.getElementById('add-music-btn');
    const fileInput = document.getElementById('file-input');
    const songList = document.getElementById('song-list');
    const playBtn = document.getElementById('play-btn');
    const stopBtn = document.getElementById('stop-btn');
    const prevBtn = document.getElementById('prev-btn');
    const nextBtn = document.getElementById('next-btn');
    const loopBtn = document.getElementById('loop-btn');
    const shuffleBtn = document.getElementById('shuffle-btn');
    const speedSlider = document.getElementById('speed-slider');
    const volumeSlider = document.getElementById('volume-slider');
    const playlistNameInput = document.getElementById('playlist-name');
    const savePlaylistBtn = document.getElementById('save-playlist-btn');
    const playlistSelect = document.getElementById('playlist-select');
    const loadPlaylistBtn = document.getElementById('load-playlist-btn');
    const deletePlaylistBtn = document.getElementById('delete-playlist-btn');

    // Key for storing playlists
    const PLAYLIST_STORAGE_KEY = "music_player_playlists_christmas"; // Changed key to avoid conflict

    // Function to save playlist
    function savePlaylist() {
        const name = playlistNameInput.value.trim();
        if (!name) {
            alert("Please enter a playlist name!");
            return;
        }

        // Get the current list of playlists
        const playlists = JSON.parse(localStorage.getItem(PLAYLIST_STORAGE_KEY) || "{}");

        // Save the playlist
        // NOTE: Saving local files this way (with Blob URLs) will only work for the current session!
        playlists[name] = {
            songs: songs.map(song => ({
                name: song.name,
                url: song.url
            })),
            currentIndex: currentSongIndex
        };

        localStorage.setItem(PLAYLIST_STORAGE_KEY, JSON.stringify(playlists));
        updatePlaylists();
        alert(`Christmas Playlist "${name}" saved successfully! (Note: Local file playback requires re-adding files after session refresh)`);
        playlistNameInput.value = '';
    }

    // Function to load playlist
    function loadPlaylist() {
        const name = playlistSelect.value;
        if (!name) return;

        const playlists = JSON.parse(localStorage.getItem(PLAYLIST_STORAGE_KEY) || "{}");
        const playlist = playlists[name];

        if (playlist) {
            // NOTE: Only playlist names and structure are loaded. Actual music files will need to be re-added
            // or the URLs must point to public/permanent sources, which this script doesn't handle.
            songs = playlist.songs;
            currentSongIndex = playlist.currentIndex || 0;
            updateSongList();
            alert(`Christmas Playlist "${name}" loaded! Please note: Local file URLs may have expired.`);
        } else {
            alert("Playlist not found!");
        }
    }

    // Function to delete playlist
    function deletePlaylist() {
        const name = playlistSelect.value;
        if (!name) return;

        if (confirm(`Are you sure you want to delete the Christmas playlist "${name}"?`)) {
            const playlists = JSON.parse(localStorage.getItem(PLAYLIST_STORAGE_KEY) || "{}");
            delete playlists[name];
            localStorage.setItem(PLAYLIST_STORAGE_KEY, JSON.stringify(playlists));
            updatePlaylists();
            alert(`Christmas Playlist "${name}" deleted!`);
        }
    }

    // Update the list of playlists in the dropdown menu
    function updatePlaylists() {
        const playlists = JSON.parse(localStorage.getItem(PLAYLIST_STORAGE_KEY) || "{}");
        const playlistNames = Object.keys(playlists);

        // Clear the list
        playlistSelect.innerHTML = '';

        if (playlistNames.length === 0) {
            const option = document.createElement('option');
            option.textContent = "No saved Christmas playlists";
            playlistSelect.appendChild(option);
        } else {
            playlistNames.forEach(name => {
                const option = document.createElement('option');
                option.value = name;
                option.textContent = name;
                playlistSelect.appendChild(option);
            });
        }
    }

    // Assign handlers for playlist buttons
    savePlaylistBtn.addEventListener('click', savePlaylist);
    loadPlaylistBtn.addEventListener('click', loadPlaylist);
    deletePlaylistBtn.addEventListener('click', deletePlaylist);

    // Player functions
    function playMusic() {
        if (songs.length === 0) {
            alert("Add Christmas music first!");
            return;
        }

        const song = songs[currentSongIndex];
        audio.src = song.url;
        audio.play()
            .then(() => {
                isPlaying = true;
                playBtn.innerHTML = '<i>⏸</i> PAUSE';
                playBtn.classList.add('playing');
            })
            .catch(err => alert("Playback error. This is common with expired local file URLs. Please re-add your carols. Error: " + err.message));
    }

    function stopMusic() {
        audio.pause();
        audio.currentTime = 0;
        isPlaying = false;
        playBtn.innerHTML = '<i>▶️</i> PLAY';
        playBtn.classList.remove('playing');
    }

    function playNext() {
        if (songs.length === 0) return;

        currentSongIndex = (currentSongIndex + 1) % songs.length;
        songList.selectedIndex = currentSongIndex;
        if (isPlaying) playMusic();
    }

    function playPrev() {
        if (songs.length === 0) return;

        currentSongIndex = (currentSongIndex - 1 + songs.length) % songs.length;
        songList.selectedIndex = currentSongIndex;
        if (isPlaying) playMusic();
    }

    // Color updates for Loop/Shuffle buttons (Theming)
    function toggleLoop() {
        loopMode = !loopMode;
        audio.loop = loopMode;
        loopBtn.innerHTML = loopMode ? '<i>🔁</i> LOOP' : '<i>🔂</i> ONE';
        loopBtn.style.background = loopMode
            ? 'linear-gradient(135deg, #8b0000, #004d00)' // Red/Green
            : 'linear-gradient(135deg, #a03000, #006600)'; // Orange-Red/Dark Green
    }

    function toggleShuffle() {
        isShuffled = !isShuffled;

        if (isShuffled) {
            originalPlaylist = [...songs];
            const currentSong = songs[currentSongIndex];
            songs = songs.filter((_, i) => i !== currentSongIndex);

            // Shuffle
            for (let i = songs.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [songs[i], songs[j]] = [songs[j], songs[i]];
            }

            songs.unshift(currentSong);
            currentSongIndex = 0;
        } else {
            if (originalPlaylist.length > 0) {
                currentSongIndex = originalPlaylist.findIndex(
                    song => song.url === songs[currentSongIndex].url
                );
                songs = [...originalPlaylist];
            }
        }

        shuffleBtn.innerHTML = isShuffled ? '<i>🔀</i> NORMAL' : '<i>🔀</i> SHUFFLE';
        shuffleBtn.style.background = isShuffled
            ? 'linear-gradient(135deg, #a03000, #006600)' // Orange-Red/Dark Green
            : 'linear-gradient(135deg, #8b0000, #004d00)'; // Red/Green

        updateSongList();
    }

    function updateSongList() {
        songList.innerHTML = songs.map((song, i) =>
            `<option value="${i}" ${i === currentSongIndex ? 'selected' : ''}>${song.name}</option>`
        ).join('');
    }

    // Player button handlers
    playBtn.addEventListener('click', () => {
        if (isPlaying) {
            audio.pause();
            isPlaying = false;
            playBtn.innerHTML = '<i>▶️</i> PLAY';
            playBtn.classList.remove('playing');
        } else {
            playMusic();
        }
    });

    stopBtn.addEventListener('click', stopMusic);
    nextBtn.addEventListener('click', playNext);
    prevBtn.addEventListener('click', playPrev);
    loopBtn.addEventListener('click', toggleLoop);
    shuffleBtn.addEventListener('click', toggleShuffle);

    // Adding music
    addBtn.addEventListener('click', () => fileInput.click());

    fileInput.addEventListener('change', (e) => {
        const files = Array.from(e.target.files);
        files.forEach(file => {
            if (file.type.startsWith('audio/')) {
                songs.push({
                    name: file.name.replace('.mp3', ''),
                    url: URL.createObjectURL(file),
                    file: file
                });
            }
        });
        updateSongList();
    });

    songList.addEventListener('change', (e) => {
        currentSongIndex = e.target.selectedIndex;
        if (isPlaying) playMusic();
    });

    // Sound settings
    speedSlider.addEventListener('input', () => {
        audio.playbackRate = speedSlider.value;
        document.getElementById('speed-value').textContent = `${speedSlider.value}x`;
    });

    volumeSlider.addEventListener('input', () => {
        audio.volume = volumeSlider.value;
        document.getElementById('volume-value').textContent = `${Math.round(volumeSlider.value * 100)}%`;
    });

    // Window management (Drag, Collapse, Close) - Unchanged
    let isDragging = false;
    let offsetX, offsetY;

    header.addEventListener('mousedown', (e) => {
        if (e.target.classList.contains('mod-btn-control')) return;

        isDragging = true;
        const rect = modElement.getBoundingClientRect();
        offsetX = e.clientX - rect.left;
        offsetY = e.clientY - rect.top;
        modElement.style.transition = 'none';
        e.preventDefault();
    });

    document.addEventListener('mousemove', (e) => {
        if (!isDragging) return;
        modElement.style.left = `${e.clientX - offsetX}px`;
        modElement.style.top = `${e.clientY - offsetY}px`;
    });

    document.addEventListener('mouseup', () => {
        isDragging = false;
        modElement.style.transition = 'all 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28)';
    });

    let isCollapsed = false;
    collapseBtn.addEventListener('click', () => {
        isCollapsed = !isCollapsed;
        content.style.display = isCollapsed ? 'none' : 'block';
        collapseBtn.textContent = isCollapsed ? '+' : '−';
    });

    closeBtn.addEventListener('click', () => {
        modElement.style.transform = 'scale(0.8)';
        modElement.style.opacity = '0';
        setTimeout(() => modElement.remove(), 300);
    });

    // Handling end of track
    audio.addEventListener('ended', () => {
        if (loopMode) {
            audio.currentTime = 0;
            audio.play();
        } else {
            playNext();
        }
    });

    // Initialization
    audio.volume = volumeSlider.value;
    audio.playbackRate = speedSlider.value;
    updatePlaylists();
    updateSongList();
})();