使用 YouTube AV1

使用 AV1 进行 YouTube 视频播放

当前为 2023-08-19 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Use YouTube AV1
  3. // @description Use AV1 for video playback on YouTube
  4. // @name:zh-TW 使用 YouTube AV1
  5. // @description:zh-TW 使用 AV1 進行 YouTube 影片播放
  6. // @name:zh-HK 使用 YouTube AV1
  7. // @description:zh-HK 使用 AV1 進行 YouTube 影片播放
  8. // @name:zh-CN 使用 YouTube AV1
  9. // @description:zh-CN 使用 AV1 进行 YouTube 视频播放
  10. // @name:ja YouTube AV1 の使用
  11. // @description:ja YouTube の動画再生に AV1 を使用する
  12. // @name:ko YouTube AV1 사용
  13. // @description:ko YouTube의 동영상 재생에 AV1을 사용하기
  14. // @name:vi Sử dụng YouTube AV1
  15. // @description:vi Sử dụng AV1 để phát video trên YouTube
  16. // @name:de YouTube AV1 verwenden
  17. // @description:de Verwende AV1 für die Videowiedergabe auf YouTube
  18. // @name:fr Utiliser YouTube AV1
  19. // @description:fr Utiliser AV1 pour la lecture des vidéos sur YouTube
  20. // @name:it Usa YouTube AV1
  21. // @description:it Usa AV1 per la riproduzione dei video su YouTube
  22. // @name:es Usar AV1 en YouTube
  23. // @description:es Usar AV1 para la reproducción de videos en YouTube
  24. // @namespace http://tampermonkey.net/
  25. // @version 2.4.0
  26. // @author CY Fung
  27. // @match https://www.youtube.com/*
  28. // @match https://www.youtube.com/embed/*
  29. // @match https://www.youtube-nocookie.com/embed/*
  30. // @exclude https://www.youtube.com/live_chat*
  31. // @exclude https://www.youtube.com/live_chat_replay*
  32. // @exclude /^https?://\S+\.(txt|png|jpg|jpeg|gif|xml|svg|manifest|log|ini)[^\/]*$/
  33. // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
  34. // @grant none
  35. // @run-at document-start
  36. // @license MIT
  37. //
  38. // @compatible firefox Violentmonkey
  39. // @compatible firefox Tampermonkey
  40. // @compatible firefox FireMonkey
  41. // @compatible chrome Violentmonkey
  42. // @compatible chrome Tampermonkey
  43. // @compatible opera Violentmonkey
  44. // @compatible opera Tampermonkey
  45. // @compatible safari Stay
  46. // @compatible edge Violentmonkey
  47. // @compatible edge Tampermonkey
  48. // @compatible brave Violentmonkey
  49. // @compatible brave Tampermonkey
  50. //
  51. // @unwrap
  52. // @allFrames true
  53. // @inject-into page
  54. // ==/UserScript==
  55.  
  56.  
  57.  
  58. (function (__Promise__) {
  59. 'use strict';
  60.  
  61. /** @type {globalThis.PromiseConstructor} */
  62. const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
  63.  
  64. console.debug("force-youtube-av1", "injected");
  65.  
  66.  
  67.  
  68. const flagConfig = () => {
  69.  
  70. let firstDa = true;
  71. let cid = 0;
  72. const { setInterval, clearInterval, setTimeout } = window;
  73. const tn = () => {
  74.  
  75. const da = (window.ytcfg && window.ytcfg.data_) ? window.ytcfg.data_ : null;
  76. if (!da) return;
  77.  
  78. const isFirstDa = firstDa;
  79. firstDa = false;
  80.  
  81. for (const EXPERIMENT_FLAGS of [da.EXPERIMENT_FLAGS, da.EXPERIMENTS_FORCED_FLAGS]) {
  82.  
  83. if (EXPERIMENT_FLAGS) {
  84. EXPERIMENT_FLAGS.html5_disable_av1_hdr = false;
  85. EXPERIMENT_FLAGS.html5_prefer_hbr_vp9_over_av1 = false;
  86. EXPERIMENT_FLAGS.html5_account_onesie_format_selection_during_format_filter = false;
  87. // EXPERIMENT_FLAGS.html5_perf_cap_override_sticky = true;
  88. // EXPERIMENT_FLAGS.html5_perserve_av1_perf_cap = true;
  89. }
  90.  
  91. }
  92.  
  93. if (isFirstDa) {
  94.  
  95.  
  96. let mo = new MutationObserver(() => {
  97.  
  98. mo.disconnect();
  99. mo.takeRecords();
  100. mo = null;
  101. setTimeout(() => {
  102. cid && clearInterval.call(window, cid);
  103. cid = 0;
  104. tn();
  105. })
  106. });
  107. mo.observe(document, { subtree: true, childList: true });
  108.  
  109.  
  110. }
  111.  
  112.  
  113. };
  114. cid = setInterval.call(window, tn);
  115.  
  116. };
  117.  
  118.  
  119. const supportedFormatsConfig = () => {
  120.  
  121.  
  122. function typeTest(type) {
  123.  
  124. if (typeof type === 'string' && type.startsWith('video/')) {
  125. if (type.includes('av01')) {
  126. if (/codecs[^\w]+av01\b/.test(type)) return true;
  127. } else if (type.includes('av1')) {
  128. if (/codecs[^\w]+av1\b/.test(type)) return true;
  129. }
  130. }
  131.  
  132. }
  133.  
  134. // return a custom MIME type checker that can defer to the original function
  135. function makeModifiedTypeChecker(origChecker) {
  136. // Check if a video type is allowed
  137. return function (type) {
  138. let res = undefined;
  139. if (type === undefined) res = false;
  140. else {
  141. res = typeTest(type);
  142. }
  143. if (res === undefined) res = origChecker.apply(this, arguments);
  144.  
  145. // console.debug(20, type, res)
  146.  
  147. return res;
  148. };
  149. }
  150.  
  151. // Override video element canPlayType() function
  152. const proto = (HTMLVideoElement || 0).prototype;
  153. if (proto && typeof proto.canPlayType == 'function') {
  154. proto.canPlayType = makeModifiedTypeChecker(proto.canPlayType);
  155. }
  156.  
  157. // Override media source extension isTypeSupported() function
  158. const mse = window.MediaSource;
  159. // Check for MSE support before use
  160. if (mse && typeof mse.isTypeSupported == 'function') {
  161. mse.isTypeSupported = makeModifiedTypeChecker(mse.isTypeSupported);
  162. }
  163.  
  164.  
  165. }
  166.  
  167. function enableAV1() {
  168.  
  169.  
  170. // This is the setting to force AV1
  171. // localStorage['yt-player-av1-pref'] = '8192';
  172. try {
  173. Object.defineProperty(localStorage.constructor.prototype, 'yt-player-av1-pref', {
  174. get() {
  175. if (this === localStorage) return '8192';
  176. return this.getItem('yt-player-av1-pref');
  177. },
  178. set(nv) {
  179. this.setItem('yt-player-av1-pref', nv);
  180. return true;
  181. },
  182. enumerable: true,
  183. configurable: true
  184. });
  185. } catch (e) {
  186. // localStorage['yt-player-av1-pref'] = '8192';
  187. }
  188.  
  189. if (localStorage['yt-player-av1-pref'] !== '8192') {
  190.  
  191. console.warn('Use YouTube AV1 is not supported in your browser.');
  192. return;
  193. }
  194.  
  195.  
  196. console.debug("force-youtube-av1", "AV1 enabled");
  197.  
  198.  
  199. flagConfig();
  200. supportedFormatsConfig();
  201.  
  202.  
  203.  
  204. }
  205.  
  206.  
  207.  
  208.  
  209. let promise = null;
  210.  
  211. try {
  212. promise = navigator.mediaCapabilities.decodingInfo({
  213. type: "file",
  214. video: {
  215. contentType: "video/mp4; codecs=av01.0.05M.08.0.110.05.01.06.0",
  216. height: 1080,
  217. width: 1920,
  218. framerate: 30,
  219. bitrate: 2826848,
  220. },
  221. audio: {
  222. contentType: "audio/webm; codecs=opus",
  223. channels: "2.1",
  224. samplerate: 44100,
  225. bitrate: 255236,
  226. }
  227. });
  228. } catch (e) {
  229. promise = null;
  230. }
  231.  
  232.  
  233. const callback = (result) => {
  234.  
  235. if (result && result.supported && result.smooth) enableAV1();
  236. else {
  237. console.warn("force-youtube-av1", 'Your browser does not support AV1. You might conside to use the latest version of Google Chrome or Mozilla FireFox.');
  238. }
  239. };
  240.  
  241. (promise || Promise.resolve(0)).catch(callback).then(callback);
  242.  
  243.  
  244.  
  245. })(Promise);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址