最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Broken Youtube thumbnails do not fire error callback - Stack Overflow

programmeradmin1浏览0评论

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 /**ID**/maxresdefault.jpg

Some videos do not have high-res thumbnails, for example, this one: .jpg

However, a lower quality thumbnail always exists: .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 = "/" + 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 = "/" + id + "/hqdefault.jpg"
            break;
        case 1:
            img.src = thumb = "/" + id + "/default.jpg"
            break;
        case 2:
            done(id, thumb)
            break;
    }
}
img.src = thumb
if (imgplete) 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?

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./vi/**ID**/maxresdefault.jpg

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

However, a lower quality thumbnail always exists: http://img.youtube./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./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./vi/" + id + "/hqdefault.jpg"
            break;
        case 1:
            img.src = thumb = "http://img.youtube./vi/" + id + "/default.jpg"
            break;
        case 2:
            done(id, thumb)
            break;
    }
}
img.src = thumb
if (img.plete) 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?

Share Improve this question edited Jan 10, 2020 at 5:25 sideshowbarker 88.6k30 gold badges215 silver badges212 bronze badges asked May 23, 2014 at 16:16 php_on_railsphp_on_rails 3193 silver badges8 bronze badges 1
  • 1 I would check firefox's live http headers or something like that over the inspector in chrome, but in the end you prob gotta use the api. - juuuuuelz santana – pepper Commented May 23, 2014 at 17:55
Add a ment  | 

3 Answers 3

Reset to default 3

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);
            }


        });

    });

I know this question is a bit older but I had the same problem today and I want to give you my solution which tries all of the YouTube thumbnails from best to worst.

My "ranking" of the different options is:

  1. maxresdefault
  2. mqdefault -> only one besides 1) that doesn't have black borders
  3. sddefault
  4. hqdefault
  5. default -> works 100%

This is my code.

function youtube_check(e) {
    var thumbnail = ["maxresdefault", "mqdefault", "sddefault", "hqdefault", "default"];
    var url = e.attr("src");
    if (e[0].naturalWidth === 120 && e[0].naturalHeight === 90) {
        for (var i = 0, len = thumbnail.length - 1; i < len; i++) {
            if (url.indexOf(thumbnail[i]) > 0) {
                e.attr("src", url.replace(thumbnail[i], thumbnail[i + 1]));
                break;
            }
        }
    }
}

<img onload="youtube_check($(this))" src="https://i3.ytimg./vi/---ID---/maxresdefault.jpg">

For Angular 2+ applications we can write:

youtube.ponent.html

<img #thumbnailImg [src]="imgSrc" alt="YouTube Player" (load)="altThumb()"/>

We are using '(load)' which triggers when image loads on browser. You can use any hook of your choice.

youtube.ponent.ts

@ViewChild('thumbnailImg') elThumbNail: ElementRef;

this.imgSrc = "https://img.youtube./vi/z7Z75q6gNNs/maxresdefault.jpg"

  altThumb() {
   let nativeElementThumbnail = this.elThumbNail.nativeElement;
   if (nativeElementThumbnail.naturalHeight <= 90) {
   const videoId = 'z7Z75q6gNNs'
   nativeElementThumbnail.src = 'https://img.youtube./vi/' + videoId + '/hqdefaultjpg';
}

Here by default we use 'maxresdefault.jpg' but if it fails and give 404 then we change the source to alternate which is 'hqdefault.jpg'

发布评论

评论列表(0)

  1. 暂无评论