Greasy Fork is available in English.

Better YouTube

Toggle mini player when scrolling down in YouTube. Video download by using youtubeinmp3.com API. Rebind space key for play/pause (no more accidentally scroll down).

  1. // ==UserScript==
  2. // @name Better YouTube
  3. // @namespace feifeihang.info
  4. // @description Toggle mini player when scrolling down in YouTube. Video download by using youtubeinmp3.com API. Rebind space key for play/pause (no more accidentally scroll down).
  5. // @include https://youtu.be/*
  6. // @include http://youtu.be/*
  7. // @include https://www.youtube.com/*
  8. // @include http://www.youtube.com/*
  9. // @version 5.2.5
  10. // @grant none
  11. // ==/UserScript==
  12. (function (window, document, undefined) {
  13. var MP3_API = 'http://youtubeinmp3.com/fetch/?video=';
  14. var fontAwesome = document.createElement('link');
  15. fontAwesome.rel = 'stylesheet';
  16. fontAwesome.href = 'https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css';
  17. document.head.appendChild(fontAwesome);
  18. var isRight = true;
  19. // find and keep a reference of the video player.
  20. var player;
  21. var stylePlayer = '';
  22. var video;
  23. var videoSize = {
  24. };
  25. var controls;
  26. var controlsWidth;
  27. // a flag to indicate is the mini player is toggled.
  28. var isToggled = false;
  29. var isTogglable = true;
  30. var originalHeight;
  31. var s2sBtn;
  32. var hasAddedMini = false;
  33. var shouldToggle = false;
  34. var urlBuffer = '';
  35. var playBtn;
  36. window.setInterval(function () {
  37. if (isToggled &&
  38. !/^http[sS]*\:\/\/www\.youtube\.com\/watch[?]*/.test(window.location.href) &&
  39. shouldToggle) {
  40. turnOff();
  41. shouldToggle = false;
  42. window.removeEventListener('keydown', bindSpaceKey, true);
  43. }
  44. if (!shouldToggle &&
  45. /^http[sS]*\:\/\/www\.youtube\.com\/watch[?]*/.test(window.location.href)) {
  46. if (window.location.href !== urlBuffer) {
  47. isToggled = false;
  48. urlBuffer = urlBuffer;
  49. // bind whitespace key.
  50. playBtn = document.querySelector('.ytp-play-button');
  51. if (playBtn) {
  52. window.addEventListener('keydown', bindSpaceKey, true);
  53. }
  54. }
  55. shouldToggle = true;
  56. }
  57. if (/^http[sS]*\:\/\/www\.youtube\.com\/watch[?]*/.test(window.location.href)) {
  58. // check and add MP3 download button.
  59. var mp3Id = 'better-youtube-mp3-download-btn';
  60. if (!document.querySelector('#' + mp3Id)) {
  61. var container = document.querySelector('#watch8-secondary-actions');
  62. var btn = document.createElement('a');
  63. btn.innerHTML = '<i class="fa fa-lg fa-download"></i> Download';
  64. btn.id = mp3Id;
  65. btn.className += ' yt-uix-button yt-uix-button-size-default yt-uix-button-opacity yt-uix-button-has-icon no-icon-markup pause-resume-autoplay action-panel-trigger';
  66. btn.style = 'display: inline-block; line-height: 25px; color: rgb(230, 33, 23); font-weight: bold;';
  67. btn.onmouseenter = function () {
  68. this.href = MP3_API + window.location.href;
  69. }
  70. btn.onmouseout = function () {
  71. this.href = '';
  72. }
  73. container.insertBefore(btn, container.firstChild);
  74. }
  75. }
  76. }, 500);
  77. var intervalId = window.setInterval(function () {
  78. if (!hasAddedMini &&
  79. /^http[sS]*\:\/\/www\.youtube\.com\/watch[?]*/.test(window.location.href)) {
  80. shouldToggle = true;
  81. player = document.querySelector('#movie_player');
  82. video = document.querySelector('#movie_player video.video-stream');
  83. controls = document.querySelector('#movie_player .ytp-chrome-bottom');
  84. window.addEventListener('scroll', function () {
  85. if (!isTogglable) {
  86. return false;
  87. }
  88. // when scrolling up to 1/3 original player height, turn off mini player.
  89.  
  90. if (isToggled && window.pageYOffset < originalHeight / 3) {
  91. turnOff();
  92. return;
  93. }
  94. // when scrolling down to 1/3 player height, go to mini player mode.
  95.  
  96. if (shouldToggle) {
  97. gotoMini();
  98. }
  99. }, false);
  100. // add a mini player toggle button.
  101. var btn = document.createElement('div');
  102. btn.className += ' yt-uix-button yt-uix-button-size-default yt-uix-button-primary';
  103. btn.innerHTML = 'Mini: on';
  104. btn.style = 'line-height: 26px; height: 26px; margin-left: 5px;';
  105. btn.onclick = function () {
  106. if (this.innerHTML === 'Mini: on') {
  107. this.innerHTML = 'Mini: off';
  108. isTogglable = false;
  109. if (isToggled) {
  110. turnOff();
  111. }
  112. }
  113. else {
  114. this.innerHTML = 'Mini: on';
  115. gotoMini();
  116. isTogglable = true;
  117. }
  118. }
  119. var dom = document.querySelector('#yt-masthead-signin') ||
  120. document.querySelector('#yt-masthead-user');
  121. dom.appendChild(btn);
  122. hasAddedMini = true;
  123. window.clearInterval(intervalId);
  124. }
  125. }, 500);
  126. function bindSpaceKey(evt) {
  127. var inputs = document.querySelectorAll('input[type=text], textarea, div.yt-simplebox-text');
  128. inputs = Array.prototype.slice.apply(inputs);
  129. if (inputs.indexOf(document.activeElement) === - 1 && evt.keyCode === 32) {
  130. evt.preventDefault();
  131. playBtn.click();
  132. }
  133. }
  134. function turnOff() {
  135. player.style = stylePlayer;
  136. video.style.width = videoSize.width;
  137. video.style.height = videoSize.height;
  138. video.style.left = videoSize.left;
  139. video.style.top = videoSize.top;
  140. controls.style.width = controlsWidth;
  141. if (document.querySelector('.ytp-size-button')) {
  142. document.querySelector('.ytp-size-button').style.display = 'inline-block';
  143. }
  144. if (s2sBtn) {
  145. s2sBtn.remove();
  146. }
  147. isToggled = false;
  148. }
  149. function gotoMini() {
  150. if (!isToggled &&
  151. window.pageYOffset >= parseInt(player.offsetHeight, 10) / 3) {
  152. originalHeight = parseInt(player.offsetHeight, 10);
  153. stylePlayer = player.style.cssText;
  154. videoSize = {
  155. height: video.style.height,
  156. width: video.style.width,
  157. left: video.style.left,
  158. top: video.style.top
  159. };
  160. controlsWidth = controls.style.width;
  161. var top = 'top: ' + (window.innerHeight - 270) + 'px;';
  162. var left = 'left: ' + (window.innerWidth - 430) + 'px;';
  163. var fontString = '';
  164. if (isRight) {
  165. player.style = 'position: fixed; bottom: 20px; left: 20px; height: 230px;' +
  166. 'width: 400px; z-index: 9999999;' + top + left;
  167. fontString = '<i class="fa fa-2x fa-caret-square-o-left"></i>';
  168. }
  169. else {
  170. player.style = 'position: fixed; bottom: 20px; left: 20px; height: 230px;' +
  171. 'width: 400px; z-index: 9999999;' + top;
  172. fontString = '<i class="fa fa-2x fa-caret-square-o-right"></i>';
  173. }
  174. video.style.height = '250px';
  175. video.style.width = '400px';
  176. video.style.top = '-10px';
  177. video.style.left = '0';
  178. controls.style.width = '350px';
  179. // now, hide the switch size button.
  180. if (document.querySelector('.ytp-size-button')) {
  181. document.querySelector('.ytp-size-button').style.display = 'none';
  182. }
  183. // add the 'Side-to-side' button.
  184.  
  185. s2sBtn = document.createElement('button');
  186. s2sBtn.className += ' ytp-button';
  187. s2sBtn.style.lineHeight = '10px';
  188. s2sBtn.innerHTML = fontString;
  189. s2sBtn.setAttribute('title', 'Mini player side to side');
  190. s2sBtn.onclick = function () {
  191. if (isRight) {
  192. player.style = 'position: fixed; bottom: 20px; left: 20px; height: 230px;' +
  193. 'width: 400px; z-index: 9999999;' + top;
  194. fontString = '<i class="fa fa-2x fa-caret-square-o-right"></i>';
  195. isRight = false;
  196. }
  197. else {
  198. player.style = 'position: fixed; bottom: 20px; left: 20px; height: 230px;' +
  199. 'width: 400px; z-index: 9999999;' + top + left;
  200. fontString = '<i class="fa fa-2x fa-caret-square-o-right"></i>';
  201. isRight = true;
  202. }
  203. s2sBtn.innerHTML = fontString;
  204. };
  205. var fullscreen = document.querySelector('.ytp-fullscreen-button');
  206. fullscreen.parentElement.insertBefore(s2sBtn, null);
  207. isToggled = true;
  208. }
  209. }
  210. }) (window, document);