Greasy Fork 支持简体中文。

Music Player for Open Directories

A full-page music player with a modern interface, including download buttons, time display, and interaction banners.

// ==UserScript==
// @name         Music Player for Open Directories
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  A full-page music player with a modern interface, including download buttons, time display, and interaction banners.
// @author       GhostyTongue
// @match        *://*/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    var e, t, n = document.links, i = [], o = 0;
    for (t in n) {
        var a = n[t].toString().toUpperCase();
        if (a.indexOf("JAVASCRIPT:") !== 0 && (a.indexOf(".MP3") !== -1 || a.indexOf(".FLAC") !== -1 || a.indexOf(".OGG") !== -1 || a.indexOf(".WAV") !== -1)) {
            i.push(n[t]);
        }
    }

    if (i.length > 0) {
        var d = x("div", "player-container", "", "", ""),
            header = x("div", "player-header", "", "", ""),
            parentButton = x("button", "parent-button", "Parent Directory", "", function() {
                window.location.href = "../";
            }),
            title = x("div", "player-title", "Music Player", "", ""),
            r = x("div", "playing", "", "", ""),
            p = x("div", "progressbar", "", "", function(t) {
                var n = t.clientX;
                n /= window.innerWidth;
                e.currentTime = e.duration * n;
            }),
            l = x("div", "progress", "", "", ""),
            timeDisplay = x("div", "time-display", "0:00", "", "");
        p.appendChild(l);
        r.appendChild(p);
        r.appendChild(timeDisplay);

        header.appendChild(parentButton);
        header.appendChild(title);
        d.appendChild(header);

        var s = x("div", "songname", "", "", "");
        r.appendChild(s);

        var u = x("div", "buttons", "", "", "");
        var playPauseButton = x("button", "control-button", "⏯", "", function() {
            e.paused ? (e.play(), this.innerHTML = "⏯") : (e.pause(), this.innerHTML = "▶️");
            showBanner(e.paused ? "Paused" : "Playing");
        });
        u.appendChild(playPauseButton);
        u.appendChild(x("button", "control-button", "⏮", "", y));
        u.appendChild(x("button", "control-button", "⏭", "", C));
        u.appendChild(x("button", "control-button", "🔀", "", function() {
            o = Math.floor(Math.random() * i.length);
            f();
        }));
        r.appendChild(u);
        d.appendChild(r);

        var c = x("ul", "playlist", "", "", "");
        for (var songIndex in i) {
            var h = decodeURIComponent(unescape(i[songIndex].href)),
                li = x("li", "playlist-item", h.substring(h.lastIndexOf("/") + 1), songIndex, function() {
                    o = parseInt(this.getAttribute("data"));
                    f();
                }),
                downloadButton = x("a", "download-button", "Download", "", function(e) {
                    e.stopPropagation();
                });
            downloadButton.href = h;
            downloadButton.download = h.substring(h.lastIndexOf("/") + 1);
            li.appendChild(downloadButton);
            c.appendChild(li);
        }
        d.appendChild(c);

        var g = x("style", "", "", "", "");
        g.innerHTML = `
            .player-container {
                position: fixed;
                top: 0;
                bottom: 0;
                left: 0;
                right: 0;
                background-color: #282c34;
                color: white;
                font-family: Arial, sans-serif;
                display: flex;
                flex-direction: column;
                justify-content: space-between;
                z-index: 1000;
            }
            .player-header {
                display: flex;
                justify-content: center;
                padding: 10px;
                background-color: #20232a;
                border-bottom: 1px solid #444;
            }
            .parent-button {
                position: absolute;
                left: 10px;
                background-color: #61dafb;
                border: none;
                color: #282c34;
                padding: 10px 20px;
                cursor: pointer;
                font-weight: bold;
            }
            .player-title {
                font-size: 2em;
                margin: auto;
                text-align: center;
            }
            .playing {
                padding: 20px;
            }
            .progressbar {
                position: relative;
                height: 20px;
                background-color: #444;
                border-radius: 10px;
                margin-bottom: 10px;
                cursor: pointer;
            }
            .progress {
                position: absolute;
                height: 100%;
                background-color: #61dafb;
                border-radius: 10px;
            }
            .time-display {
                text-align: center;
                font-size: 1em;
                margin-bottom: 20px;
            }
            .songname {
                margin-bottom: 20px;
                text-align: center;
                font-size: 1.5em;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }
            .buttons {
                text-align: center;
                margin-bottom: 20px;
            }
            .control-button {
                background: none;
                border: none;
                color: #61dafb;
                font-size: 3em;
                cursor: pointer;
                margin: 0 20px;
            }
            .playlist {
                flex: 1;
                overflow-y: auto;
                background-color: #20232a;
                padding: 20px;
                list-style: none;
                margin: 0;
            }
            .playlist-item {
                padding: 10px;
                cursor: pointer;
                border-bottom: 1px solid #444;
                font-size: 1.2em;
                display: flex;
                justify-content: space-between;
                align-items: center;
            }
            .playlist-item:hover {
                background-color: #61dafb;
                color: #282c34;
            }
            .download-button {
                background-color: #61dafb;
                border: none;
                color: #282c34;
                padding: 5px 10px;
                cursor: pointer;
                font-size: 0.9em;
                text-decoration: none;
                border-radius: 5px;
            }
            .banner {
                position: fixed;
                bottom: 20px;
                left: 50%;
                transform: translateX(-50%);
                background-color: #61dafb;
                color: #282c34;
                padding: 10px 20px;
                border-radius: 5px;
                display: none;
                font-size: 1.2em;
                z-index: 1001;
                transition: opacity 0.5s;
            }
        `;
        d.appendChild(g);

        var banner = x("div", "banner", "", "", "");
        d.appendChild(banner);

        var m = document.createElement("meta"),
            b = document.createAttribute("name");
        b.value = "viewport";
        m.setAttributeNode(b);
        b = document.createAttribute("content");
        b.value = "width=device-width, initial-scale=1";
        m.setAttributeNode(b);
        document.head.appendChild(m);
        document.body.innerHTML = "";
        document.body.appendChild(d);

        (e = new Audio()).addEventListener("ended", C, !1);
        v();
        f();
        navigator.mediaSession.setActionHandler("previoustrack", y);
        navigator.mediaSession.setActionHandler("nexttrack", C);

        document.addEventListener("keydown", function(event) {
            if (event.code === "Space") {
                event.preventDefault();
                playPauseButton.click();
            }
        });
    }

    function f() {
        e.src = i[o];
        e.play();
        var t = decodeURIComponent(i[o].href);
        s.innerHTML = t.substring(t.lastIndexOf("/") + 1);
        navigator.mediaSession.metadata = new MediaMetadata({
            title: s.innerHTML
        });
        showBanner("Playing");
    }

    function x(e, t, n, i, o) {
        var a = document.createElement(e);
        t !== "" && a.classList.add(t);
        var d = document.createAttribute("data");
        d.value = i;
        a.setAttributeNode(d);
        a.appendChild(document.createTextNode(n));
        a.onclick = o;
        return a;
    }

    function v() {
        l.style.width = e.currentTime / e.duration * 100 + "%";
        timeDisplay.innerHTML = formatTime(e.currentTime) + " / " + formatTime(e.duration);
        requestAnimationFrame(v);
    }

    function formatTime(seconds) {
        var minutes = Math.floor(seconds / 60);
        var seconds = Math.floor(seconds % 60);
        return minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
    }

    function y() {
        o > 0 ? o-- : o = i.length - 1;
        f();
    }

    function C() {
        o < i.length - 1 ? o++ : o = 0;
        f();
    }

    function showBanner(message) {
        banner.innerHTML = message;
        banner.style.display = "block";
        setTimeout(function() {
            banner.style.opacity = 0;
            setTimeout(function() {
                banner.style.display = "none";
                banner.style.opacity = 1;
            }, 500);
        }, 2000);
    }
})();