Youtube Player Api Get Screenshot
Asked Answered
K

1

5

There is an iframe on this page I want to get a screenshot from the video tag, so I have to reach video tag that in the iframe tag.

When I open the console and run this code:

 const videoElement = document.getElementsByTagName('iframe')[0]
                 .contentWindow.document.getElementsByTagName('video')[0];

//Extracting picture from video tag
    const canvas = document.createElement('canvas');
        canvas.width = videoElement.videoWidth;
        canvas.height = videoElement.videoHeight;
        canvas.getContext('2d').drawImage(videoElement, 0, 0, canvas.width, canvas.height);

This error has been thrown:

Uncaught DOMException: Blocked a frame with origin "https://developers.google.com" from accessing a cross-origin frame.
    at <anonymous>:1:57

Also, I checked this question

My question is how can I get a screenshot from YouTube Player API?

Khalkha answered 24/5, 2019 at 22:3 Comment(9)
You say that you checked the question you linked to, but it directly addresses your concern - you cannot interact directly with the content of an iframe that is from a different origin. If you could, that would wreck the security of the internet. Also, why not just use the official API, which allows you to get thumbnails / screenshots? - stackoverflow.com/a/2108248Molal
I need to take a screenshot from a specific time lets say video length is 100 second, I would able to take a screenshot at 44'th second. But thumbnails are staticKhalkha
That makes sense, but that doesn't change the fact that you simply can't do with that embeds by themselves (your main question). Your options are basically - A) Download the video and use something like FFMPEG to extract the frame, B) use something like puppeteer to run a headless Chrome and screenshot the video, or C) use a screenshot-api service like URL2PNG and pass it the embed URL as the page to screenshot.Molal
Option A looks perfect apart of downloading the video I think vlc can play youtube video from network stream if I could open vlc from command line with url parameter time parameter it can produce thumbnails dynamicaly: videosolo.com/tutorials/download-video-with-vlc.htmlKhalkha
@Joshua T Can you check out this question: askubuntu.com/questions/796575/… I mean vlc can open youtube conections If I could extract the frames as images with vlc it would be great.Khalkha
I would check out this doc page for a much better example. This code should work in bash - vlc "https://www.youtube.com/watch?v=bHQqvYy5KYo" --rate=1 --video-filter=scene --vout=dummy --start-time=60 --stop-time=61 --scene-ratio=30 --scene-format=png --scene-prefix=screengrab_ vlc://quitMolal
Joshua T I could not achieve to run that code it gives multiple errors even in a video that in my file system did you run it?Khalkha
Also what about the webrtc if I get screenshot with webrtc while video full screen mode can it capture contains of Iframe because when I try it with html2canvas library it shows blank the content of iframeKhalkha
Let us continue this discussion in chat.Molal
O
9

As far as I could find, there is no way to take Screenshots from YouTube Player API as it is based on iFrame. If you want to make them in your own app (not just a browser extension), this operation will be forbidden by CORS (the cause of of the exception that you get).

The only workaround is to put YouTube video as a source into video HTML element using data that you can obtain from YouTube. This code should be handy to get the source urls for video:

class YoutubeVideo {

    constructor(video_id, callback) {
        return (async () => {
            // You should also redirect those requests
            // through your own API that would permit CORS
            const response = await fetch(`https://www.youtube.com/get_video_info?video_id=${video_id}`, {
                headers: { 'Content-Type' : 'text/plain'}
            });
            const video_info = await response.text();
            
            let video = this.decodeQueryString(video_info);
            if (video.status === 'fail') {
                return callback(video);
            }
            
            if (video.url_encoded_fmt_stream_map) 
                video.source = this.decodeStreamMap(video.url_encoded_fmt_stream_map);

            return callback(video);
        })();
    }

    decodeQueryString(queryString) {
        var key, keyValPair, keyValPairs, r, val, _i, _len;
        r = {};
        keyValPairs = queryString.split("&");
        for (_i = 0, _len = keyValPairs.length; _i < _len; _i++) {
            keyValPair = keyValPairs[_i];
            key = decodeURIComponent(keyValPair.split("=")[0]);
            val = decodeURIComponent(keyValPair.split("=")[1] || "");
            r[key] = val;
        }
        return r;
    }

    decodeStreamMap(url_encoded_fmt_stream_map) {
        var quality, sources, stream, type, urlEncodedStream, _i, _len, _ref;
        sources = {};
        _ref = url_encoded_fmt_stream_map.split(",");
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            urlEncodedStream = _ref[_i];
            stream = this.decodeQueryString(urlEncodedStream);
            type = stream.type.split(";")[0];
            quality = stream.quality.split(",")[0];
            stream.original_url = stream.url;
            stream.url = "" + stream.url + "&signature=" + stream.sig;
            sources["" + type + " " + quality] = stream;
        }
        return sources;
    }
}

The object passed to the callback in the constructor would have source property that contains source links for all the available video types and qualities, you can examine them better at your browser's console. Nevertheless, not all YouTube videos can be handled that way, I have met files with further restrictions when all you can get is forbidden error or empty sources.

Resource that helped me to find this solution: https://github.com/endlesshack/youtube-video

Resource that works based on this solution: http://youtubescreenshot.com/

Proof of concept simple Web App based on expressjs server: https://github.com/RinSer/YouCut

Odontoblast answered 13/11, 2019 at 11:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.