Drawaria - Music Player PRO (Fixed)

Мод-меню для прослушивания музыки

// ==UserScript==
// @name         Drawaria - Music Player PRO (Fixed)
// @namespace    http://violentmonkey.com/
// @version      6.6
// @description  Мод-меню для прослушивания музыки
// @match        *://drawaria.com/*
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Стили
    const style = document.createElement('style');
    style.textContent = `
    #music-mod {
        position: fixed;
        top: 20px;
        right: 20px;
        width: 320px;
        max-height: 80vh;
        background: rgba(10, 15, 25, 0.95);
        border: 1px solid #1e3a5a;
        border-radius: 12px;
        padding: 0;
        z-index: 9999;
        color: white;
        font-family: 'Segoe UI', sans-serif;
        box-shadow: 0 10px 25px rgba(0, 50, 100, 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;
        background: linear-gradient(to right, #0a1a2a, #0d2b40);
        cursor: move;
        user-select: none;
    }
    
    #music-mod-title {
        margin: 0;
        color: #00e1ff;
        font-size: 18px;
        font-weight: 600;
        text-shadow: 0 0 10px rgba(0, 225, 255, 0.5);
    }
    
    #music-mod-controls {
        display: flex;
        gap: 8px;
    }
    
    .mod-btn-control {
        width: 24px;
        height: 24px;
        border: none;
        border-radius: 6px;
        background: rgba(0, 150, 255, 0.2);
        color: #00e1ff;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        transition: all 0.2s;
    }
    
    .mod-btn-control:hover {
        background: rgba(0, 180, 255, 0.4);
        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;
        background: linear-gradient(135deg, #0d2b40, #003366);
        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%;
        background: linear-gradient(135deg, rgba(0, 200, 255, 0.3), transparent);
        opacity: 0;
        transition: opacity 0.3s;
    }
    
    .mod-btn:hover {
        background: linear-gradient(135deg, #0e3a5a, #004488);
        box-shadow: 0 6px 10px rgba(0, 100, 200, 0.3);
        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;
        background: rgba(5, 15, 25, 0.5);
        border-radius: 10px;
        border: 1px solid #1a3a5a;
    }
    
    .mod-section-title {
        margin: 0 0 12px 0;
        color: #00a8ff;
        font-size: 14px;
        font-weight: 500;
        display: flex;
        align-items: center;
        gap: 8px;
    }
    
    #music-mod-content::-webkit-scrollbar {
        width: 6px;
    }
    
    #music-mod-content::-webkit-scrollbar-track {
        background: rgba(10, 20, 30, 0.3);
        border-radius: 3px;
    }
    
    #music-mod-content::-webkit-scrollbar-thumb {
        background: linear-gradient(#00a8ff, #0088ff);
        border-radius: 3px;
    }
    
    @keyframes pulse {
        0% { box-shadow: 0 0 0 0 rgba(0, 200, 255, 0.4); }
        70% { box-shadow: 0 0 0 12px rgba(0, 200, 255, 0); }
        100% { box-shadow: 0 0 0 0 rgba(0, 200, 255, 0); }
    }
    
    .playing {
        animation: pulse 2s infinite;
    }
    
    select, input[type="text"], input[type="range"] {
        width: 100%;
        padding: 8px;
        margin: 5px 0;
        background: rgba(0, 20, 40, 0.7);
        border: 1px solid #1a3a5a;
        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;
        background: #00e1ff;
        border-radius: 50%;
        cursor: pointer;
        box-shadow: 0 0 5px rgba(0, 225, 255, 0.5);
    }
    `;
    document.head.appendChild(style);

    // HTML структура
    const mod = document.createElement('div');
    mod.id = 'music-mod';
    mod.innerHTML = `
    <div id="music-mod-header">
        <h3 id="music-mod-title">MUSIC PLAYER PRO</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">🎵 УПРАВЛЕНИЕ МУЗЫКОЙ</div>
            <button id="add-music-btn" class="mod-btn"><i>🎵</i> ДОБАВИТЬ ТРЕКИ</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> ИГРАТЬ</button>
                <button id="stop-btn" class="mod-btn" style="flex:1;"><i>⏹</i> СТОП</button>
            </div>
            
            <div style="display:flex; gap:8px;">
                <button id="prev-btn" class="mod-btn" style="flex:1;"><i>⏮</i> НАЗАД</button>
                <button id="next-btn" class="mod-btn" style="flex:1;"><i>⏭</i> ВПЕРЕД</button>
            </div>
        </div>
        
        <div class="mod-section">
            <div class="mod-section-title">⚙️ НАСТРОЙКИ</div>
            <div style="margin:12px 0;">
                <div style="display:flex; justify-content:space-between; margin-bottom:5px;">
                    <span style="color:#88ccff;">СКОРОСТЬ:</span>
                    <span id="speed-value" style="color:#00e1ff;">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:#88ccff;">ГРОМКОСТЬ:</span>
                    <span id="volume-value" style="color:#00e1ff;">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> ПОВТОР</button>
                <button id="shuffle-btn" class="mod-btn" style="flex:1;"><i>🔀</i> МИКС</button>
            </div>
        </div>
        
        <div class="mod-section">
            <div class="mod-section-title">💾 УПРАВЛЕНИЕ ПЛЕЙЛИСТАМИ</div>
            <input type="text" id="playlist-name" placeholder="Имя плейлиста">
            <button id="save-playlist-btn" class="mod-btn"><i>💾</i> СОХРАНИТЬ</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> ЗАГРУЗИТЬ</button>
                <button id="delete-playlist-btn" class="mod-btn" style="flex:1;"><i>🗑️</i> УДАЛИТЬ</button>
            </div>
        </div>
    </div>
    `;
    document.body.appendChild(mod);

    // Инициализация плеера
    const audio = new Audio();
    let songs = [];
    let currentSongIndex = 0;
    let isPlaying = false;
    let loopMode = true;
    let isShuffled = false;
    let originalPlaylist = [];
    
    // Получаем все элементы
    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');

    // Ключ для хранения плейлистов
    const PLAYLIST_STORAGE_KEY = "music_player_playlists";
    
    // Функция сохранения плейлиста
    function savePlaylist() {
        const name = playlistNameInput.value.trim();
        if (!name) {
            alert("Пожалуйста, введите название плейлиста!");
            return;
        }
        
        // Получаем текущий список плейлистов
        const playlists = JSON.parse(localStorage.getItem(PLAYLIST_STORAGE_KEY) || "{}");
        
        // Сохраняем плейлист
        playlists[name] = {
            songs: songs.map(song => ({
                name: song.name,
                url: song.url
            })),
            currentIndex: currentSongIndex
        };
        
        localStorage.setItem(PLAYLIST_STORAGE_KEY, JSON.stringify(playlists));
        updatePlaylists();
        alert(`Плейлист "${name}" успешно сохранен!`);
        playlistNameInput.value = '';
    }
    
    // Функция загрузки плейлиста
    function loadPlaylist() {
        const name = playlistSelect.value;
        if (!name) return;
        
        const playlists = JSON.parse(localStorage.getItem(PLAYLIST_STORAGE_KEY) || "{}");
        const playlist = playlists[name];
        
        if (playlist) {
            songs = playlist.songs;
            currentSongIndex = playlist.currentIndex || 0;
            updateSongList();
            alert(`Плейлист "${name}" загружен!`);
        } else {
            alert("Плейлист не найден!");
        }
    }
    
    // Функция удаления плейлиста
    function deletePlaylist() {
        const name = playlistSelect.value;
        if (!name) return;
        
        if (confirm(`Вы уверены, что хотите удалить плейлист "${name}"?`)) {
            const playlists = JSON.parse(localStorage.getItem(PLAYLIST_STORAGE_KEY) || "{}");
            delete playlists[name];
            localStorage.setItem(PLAYLIST_STORAGE_KEY, JSON.stringify(playlists));
            updatePlaylists();
            alert(`Плейлист "${name}" удален!`);
        }
    }
    
    // Обновление списка плейлистов в выпадающем меню
    function updatePlaylists() {
        const playlists = JSON.parse(localStorage.getItem(PLAYLIST_STORAGE_KEY) || "{}");
        const playlistNames = Object.keys(playlists);
        
        // Очищаем список
        playlistSelect.innerHTML = '';
        
        if (playlistNames.length === 0) {
            const option = document.createElement('option');
            option.textContent = "Нет сохраненных плейлистов";
            playlistSelect.appendChild(option);
        } else {
            playlistNames.forEach(name => {
                const option = document.createElement('option');
                option.value = name;
                option.textContent = name;
                playlistSelect.appendChild(option);
            });
        }
    }
    
    // Назначаем обработчики для кнопок плейлистов
    savePlaylistBtn.addEventListener('click', savePlaylist);
    loadPlaylistBtn.addEventListener('click', loadPlaylist);
    deletePlaylistBtn.addEventListener('click', deletePlaylist);
    
    // Функции плеера
    function playMusic() {
        if (songs.length === 0) {
            alert("Добавьте музыку сначала!");
            return;
        }
        
        const song = songs[currentSongIndex];
        audio.src = song.url;
        audio.play()
            .then(() => {
                isPlaying = true;
                playBtn.innerHTML = '<i>⏸</i> ПАУЗА';
                playBtn.classList.add('playing');
            })
            .catch(err => alert("Ошибка воспроизведения: " + err.message));
    }

    function stopMusic() {
        audio.pause();
        audio.currentTime = 0;
        isPlaying = false;
        playBtn.innerHTML = '<i>▶️</i> ИГРАТЬ';
        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();
    }

    function toggleLoop() {
        loopMode = !loopMode;
        audio.loop = loopMode;
        loopBtn.innerHTML = loopMode ? '<i>🔁</i> ПОВТОР' : '<i>🔂</i> ОДНА';
        loopBtn.style.background = loopMode 
            ? 'linear-gradient(135deg, #0d2b40, #003366)' 
            : 'linear-gradient(135deg, #0d3b40, #005566)';
    }

    function toggleShuffle() {
        isShuffled = !isShuffled;
        
        if (isShuffled) {
            originalPlaylist = [...songs];
            const currentSong = songs[currentSongIndex];
            songs = songs.filter((_, i) => i !== currentSongIndex);
            
            // Перемешиваем
            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> ОБЫЧНЫЙ' : '<i>🔀</i> МИКС';
        shuffleBtn.style.background = isShuffled 
            ? 'linear-gradient(135deg, #0d3b40, #005566)' 
            : 'linear-gradient(135deg, #0d2b40, #003366)';
            
        updateSongList();
    }

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

    // Обработчики кнопок плеера
    playBtn.addEventListener('click', () => {
        if (isPlaying) {
            audio.pause();
            isPlaying = false;
            playBtn.innerHTML = '<i>▶️</i> ИГРАТЬ';
            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);

    // Добавление музыки
    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();
    });

    // Настройки звука
    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)}%`;
    });

    // Управление окном
    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);
    });

    // Обработка окончания трека
    audio.addEventListener('ended', () => {
        if (loopMode) {
            audio.currentTime = 0;
            audio.play();
        } else {
            playNext();
        }
    });

    // Инициализация
    audio.volume = volumeSlider.value;
    audio.playbackRate = speedSlider.value;
    updatePlaylists();
    updateSongList();
})();