No Volume Normalization 4 YouTube

Enjoy YouTube videos at their true volume

// ==UserScript==
// @name        No Volume Normalization 4 YouTube
// @namespace   https://gist.github.com/abec2304
// @description Enjoy YouTube videos at their true volume
// @author      abec2304
// @version     4.1
// @match       https://*.youtube.com/*
// @match       https://*.youtube-nocookie.com/*
// @run-at      document-start
// @grant       GM_addElement
// @license     AGPLv3
// ==/UserScript==

function ytvt_hook() {
  function ytvt_patchDescriptor(targetProto, targetProp) {
    let desc = Object.getOwnPropertyDescriptor(targetProto, targetProp);
    Object.defineProperty(targetProto, targetProp, {
      enumerable: true,
      configurable: true,
      get: function() { return desc.get.call(this); },
      set: function(e) { void e; }
    });
    return desc;
  }

  let ytvt_desc = ytvt_patchDescriptor(HTMLMediaElement.prototype, 'volume');
  let ytvt_valSetter = HTMLElement.prototype.setAttribute;
  HTMLElement.prototype.setAttribute = function(name, val) {
    if(name === 'aria-valuenow') {
      let isVolume = this.matches('[aria-label="Volume"][role="slider"]');
      if(isVolume) {
        let newVolume = val / 100;
        let players = document.querySelectorAll('.video-stream');
        // players[1] can be the active, so just set the volume on all players
        for(let player of players) {
          if(player.volume !== newVolume) {
            ytvt_desc.set.call(player, newVolume);
          }
        }
      }
    }
    ytvt_valSetter.call(this, name, val);
  };

  let ytvt_rule = '.ytp-sfn-content::after, ytmusic-nerd-stats::after { content: "using No Volume Normalization" }';
  let ytvt_sheet = new CSSStyleSheet();
  ytvt_sheet.insertRule(ytvt_rule);
  document.adoptedStyleSheets = (document.adoptedStyleSheets || []).concat([ytvt_sheet]);

  let ytvt_script = document.getElementById('ytvoltweak');
  if(ytvt_script) { ytvt_script.remove(); }
}

function ytvt_inject() {
  let ytvt_textContent = ytvt_hook + '\n' + ytvt_hook.name + '();';
  GM_addElement('script', {textContent: ytvt_textContent, id: 'ytvoltweak'});
}

if(!document.head) {
  let ytvt_headObserver = new MutationObserver(function(_arr, obs) {
    if(document.head) { obs.disconnect(); ytvt_inject(); }
  });
  ytvt_headObserver.observe(document, {subtree: true, childList: true});
} else {
  ytvt_inject();
}