Greasy Fork is available in English.

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.

// ==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/hack-font@3.3.0/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)
}