Drawaria Music Player

Music player for drawaria.online

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Drawaria Music Player
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Music player for drawaria.online
// @author       You
// @match        https://drawaria.online/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Create music player container
    const playerContainer = document.createElement('div');
    playerContainer.style.position = 'fixed';
    playerContainer.style.top = '20px';
    playerContainer.style.right = '20px';
    playerContainer.style.zIndex = '1000';
    playerContainer.style.backgroundColor = 'white';
    playerContainer.style.padding = '1.5rem';
    playerContainer.style.borderRadius = '0.75rem';
    playerContainer.style.boxShadow = '0 10px 15px -3px rgba(0, 0, 0, 0.1)';
    playerContainer.style.minWidth = '320px';

    // State variables
    let audioFiles = [];
    let currentTrackIndex = 0;
    let isPlaying = false;
    let volume = 0.5;
    let currentTime = 0;
    let duration = 0;
    const audioElement = new Audio();

    // UI Elements
    const title = document.createElement('h2');
    title.textContent = 'Music Player';
    title.style.fontSize = '1.5rem';
    title.style.fontWeight = 'bold';
    title.style.marginBottom = '1rem';
    title.style.textAlign = 'center';

    const uploadLabel = document.createElement('label');
    uploadLabel.style.display = 'block';
    uploadLabel.style.backgroundColor = '#3b82f6';
    uploadLabel.style.color = 'white';
    uploadLabel.style.padding = '0.5rem 1rem';
    uploadLabel.style.borderRadius = '0.375rem';
    uploadLabel.style.cursor = 'pointer';
    uploadLabel.style.textAlign = 'center';
    uploadLabel.style.marginBottom = '1rem';
    uploadLabel.innerHTML = `
        Upload Music
        <input type="file" id="audio-upload" multiple accept="audio/*" style="display:none;">
    `;

    const fileList = document.createElement('ul');
    fileList.style.maxHeight = '128px';
    fileList.style.overflowY = 'auto';
    fileList.style.marginTop = '0.5rem';

    const trackInfo = document.createElement('div');
    trackInfo.style.display = 'flex';
    trackInfo.style.justifyContent = 'space-between';
    trackInfo.style.marginBottom = '0.5rem';

    const timeDisplay = document.createElement('div');
    const progressSlider = document.createElement('input');
    progressSlider.type = 'range';
    progressSlider.style.width = '100%';
    progressSlider.style.marginBottom = '1rem';

    const controls = document.createElement('div');
    controls.style.display = 'flex';
    controls.style.justifyContent = 'center';
    controls.style.gap = '1rem';
    controls.style.marginTop = '1rem';

    const prevButton = createButton('❮', () => prevTrack());
    const playButton = createButton('▶', () => playPause());
    const nextButton = createButton('❯', () => nextTrack());

    const volumeContainer = document.createElement('div');
    volumeContainer.style.display = 'flex';
    volumeContainer.style.alignItems = 'center';
    volumeContainer.style.gap = '0.5rem';
    volumeContainer.style.marginTop = '1rem';
    volumeContainer.innerHTML = '🔊';
    const volumeSlider = document.createElement('input');
    volumeSlider.type = 'range';
    volumeSlider.min = '0';
    volumeSlider.max = '1';
    volumeSlider.step = '0.01';
    volumeSlider.value = volume;
    volumeSlider.style.flexGrow = '1';
    volumeContainer.appendChild(volumeSlider);

    // Assemble UI
    controls.append(prevButton, playButton, nextButton);
    trackInfo.append(timeDisplay);
    playerContainer.append(
        title,
        uploadLabel,
        fileList,
        trackInfo,
        progressSlider,
        controls,
        volumeContainer
    );
    document.body.appendChild(playerContainer);

    // Event listeners
    uploadLabel.querySelector('input').addEventListener('change', handleFileUpload);
    playButton.addEventListener('click', () => updatePlayButton());
    prevButton.addEventListener('click', () => updateUI());
    nextButton.addEventListener('click', () => updateUI());
    progressSlider.addEventListener('input', handleProgressChange);
    volumeSlider.addEventListener('input', handleVolumeChange);
    audioElement.addEventListener('timeupdate', updateTimeDisplay);
    audioElement.addEventListener('durationchange', updateDuration);
    audioElement.addEventListener('ended', handleTrackEnd);

    function createButton(text, onClick) {
        const btn = document.createElement('button');
        btn.textContent = text;
        btn.style.padding = '0.5rem';
        btn.style.borderRadius = '9999px';
        btn.style.backgroundColor = '#e5e7eb';
        btn.addEventListener('click', onClick);
        return btn;
    }

    function handleFileUpload(e) {
        const files = Array.from(e.target.files);
        audioFiles = [...audioFiles, ...files];
        updateFileList();
        if (audioFiles.length === 1) loadTrack(0);
    }

    function updateFileList() {
        fileList.innerHTML = '';
        audioFiles.forEach((file, index) => {
            const li = document.createElement('li');
            li.textContent = file.name;
            li.style.padding = '0.5rem';
            li.style.cursor = 'pointer';
            li.style.backgroundColor = index === currentTrackIndex ? '#f3f4f6' : 'transparent';
            li.addEventListener('click', () => {
                currentTrackIndex = index;
                loadTrack(index);
                updateUI();
            });
            fileList.appendChild(li);
        });
    }

    function loadTrack(index) {
        if (!audioFiles[index]) return;
        const url = URL.createObjectURL(audioFiles[index]);
        audioElement.src = url;
        audioElement.volume = volume;
        if (isPlaying) audioElement.play();
        updateTimeDisplay();
    }

    function playPause() {
        isPlaying = !isPlaying;
        if (isPlaying) {
            audioElement.play();
        } else {
            audioElement.pause();
        }
        updatePlayButton();
    }

    function updatePlayButton() {
        playButton.textContent = isPlaying ? '⏸' : '▶';
        playButton.style.backgroundColor = isPlaying ? '#3b82f6' : '#e5e7eb';
        playButton.style.color = isPlaying ? 'white' : 'inherit';
    }

    function prevTrack() {
        currentTrackIndex = (currentTrackIndex - 1 + audioFiles.length) % audioFiles.length;
        loadTrack(currentTrackIndex);
    }

    function nextTrack() {
        currentTrackIndex = (currentTrackIndex + 1) % audioFiles.length;
        loadTrack(currentTrackIndex);
    }

    function handleProgressChange(e) {
        const time = parseFloat(e.target.value);
        currentTime = time;
        audioElement.currentTime = time;
    }

    function handleVolumeChange(e) {
        volume = parseFloat(e.target.value);
        audioElement.volume = volume;
    }

    function updateTimeDisplay() {
        currentTime = audioElement.currentTime;
        duration = audioElement.duration || 0;
        progressSlider.max = duration;
        progressSlider.value = currentTime;
        timeDisplay.textContent = `${formatTime(currentTime)} / ${formatTime(duration)}`;
    }

    function updateDuration() {
        duration = audioElement.duration;
        progressSlider.max = duration;
    }

    function handleTrackEnd() {
        nextTrack();
    }

    function formatTime(seconds) {
        const minutes = Math.floor(seconds / 60);
        seconds = Math.floor(seconds % 60);
        return `${minutes}:${seconds.toString().padStart(2, '0')}`;
    }

    function updateUI() {
        updateFileList();
        updateTimeDisplay();
        updatePlayButton();
    }
})();