Youtube Player Controls below Video

Move YouTube Player Controls below the video

当前为 2023-06-29 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Youtube Player Controls below Video
  3. // @description Move YouTube Player Controls below the video
  4. // @namespace Userscript
  5. // @version 0.1.9
  6. // @match https://www.youtube.com/*
  7. // @grant none
  8. // @noframes
  9. // @author CY Fung
  10. // @license MIT
  11. // @run-at document-start
  12. // ==/UserScript==
  13.  
  14. (() => {
  15. const SCRIPT_CLASSNAME = 'yt8447-enabled'
  16. const SCRIPT_CSS_ID = 'fj74F'
  17.  
  18. const css_text = `
  19.  
  20. html{
  21. --yt8447-chrome-background: black;
  22. }
  23. html[dark] {
  24. --yt8447-chrome-background: transparent;
  25. }
  26.  
  27. .${SCRIPT_CLASSNAME} {
  28. --yt8446-gap: 64px;
  29. --yt8447-height: 52px;
  30. --yt8446-offset-y-min: 4px;
  31.  
  32. --yt8448-gap: max(var(--yt8446-gap), var(--subs-gap, 0px));
  33. --yt8448-gap-theater: max(var(--yt8446-gap), var(--subs-gap-theater, 0px));
  34.  
  35. --yt8446-offset-y: 0px;
  36. --yt8446-offset-y: calc( ( var(--yt8448-gap) - var(--yt8446-gap) ) / 2 );
  37. --yy8446-offset-y1: max(var(--yt8446-offset-y-min), var(--yt8446-offset-y, 0px));
  38. }
  39.  
  40. .${SCRIPT_CLASSNAME} #columns.ytd-watch-flexy {
  41. --subs-gap: var(--yt8448-gap);
  42. --subs-gap-theater: var(--yt8448-gap-theater);
  43. }
  44.  
  45. .${SCRIPT_CLASSNAME}:not([fullscreen]) ytd-player#ytd-player .ytp-chrome-bottom {
  46. bottom: calc( var(--yt8447-height) * -1 - var(--yy8446-offset-y1) );
  47. }
  48.  
  49. .${SCRIPT_CLASSNAME}:not([fullscreen]) ytd-player#ytd-player .ytp-chrome-bottom::before {
  50. position: absolute;
  51. left: -12px;
  52. right: -12px;
  53. content: '';
  54. display: block;
  55. bottom: 0px;
  56. top: calc( -5px - ( var(--yy8446-offset-y1) - 4px ) ); /* actual size 51px instead of 52px */
  57. background-color: var(--yt8447-chrome-background, transparent);
  58. z-index: -1;
  59. transform: translateZ(-1px);
  60. }
  61.  
  62. .${SCRIPT_CLASSNAME}:not([fullscreen]) ytd-player#ytd-player #movie_player::after {
  63. position: absolute;
  64. display: block;
  65. content: '';
  66. left: 0;
  67. right: 0;
  68. height: var(--yt8447-height);
  69. bottom: calc( var(--yt8447-height) * -1 );
  70. opacity: 0 !important;
  71. pointer-events: auto !important;
  72. }
  73.  
  74. .${SCRIPT_CLASSNAME}:not([fullscreen]) ytd-player#ytd-player #movie_player {
  75. overflow: visible;
  76. z-index: 999;
  77. }
  78.  
  79. .${SCRIPT_CLASSNAME}[theater]:not([fullscreen]) #below.ytd-watch-flexy, .${SCRIPT_CLASSNAME}[theater]:not([fullscreen]) #secondary.ytd-watch-flexy {
  80. --yt8448-gap: var(--yt8448-gap-theater);
  81. }
  82.  
  83. .${SCRIPT_CLASSNAME}:not([fullscreen]) #below.ytd-watch-flexy, .${SCRIPT_CLASSNAME}[theater]:not([fullscreen]) #secondary.ytd-watch-flexy {
  84. margin-top: var(--yt8448-gap) !important;
  85. transition: margin-top 0.25s;
  86. }
  87.  
  88. `
  89.  
  90. function isItVideoPage() {
  91. return window.location.href.includes('/watch?v=');
  92. }
  93.  
  94. let mState = 0;
  95. function main(evt) {
  96.  
  97. if (mState === 0) {
  98. if (document.getElementById(SCRIPT_CSS_ID)) {
  99. mState = -1;
  100. console.warn('yt8447: duplicated script');
  101. return;
  102. }
  103. const style = document.createElement('style');
  104. style.textContent = css_text;
  105. style.id = SCRIPT_CSS_ID;
  106. document.head.appendChild(style);
  107. } else if (mState < 0) {
  108. return;
  109. }
  110. if (evt.type === 'yt-page-data-updated') {
  111. mState = 1;
  112. } else if (mState === 0) {
  113. mState = 2;
  114. } else if (mState >= 1) {
  115. return;
  116. }
  117.  
  118. const ytdFlexy = document.querySelector('ytd-watch-flexy');
  119. if (ytdFlexy !== null) {
  120.  
  121. let isValid = true;
  122. if(ytdFlexy.hasAttribute('hidden')) isValid = false;
  123. else if(ytdFlexy.matches('[hidden] ytd-watch-flexy')) isValid=false;
  124. ytdFlexy.classList.toggle(SCRIPT_CLASSNAME, isValid);
  125. /*
  126. // when channel page switches to watch page, the url is not yet changed when yt-page-data-fetched is called.
  127. if (isItVideoPage()) {
  128. ytdFlexy.classList.add(SCRIPT_CLASSNAME);
  129. } else {
  130. ytdFlexy.classList.remove(SCRIPT_CLASSNAME);
  131. }
  132. */
  133. }
  134.  
  135. }
  136.  
  137. document.addEventListener('yt-navigate-finish', main);
  138. document.addEventListener('yt-page-data-fetched', main);
  139. })();