Skip to content

Instantly share code, notes, and snippets.

@fa7ad
Forked from WouterG/tampermonkey-script.js
Last active April 24, 2024 11:04
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save fa7ad/fa995474f5cb9fe91fb209686881373d to your computer and use it in GitHub Desktop.
Save fa7ad/fa995474f5cb9fe91fb209686881373d to your computer and use it in GitHub Desktop.
Disable youtube volume normalization (allow true video 100% volume)
// ==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);
})();
@ilikenwf
Copy link

Does this automatically enable 100% volume on page load by default or do I need to add a call somewhere to maxVol() ?

Thanks!

@fa7ad
Copy link
Author

fa7ad commented Jul 19, 2023

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)

@k4mgur
Copy link

k4mgur commented Jul 26, 2023

works great!

@alma359
Copy link

alma359 commented Aug 7, 2023

thanks

@Nekotekina
Copy link

Thanks, but the button is invisible unless hovered.

@fa7ad
Copy link
Author

fa7ad commented Sep 19, 2023

@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

@Nekotekina
Copy link

Okay, thank you.

@K4sum1
Copy link

K4sum1 commented Oct 8, 2023

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.

@mara004
Copy link

mara004 commented Mar 6, 2024

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

  1. 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.

@fa7ad
Copy link
Author

fa7ad commented Mar 7, 2024

@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.

@mara004
Copy link

mara004 commented Mar 7, 2024

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 or not, 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

  1. The better workaround would probably be to procure a JACK-enabled build of firefox, anyway.

@mara004
Copy link

mara004 commented Mar 7, 2024

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))

@mara004
Copy link

mara004 commented Mar 7, 2024

Whoops, I think I'll have to eat my own 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%.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment