-
-
Save fa7ad/fa995474f5cb9fe91fb209686881373d to your computer and use it in GitHub Desktop.
// ==UserScript== | |
// @name YouTube Disable Normalization | |
// @namespace https://gist.github.com/fa7ad/fa995474f5cb9fe91fb209686881373d | |
// @version 0.2 | |
// @description Allows true 100% volume on youtube videos. | |
// @author Wouter Gerarts | |
// @match https://www.youtube.com/* | |
// @match https://youtube.com/* | |
// @grant none | |
// ==/UserScript== | |
(function () { | |
"use strict"; | |
function baseElement() { | |
return document.querySelector("#content"); | |
} | |
if (typeof fullVolumeButtonTaskId === "number") { | |
console.log("clearing interval"); | |
clearInterval(fullVolumeButtonTaskId); | |
} | |
function maxVol() { | |
var videos = document.querySelectorAll("video"); | |
videos.forEach(function (video) { | |
video.volume = 1; | |
console.log(video, video.volume); | |
}); | |
} | |
function createFullVolumeButton() { | |
var css = ` | |
.full-volume-addon-button { | |
margin: 0 0.5em; | |
padding: 0.25em 1em; | |
background: transparent; | |
color: #fff; | |
border: 1px solid #fff; | |
border-radius: 1em; | |
font: caption; | |
} | |
.full-volume-addon-button:hover { | |
cursor: pointer; | |
background: #fff; | |
color: #000; | |
} | |
`; | |
var style = document.createElement("style"); | |
if (style.styleSheet) { | |
style.styleSheet.cssText = css; | |
} else { | |
style.appendChild(document.createTextNode(css)); | |
} | |
document.querySelector("head").appendChild(style); | |
var el = document.createElement("button"); | |
el.textContent = "100% Volume"; | |
el.classList.add("full-volume-addon-button"); | |
el.onclick = function (e) { | |
e.preventDefault(); | |
maxVol(); | |
}; | |
return el; | |
} | |
function round(num, sig) { | |
var mult = Math.pow(10, sig); | |
return Math.round(num * mult) / mult; | |
} | |
var fullVolumeButtonTaskId = setInterval(function () { | |
if (baseElement().querySelector("video") === undefined) { | |
console.log("video element not found"); | |
return; | |
} | |
var volTimer = setInterval(function () { | |
if ( | |
[].every.call(document.querySelectorAll("video"), function (vid) { | |
return vid.volume === 1; | |
}) | |
) { | |
console.log("vol maxed out"); | |
clearInterval(volTimer); | |
return; | |
} else { | |
maxVol(); | |
} | |
}, 500); | |
if (baseElement().querySelector(".full-volume-addon-button") != undefined) { | |
console.log("full volume addon button already found"); | |
clearInterval(fullVolumeButtonTaskId); | |
clearInterval(volTimer); | |
return; | |
} | |
var video = baseElement().querySelector("video"); | |
var videoTitleElement = baseElement().querySelector("#title h1"); | |
videoTitleElement.appendChild(createFullVolumeButton()); | |
}, 500); | |
})(); |
Hi, the script (this version) will try to run maxVol
, but often this will fail due to some rules in browsers (changes in audio/video context needs to be initiated by trusted user events). So as a sort of redundancy, a Button will be added next to the video title. If you're unsure whether there script worked, you can just press the button to trigger maxVol
(button click is a trusted user event)
works great!
thanks
Thanks, but the button is invisible unless hovered.
@Nekotekina You might be using the Light theme on youtube, I'm guessing. I styled the button to match the dark mode styles (because that's what I use on all my browsers). You can try changing line 36 and 37 to
color: #000;
border: 1px solid #000;
That should be enough to match the light mode
Okay, thank you.
Does anyone know how I'd do the reverse of this? I have no loudness normalization without any modifications, and I'd like to get it so I don't need to keep adjusting my volume for videos.
Hi, the script (this version) will try to run maxVol, but often this will fail due to some rules in browsers (changes in audio/video context needs to be initiated by trusted user events). So as a sort of redundancy, a Button will be added next to the video title. If you're unsure whether there script worked, you can just press the button to trigger maxVol (button click is a trusted user event)
Hi @fa7ad,
thanks for the explanation. The button works, but without this explicit action the script usually doesn't catch.
Sometimes volume also drops back to normalized level half-way during play of a video, so you have to re-press the button.
This is annoying when wanting to listen to a playlist in background without normalization.
Would there be any more reliable way to disable normalization and overcome browser restrictions, like, by making this a standalone extension with extra permissions or something?
Background: Firefox on Linux has a long-standing bug causing website volume adjustments to be applied to the system mixer rather than to Firefox internally.1 (Incidentally, this allows to precisely monitor normalization, and whether the script worked or not.)
But as that behavior is unfortunate, I'd like to reliably disable YT's normalization as a workaround.
Footnotes
-
That is, the PulseAudio API backend. The JACK backend is said not to have this problem, but it has to be enabled at build time, and most distros don't. ↩
@mara004 I think an extension might be able to bypass the trusted user event requirement. I will try to find some time and convert the script (or something similar) to an extension and see how that goes. But I don't know if it will solve your PulseAudio issue. I don't have a desktop linux machine, and mostly use an ARM mac for watching youtube; the only linux machine that I have access to is my homelab "server" but I don't think I have any audio backend or desktop environment installed on that.
If you're up for it, I can send you some builds of the extension to test out once I'm done.
But fair warning, My schedule is pretty packed at the moment so it might take a couple of weeks until I can send you something.
If you're up for it, I can send you some builds of the extension to test out once I'm done.
But fair warning, My schedule is pretty packed at the moment so it might take a couple of weeks until I can send you something.
Thanks for the reply! I'd definitely be interested in that, but take your time. :)
Regardless of the bug, I'd also like to disable normalization on its own.1
I tend to prefer having all sources at 100% and adjust volume only at the final output sink.
That said, I'm not sure whether it would work around the bug, either:
If any volume change API call to PulseAudio were be prevented, then I think it should.
But if two calls were made, one to normalized volume and another to go back to 100%, then I suppose it would still make the system mixer jump (i.e. lose any user-defined volume).
IIRC, enhanced-h264ify used to have successful prevention of normalization, but it stopped working at some point.
Footnotes
-
The better workaround would probably be to procure a JACK-enabled build of firefox, anyway. ↩
IIRC, enhanced-h264ify used to have successful prevention of normalization, but it stopped working at some point.
cf. https://github.com/alextrv/enhanced-h264ify/blob/e5f2ea22378e85fc55b9e6ccab27644b1bc66ba5/src/inject/inject.js#L79-L104
(and alextrv/enhanced-h264ify#1 (comment))
Whoops, I think I'll have to eat my words. It seems like enhanced-h264ify actually still does work after disabling and re-enabling the checkbox as suggested in alextrv/enhanced-h264ify#7. Crazy.
FWIW, when lowering volume in the mixer, pausing and re-starting, then it stays. But when moving to a new video, it jumps back to 100%.
Does this automatically enable 100% volume on page load by default or do I need to add a call somewhere to maxVol() ?
Thanks!