Drawaria Music Player

Music player for drawaria.online

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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();
    }
})();