YouTube Mousemove Volume Control

Drag the mouse's middle button to set volume according to where the cursor is along the width of the video.

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

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

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

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

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

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

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         YouTube Mousemove Volume Control
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  Drag the mouse's middle button to set volume according to where the cursor is along the width of the video.
// @author       Rasutei
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant        none
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @license      GNU GPLv3
// ==/UserScript==
/* eslint-disable curly */

// ----- Utility stuff -----
var $ = window.jQuery;
const logcss = `
	font-family: Hack, monospace;
	text-shadow: 0 0 10px black, 0 0 10px black;
	background: linear-gradient(to right, #4d94ff 0%, #4d94ff 8px, rgb(77 148 255 / 30%) 8px, transparent 50px);
	color: #4d94ff;
	padding: 2px 0 2px 30px;
	`
const warncss = `
	font-family: Hack, monospace;
	text-shadow: 0 0 10px black, 0 0 10px black;
	background: linear-gradient(to right, #ffa621 0%, #ffa621 0% 8px, rgb(255 166 33 / 30%) 8px, transparent 50px);
	color: #ffa621;
	padding: 2px 0 2px 30px;
	`
const log = (e) => console.log('%c'+e, logcss)
const warn = (e) => console.log('%c'+e, warncss)
const warn_element = (e) => console.log('%c%o', warncss, e)

// ----- Variables and elements -----
const spn = $('<span id="ras-volumebar-text">')
	.css('color','black')
	.css('font-size','17px')
	.css('font-family','Hack')
const fill = $('<div id="ras-volumebar-fill">')
	.append(spn)
	.css('position','relative')
	.css('left','0')
	.css('top','0')
	.css('height','100%')
	.css('transition','width 50ms ease')
	.css('background-color','white')
	.css('display','flex')
	.css('align-items','center')
	.css('justify-content','center')
	.css('overflow','hidden')
	.css('padding','0 4px')
const bar = $('<div id="ras-volumebar">')
	.append(fill)
	.css('position','absolute')
	.css('top','50%')
	.css('left','50%')
	.css('transform','translate(-50%, -50%)')
	.css('width','300px')
	.css('height','20px')
	.css('border','3px solid black')
	.css('outline','1px solid white')
	.css('background-color','rgb(0 0 0 / 50%)')
	.fadeToggle(0)
const wrapper = $('<div id="ras-vidwrapper">')
	.append(bar)
	.css('position','relative')
	.css('margin','auto')
let vid
let isMDown = false
let isSetVolume = false
let hasMouseMoved = false
let rect

// ----- Actual code -----
$(document).ready(function(){
	log('RDrag Volume: Applying script...')

	// ----- Importing a nice font I've been enjoying as of late -----
	let hackfont = document.createElement('link')
	hackfont.setAttribute('rel','stylesheet')
	hackfont.setAttribute('type','text/css')
	hackfont.setAttribute('href','//cdn.jsdelivr.net/npm/[email protected]/build/web/hack-subset.css')

	// ----- Loop to check if page has a video -----
	let prev_url = window.location.href
	setInterval(() => {
		if (document.querySelector('#ras-vidwrapper'))
			return
		if (window.location.href != prev_url)
			prev_url = window.location.href
		if (window.location.href.includes('/watch?v=')) {

			// ----- Attach nice font -----
			document.head.appendChild(hackfont)

			// ----- Find video element -----
			vid = $('video.video-stream')

			// ----- Attach utility to video element -----
			vid[0].parentElement.append(wrapper[0])

			// ----- Apply video's size to wrapper element -----
			new ResizeObserver(() => {
				wrapper.css('width',vid.css('width'))
				wrapper.css('height',vid.css('height'))
			}).observe(vid[0])

			// ----- Getting wrapper's rect -----
			rect = wrapper[0].getBoundingClientRect()

			log('RDrag Volume: Script applied.')
		}
	}, 100)

	// ----- Mouse event handling -----
	rect = wrapper[0].getBoundingClientRect()
	wrapper.mousedown((evemt) => {
		let interval
		if (event.which == 2){
			event.preventDefault()
			event.stopPropagation()
			isSetVolume = true
			rect = wrapper[0].getBoundingClientRect()
			bar.fadeIn(100)
			SetVolume(event)
			interval = setInterval(() => {
				if (!document.hasFocus()){
					StopSetting()
					clearInterval(interval)
				}
			}, 32)
		}
	})
	wrapper.mouseup((event) => {
		if (!event.which == 3) return
		StopSetting()
	})
	wrapper.mouseleave((event) => {
		StopSetting()
	})
	wrapper.mousemove((event) => {
		if (!isSetVolume) return
		SetVolume(event)
	})
	window.blur(() => {
		warn('Blurred')
		StopSetting()
	})
})

// ----- Auxiliary functions to prevent repeats -----
function StopSetting(){
	//warn('StopSetting')
	isSetVolume = false
	bar.delay(300).fadeOut(100)
}
function SetVolume(event){
	//warn('SetVolume')
	let vol = (event.clientX - rect.left) / rect.width
	let per = (vol*100).toFixed(1)+'%'
	vid[0].volume = vol
	spn.text(per)
	fill.css('width', per)
}