Title Youtube Locations

Puts the video title in the location bar of all YouTube video pages. Now with extra features add scrollbars, animate thumbnails, reduce font sizes and un-float the header.

当前为 2015-10-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Title Youtube Locations
  3. // @namespace TYTLs
  4. // @description Puts the video title in the location bar of all YouTube video pages. Now with extra features add scrollbars, animate thumbnails, reduce font sizes and un-float the header.
  5. // @version 1.1.8
  6. // @downstreamURL http://userscripts.org/scripts/source/87416.user.js
  7. // @include http://*.youtube.*/*
  8. // @include http://youtube.*/*
  9. // @include https://*.youtube.*/*
  10. // @include https://youtube.*/*
  11. //// YouTube thumbnails almost certainly appear if you do a video search:
  12. // @include https://www.google.co.uk/search?*&tbm=vid&*
  13. //// YouTube thumbnails occasionally appear in normal Google search results:
  14. // @include https://www.google.co.uk/search*
  15. // @grant GM_addStyle
  16. // @grant GM_log
  17. // ==/UserScript==
  18.  
  19. // TODO: In case for some reason YouTube or another script redirects us to
  20. // another URL which has lost the title param we added, we will re-run forever.
  21. // To avoid this we should have a fallback. E.g. if the title we want to set
  22. // is the same as the last one we did set (via GM_set/getValue) then do not try
  23. // again.
  24. // This has never happened so far. :)
  25.  
  26. // If you are interested in YouTube images:
  27. // Thumbnails url looks like http://img.youtube.com/vi/8aYQ_wjmriQ/2.jpg
  28. // Youtube generates 4 thumbnails: 0.jpg at 320x240, and 1.jpg, 2.jpg, 3.jpg
  29. // Also large: hqdefault.jpg (480x360) and sometimes but not always hq1.jpg, hq2.jpg, hq3.jpg
  30.  
  31.  
  32.  
  33. var addTitleToLocation = true;
  34. var reduceFontSizes = true;
  35. var addScrollbars = true;
  36. var scrollDownToVideo = false; // YouTube's header ("masthead") is now floating. Setting this true will un-float it, then scroll down to hide it. But scrolling containers should then be enlarged.
  37. var animateThumbnails = true;
  38. var unfloatTheHeader = true;
  39.  
  40.  
  41.  
  42. if (addTitleToLocation) {
  43.  
  44. // NOTE: This code is deprecated, as I now use the userscripts URLs_Need_Titles
  45.  
  46. setTimeout(function(){
  47. if (document.location.pathname == "/watch") {
  48.  
  49. var title = document.title.replace(/ - YouTube$/,'')
  50. || null;
  51.  
  52. if (title)
  53. title = title.replace(/ /g,'_').replace(/^[\r\n_]*/,'').replace(/[\r\n_]*$/,''); // "_"s paste better into IRC, since " "s become "%20"s which are hard to read. The second and third parts trim "_"s and newlines from the start and end of the string.
  54.  
  55. if (title) {
  56. if (!document.location.hash) {
  57. document.location.replace(document.location.href + '#' + title); // Does not alter browser history
  58. // document.location.hash = title; // Crashes Chrome less often
  59. }
  60. }
  61. }
  62. },5000); // This is what really stops the crashing!
  63.  
  64. }
  65.  
  66.  
  67.  
  68. if (reduceFontSizes) {
  69. // == Reduce font size of thumbnail titles ==
  70. GM_addStyle(".yt-tile-default.video-list-item a .title, #watch-sidebar .video-list-item .title { font-size: 11px; line-height: 10px; }");
  71. // Defaults are font-size: 13px; and line-height: 15px; which show only two lines in my browser.
  72. }
  73.  
  74.  
  75.  
  76. if (addScrollbars) {
  77.  
  78. // == Scrollbars on comments and related vids, to keep the video in view. ==
  79. setTimeout(function(){
  80. // We could alternatively act on watch-panel but that includes the video navigation buttons!
  81. // BUG: Interferes with YouTube's lazy-loading of thumbnails for related video.
  82. if (document.location.href.indexOf("/all_comments?") >= 0) {
  83. return; // Leave the full comments page alone.
  84. }
  85.  
  86. // The top of watch7-content has become very large, so put a scrollbar on the whole lot.
  87. var watchDiscussion = /* document.getElementById("watch-discussion") || */ document.getElementById("watch7-content");
  88. if (watchDiscussion) {
  89. var toSubtract = 464; // Small video screen
  90. //var toSubtract = 544; // Medium size video screen
  91. var roomForComments = window.innerHeight - toSubtract;
  92. if (roomForComments < 200) {
  93. roomForComments = 200;
  94. }
  95. watchDiscussion.style.overflow = "auto";
  96. watchDiscussion.style.maxHeight = roomForComments+"px"; /* For a video height 360p */
  97. GM_addStyle(" #watch7-content { border: 1px solid; border-color: #c8c8c8 #dddddd #dddddd #c8c8c8; margin-top: 5px; } #watch-header { margin-top: 0px; margin-bottom: 0px; } ");
  98. }
  99.  
  100. var watchSidebar = document.getElementById("watch-sidebar") || document.getElementById("watch7-sidebar");
  101. if (watchSidebar) {
  102. watchSidebar.style.overflow = "auto";
  103. watchSidebar.style.maxHeight = (window.innerHeight - 69)+"px";
  104. // May 2012 - fixes below no longer needed.
  105. // Now the text wraps because of the scrollbar, so we widen the element:
  106. // watchSidebar.style.width = (320+24)+"px";
  107. // watchSidebar.style.width = '300px';
  108. // And we must widen its container also:
  109. // TODO BUG: Why does this work in the console, but not from the userscript?
  110. // document.getElementById("watch-main").style.width = (960+24)+"px";
  111. GM_addStyle(" #watch-sidebar, #watch7-sidebar { border: 1px solid; border-color: #c8c8c8 #dddddd #dddddd #c8c8c8; } ");
  112. }
  113.  
  114. if (scrollDownToVideo) {
  115. // Un-float the header:
  116. GM_addStyle(" #masthead-positioner { position: initial; } #masthead-positioner-height-offset { height: 0px; } ");
  117. //// Title text
  118. // document.getElementById("eow-title").scrollIntoView();
  119. //// Uploader info and videolist popdown.
  120. // document.getElementById("watch-headline-user-info").scrollIntoView();
  121. //// The author's video list (was supposed to be a small gap above the video when collapsed, but it's not)
  122. // document.getElementById("watch-more-from-user").scrollIntoView();
  123. //// The video
  124. // document.getElementsByTagName("embed")[0].scrollIntoView();
  125. //// The video
  126. var watchVideo = document.getElementById("movie_player") || document.getElementById("player-api");
  127. if (watchVideo) {
  128. watchVideo.scrollIntoView();
  129. }
  130. //// Slight gap above the video (I prefer that)
  131. // var watchContainer = document.getElementById("watch7-container");
  132. // if (watchContainer) {
  133. // watchContainer.scrollIntoView();
  134. // }
  135. }
  136.  
  137. // ~ October 2014
  138. // This feels like a bug in Chrome 38. The element is given position:absolute but it does not move up when its parent does! We can fix it anyway:
  139. GM_addStyle(" #watch8-secondary-actions { position: initial; } ");
  140. },1000);
  141.  
  142. }
  143.  
  144.  
  145.  
  146. if (animateThumbnails) {
  147.  
  148. // == Thumbnail animation ==
  149. // TODO: This is working fine on "related videos" thumbnails, but not on queue
  150. // thumbnails, even if I have the queue open when I load the page.
  151. // Perhaps we are responding to a mouseout event from a child element, because
  152. // we are not checking the event target like we should do.
  153. function initThumbnailAnimator() {
  154. // function createThumbnailAnimatorEvent(thumbImage) {
  155. var thumbImage = null;
  156. var originalHref = null;
  157. var evt = null;
  158. var timer = null;
  159. //var frames = ["1.jpg","2.jpg","3.jpg"]; // "default.jpg",
  160. var frames = ["1","2","3"];
  161. var frameI = 0;
  162. function changeFrame() {
  163. frameI = (frameI + 1) % frames.length;
  164. var extension = originalHref.replace(/^.*\./, '');
  165. var filename = frames[frameI] + '.' + extension;
  166. thumbImage.src = originalHref.replace(/\/[^/]*$/,'') + '/' + filename;
  167. }
  168. function startAnimation() {
  169. originalHref = thumbImage.src;
  170. if (originalHref.match(/^data:/)) {
  171. return;
  172. }
  173. // We make this check quite late, due to lazy loading
  174. if (originalHref.match(/\/(.qdefault|default|0)\.(jpg|webp)$/)) {
  175. // logElem("Starting animation",thumbImage);
  176. timer = setInterval(changeFrame,600);
  177. }
  178. }
  179. function stopAnimation() {
  180. if (timer) {
  181. // logElem("Stopping animation",thumbImage);
  182. clearInterval(timer);
  183. timer = null;
  184. // This isn't really neccessary, except to ensure the check for default\.jpg above works next time!
  185. //thumbImage.src = thumbImage.src.replace(/\/[^/]*$/,'') + '/' + "default.jpg";
  186. thumbImage.src = originalHref;
  187. }
  188. }
  189. function logElem(name,elem) {
  190. report = "<"+elem.tagName+" id="+elem.id+" class="+elem.className+" src="+elem.src+" />";
  191. GM_log(name+" = "+report);
  192. }
  193. function check(fn) {
  194. return function(evt) {
  195. // logElem("["+evt.type+"] evt.target",evt.target);
  196. var elemToCheck = evt.target || evt.srcElement;
  197. if (elemToCheck.tagName == "IMG") {
  198. thumbImage = elemToCheck;
  199. return fn();
  200. } else if (elemToCheck.className=='screen') {
  201. var seekImg = elemToCheck.parentNode.getElementsByTagName("img")[0];
  202. if (seekImg) {
  203. thumbImage = seekImg;
  204. return fn();
  205. }
  206. // } else {
  207. // var imgCount = elemToCheck.getElementsByTagName("img").length;
  208. // if (imgCount == 1) {
  209. // thumbImage = elemToCheck.getElementsByTagName("img")[0];
  210. // // logElem("["+evt.type+"] checking sub-image",thumbImage);
  211. // logElem("Whilst checking",elemToCheck);
  212. // logElem(" Animating elem",thumbImage);
  213. // logElem(" with parent",thumbImage.parentNode);
  214. // logElem(" whilst currentTarget",evt.currentTarget);
  215. // logElem(" and srcElement",evt.srcElement);
  216. // return fn();
  217. // }
  218. }
  219. };
  220. }
  221. //// Unfortunately these do not fire on any HTMLImageElements when browsing the queue.
  222. document.body.addEventListener("mouseover",check(startAnimation),false);
  223. document.body.addEventListener("mouseout",check(stopAnimation),false);
  224. // var videoList = document.getElementById("watch-sidebar"); // or watch-module or watch-module-body or watch-related or watch-more-related
  225. // var videoList = document.getElementsByClassName("video-list")[0]; // can be 4 of these!
  226. // var thumbs = document.getElementsByTagName("img");
  227. // for (var i=0;i<thumbs.length;i++) {
  228. // createThumbnailAnimatorEvent(thumbs[i]);
  229. // }
  230. }
  231. setTimeout(initThumbnailAnimator,1000);
  232.  
  233. }
  234.  
  235.  
  236.  
  237. if (unfloatTheHeader) {
  238. GM_addStyle("#masthead-positioner { position: static; }");
  239. var gapElement = document.getElementById("masthead-positioner-height-offset");
  240. if (gapElement) {
  241. gapElement.parentNode.removeChild(gapElement);
  242. }
  243. }
  244.