Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Youtube Player Api Get Screenshot

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?

like image 840
Muhammed Ozdogan Avatar asked Jan 27 '23 06:01

Muhammed Ozdogan


1 Answers

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

like image 71
Serj DuKareff Avatar answered Jan 28 '23 20:01

Serj DuKareff