Shift Space Toggle Youtube CE Element

This is to toggle annoying Youtube CE Element near the end of the video

当前为 2022-08-14 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Shift Space Toggle Youtube CE Element
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.5
  5. // @description This is to toggle annoying Youtube CE Element near the end of the video
  6. // @author CY Fung
  7. // @match https://www.youtube.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. /* jshint esversion:6 */
  14. (function() {
  15. 'use strict';
  16.  
  17. let videoElm = null;
  18. const ceElems = [];
  19. let isPassiveAvailable = null
  20.  
  21. let earliestShown = -1;
  22. let endTime = -1;
  23.  
  24. const WeakRef = window?.WeakRef;
  25.  
  26. let videoReady = false
  27.  
  28. let lastPress = -1
  29. const allowList = [
  30. 'DIV', 'SPAN', 'BODY', 'HTML', 'VIDEO', 'A',
  31. 'YTD-PLAYER', 'YTD-WATCH-FLEXY', 'YTD-PAGE-MANAGER', 'YTD-MINIPLAYER'
  32. ];
  33.  
  34. function cacheCEElems() {
  35.  
  36. const m = document.querySelectorAll('ytd-player#ytd-player .ytp-ce-element');
  37. if (m.length === 0) return false;
  38.  
  39. ceElems.length = 0;
  40. for (const elm of m) {
  41. ceElems.push(new WeakRef(elm))
  42. }
  43.  
  44. return true;
  45.  
  46. }
  47.  
  48. function videoTimeUpdate(evt) {
  49.  
  50. //passive = true
  51. //capture = false
  52.  
  53. if (!videoReady) {
  54. if (evt?.target?.matches('ytd-player#ytd-player video')) {
  55. videoReady = true
  56. if (cacheCEElems() === false) setTimeout(cacheCEElems, 180);
  57. }
  58. }
  59.  
  60. if (ceElems.length === 0) return;
  61.  
  62. const video = evt.target;
  63. const anyShown = ceElems.some((elmRef) => elmRef.deref()?.classList?.contains('ytp-ce-element-show') === true)
  64. //console.log(135, anyShown, video.currentTime)
  65. if (anyShown) {
  66. if (earliestShown > 0 && -earliestShown < -video.currentTime) {
  67. earliestShown = video.currentTime
  68. endTime = video.duration
  69. } else if (earliestShown < 0) {
  70. videoElm = new WeakRef(video);
  71. earliestShown = video.currentTime
  72. endTime = video.duration
  73. }
  74. }
  75.  
  76.  
  77. }
  78.  
  79. function initialForVideoDetection(evt) {
  80.  
  81. //passive = true
  82. //capture = true
  83.  
  84. const video = evt?.target;
  85. if (video?.nodeName === 'VIDEO' && typeof video.src == 'string') {} else return;
  86.  
  87. videoReady = false;
  88. ceElems.length = 0;
  89.  
  90. videoElm = null;
  91. earliestShown = -1;
  92. endTime = -1;
  93.  
  94.  
  95. new Promise(function() {
  96.  
  97.  
  98. if (video.hasAttribute('usr-video-cem')) return;
  99. video.setAttribute('usr-video-cem', '');
  100.  
  101. if (isPassiveAvailable === null) isPassiveAvailable = checkPassive();
  102. video.addEventListener('timeupdate', videoTimeUpdate, optCapture(true, false));
  103.  
  104. })
  105.  
  106. }
  107.  
  108. function pageKeyDownfunction(evt) {
  109. //passive = false
  110. //capture = true
  111.  
  112. if (evt.code === 'Space' && evt.shiftKey) {
  113.  
  114. if (!allowList.includes(evt.target.nodeName)) return;
  115.  
  116. if (endTime > earliestShown && earliestShown > 0) {
  117.  
  118. let video = videoElm?.deref();
  119.  
  120. if (!video) return;
  121.  
  122. let p = (video.currentTime - earliestShown) / (endTime - earliestShown);
  123. if (p >= 0 && p <= 1) {
  124. evt.preventDefault();
  125. evt.stopPropagation();
  126. evt.stopImmediatePropagation();
  127.  
  128. for (const ceElem of ceElems) {
  129. ceElem?.deref()?.classList.toggle('ytp-ce-element-show');
  130. }
  131. }
  132.  
  133. }
  134.  
  135. }
  136. }
  137.  
  138. function checkPassive() {
  139.  
  140. let passiveSupported = false;
  141.  
  142. try {
  143. const options = {
  144. get passive() {
  145. passiveSupported = true;
  146. return false;
  147. }
  148. };
  149.  
  150. window.addEventListener("test", null, options);
  151. window.removeEventListener("test", null, options);
  152. } catch (err) {
  153. passiveSupported = false;
  154. }
  155.  
  156. return passiveSupported
  157.  
  158. }
  159.  
  160. const optCapture = (passive, capture) => isPassiveAvailable ? { passive, capture } : capture;
  161.  
  162. new Promise(function() {
  163.  
  164. if (isPassiveAvailable === null) isPassiveAvailable = checkPassive();
  165. document.addEventListener('canplay', initialForVideoDetection, optCapture(true, true));
  166.  
  167. })
  168.  
  169. document.addEventListener('keydown', pageKeyDownfunction, true)
  170.  
  171. //ytp-ce-video ytp-ce-top-left-quad ytp-ce-size-853 ytp-ce-element-show
  172.  
  173. // Your code here...
  174. })();