Greasy Fork镜像 还支持 简体中文。

Better youtube volume control

Adds a slider to the youtube video player to feel the volume changes more naturally.

目前為 2025-05-30 提交的版本,檢視 最新版本

// ==UserScript==
// @name        Better youtube volume control
// @namespace   Violentmonkey Scripts
// @match       https://www.youtube.com/*
// @grant       none
// @version     3.1
// @author      MarcosTypeAP
// @description Adds a slider to the youtube video player to feel the volume changes more naturally.
// @run-at document-end
// @noframes
// ==/UserScript==

let watchSliderClassname = "custom-watch-volume-slider"
let shortsSliderClassname = "custom-shorts-volume-slider"

function setupWatchSlider() {
    "use strict"

    const videoPlayer = document.querySelector("#movie_player.html5-video-player")
    const ytLeftControls = document.querySelector(".ytp-left-controls")

	const setVolume = (volume) => videoPlayer.setVolume((volume ** 2) * 100) // to notice that the volume increases more naturally

    const getVideo = () => videoPlayer.querySelector(".video-stream.html5-main-video") // if video tag changes

    getVideo().onplay = () => {
        document.querySelector(".ytp-chapter-container").style.flexBasis = "30%"

        getVideo().focus()
    }

    const customVideoVolume = localStorage.getItem("custom-player-volume") ?? 0.4

    setVolume(customVideoVolume)

    const $newVolumeControl = document.createElement("input")
    $newVolumeControl.className = watchSliderClassname
    $newVolumeControl.setAttribute("type", "range")
    $newVolumeControl.setAttribute("min", "0.099")
    $newVolumeControl.setAttribute("max", "1")
    $newVolumeControl.setAttribute("step", "0.005")
    $newVolumeControl.setAttribute("value", customVideoVolume)

    $newVolumeControl.style.width = "30vw"
    $newVolumeControl.style.height = "43px"
    $newVolumeControl.style.marginLeft = "20px"

    $newVolumeControl.oninput = () => {
        setVolume($newVolumeControl.value)
    }

    $newVolumeControl.onmouseup = () => {
        getVideo().focus()
    }

    $newVolumeControl.onchange = () => {
        localStorage.setItem("custom-player-volume", $newVolumeControl.value)
    }

    if (document.getElementsByClassName(watchSliderClassname).length > 0) {
        return
    }

    ytLeftControls.appendChild($newVolumeControl)

    window.addEventListener("keydown", event => {
		const hasArrowUpOrDownPressed = event.key === "ArrowUp" || event.key === "ArrowDown"
		const isMoviePlayerOrProgressBarActive = (
			document.querySelector("#movie_player") === document.activeElement ||
			document.activeElement.classList.contains("ytp-progress-bar")
		)

        if (hasArrowUpOrDownPressed && isMoviePlayerOrProgressBarActive) {

            if (event.key === "ArrowUp") {
                $newVolumeControl.stepUp(10)
            } else if (event.key === "ArrowDown") {
                $newVolumeControl.stepDown(10)
            }

            $newVolumeControl.onchange()
            $newVolumeControl.oninput()
            event.preventDefault()
            event.stopImmediatePropagation()
        }
    }, true)
}

function setupShortsSlider() {
    "use strict"

    const videoPlayer = document.querySelector("#shorts-player.html5-video-player")

	const setVolume = (volume) => videoPlayer.setVolume((volume ** 2) * 100) // to notice that the volume increases more naturally

    const getCustomVideoVolume = () => localStorage.getItem("custom-player-volume") ?? 0.4

    const getVideo = () => videoPlayer.querySelector(".video-stream.html5-main-video") // if video tag changes

    getVideo().onplay = () => {
        setVolume(getCustomVideoVolume())
    }

    setVolume(getCustomVideoVolume())

    const $newVolumeControl = document.createElement("input")
    $newVolumeControl.className = shortsSliderClassname
    $newVolumeControl.setAttribute("type", "range")
    $newVolumeControl.setAttribute("min", "0.099")
    $newVolumeControl.setAttribute("max", "1")
    $newVolumeControl.setAttribute("step", "0.005")
    $newVolumeControl.setAttribute("value", getCustomVideoVolume())

    $newVolumeControl.style.width = "40vh"
    $newVolumeControl.style.height = "40px"
    $newVolumeControl.style.position = "fixed"
    $newVolumeControl.style.right = "-100px"
    $newVolumeControl.style.bottom = "40vh"
    $newVolumeControl.style.transform = "rotateZ(-90deg)"

    $newVolumeControl.oninput = () => {
        setVolume($newVolumeControl.value)
    }

    $newVolumeControl.onchange = () => {
        localStorage.setItem("custom-player-volume", $newVolumeControl.value)
    }

    if (document.getElementsByClassName(shortsSliderClassname).length > 0) {
        return
    }

    document.body.appendChild($newVolumeControl)
}

const observer = new MutationObserver(() => {

    const $shortsSlider = document.querySelector('.' + shortsSliderClassname)

    if ($shortsSlider) {
        $shortsSlider.style.visibility = "hidden"
    }

    if (window.location.pathname.startsWith("/watch")) {
        if (!document.querySelector("#movie_player.html5-video-player") ||
            !document.querySelector(".ytp-left-controls")) {

            return
        }

        const $watchSlider = document.querySelector('.' + watchSliderClassname)

        if ($watchSlider === null) {
            setupWatchSlider()
        }

        return
    }

    if (window.location.pathname.startsWith("/shorts")) {
        if (!document.querySelector("#shorts-player.html5-video-player")) {

            return
        }

        if ($shortsSlider === null) {
            setupShortsSlider()
            return
        }

        $shortsSlider.style.visibility = "visible"
    }
});

observer.observe(document.querySelector("body"), { childList: true, subtree: true });

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址