Skip to content

Instantly share code, notes, and snippets.

@akku1139
Last active May 1, 2026 04:50
Show Gist options
  • Select an option

  • Save akku1139/8a098c004ead96c74a70a235b8926b66 to your computer and use it in GitHub Desktop.

Select an option

Save akku1139/8a098c004ead96c74a70a235b8926b66 to your computer and use it in GitHub Desktop.
User script version of enhanced-h264ify
// ==UserScript==
// @name enhanced-h264ify
// @namespace Violentmonkey Scripts
// @version 0.1
// @description enhanced-h264ify for user script.
// @author akku
// @match *://*.youtube.com/*
// @match *://*.youtube-nocookie.com/*
// @match *://*.youtu.be/*
// @grant none
// @run-at document-start
// ==/UserScript==
/**
* The MIT License (MIT)
*
* Copyright (c) 2024 akku
* Copyright (c) 2019 alextrv
* Copyright (c) 2015 erkserkserks
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
const config = {
'block_60fps': true,
'block_h264': false,
'block_vp8': true,
'block_vp9': true,
'block_av1': true,
'disable_LN': true,
};
function inject () {
override();
function override() {
// Override video element canPlayType() function
var videoElem = document.createElement('video');
var origCanPlayType = videoElem.canPlayType.bind(videoElem);
videoElem.__proto__.canPlayType = makeModifiedTypeChecker(origCanPlayType);
// Override media source extension isTypeSupported() function
var mse = window.MediaSource;
// Check for MSE support before use
if (mse === undefined) return;
var origIsTypeSupported = mse.isTypeSupported.bind(mse);
mse.isTypeSupported = makeModifiedTypeChecker(origIsTypeSupported);
}
// return a custom MIME type checker that can defer to the original function
function makeModifiedTypeChecker(origChecker) {
// Check if a video type is allowed
return function (type) {
if (type === undefined) return '';
var disallowed_types = [];
if (config['block_h264']) {
disallowed_types.push('avc');
}
if (config['block_vp8']) {
disallowed_types.push('vp8');
}
if (config['block_vp9']) {
disallowed_types.push('vp9', 'vp09');
}
if (config['block_av1']) {
disallowed_types.push('av01');
}
// If video type is in disallowed_types, say we don't support them
for (var i = 0; i < disallowed_types.length; i++) {
if (type.indexOf(disallowed_types[i]) !== -1) return '';
}
if (config['block_60fps']) {
var match = /framerate=(\d+)/.exec(type);
if (match && match[1] > 30) return '';
}
// Otherwise, ask the browser
return origChecker(type);
};
}
}
function useActualVolumeLevel() {
if (!config['disable_LN']) {
return;
}
var video = document.querySelector('video');
var observerConfig = {attributes: true};
var onVolumeChange = function(mutationList) {
var attr = 'aria-valuenow';
for (var mutation of mutationList) {
if (mutation.attributeName == attr) {
// Get current volume level from player's attribute
// and set the actual volume
video.volume = mutation.target.attributes[attr].value / 100;
}
}
}
var volumePanel = document.querySelector('.ytp-volume-panel');
if (volumePanel) {
var observer = new MutationObserver(onVolumeChange);
observer.observe(volumePanel, observerConfig);
}
}
inject();
document.onreadystatechange = useActualVolumeLevel;
@akku1139

Copy link
Copy Markdown
Author

Not working

@talhoid

talhoid commented Apr 10, 2026

Copy link
Copy Markdown

it does not work because you are using a strict equality check between the boolean value true and the string "true". also everything in the config is set to true by default, so even if that problem wasn't there no video would play.
to fix this you can simply replace the makeModifiedTypeChecker and useActualVolumeLevel functions with these versions

function makeModifiedTypeChecker(origChecker) {
    // Check if a video type is allowed
    return function (type) {
      if (type === undefined) return '';
      var disallowed_types = [];
      if (config['block_h264']) {
        disallowed_types.push('avc');
      }
      if (config['block_vp8']) {
        disallowed_types.push('vp8');
      }
      if (config['block_vp9']) {
        disallowed_types.push('vp9', 'vp09');
      }
      if (config['block_av1']) {
        disallowed_types.push('av01');
      }

      // If video type is in disallowed_types, say we don't support them
      for (var i = 0; i < disallowed_types.length; i++) {
        if (type.indexOf(disallowed_types[i]) !== -1) return '';
      }

      if (config['block_60fps']) {
        var match = /framerate=(\d+)/.exec(type);
        if (match && match[1] > 30) return '';
      }

      // Otherwise, ask the browser
      return origChecker(type);
    };
  }

function useActualVolumeLevel() {

  if (!config['disable_LN']) {
    return;
  }

  var video = document.querySelector('video');
  var observerConfig = {attributes: true};

  var onVolumeChange = function(mutationList) {
    var attr = 'aria-valuenow';
    for (var mutation of mutationList) {
      if (mutation.attributeName == attr) {
        // Get current volume level from player's attribute
        // and set the actual volume
        video.volume = mutation.target.attributes[attr].value / 100;
      }
    }
  }

  var volumePanel = document.querySelector('.ytp-volume-panel');
  if (volumePanel) {
    var observer = new MutationObserver(onVolumeChange);
    observer.observe(volumePanel, observerConfig);
  }
}

please forgive my indentation this was cancer to type out on mobile
also might i add, since this is a userscript, the injection section is not necessary.
it is trivial to replace this

var injectScript = document.createElement('script');
// Use textContent instead of src to run inject() synchronously
injectScript.textContent = inject.toString() + "inject();";
injectScript.onload = function() {
  // Remove <script> node after injectScript runs.
  this.parentNode.removeChild(this);
};
(document.head || document.documentElement).appendChild(injectScript);


document.onreadystatechange = function() {
  if (document.readyState == 'interactive') {
    var script = document.createElement('script');
    script.text = useActualVolumeLevel.toString() + "useActualVolumeLevel();";
    document.body.appendChild(script);
  }
}

with this

inject(); // we're already running at document-start

document.onreadystatechange = useActualVolumeLevel;

hope this helps anyone who stumbles across this
no ai was used in the creation of this comment

@akku1139

Copy link
Copy Markdown
Author

ohno!
thank you

but I don't use this script now...

@talhoid

talhoid commented Apr 10, 2026

Copy link
Copy Markdown

yeah i thought so, it's been more than 2 years now. but after applying the modifications I documented it works perfectly. what do you use now?

@akku1139

akku1139 commented Apr 10, 2026

Copy link
Copy Markdown
Author

i bought dGPU,
before: Intel HD Graphics 4400, 4600
now: Radeon RX 6700 XT

it also supports VP9,
so no longer need h246ify

Trying display: wayland
vainfo: VA-API version: 1.22 (libva 2.22.0)
vainfo: Driver version: Mesa Gallium driver 25.3.1-arch1.3 for AMD Radeon RX 6700 XT (radeonsi, navi22, LLVM 21.1.6, DRM 3.64, 6.18.1-2-cachyos)
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            :    VAEntrypointVLD
      VAProfileMPEG2Main              :    VAEntrypointVLD
      VAProfileVC1Simple              :    VAEntrypointVLD
      VAProfileVC1Main                :    VAEntrypointVLD
      VAProfileVC1Advanced            :    VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:    VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:    VAEntrypointEncSlice
      VAProfileH264Main               :    VAEntrypointVLD
      VAProfileH264Main               :    VAEntrypointEncSlice
      VAProfileH264High               :    VAEntrypointVLD
      VAProfileH264High               :    VAEntrypointEncSlice
      VAProfileHEVCMain               :    VAEntrypointVLD
      VAProfileHEVCMain               :    VAEntrypointEncSlice
      VAProfileHEVCMain10             :    VAEntrypointVLD
      VAProfileHEVCMain10             :    VAEntrypointEncSlice
      VAProfileJPEGBaseline           :    VAEntrypointVLD
      VAProfileVP9Profile0            :    VAEntrypointVLD
      VAProfileVP9Profile2            :    VAEntrypointVLD
      VAProfileAV1Profile0            :    VAEntrypointVLD
      VAProfileNone                   :    VAEntrypointVideoProc

(Intel HD Graphics 4600)

Trying display: wayland
error: failed to resolve wl_drm_interface(): /usr/lib/libEGL_mesa.so.0: undefined symbol: wl_drm_interface
vainfo: VA-API version: 1.22 (libva 2.22.0)
vainfo: Driver version: Intel i965 driver for Intel(R) Haswell Desktop - 2.4.1
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            :    VAEntrypointVLD
      VAProfileMPEG2Simple            :    VAEntrypointEncSlice
      VAProfileMPEG2Main              :    VAEntrypointVLD
      VAProfileMPEG2Main              :    VAEntrypointEncSlice
      VAProfileH264ConstrainedBaseline:    VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:    VAEntrypointEncSlice
      VAProfileH264Main               :    VAEntrypointVLD
      VAProfileH264Main               :    VAEntrypointEncSlice
      VAProfileH264High               :    VAEntrypointVLD
      VAProfileH264High               :    VAEntrypointEncSlice
      VAProfileH264MultiviewHigh      :    VAEntrypointVLD
      VAProfileH264MultiviewHigh      :    VAEntrypointEncSlice
      VAProfileH264StereoHigh         :    VAEntrypointVLD
      VAProfileH264StereoHigh         :    VAEntrypointEncSlice
      VAProfileVC1Simple              :    VAEntrypointVLD
      VAProfileVC1Main                :    VAEntrypointVLD
      VAProfileVC1Advanced            :    VAEntrypointVLD
      VAProfileNone                   :    VAEntrypointVideoProc
      VAProfileJPEGBaseline           :    VAEntrypointVLD

@talhoid

talhoid commented Apr 10, 2026

Copy link
Copy Markdown

i guess that's one way to solve the problem. even though this cpu supports vp9 I'm using h264 for better battery life (it's an sd678).

@akku1139

akku1139 commented Apr 10, 2026

Copy link
Copy Markdown
Author

good,
i'll update the code after test your fix

@akku1139

akku1139 commented May 1, 2026

Copy link
Copy Markdown
Author

thank you very much, your fix is working well!
i updated the code

without script
image

with script
image

@akku1139

akku1139 commented May 1, 2026

Copy link
Copy Markdown
Author

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