Greasy Fork is available in English.

Youtube Player Controls below Video

Move YouTube Player Controls below the video

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
  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.20
  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.  
  16. /** @type {globalThis.PromiseConstructor} */
  17. const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
  18.  
  19. const SCRIPT_CLASSNAME = 'yt8447-enabled'
  20. const SCRIPT_CSS_ID = 'fj74F'
  21.  
  22. const css_text = `
  23.  
  24. html{
  25. --yt8447-chrome-background: black;
  26. }
  27. html[dark] {
  28. --yt8447-chrome-background: transparent;
  29. }
  30.  
  31. .${SCRIPT_CLASSNAME} {
  32. --yt8446-gap: 64px;
  33. --yt8447-height: 52px;
  34. --yt8446-offset-y-min: 4px;
  35.  
  36. --yt8448-gap: max(var(--yt8446-gap), var(--subs-gap, 0px));
  37. --yt8448-gap-theater: max(var(--yt8446-gap), var(--subs-gap-theater, 0px));
  38.  
  39. --yt8446-offset-y: 0px;
  40. --yt8446-offset-y: calc( ( var(--yt8448-gap) - var(--yt8446-gap) ) / 2 );
  41. --yy8446-offset-y1: max(var(--yt8446-offset-y-min), var(--yt8446-offset-y, 0px));
  42. }
  43.  
  44. .${SCRIPT_CLASSNAME} #columns.ytd-watch-flexy {
  45. --subs-gap: var(--yt8448-gap);
  46. --subs-gap-theater: var(--yt8448-gap-theater);
  47. }
  48.  
  49. .${SCRIPT_CLASSNAME}:not([fullscreen]) ytd-player#ytd-player .ytp-chrome-bottom {
  50. bottom: calc( var(--yt8447-height) * -1 - var(--yy8446-offset-y1) );
  51. }
  52.  
  53. .${SCRIPT_CLASSNAME}:not([fullscreen]) ytd-player#ytd-player .ytp-tooltip.ytp-bottom {
  54. margin-top: calc( var(--yt8447-height) + var(--yy8446-offset-y1) );
  55. }
  56.  
  57. .${SCRIPT_CLASSNAME}:not([fullscreen]) ytd-player#ytd-player .ytp-chrome-bottom::before {
  58. position: absolute;
  59. left: -12px;
  60. right: -12px;
  61. content: '';
  62. display: block;
  63. bottom: 0px;
  64. top: calc( -5px - ( var(--yy8446-offset-y1) - 4px ) ); /* actual size 51px instead of 52px */
  65. background-color: var(--yt8447-chrome-background, transparent);
  66. z-index: -1;
  67. transform: translateZ(-1px);
  68. }
  69.  
  70. .${SCRIPT_CLASSNAME}:not([fullscreen]) ytd-player#ytd-player #movie_player::after {
  71. position: absolute;
  72. display: block;
  73. content: '';
  74. left: 0;
  75. right: 0;
  76. height: var(--yt8447-height);
  77. bottom: calc( var(--yt8447-height) * -1 );
  78. opacity: 0 !important;
  79. pointer-events: auto !important;
  80. }
  81.  
  82. .${SCRIPT_CLASSNAME}:not([fullscreen]) ytd-player#ytd-player #movie_player .ytp-popup.ytp-settings-menu {
  83. transform: translateY( var(--yt8447-height) );
  84. }
  85.  
  86. .${SCRIPT_CLASSNAME}:not([fullscreen]) ytd-player#ytd-player #movie_player {
  87. overflow: visible;
  88. z-index: 999;
  89. }
  90.  
  91. .${SCRIPT_CLASSNAME}[theater]:not([fullscreen]) #below.ytd-watch-flexy, .${SCRIPT_CLASSNAME}[theater]:not([fullscreen]) #secondary.ytd-watch-flexy {
  92. --yt8448-gap: var(--yt8448-gap-theater);
  93. }
  94.  
  95. .${SCRIPT_CLASSNAME}:not([fullscreen]) #below.ytd-watch-flexy, .${SCRIPT_CLASSNAME}[theater]:not([fullscreen]) #secondary.ytd-watch-flexy {
  96. margin-top: var(--yt8448-gap) !important;
  97. transition: margin-top 0.25s;
  98. }
  99.  
  100. @supports (color: var(--general-fix-video-ended-mode-display)) {
  101. /* this is a general fix, might or might not directly related to this script */
  102. #movie_player .html5-video-container {
  103. position: absolute;
  104. bottom: 0;
  105. top: 0;
  106. left: 0;
  107. right: 0;
  108. overflow: hidden; /* to against overflow:visible in #movie_player in some userscripts */
  109. contain: layout size paint style; /* if supported */
  110. }
  111. #movie_player .html5-video-container > video[style*="top: -"],
  112. #movie_player .html5-video-container > video[style*="top:-"] {
  113. margin-top: -1px !important; /* (.ended-mode#movie_player) video size 943 x 530.44, but top: -530px only */
  114. }
  115. }
  116.  
  117.  
  118.  
  119. .${SCRIPT_CLASSNAME}:not([fullscreen]) .html5-video-player[class]:not(.ytp-fullscreen) .ytp-chrome-bottom[class]:hover {
  120. opacity: initial;
  121. visibility: initial;
  122. }
  123.  
  124. html body ytd-watch-flexy.${SCRIPT_CLASSNAME}:not([fullscreen])[rounded-player-large][default-layout] #ytd-player.ytd-watch-flexy {
  125. overflow: initial;
  126. }
  127.  
  128. html body ytd-watch-flexy.${SCRIPT_CLASSNAME}:not([fullscreen])[class] #ytd-player.ytd-watch-flexy[class] {
  129. overflow: initial;
  130. }
  131.  
  132. `;
  133.  
  134. let mState = 0;
  135. async function main(evt) {
  136. try {
  137. await Promise.resolve();
  138. if (mState === 0) {
  139. if (document.getElementById(SCRIPT_CSS_ID)) {
  140. mState = -1;
  141. console.warn('yt8447: duplicated script');
  142. return;
  143. }
  144. const style = document.createElement('style');
  145. style.textContent = css_text;
  146. style.id = SCRIPT_CSS_ID;
  147. document.head.appendChild(style);
  148. mState = 1;
  149. }
  150. if (mState < 1) return;
  151.  
  152. const ytdFlexy = document.querySelector('ytd-watch-flexy');
  153. if (ytdFlexy !== null) {
  154.  
  155. let isValid = true;
  156. if (ytdFlexy.hasAttribute('hidden')) isValid = false;
  157. else if (ytdFlexy.matches('[hidden] ytd-watch-flexy')) isValid = false;
  158.  
  159. ytdFlexy.classList.toggle(SCRIPT_CLASSNAME, isValid);
  160. }
  161. } catch (e) { console.log(e) }
  162.  
  163. }
  164.  
  165. document.addEventListener('yt-navigate-finish', main, false);
  166. document.addEventListener('yt-page-data-fetched', main, false);
  167. })();