Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Onurtag/d653d166b6509ce9c6a71e69ba7219c7 to your computer and use it in GitHub Desktop.
Save Onurtag/d653d166b6509ce9c6a71e69ba7219c7 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name No YouTube Volume Normalization
// @namespace https://gist.github.com/abec2304
// @match https://www.youtube.com/*
// @grant none
// @version 2.1
// @author abec2304
// @description Enjoy YouTube videos at their true volume
// @inject-into content
// @run-at document-start
// ==/UserScript==
(function(recurse) {
// try in case script ran later than document-start
if(!recurse())
return;
// fallback to waiting for video element to be added
const videoObserver = new MutationObserver(function(records) {
records.forEach(function(mutation) {
Array.prototype.forEach.call(mutation.addedNodes, function(node) {
if("VIDEO" === node.tagName) {
videoObserver.disconnect();
recurse();
}
});
});
})
// begin waiting
videoObserver.observe(document.documentElement, {
subtree: true,
childList: true
});
})(function() {
// get volume bar element
const volumeElement = document.querySelector(".ytp-volume-panel");
// get video element
const videoElement = document.querySelector(".html5-main-video");
// if elements weren't found, don't continue
if(!volumeElement || !videoElement)
return 1;
// get volume set function and bind to video element
const setVolume = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, "volume").set.bind(videoElement);
// define convenience function
function ytSetVolume(widget) {
const newVolume = widget.getAttribute("aria-valuenow") / 100;
setVolume(newVolume);
}
// determine index of video element for non-sandboxed world
const globalIndex = [].slice.call(document.getElementsByTagName("video")).indexOf(videoElement);
// define function for shadowing the volume field
const volumeShadow = function(targetIndex) {
const targetVideo = document.getElementsByTagName("video")[targetIndex];
Object.defineProperty(targetVideo, "volume", {
value: 42
});
}
// inject shadowing script (this breaks the volume bar; fixed below)
const contextScript = document.createElement("script");
contextScript.id = "ytvolfix2";
contextScript.textContent = "(" + volumeShadow+ ")(" + globalIndex + ")";
contextScript.onload = function() {
// remove script after execution
this.parentElement.removeChild(this);
};
(document.head || document.documentElement).appendChild(contextScript);
// define observer for volume bar change
const volumeObserver = new MutationObserver(function(records) {
ytSetVolume(records[0].target);
});
// register observer to make volume bar function
volumeObserver.observe(volumeElement, {
attributes: true,
attributeFilter: ["aria-valuenow"]
});
// set volume to current value of bar
ytSetVolume(volumeElement);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment