YouTube Minimal Fixs

This is to fix various features of YouTube Minimal on PC

当前为 2024-06-18 提交的版本,查看 最新版本

  1. /*
  2.  
  3. MIT License
  4.  
  5. Copyright 2023 CY Fung
  6.  
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13.  
  14. The above copyright notice and this permission notice shall be included in all
  15. copies or substantial portions of the Software.
  16.  
  17. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. SOFTWARE.
  24.  
  25. */
  26. // ==UserScript==
  27. // @name YouTube Minimal Fixs
  28. // @version 0.7.0
  29. // @description This is to fix various features of YouTube Minimal on PC
  30. // @namespace http://tampermonkey.net/
  31. // @author CY Fung
  32. // @license MIT
  33. // @supportURL https://github.com/cyfung1031/userscript-supports
  34. // @run-at document-start
  35. // @match https://m.youtube.com/*
  36. // @icon https://raw.githubusercontent.com/cyfung1031/userscript-supports/main/icons/youtube-minimal.png
  37. // @grant none
  38. // @unwrap
  39. // @allFrames true
  40. // @inject-into page
  41. // ==/UserScript==
  42. "use strict";
  43.  
  44. //document.addEventListener('visibilitychange',function(evt){ evt.isTrusted && document.visibilityState==='hidden' && evt.stopPropagation() }, true)
  45.  
  46. (function (__CONTEXT__) {
  47. "use strict";
  48.  
  49. const showNativeControls = true;
  50.  
  51. const { Promise } = __CONTEXT__;
  52.  
  53. let [window] = new Function('return [window]')();
  54.  
  55. if (window.document.addEventListener399) return;
  56. window.document.addEventListener399 = window.document.addEventListener
  57. // let i = 0
  58. window.document.addEventListener = function (type, listener, options) {
  59. if (type === 'visibilitychange') {
  60. // i++
  61. if (listener.length === 0 && !listener.name) {
  62.  
  63.  
  64. let s = listener + "";
  65. if (s.length >= 17 && s.length <= 19) {
  66. return // ƒ (){a.Eh()} 18
  67. } else if (s.length > 348 && s.indexOf(".getVisibilityState()") > 0) {
  68.  
  69. return
  70.  
  71. }
  72.  
  73. }
  74. /*
  75. if(i==4 || i==2){
  76. console.log(listener, (listener+"").length)
  77. return
  78. }
  79. */
  80. // return
  81. }
  82. return this.addEventListener399.apply(this, arguments)
  83. }
  84.  
  85.  
  86.  
  87.  
  88. let styleElm = document.createElement('style')
  89. styleElm.textContent = `
  90.  
  91. @keyframes addFadeIn {
  92. from{background-position:1px;}
  93. to{background-position:2px;}
  94. }
  95. @keyframes removeFadeIn {
  96. from{background-position:1px;}
  97. to{background-position:2px;}
  98. }
  99. #player-control-overlay[class] {
  100. animation: removeFadeIn 1ms;
  101. }
  102. #player-control-overlay[class]:hover
  103. {
  104. animation: addFadeIn 1ms;
  105. }
  106. h2.slim-video-information-title{
  107. animation: initUI 1ms;
  108.  
  109. }
  110.  
  111. #player-control-overlay[class]{
  112. pointer-events: all !important;
  113. }
  114.  
  115. ytm-cinematic-container-renderer, ytm-cinematic-container-renderer * {
  116. contain: layout size style;
  117. user-select: none;
  118. touch-action: none;
  119. pointer-events: none;
  120. }
  121.  
  122. ytm-custom-control .player-controls-bottom .icon-button:hover>c3-icon svg path,
  123. ytm-custom-control .player-controls-middle .icon-button:hover>c3-icon svg path,
  124. ytm-custom-control .player-controls-top .icon-button:hover>c3-icon svg path,
  125. ytm-custom-control .player-controls-pb .icon-button:hover>c3-icon,
  126. ytm-custom-control .player-controls-top ytm-closed-captioning-button button[aria-pressed=true]:hover>c3-icon svg path,
  127. ytm-custom-control .player-controls-top ytm-closed-captioning-button button[aria-pressed=false]:hover>c3-icon svg path ,
  128.  
  129. ytm-custom-control .player-controls-top ytm-closed-captioning-button button:hover>c3-icon svg path,
  130. ytm-custom-control .player-controls-middle .icon-button.icon-disable:hover>c3-icon svg path
  131. {
  132.  
  133.  
  134. fill: #006aff;
  135.  
  136. }
  137.  
  138.  
  139. `
  140.  
  141. let controlsInitialized = false
  142.  
  143. async function videoToggle(video) {
  144.  
  145. if (video.paused) video.play(); else video.pause();
  146. }
  147.  
  148. let elements = {
  149.  
  150. }
  151.  
  152. const eventHandlers = {
  153.  
  154. pbMouseUp(evt) {
  155.  
  156.  
  157. let pb = this
  158. // console.log(evt.target, evt, this)
  159. let m = evt.offsetX / pb.offsetWidth
  160. if (m < 0 || m > 1) return
  161.  
  162. let video = document.querySelector('#movie_player video[src]')
  163. if (!video) return
  164.  
  165. let ct = video.currentTime
  166. let d = video.duration
  167. if (!ct || ct < 0) return
  168. if (!d || d < 0) return
  169.  
  170. video.currentTime = m * d
  171.  
  172.  
  173. evt.preventDefault()
  174. evt.stopPropagation()
  175. evt.stopImmediatePropagation()
  176.  
  177.  
  178. },
  179. pbMouseClick(evt) {
  180.  
  181.  
  182.  
  183. evt.preventDefault()
  184. evt.stopPropagation()
  185. evt.stopImmediatePropagation()
  186.  
  187.  
  188. },
  189. pbMouseDown(evt) {
  190.  
  191.  
  192.  
  193. evt.preventDefault()
  194. evt.stopPropagation()
  195. evt.stopImmediatePropagation()
  196.  
  197.  
  198. },
  199. backDropClick(evt) {
  200.  
  201.  
  202.  
  203.  
  204. if (evt && evt.target) { } else return;
  205.  
  206. let target = evt.target
  207. if (target.nodeName === "DIV" && (target.className || '').indexOf('player-controls-background') >= 0) { } else return;
  208.  
  209.  
  210. let video = document.querySelector('#movie_player video[src]')
  211. if (!video) return;
  212.  
  213.  
  214. evt.preventDefault();
  215. evt.stopPropagation();
  216. evt.stopImmediatePropagation();
  217.  
  218. videoToggle(video);
  219.  
  220.  
  221. },
  222. docKeyDown(evt) {
  223. if (evt.target.nodeName === 'BODY') {
  224. // console.log(evt)
  225. if (evt.code === "Space") {
  226.  
  227. let video = document.querySelector('#movie_player video[src]')
  228. if (!video) return;
  229. videoToggle(video);
  230. evt.preventDefault();
  231. evt.stopPropagation();
  232. evt.stopImmediatePropagation();
  233.  
  234. } else if (evt.code === 'ArrowLeft') {
  235.  
  236.  
  237. let video = document.querySelector('#movie_player video[src]')
  238. if (!video) return;
  239.  
  240. if (video.currentTime >= 5)
  241. video.currentTime = video.currentTime - 5
  242.  
  243. } else if (evt.code === 'ArrowRight') {
  244.  
  245.  
  246. let video = document.querySelector('#movie_player video[src]')
  247. if (!video) return;
  248.  
  249. if (video.duration >= video.currentTime + 5)
  250. video.currentTime = video.currentTime + 5
  251.  
  252.  
  253. }
  254.  
  255. }
  256. }
  257.  
  258. }
  259.  
  260. function uiSetup(elm) {
  261.  
  262.  
  263. if (!controlsInitialized) {
  264. controlsInitialized = true;
  265.  
  266. let pb = document.querySelector('.player-controls-pb .ytm-progress-bar')
  267.  
  268. if (!pb) {
  269. console.log("'.player-controls-pb .ytm-progress-bar' cannot be found");
  270. } else {
  271.  
  272. pb.addEventListener('mouseup', eventHandlers.pbMouseUp, true)
  273.  
  274. elm.addEventListener('click', eventHandlers.backDropClick, true)
  275.  
  276. document.addEventListener('keydown', eventHandlers.docKeyDown, true)
  277.  
  278. }
  279.  
  280. }
  281.  
  282. }
  283.  
  284. const cssFNs = {
  285.  
  286. addFadeIn(elm) {
  287. elm.classList.add('fadein')
  288. uiSetup(elm)
  289. },
  290.  
  291. removeFadeIn(elm) {
  292. let skip = false
  293. let video = document.querySelector('#movie_player video[src]')
  294. if (video && video.paused) {
  295. skip = true
  296. }
  297. if (!skip) elm.classList.remove('fadein')
  298.  
  299. uiSetup(elm)
  300. },
  301. initUI() {
  302.  
  303. let elm = document.querySelector('#player-control-overlay[class]')
  304. uiSetup(elm)
  305.  
  306. }
  307.  
  308. }
  309.  
  310. document.addEventListener('animationstart', (evt) => {
  311.  
  312. let n = (evt || 0).animationName
  313.  
  314. let f = cssFNs[n]
  315. if (f) f(evt.target)
  316.  
  317.  
  318. }, true)
  319.  
  320.  
  321.  
  322. function onReady() {
  323.  
  324. (document.head || document.documentElement).appendChild(styleElm);
  325. styleElm = null;
  326.  
  327. }
  328.  
  329.  
  330.  
  331. Promise.resolve().then(() => {
  332. if (document.readyState !== 'loading') {
  333. onReady();
  334. } else {
  335. window.addEventListener("DOMContentLoaded", onReady, false);
  336. }
  337. });
  338.  
  339. if (showNativeControls) {
  340. // ==UserScript==
  341. // @name Show Native Controls
  342. // @match https://m.youtube.com/*
  343. // @run-at document-start
  344. // ==/UserScript==
  345.  
  346.  
  347. let addedCSS = false;
  348. function setupVideo(video) {
  349.  
  350. if (!addedCSS) {
  351.  
  352. document.documentElement.appendChild(document.createElement('style')).textContent = `
  353.  
  354. #player-control-overlay:not(.fadein){
  355. height: calc(100% - 64px);
  356. }
  357.  
  358. #player-control-overlay .player-controls-background{
  359. pointer-events: none;
  360. }
  361.  
  362. #player-control-overlay:not(.fadein) .player-controls-background{
  363. bottom: -64px;
  364. }
  365.  
  366. `
  367. }
  368. const v = video;
  369. /*
  370. try {
  371. v.controls = true;
  372. v.nextSibling.childNodes[0].style['pointer-events'] = 'none'
  373. v.nextSibling.childNodes[0].childNodes[1].style['pointer-events'] = 'auto'
  374. } catch (e) { }
  375. */
  376.  
  377. v.controls = true;
  378.  
  379. const observer = new MutationObserver((list, observer) => {
  380. let q = !!document.querySelector('#player-control-overlay:not(.fadein)');
  381. if (v.controls !== q) {
  382.  
  383. v.controls = q;
  384. }
  385.  
  386. })
  387.  
  388. observer.observe(v, { attributes: true, attributeFilter: ['controls'] });
  389. v.setAttribute('w68u4', '1')
  390.  
  391. }
  392.  
  393. const parentMO = new MutationObserver(() => {
  394.  
  395. let q = !!document.querySelector('#player-control-overlay:not(.fadein)');
  396.  
  397. if (q) {
  398.  
  399. for (const v of document.querySelectorAll('.html5-main-video[w68u4="1"]')) {
  400.  
  401. if (v.controls !== q) {
  402. v.controls = q;
  403. }
  404. }
  405.  
  406. }
  407.  
  408. });
  409.  
  410.  
  411. new MutationObserver(() => {
  412.  
  413. const video = document.querySelector('.html5-main-video:not([w68u4])');
  414. if (!video) return;
  415. video.setAttribute('w68u4', '');
  416. if (!(video instanceof HTMLMediaElement)) return;
  417.  
  418. setupVideo(video);
  419.  
  420. for (const elm of document.querySelectorAll('#player-control-overlay, ytm-custom-control, ytm-custom-control .new-controls, ytm-custom-control .player-controls-content, ytm-custom-control .player-controls-content, ytm-custom-control .player-controls-background-container, #player')) {
  421. parentMO.observe(elm, { childList: true, attributes: true });
  422. }
  423.  
  424.  
  425. }).observe(document, { subtree: true, childList: true });
  426.  
  427. }
  428.  
  429.  
  430. })({ Promise });

QingJ © 2025

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