TesterTV_YouTube_Screenshots

Create YouTube Screenshots

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         TesterTV_YouTube_Screenshots
// @namespace    https://greasyfork.org/ru/scripts/482417-testertv-youtube-screenshots
// @version      2023.12.16
// @description  Create YouTube Screenshots
// @license      GPL version 3 or any later version
// @author       TesterTV
// @match        https://www.youtube.com/*
// @match        https://m.youtube.com/*
// @match        https://music.youtube.com/*
// @grant        GM_download
// ==/UserScript==


setInterval(function() {
    if (window.location.href !== "https://www.youtube.com" && window.location.href !== "https://www.youtube.com/" && window.location.href !== "https://m.youtube.com/" && window.location.href !== "https://m.youtube.com" && window.location.href !== "https://music.youtube.com/" && window.location.href !== "https://music.youtube.com") {
        // Check if the page contains an element with id "ButtonEffects"
        if (!document.getElementById("ScreenshotButton")) {
            // If the element isn't found, start the effects script
            YoutubeScreenshots();
        }
    }
}, 1000);

function YoutubeScreenshots() {

    // Check if current window isn't an iframe
    var isInIframe = window === window.top;
    if (isInIframe) {

//********************************************************************************************************************
//***                                             Screenshot 📷                                                   ***
//********************************************************************************************************************

//***************************
//*** ButtonScreenshot 📷 ***
//***************************

    // Create the screenshot button
    const ScreenshotButton = document.createElement('button');
    ScreenshotButton.id = 'ScreenshotButton';
    ScreenshotButton.style.position = 'relative';
    ScreenshotButton.textContent = '📷';
    ScreenshotButton.style.fontSize = '20px';
    ScreenshotButton.style.background = 'none';
    ScreenshotButton.style.border = "3px solid rgba(0, 0, 0, 0)";
    ScreenshotButton.style.color = 'white';
    ScreenshotButton.style.margin = '6px 10px 0';
    ScreenshotButton.style.height= '34px';
    ScreenshotButton.style.width= '36px';
    ScreenshotButton.style.borderRadius = '5%';
    ScreenshotButton.style.left = '10px';
    ScreenshotButton.style.display = 'flex';
    ScreenshotButton.style.justifyContent = 'center';
    ScreenshotButton.style.alignItems = 'center';

    // Insert into the YouTube player controls
    var ControlsLeft = document.querySelector('.ytp-left-controls');
    ControlsLeft.style.position = 'relative';
    ControlsLeft.style.display = 'flex';
    //ControlsLeft.style.alignItems = 'center';
    var TimeDisplay = document.querySelector('.ytp-time-display');
    ControlsLeft.insertBefore(ScreenshotButton, TimeDisplay.nextSibling);

//********************************************************************************************************************
//***                               Listener event - Screenshot function 📷👂                                      ***
//********************************************************************************************************************

    // Add event listener to the screenshot button
    ScreenshotButton.addEventListener("click", function(event) {
        const VideoElement = document.querySelector('video');
        const Canvas = document.createElement('canvas');
        const Context = Canvas.getContext('2d');
        Canvas.width = VideoElement.videoWidth;
        Canvas.height = VideoElement.videoHeight;
        Context.drawImage(VideoElement, 0, 0, Canvas.width, Canvas.height);

        // Get the current video timing
        const CurrentTime = VideoElement.currentTime;
        const Hours = Math.floor(CurrentTime / 3600);
        const Minutes = Math.floor((CurrentTime % 3600) / 60);
        const Seconds = Math.floor(CurrentTime % 60);
        const FormattedTime = `${Hours.toString().padStart(2, '0')}:${Minutes.toString().padStart(2, '0')}:${Seconds.toString().padStart(2, '0')}`;

        // Save the screenshot to local drive with the timing in the filename
        const ScreenshotImage = Canvas.toDataURL('image/png');
        GM_download({
            url: ScreenshotImage,
            name: `screenshot_${FormattedTime}.png`,

            // Screenshot will be downloaded directly to the download folder without asking the user for the title or location.
            saveAs: false //"true" for SaveAs request
        });

        // Set focus on player
        var playButton = document.querySelector('.html5-main-video');
        playButton.focus();

    });

//****************************************
//***   Listener event - Button 📷👂   ***
//****************************************

    // Add an event listener to check if the user has pressed the screenshot button
    ScreenshotButton.addEventListener("click", function(event) {
        ScreenshotButton.style.border = "3px solid rgba(255, 0, 0, 0.5)";

          if (ScreenshotButton) {
              setTimeout(function() {
                  ScreenshotButton.style.border = "3px solid rgba(0, 0, 0, 0)";
              }, 150);
          }

    });

    // Add mouseover event listener to the button...
	ScreenshotButton.addEventListener('mouseover', function() {
		ScreenshotButton.style.border = "3px solid #74e3ff";
	});

    // Add mouseover event listener to the button...
    ScreenshotButton.addEventListener('mouseleave', function() {
        ScreenshotButton.style.border = "3px solid rgba(0, 0, 0, 0)";
    });

//********************************************************************************************************************
//***                                         Screenshot drawing 📸🖌️                                             ***
//********************************************************************************************************************

//***************************
//***  ButtonShow/Hide 👀 ***
//***************************

    // Create the hide/show draw options button
    const ButtonDrawHideShow = document.createElement('button');
    ButtonDrawHideShow.id = 'ButtonDrawHideShow';
    ButtonDrawHideShow.style.position = 'relative';
    ButtonDrawHideShow.textContent = '🖌️';
    ButtonDrawHideShow.style.fontSize = '20px';
    ButtonDrawHideShow.style.background = 'none';
    ButtonDrawHideShow.style.border = "3px solid rgba(0, 0, 0, 0)";
    ButtonDrawHideShow.style.color = 'white';
    ButtonDrawHideShow.style.margin = '6px 0px 0';
    ButtonDrawHideShow.style.height= '34px';
    ButtonDrawHideShow.style.width= '36px';
    ButtonDrawHideShow.style.borderRadius = '5%';
    ButtonDrawHideShow.style.left = '10px';
    ButtonDrawHideShow.style.display = 'flex';
    ButtonDrawHideShow.style.justifyContent = 'center';
    ButtonDrawHideShow.style.alignItems = 'center';

    // Insert into the YouTube player controls
    //var ControlsLeft = document.querySelector('.ytp-left-controls');
    ControlsLeft.style.position = 'relative';
    ControlsLeft.style.display = 'flex';
    //ControlsLeft.style.alignItems = 'center';
    //var TimeDisplay = document.querySelector('.ytp-time-display');
    ControlsLeft.insertBefore(ButtonDrawHideShow, TimeDisplay.nextSibling);

//**********************************
//*** ButtonScreenshotForDraw 📸 ***
//**********************************

    // Create button
    const ButtonScreenshotForDraw = document.createElement('button');
    ButtonScreenshotForDraw.id = "ButtonScreenshotForDraw"
    ButtonScreenshotForDraw.style.position = 'fixed';
    ButtonScreenshotForDraw.style.height= '34px';
    ButtonScreenshotForDraw.style.width= '36px';
    ButtonScreenshotForDraw.style.top = '80px';
    ButtonScreenshotForDraw.style.left = '10px';
    ButtonScreenshotForDraw.textContent = '📸';
    ButtonScreenshotForDraw.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
    ButtonScreenshotForDraw.style.border = '1px solid grey';
    ButtonScreenshotForDraw.style.fontSize = '20px';
    ButtonScreenshotForDraw.style.display = 'flex';
    ButtonScreenshotForDraw.style.justifyContent = 'center';
    ButtonScreenshotForDraw.style.alignItems = 'center';
    ButtonScreenshotForDraw.style.zIndex = '9995';
    ButtonScreenshotForDraw.style.display = 'none'
    document.body.appendChild(ButtonScreenshotForDraw);

//*************************
//***  Color picker 🎨 ***
//*************************

    // Create color picker
    const ColorPicker = document.createElement('input');
    ColorPicker.id = 'ColorPicker';
    ColorPicker.type = 'color';
    ColorPicker.style.position = 'fixed';
    ColorPicker.style.width= '36px'
    ColorPicker.style.top = '120px';
    ColorPicker.style.left = '10px';
    ColorPicker.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
    ColorPicker.style.border = '1px solid grey';
    ColorPicker.value = '#74e3ff'; // Initial color is red
    ColorPicker.style.zIndex = '9996';
    ColorPicker.style.display = 'none'
    document.body.appendChild(ColorPicker);

//***************************
//***    ButtonSave 💾   ***
//***************************

    // Create save button
    const SaveButton = document.createElement('button');
    SaveButton.id = "SaveButton"
    SaveButton.style.position = 'fixed';
    SaveButton.style.height= '34px';
    SaveButton.style.width= '36px';
    SaveButton.style.top = '158px';
    SaveButton.style.left = '10px';
    SaveButton.textContent = '💾';
    SaveButton.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
    SaveButton.style.border = '1px solid grey';
    SaveButton.style.fontSize = '20px';
    SaveButton.style.zIndex = '9997';
    SaveButton.style.display = 'none'
    document.body.appendChild(SaveButton);

//***************************
//***   ExitDrawMode ❌  ***
//***************************

    // Create exit button
    const ButtonExitDraw = document.createElement('button');
    ButtonExitDraw.id = "ButtonExitDraw"
    ButtonExitDraw.style.position = 'fixed';
    ButtonExitDraw.style.height= '34px';
    ButtonExitDraw.style.width= '36px';
    ButtonExitDraw.style.top = '198px';
    ButtonExitDraw.style.left = '10px';
    ButtonExitDraw.textContent = '❌';
    ButtonExitDraw.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
    ButtonExitDraw.style.border = '1px solid grey';
    ButtonExitDraw.style.fontSize = '20px';
    ButtonExitDraw.style.zIndex = '9998';
    ButtonExitDraw.style.display = 'none'
    document.body.appendChild(ButtonExitDraw);

//*************************
//***   Container 📦   ***
//*************************

    // Create image container
    const ImageContainer = document.createElement('div');
    ImageContainer.id = 'ImageContainer';
    ImageContainer.style.position = 'fixed';
    ImageContainer.style.transform = 'translate(-50%, -50%)';
    ImageContainer.style.top = '50%';
    ImageContainer.style.left = '50%';
    ImageContainer.style.display = 'none';
    ImageContainer.style.zIndex = '9990';
    ImageContainer.style.display = 'none'
    document.body.appendChild(ImageContainer);

//***************************
//***Take a Screenshot 🖼️***
//***************************

    // Create canvas for drawing
    const canvas = document.createElement('canvas');
    canvas.style.position = 'absolute';
    canvas.style.top = '50%';
    canvas.style.left = '50%';
    canvas.style.transform = 'translate(-50%, -50%)';
    ImageContainer.appendChild(canvas);
    const context = canvas.getContext('2d');

//*****************************
//***BrushThicknessSlider 🎚️***
//*****************************

    // Create the BrushThicknessSlider element
    var BrushThicknessSlider = document.createElement('input');
    BrushThicknessSlider.id = 'BrushThicknessSlider';
    BrushThicknessSlider.type = 'range';
    BrushThicknessSlider.min = '1';
    BrushThicknessSlider.max = '30';
    BrushThicknessSlider.step = '0.1';
    BrushThicknessSlider.value = '5';
    BrushThicknessSlider.style.transform = 'rotate(270deg)'; // Rotate the slider vertically
    BrushThicknessSlider.style.position = 'absolute';
    BrushThicknessSlider.style.zIndex = '9999';
    BrushThicknessSlider.style.display = 'none'

    // Chnage sliders color
    BrushThicknessSlider.style.background = ColorPicker.value;
    BrushThicknessSlider.style.border = 'none';
    BrushThicknessSlider.style.height = '5px';
    BrushThicknessSlider.style.top = '151px';
    BrushThicknessSlider.style.left = '-15px';
    BrushThicknessSlider.style.width = '152px';
    BrushThicknessSlider.style.outline = 'none';
    BrushThicknessSlider.style.appearance = 'none';
    BrushThicknessSlider.style.webkitAppearance = 'none';
    BrushThicknessSlider.style.mozAppearance = 'none';
    BrushThicknessSlider.style.msAppearance = 'none';
    BrushThicknessSlider.style.webkitSliderThumb = '-webkit-slider-thumb';
    BrushThicknessSlider.style.mozSliderThumb = '-moz-slider-thumb';
    BrushThicknessSlider.style.msSliderThumb = '-ms-slider-thumb';
    BrushThicknessSlider.style.sliderThumb = 'slider-thumb';

    // Append the slider to the document body or any other desired parent element
    document.body.appendChild(BrushThicknessSlider);

//********************************************************************************************************************
//***                               Listener event - Screenshot draw 🖌️👂                                          ***
//********************************************************************************************************************

//****************************************
//***   ButtonDrawHideShow 🖌️👂        ***
//****************************************

    // Add an event listener to check if the user has pressed the screenshot button
    ButtonDrawHideShow.addEventListener("click", function(event) {
        ButtonDrawHideShow.style.border = "3px solid rgba(255, 0, 0, 0.5)";
          if (ButtonDrawHideShow) {
              setTimeout(function() {
                  ButtonDrawHideShow.style.border = "3px solid rgba(0, 0, 0, 0)";
              }, 150);
          }
    });

    // Add mouseover event listener to the button...
	ButtonDrawHideShow.addEventListener('mouseover', function() {
		ButtonDrawHideShow.style.border = "3px solid #74e3ff";
	});

    // Add mouseover event listener to the button...
    ButtonDrawHideShow.addEventListener('mouseleave', function() {
        ButtonDrawHideShow.style.border = "3px solid rgba(0, 0, 0, 0)";
    });

//************************************
//*** DrawFunctionsHide/Show 🖌️🖼️ ***
//************************************

    // Add event listener to the draw button. Function to show/hide video frame
    document.getElementById("ButtonDrawHideShow").addEventListener("click", function(event) {

        if (ImageContainer.style.display === 'none') {
            ButtonScreenshotForDraw.style.display = 'block';
            ColorPicker.style.display = 'block';
            SaveButton.style.display = 'block';
            ButtonExitDraw.style.display = 'block'
            BrushThicknessSlider.style.display = 'block'

            ButtonScreenshotForDraw.style.display = 'flex';
            ButtonScreenshotForDraw.style.justifyContent = 'center';
            ButtonScreenshotForDraw.style.alignItems = 'center';

            ColorPicker.style.display = 'flex';
            ColorPicker.style.justifyContent = 'center';
            ColorPicker.style.alignItems = 'center';

            SaveButton.style.display = 'flex';
            SaveButton.style.justifyContent = 'center';
            SaveButton.style.alignItems = 'center';

            ButtonExitDraw.style.display = 'flex';
            ButtonExitDraw.style.justifyContent = 'center';
            ButtonExitDraw.style.alignItems = 'center';

            //Click Screenshot button
            var button = document.getElementById('ButtonScreenshotForDraw');
            if (button) {button.click();}

        } else {
            ButtonScreenshotForDraw.style.display = 'none';
            ColorPicker.style.display = 'none';
            SaveButton.style.display = 'none';
            ButtonExitDraw.style.display = 'none'
            BrushThicknessSlider.style.display = 'none'

            // Hide video frame
            canvas.removeEventListener('mousedown', startDrawing);
            canvas.removeEventListener('mousemove', draw);
            canvas.removeEventListener('mouseup', stopDrawing);
            canvas.removeEventListener('mouseout', stopDrawing);

            ImageContainer.style.display = 'none';
        }
    });

//*****************************
//***   DrawControl 🖱️🖼️   ***
//*****************************

    // Add event listener to the draw button. Function to show/hide video frame
    document.getElementById("ButtonScreenshotForDraw").addEventListener("click", function(event) {

        //Remove old screenshot
            canvas.removeEventListener('mousedown', startDrawing);
            canvas.removeEventListener('mousemove', draw);
            canvas.removeEventListener('mouseup', stopDrawing);
            canvas.removeEventListener('mouseout', stopDrawing);
            ImageContainer.style.display = 'none';

        //Create new screenshot
        const videoElement = document.querySelector('video');

        // Show video frame
        canvas.width = videoElement.videoWidth;
        canvas.height = videoElement.videoHeight;
        context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);

        // Add mouse event listeners for drawing
        canvas.addEventListener('mousedown', startDrawing);
        canvas.addEventListener('mousemove', draw);
        canvas.addEventListener('mouseup', stopDrawing);
        canvas.addEventListener('mouseout', stopDrawing);

        ImageContainer.style.display = 'block';
    });

//***************************
//***      Drawing 🖌️    ***
//***************************

    // Variables for drawing
    let isDrawing = false;
    let lastX = 0;
    let lastY = 0;

    // Set initial drawing color
    let DrawingColor = ColorPicker.value;

    // Add event listener to the color picker. Function to change drawing color
    document.getElementById("ColorPicker").addEventListener("change", function(event) {
        DrawingColor = ColorPicker.value;
        BrushThicknessSlider.style.background = ColorPicker.value;
    });

    function draw(e) {
        if (!isDrawing) return;

        context.beginPath();
        context.moveTo(lastX, lastY);
        context.lineTo(e.offsetX, e.offsetY);

        context.strokeStyle = DrawingColor;
        //context.lineWidth = 5;
        context.lineWidth = BrushThicknessSlider.value;

        context.lineCap = 'round';
        context.stroke();

        [lastX, lastY] = [e.offsetX, e.offsetY];
    }

    function startDrawing(e) {
        isDrawing = true;
        [lastX, lastY] = [e.offsetX, e.offsetY];
    }

    function stopDrawing() {
        isDrawing = false;
    }

//****************************
//*** ScreenshotSave 💾🖼️ ***
//****************************

    // Add event listener to the save button
    document.getElementById("SaveButton").addEventListener("click", function(event) {
        // Get the current video timing
        const VideoElement = document.querySelector('video');
        const CurrentTime = VideoElement.currentTime;
        const Hours = Math.floor(CurrentTime / 3600);
        const Minutes = Math.floor((CurrentTime % 3600) / 60);
        const Seconds = Math.floor(CurrentTime % 60);
        const FormattedTime = `${Hours.toString().padStart(2, '0')}:${Minutes.toString().padStart(2, '0')}:${Seconds.toString().padStart(2, '0')}`;

        const dataUrl = canvas.toDataURL('image/png');
        GM_download({
            url: dataUrl,
            name: `screenshot_${FormattedTime}.png`,

            //Video will be downloaded directly to the download folder without asking the user for the title or location.
            saveAs: false //"true" for SaveAs request
        });
    });

//****************************
//*** ScreenshotExit ❌🖼️ ***
//****************************

    // Add event listener to the save button
    document.getElementById("ButtonExitDraw").addEventListener("click", function(event) {
            //Click Screenshot button
            var button = document.getElementById('ButtonDrawHideShow');
            if (button) {button.click();}
    });

//***************************
//*** Thickness change 🎚️ ***
//***************************

    // Add an event listener to update the thickness when the slider value changes by user
    BrushThicknessSlider.addEventListener('input', function() {context.lineWidth = BrushThicknessSlider.value;});

//********************************************************************************************************************
//***                                  Remove player notifications 💬🗑️                                           ***
//********************************************************************************************************************

    // Select the elements to be removed
        //Remove video notification by selector (ytp-fullerscreen-edu-text , ytp-fullerscreen-edu-chevron,)
        //Remove video time by class (ytp-time-display.notranslate)
        //Remove next video button by class (ytp-next-button)
    const elementsToRemove = document.querySelectorAll('.ytp-fullerscreen-edu-text, .ytp-fullerscreen-edu-chevron');

    // Loop through each element and remove it
    elementsToRemove.forEach(element => {element.remove();});

    }//window isn't an iframe

}