HTML5 Video Screenshot with Button

Capture screenshot from HTML5 video player using button or Ctrl+Shift+S

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         HTML5 Video Screenshot with Button
// @version      1.0
// @description  Capture screenshot from HTML5 video player using button or Ctrl+Shift+S
// @match        *://*/*
// @grant        none
// @license MIT
// @namespace https://greasyfork.org/users/1349839
// ==/UserScript==

(function() {
    'use strict';

    function captureScreenshot(video) {
        const canvas = document.createElement('canvas');
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);

        canvas.toBlob((blob) => {
            navigator.clipboard.write([
                new ClipboardItem({ 'image/png': blob })
            ]).then(() => {
                showTip('Screenshot copied to clipboard');
            }).catch((error) => {
                showTip('Failed to copy screenshot', true);
                console.error('Failed to copy screenshot: ', error);
            });
        }, 'image/png');
    }

    function showTip(message, isError = false) {
        const tip = document.createElement('div');
        tip.textContent = message;
        tip.style.position = 'fixed';
        tip.style.bottom = '20px';
        tip.style.right = '20px';
        tip.style.padding = '10px';
        tip.style.backgroundColor = isError ? 'rgba(255, 0, 0, 0.8)' : 'rgba(0, 0, 0, 0.8)';
        tip.style.color = 'white';
        tip.style.borderRadius = '5px';
        tip.style.zIndex = '9999999';
        document.body.appendChild(tip);
        setTimeout(() => tip.remove(), 3000);
    }

    function createButton(text, onClick) {
        const button = document.createElement('button');
        button.textContent = text;
        button.style.padding = '5px 10px';
        button.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
        button.style.color = 'white';
        button.style.border = 'none';
        button.style.borderRadius = '5px';
        button.style.cursor = 'pointer';
        button.style.fontSize = '16px';
        button.style.transition = 'opacity 0.3s';
        button.style.opacity = '0';
        button.onclick = onClick;
        return button;
    }

    function addControlsToVideo(video) {
        const wrapper = document.createElement('div');
        wrapper.style.position = 'absolute';
        wrapper.style.top = '10px';
        wrapper.style.right = '10px';
        wrapper.style.zIndex = '9999998';

        const screenshotButton = createButton('📷', (e) => {
            e.preventDefault();
            e.stopPropagation();
            captureScreenshot(video);
        });

        wrapper.appendChild(screenshotButton);

        let hideTimeout;
        let isMouseOverControls = false;

        function showControls() {
            screenshotButton.style.opacity = '1';
            clearTimeout(hideTimeout);
            if (!isMouseOverControls) {
                hideTimeout = setTimeout(() => {
                    if (!isMouseOverControls) {
                        screenshotButton.style.opacity = '0';
                    }
                }, 2000);
            }
        }

        // Show controls on mouse move and hide after 2 seconds of inactivity
        video.parentElement.addEventListener('mousemove', showControls);
        video.parentElement.addEventListener('mouseenter', showControls);

        // Clear timeout when leaving the video area
        video.parentElement.addEventListener('mouseleave', () => {
            if (!isMouseOverControls) {
                screenshotButton.style.opacity = '0';
                clearTimeout(hideTimeout);
            }
        });

        // Keep controls visible when mouse is over them
        wrapper.addEventListener('mouseenter', () => {
            isMouseOverControls = true;
            clearTimeout(hideTimeout);
            screenshotButton.style.opacity = '1';
        });

        wrapper.addEventListener('mouseleave', () => {
            isMouseOverControls = false;
            showControls();
        });

        // Create a wrapper for the video if it doesn't exist
        let videoWrapper = video.parentElement;
        if (!videoWrapper.style.position || videoWrapper.style.position === 'static') {
            videoWrapper = document.createElement('div');
            videoWrapper.style.position = 'relative';
            videoWrapper.style.display = 'inline-block';
            video.parentNode.insertBefore(videoWrapper, video);
            videoWrapper.appendChild(video);
        }

        videoWrapper.appendChild(wrapper);

        // Add keyboard shortcut functionality to the button
        screenshotButton.addEventListener('keydown', function(e) {
            if (e.ctrlKey && e.shiftKey && e.key === 'S') {
                e.preventDefault();
                captureScreenshot(video);
            }
        });
    }

    // Listen for the shortcut key (Ctrl+Shift+S)
    document.addEventListener('keydown', function(e) {
        if (e.ctrlKey && e.shiftKey && e.key === 'S') {
            e.preventDefault();
            const video = document.querySelector('video');
            if (video) {
                captureScreenshot(video);
            } else {
                showTip('No video element found on the page', true);
            }
        }
    });

    // Add controls to video players
    function addControlsToVideos() {
        const videos = document.querySelectorAll('video');
        videos.forEach(addControlsToVideo);
    }

    // Initial addition of controls
    addControlsToVideos();

    // Use a MutationObserver to add controls to dynamically loaded videos
    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.addedNodes) {
                mutation.addedNodes.forEach((node) => {
                    if (node.nodeName === 'VIDEO') {
                        addControlsToVideo(node);
                    } else if (node.querySelector) {
                        const videos = node.querySelectorAll('video');
                        videos.forEach(addControlsToVideo);
                    }
                });
            }
        });
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
})();