Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Broken Youtube thumbnails do not fire error callback

Will an image error callback fire if an image is 404, but the host returns an image anyway?

I am trying to determine on the client whether a Youtube thumbnail is valid before submitting the URL to the server. Normally you can generate a thumbnail URL without querying their API with the format http://img.youtube.com/vi/**ID**/maxresdefault.jpg

Some videos do not have high-res thumbnails, for example, this one: http://img.youtube.com/vi/ty62YzGryU4/maxresdefault.jpg

However, a lower quality thumbnail always exists: http://img.youtube.com/vi/ty62YzGryU4/default.jpg

Ideally I would be able to detect whether the thumbnail did load via this code snippet, which would call "done" when it loaded a valid thumbnail:

var id = "ty62YzGryU4"
var tries = 0
var thumb = "http://img.youtube.com/vi/" + id + "/maxresdefault.jpg"
var img = new Image ()
img.onload = function(){ console.log('ok'); done(id, thumb) }
img.onerror = function(){
    switch (tries++){
        case 0:
            img.src = thumb = "http://img.youtube.com/vi/" + id + "/hqdefault.jpg"
            break;
        case 1:
            img.src = thumb = "http://img.youtube.com/vi/" + id + "/default.jpg"
            break;
        case 2:
            done(id, thumb)
            break;
    }
}
img.src = thumb
if (img.complete) img.onload()

However this is not the case -- while I see a 404 error in the console, neither the onload nor the onerror callbacks fire, and thus done is never called.

If I set img.crossOrigin = "Anonymous" the onerror callback fires... for every thumbnail, because of the accursed Cross-Origin Resource Sharing policy.

I have also tried crafting an XMLHttpRequest, but to no avail:

xmlhttp = new XMLHttpRequest()
xmlhttp.onreadystatechange = function() {
    console.log(xmlhttp.readyState)
    console.log(xmlhttp.status)
};
xmlhttp.open('GET', url, true);
xmlhttp.send(null);

Whether I set X-Requested-With: XMLHttpRequest or not, the readyState goes from 1 to 4 but status is always zero!

Is there any way to see if this particular image gave a 404 without using the API?

like image 203
php_on_rails Avatar asked May 23 '14 16:05

php_on_rails


1 Answers

YouTube thumbnails will not fire the onerror() function because YouTube sends another base64 gif image which shows the empty video icon which has the resolution of 120X90. (this is the key to the solution)

Note that you should load the image tag with the maxresdefault image and give it or (them) a certain class, e.g. "youtube-thumb".

For info: maxresdefault 1080, sddefault 720, hqdefault 480, mqdefault 360, default 240.

According to limited experiments, 0.jpg is 480 or the best low-res image available for a video.

        $(function()
        {

        $('.youtube-thumb').each(function(ix, it){

            if($(it)[0].naturalHeight <= 90 )
           {
            var path = $(it).attr('src');
            var altpath = path.replace('maxresdefault.jpg','0.jpg');

            $(it).attr('src', altpath);
            }


        });

    });
like image 83
Shadi Namrouti Avatar answered Oct 10 '22 04:10

Shadi Namrouti