YouTube Preview

A userscript to play youtube videos by hovering over their thumbnails.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         YouTube Preview
// @author       sooqua
// @namespace    https://github.com/sooqua/
// @version      0.9
// @description  A userscript to play youtube videos by hovering over their thumbnails.
// @match        *://*.youtube.com/*
// @run-at       document-end
// @grant        none
// ==/UserScript==

var APIready = new Promise(function(resolve) {
    window.onYouTubeIframeAPIReady = resolve;
});

(function() {
    'use strict';

    function init() {
        // requesting api
        var scriptTag = document.createElement('script');
        scriptTag.src = "https://www.youtube.com/iframe_api";
        var firstScriptTag = document.getElementsByTagName('script')[0];
        firstScriptTag.parentNode.insertBefore(scriptTag, firstScriptTag);

        addGlobalStyle(
            ".watch-sidebar-section { " +
            "z-index: auto !important; " +
            "} " +

            ".yt-lockup-thumbnail:not(.yt-pl-thumb),.thumb-wrapper { " +
            "-webkit-transition: all 200ms ease-in !important; " +
            "-webkit-transform: scale(1) !important; " +
            "-moz-transition: all 200ms ease-in !important; " +
            "-moz-transform: scale(1) !important; " +
            "transition: all 200ms ease-in !important; " +
            "transform: scale(1) !important; " +
            "} " +

            ".yt-lockup-thumbnail:not(.yt-pl-thumb):hover,.thumb-wrapper:hover { " +
            "z-index: 9999999999 !important; " +
            "box-shadow: 0px 0px 100px #000000 !important; " +
            "-webkit-transition: all 200ms ease-in !important; " +
            "-webkit-transform: scale(2.0) !important; " +
            "-moz-transition: all 200ms ease-in !important; " +
            "-moz-transform: scale(2.0) !important; " +
            "transition: all 200ms ease-in !important; " +
            "transform: scale(2.0) !important; " +
            "} " +

            ".yt-thumb.video-thumb, .yt-uix-simple-thumb-wrap.yt-uix-simple-thumb-related { " +
            "background-color: black !important; " +
            "} " +

            ".xspinner { " +
            "pointer-events: none; " +
            "position: absolute; " +
            "top: 0; " +
            "right: 0; " +
            "bottom: 0; " +
            "left: 0; " +
            "background: rgba(255,255,255,0.5); " +
            "font-size: 14px; " +
            "text-align: center; " +
            "line-height: 2; " +
            "color: rgb(0,0,0); " +
            "font-weight: bold; " +
            "} ");

        initOn(document);
        var mo = new MutationObserver(function(muts) {
            muts.forEach(function(mut) {
                [].forEach.call(mut.addedNodes, function(node) {
                    if (node instanceof HTMLElement) {
                        initOn(node);
                    }
                });
            });
        });
        mo.observe(document.body, {childList: true, subtree: true});
    }

    function initOn(base) {
        [].forEach.call(base.querySelectorAll('.yt-lockup-thumbnail:not(.yt-pl-thumb) a[href^="/watch"], .thumb-wrapper a[href^="/watch"]'), function(thumbnail) {

            thumbnail.parentNode.addEventListener('mouseover', function() {
                if(thumbnail.overlocker) return;
                thumbnail.overlocker = new Promise(function (unlock) {
                    var rect = thumbnail.parentElement.getBoundingClientRect();
                    var farRight = (rect.right + thumbnail.parentElement.clientWidth/2.0) > window.innerWidth;
                    var farDown = (rect.bottom + thumbnail.parentElement.clientHeight/2.0) > window.innerHeight;
                    var farLeft = (rect.left - thumbnail.parentElement.clientWidth/2.0) < 0;
                    var farUp = (rect.top - thumbnail.parentElement.clientHeight/2.0) < 0;
                    if(farRight || farDown || farLeft || farUp) {
                        var transformOrig = (farRight ? 'right ':'') + (farDown ? 'bottom ':'') + (farLeft ? 'left ':'') + (farUp ? 'top ':'');
                        thumbnail.parentElement.style.webkitTransformOrigin = transformOrig;
                        thumbnail.parentElement.style.mozTransformOrigin = transformOrig;
                        thumbnail.parentElement.style.transformOrigin = transformOrig;
                    }

                    var spinner = document.createElement('div');
                    spinner.className = 'xspinner';
                    spinner.textContent = 'Loading...';

                    var childThumb = thumbnail.querySelector('.yt-thumb.video-thumb, .yt-uix-simple-thumb-wrap.yt-uix-simple-thumb-related');
                    childThumb.appendChild(spinner);

                    thumbnail.watchedContainer = [];
                    for (var el = thumbnail; el; el = el.parentElement) {
                        if (el.classList.contains('watched')) {
                            thumbnail.watchedContainer.push(el);
                            el.classList.remove('watched');
                        }
                    }
                    thumbnail.watchedBadgeContainer = [];
                    [].forEach.call(thumbnail.parentNode.querySelectorAll('.watched-badge'), function (watchedBadge) {
                        thumbnail.watchedBadgeContainer.push(watchedBadge);
                        watchedBadge.style.display = 'none';
                    });
                    thumbnail.imageContainer = [];
                    [].forEach.call(thumbnail.getElementsByTagName('img'), function(img) {
                        thumbnail.imageContainer.push(img);
                        img.style.opacity = 0;
                    });

                    var vidId = thumbnail.href.split('v=')[1];
                    thumbnail.PPlayer = new Promise(function (resolve) {
                        var playerTag = document.createElement('div');
                        playerTag.id = vidId;
                        playerTag.style.pointerEvents = 'none';
                        playerTag.style.position = 'absolute';
                        childThumb.insertBefore(playerTag, childThumb.firstChild);
                        APIready.then(function () {
                            var pplayer = new YT.Player(playerTag.id, {
                                width: childThumb.offsetWidth,
                                height: childThumb.offsetHeight,
                                videoId: vidId,
                                playerVars: {
                                    'enablejsapi': 1, 'autoplay': 1, 'showinfo': 0, 'controls': 0,
                                    'modestbranding': 1, 'ps': 'docs', 'iv_load_policy': 3, 'rel': 0,
                                    'vq': 'medium'
                                },
                                events: {
                                    'onReady': function() { resolve(pplayer); }
                                }
                            });
                        });
                    });
                    thumbnail.PPlayer.then(function () {
                        childThumb.removeChild(spinner);
                        unlock();
                    });
                });
            });

            thumbnail.parentNode.addEventListener('mousemove', function(evt) {
                if (thumbnail.spinner) return;

                if(thumbnail.lastX !== evt.screenX) {
                    var offsetX = evt.offsetX || evt.layerX - thumbnail.offsetLeft;

                    if(thumbnail.PPlayer) {
                        thumbnail.PPlayer.then(function (PPlayer) {
                            try {
                                PPlayer.seekTo(PPlayer.getDuration() * offsetX / thumbnail.parentElement.offsetWidth, true);
                            } catch (e){}
                        });
                    }
                }
                thumbnail.lastX = evt.screenX;
            });

            thumbnail.parentNode.addEventListener('mouseout', function(evt) {
                if(!thumbnail.overlocker) return;
                thumbnail.overlocker.then(function () {
                    if(evt.relatedTarget) {
                        if (thumbnail.parentElement.contains(evt.relatedTarget)) return;
                        if (evt.relatedTarget.className.indexOf('yt-uix-tooltip-tip') !== -1) return;
                    }

                    if(thumbnail.watchedContainer) {
                        for (var i = 0; i < thumbnail.watchedContainer.length; i++)
                            thumbnail.watchedContainer[i].classList.add('watched');
                        thumbnail.watchedContainer = null;
                    }
                    if(thumbnail.watchedBadgeContainer) {
                        for (var i = 0; i < thumbnail.watchedBadgeContainer.length; i++)
                            thumbnail.watchedBadgeContainer[i].style.display = null;
                        thumbnail.watchedBadgeContainer = null;
                    }
                    if(thumbnail.imageContainer) {
                        for (var i = 0; i < thumbnail.imageContainer.length; i++)
                            thumbnail.imageContainer[i].style.opacity = null;
                        thumbnail.imageContainer = null;
                    }

                    if(thumbnail.PPlayer) {
                        thumbnail.PPlayer.then(function(PPlayer) {
                            if(PPlayer.a.parentNode)
                                PPlayer.a.parentNode.removeChild(PPlayer.a);
                            thumbnail.PPlayer = null;
                            thumbnail.overlocker = null;
                        });
                    }
                    else {
                        thumbnail.overlocker = null;
                    }
                });
            });

        });
    }

    function addGlobalStyle(css) {
        var head = document.getElementsByTagName('head')[0];
        if (!head) { return; }
        var style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = css;
        head.appendChild(style);
    }

    init();
})();