Greasy Fork is available in English.

Easy Picture-in-Picture

動画上部にポップアウト ボタンを表示して、ピクチャー・イン・ピクチャーを簡単に実行できるようにします。

As of 01.01.2019. See ბოლო ვერსია.

// ==UserScript==
// @name         Easy Picture-in-Picture
// @namespace    easy-picture-in-picture.user.js
// @version      1.0
// @description  動画上部にポップアウト ボタンを表示して、ピクチャー・イン・ピクチャーを簡単に実行できるようにします。
// @author       nafumofu
// @match        http://*/*
// @match        https://*/*
// @grant        none
// @license      MIT License
// ==/UserScript==

class EasyPictureInPicture {
    constructor() {
        this.epipButton = this.createButton();
        document.body.addEventListener('mousemove', (event) => this.event(event), {passive: true});
        document.body.addEventListener('touchstart', (event) => this.event(event), {passive: true});
    }
    event(event) {
        if (!this.eventLocked) {
            this.eventLocked = !!setTimeout(() => {
                this.eventLocked = false;
            }, 50);
            
            var posX = event.screenX || event.changedTouches[0].screenX;
            var posY = event.screenY || event.changedTouches[0].screenY;
            var nodes = document.elementsFromPoint(posX, posY);
            for (let node of nodes) {
                if (node.tagName === 'VIDEO') {
                    this.showButton(node);
                    break;
                }
            }
        }
    }
    popout() {
        document.pictureInPictureElement ? document.exitPictureInPicture() : this.epipTarget.requestPictureInPicture();
    }
    showButton(target) {
        if (!target.disablePictureInPicture) {
            this.epipTarget = target;
            
            var style = this.epipButton.style;
            var rect =this.epipTarget.getBoundingClientRect();
            var posY = window.scrollY + rect.top;
            var posX = window.scrollX + rect.left + (rect.width / 2 - parseInt(style.width) / 2);
            
            style.setProperty('top', `${posY}px`, 'important');
            style.setProperty('left', `${posX}px`, 'important');
            style.setProperty('display', 'unset', 'important');
            
            clearTimeout(this.epipTimer);
            this.epipTimer = setTimeout(() => {
                style.setProperty('display', 'none', 'important');
            }, 3000);
        }
    }
    createButton() {
        var button = document.createElement('button');
        button.id = 'epip-button';
        button.textContent = 'Popout';
        button.style.cssText = `
            all: unset !important;
            display: none !important;
            position: absolute !important;
            background: rgba(0,0,0,0.4) !important;
            color: #ffffff !important;
            font-size: 13px !important;
            text-align: center !important;
            width: 80px !important;
            height: 30px !important;
            border: solid 1px rgba(255,255,255,0.4) !important;
            border-top: none !important;
            border-radius: 0 0 8px 8px !important;
            z-index: 2147483647 !important;
        `;
        button.addEventListener('click', () => this.popout());
        document.documentElement.append(button);
        return button;
    }
}

setTimeout(() => {
    if (document.pictureInPictureEnabled) {
        new EasyPictureInPicture();
    }
}, 1000);