您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
On hover, each thumbnail cycles though its 3 thumbnails. Additional feature to view those 3 thumbnails all at once (non-animated)
- // ==UserScript==
- // @name YouTube Animated Thumbnails & Preview Videos
- // @namespace http://userscripts.org/users/23652
- // @description On hover, each thumbnail cycles though its 3 thumbnails. Additional feature to view those 3 thumbnails all at once (non-animated)
- // @include http://*.youtube.com/*
- // @include http://youtube.com/*
- // @include https://*.youtube.com/*
- // @include https://youtube.com/*
- // @exclude http://*youtube.com/my_videos_edit*
- // @exclude http://*youtube.com/my_subscribers*
- // @exclude https://*youtube.com/my_videos_edit*
- // @exclude https://*youtube.com/my_subscribers*
- // @copyright JoeSimmons
- // @version 1.1.0
- // @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
- // @require https://greasyfork.org/scripts/1884-gm-config/code/GM_config.js?version=4836
- // @require https://greasyfork.org/scripts/1885-joesimmons-library/code/JoeSimmons'%20Library.js?version=4838
- // @require https://greasyfork.org/scripts/2817-jsl-ajax-plugin/code/JSL%20-%20AJAX%20plugin.js?version=7911
- // @grant GM_getValue
- // @grant GM_registerMenuCommand
- // @grant GM_setValue
- // @grant GM_xmlhttpRequest
- // ==/UserScript==
- /* CHANGELOG -------------------------------------------------------------------------------------------
- 1.1.0 (4/8/2014)
- - fixed thumbnail previews sometimes not displaying the right video's thumbnail
- 1.0.94 (2/25/2014)
- - fixed problem with thumbnails appearing under the masthead
- 1.0.93 (11/18/2013)
- - removed fading, too inconsistent & laggy
- 1.0.92 (10/8/2013)
- - re-write of the entire script for readability and efficiency
- - added some minor fade effects
- - instead of making the video black when hovering over a thumbnail,
- the script will now keep showing the video
- - previews open in the opposite corner of where your mouse is
- - more reliable HQ image getting
- - only the hovered over thumbnail is animated, not all the images now
- 1.0.91
- - Added a new option that allows animated thumbnails only on hovered images
- 1.0.90
- - Moved the options button to inside the YouTube dropdown menu
- 1.0.89
- - Added compatibility for Opera & Chrome
- ------------------------------------------------------------------------------------------------------ */
- (function () {
- 'use strict';
- var rVi = /[a-z0-9-]+\.ytimg\.com\/vi\/([^\/]+)\//i,
- rYtimgUrl = /[a-z0-9-]+\.ytimg\.com\/vi\//i,
- rWhichImage = /(vi\/[a-z0-9-_]+\/)(1|3|mqdefault)(\.jpg)/i,
- x = 0, y = 0,
- isHoverEnabled, thumbSize, isAnimationEnabled, animationSpeed,
- menulist, __preview_timeout, __animation_interval, stillOnThumb;
- var preview = {
- // clears the timeout and hides the hover preview
- hide : function () {
- window.clearInterval(__preview_timeout);
- JSL('#hover_img').hide().find('img').attribute('src', '');
- },
- show : function () {
- // sets the timeout to show the hover preview
- __preview_timeout = window.setTimeout(function () {
- JSL('#hover_img').show('block');
- }, 400);
- }
- };
- function getNextImage(currentImage) {
- var imagesInOrder = ['1', 'mqdefault', '3'],
- indexOfNextImage = imagesInOrder.indexOf(currentImage) + 1;
- if ( indexOfNextImage > (imagesInOrder.length - 1) ) {
- // if it's on the last one, go back to the first
- return imagesInOrder[0];
- } else {
- // if it's not on the last one, show the next one
- return imagesInOrder[indexOfNextImage];
- }
- }
- function handleHoverLogic(urlIdPrefix) {
- var box = JSL('#hover_img'),
- hori, vert;
- preview.hide();
- // set the previews for this thumbnail
- JSL('#hover_img_1').attribute('src', urlIdPrefix + '1.jpg');
- JSL('#hover_img_2').attribute('src', urlIdPrefix + 'mqdefault.jpg');
- JSL('#hover_img_3').attribute('src', urlIdPrefix + '3.jpg');
- // check for a higher quality preview while we
- // wait for the image to display
- JSL.ajax([
- urlIdPrefix + 'maxresdefault.jpg',
- urlIdPrefix + 'hqdefault.jpg'
- ], {
- method : 'HEAD',
- onload : function (resp) {
- var img2 = JSL('#hover_img_2');
- // check for a 200 (OK) status
- // & that we're showing the correct thumbnail
- if ( resp.status === 200 && resp.url.getMatch(rVi, 1) === img2.attribute('src').getMatch(rVi, 1) ) {
- img2.attribute('src', resp.url);
- JSL.ajaxClear();
- }
- }
- });
- vert = !(y < (window.innerHeight / 2) ) ? 'top' : 'bottom'; // should the preview be on the top or bottom
- hori = !(x < ( (window.innerWidth - 15) / 2) ) ? 'left' : 'right'; // should the preview be on the left or right
- // set the vertical align style property of each of the 3 preview images
- JSL('#hover_img img').css('vertical-align', vert);
- // reset the position of the hover box
- box.css('top', 'auto').css('right', 'auto').css('bottom', 'auto').css('left', 'auto');
- // set the corner it will appear in
- box.css(vert, '0').css(hori, '0');
- // set a delay for the previews to show
- preview.show();
- }
- function handleAnimationLogic(elem) {
- __animation_interval = JSL.setInterval(function () {
- var currentImage = elem.attribute('src').getMatch(rWhichImage, 2),
- nextImage = getNextImage(currentImage);
- elem.attribute( 'src', elem.attribute('src').replace(rWhichImage, '$1' + nextImage + '$3') );
- }, animationSpeed);
- }
- function show(event) {
- var elem = JSL(event.target),
- id = elem.attribute('src').getMatch(rVi, 1),
- urlIdPrefix = 'http://' + elem.attribute('src').getMatch(rYtimgUrl) + id + '/';
- // filter out non-thumbnails
- if ( elem.is('img') && elem.isnt('#hover_img, img[id^="hover_img_"]') && urlIdPrefix.getMatch(rVi) ) {
- if (isHoverEnabled) {
- handleHoverLogic(urlIdPrefix);
- }
- if (isAnimationEnabled) {
- handleAnimationLogic(elem);
- }
- }
- }
- function hide(event) {
- var elem = JSL(event.target),
- id = elem.attribute('src').getMatch(rVi, 1),
- urlIdPrefix = 'http://' + elem.attribute('src').getMatch(rYtimgUrl) + id + '/';
- // clear the last HQ thumbnail request
- JSL.ajaxClear();
- // don't hide the preview if the mouse goes over it
- if ( elem.isnt('#hover_img, img[id^="hover_img_"]') ) {
- preview.hide();
- }
- // stop animating the current thumbnail
- if ( elem.is('img') && elem.isnt('#hover_img, img[id^="hover_img_"]') && elem.attribute('src').getMatch(rWhichImage) ) {
- JSL.clearInterval(__animation_interval); // stop the animation
- elem.attribute( 'src', elem.attribute('src').replace(rWhichImage, '$1mqdefault$3') ); // reset the thumbnail
- }
- }
- function trackMouse(event) {
- x = event.pageX - window.pageXOffset;
- y = event.pageY - window.pageYOffset;
- }
- function GM_config_open() {
- GM_config.open();
- }
- // Make sure the page is not in a frame
- if (window.self !== window.top) { return; }
- // String.prototype.getMatch by JoeSimmons
- // e.g., 'foobar'.getMatch(/foo(bar)/, 1) ==> 'bar'
- Object.defineProperty(String.prototype, 'getMatch', {
- value : function (regex, index) {
- var match = this.match(regex) || ['', '', '', '', '', '', '', '', '', ''];
- if (typeof index === 'number' && index > -1) {
- return match[index];
- }
- return match[0];
- }
- });
- GM_config.init('YouTube Animated Thumbnails Options', {
- hoverimages : {
- section : ['Hover Options'],
- label : 'Enable Hover Images?',
- type : 'checkbox',
- 'default' : true,
- title : 'Hovering over a thumbnail shows 3 preview images.'
- },
- thumbSize : {
- label : 'Hover Thumbnail Size',
- type : 'select',
- options : {
- '90' : 'Small',
- '216' : 'Medium',
- '432' : 'Large'
- },
- 'default' : '432',
- 'title' : 'Choose the size of the hovering thumbnails'
- },
- animatedthumbnails : {
- section : ['Animated Thumbs Options'],
- label : 'Enable Animated Thumbnails?',
- type : 'checkbox',
- 'default' : true,
- title : 'Thumbnails cycle through the 3 images while hovering.'
- },
- animationspeed : {
- label : 'Animation (Cycle) Speed',
- type : 'select',
- options : {
- '1200' : 'Super Slow',
- '800' : 'Slow',
- '600' : 'Medium',
- '400' : 'Fast',
- '200' : 'Super Fast'
- },
- 'default' : '600',
- title : 'Set the speed of the cycled images'
- }
- });
- JSL.runAt('interactive', function () {
- isHoverEnabled = GM_config.get('hoverimages') === true;
- thumbSize = GM_config.get('thumbSize');
- isAnimationEnabled = GM_config.get('animatedthumbnails') === true;
- animationSpeed = parseInt(GM_config.get('animationspeed'), 10);
- JSL.addStyle('' +
- '#hover_img { ' +
- 'position: fixed; ' +
- 'z-index: 999999999999; ' +
- 'background: #000000; ' +
- 'border: 1px solid #000000; ' +
- 'outline: 1px solid #CCCCCC; ' +
- '}' +
- '#hover_img img { ' +
- 'max-height: ' + thumbSize + 'px; ' +
- '}' +
- // fix for images showing under the youtube player
- '#hover_img img { ' +
- 'background-color: #000000; ' +
- '}' +
- '#yt_at_ops { ' +
- 'display: inline-block; ' +
- 'padding: 6px; ' +
- '}' +
- '#GM_config { ' +
- 'z-index: 999999999999 !important; ' + // 999,999,999,999
- '}' +
- '');
- JSL(document.body).append('' +
- '<div id="hover_img" style="display: none;">' +
- '<img src="" alt="" id="hover_img_1" />' +
- '<img src="" alt="" id="hover_img_2" />' +
- '<img src="" alt="" id="hover_img_3" />' +
- '</div>' +
- '');
- // Add a user script command for the options menu
- if (typeof GM_registerMenuCommand === 'function') {
- GM_registerMenuCommand('YouTube Animated Thumbnails Options', GM_config.open);
- }
- // Add an options button to the page
- JSL('#masthead-expanded-menu-list, #footer-main').append('' +
- '<li id="yt_at_ops" class="masthead-expanded-menu-item">' +
- '<a href="javascript: void(0);" class="yt-uix-sessionlink">Animated Thumbnails Options</a>' +
- '</li>' +
- '');
- JSL('#yt_at_ops a').addEvent('click', GM_config.open);
- if (isHoverEnabled) {
- JSL.addEvent(window, 'mousemove', trackMouse);
- JSL.addEvent(window, 'click', preview.hide);
- }
- JSL.addEvent(window, 'mouseover', show);
- JSL.addEvent(window, 'mouseout', hide);
- });
- })();