Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force high quality thumbnails for YouTube Player API iframe Embeds?

The thumbnails looked fine for over a year, but suddenly became blurry. The thumbnail that appears on page load looks correct, but anytime a new thumbnail is displayed using 'player.cueVideoById', it looks very blurry.

There is no mention in the documentation of how to control the thumbnail quality (only video quality settings, such as 'setPlaybackQuality' are available). The documentation: https://developers.google.com/youtube/iframe_api_reference

How can I force high quality thumbnail images?

like image 979
edt Avatar asked Nov 22 '14 00:11

edt


Video Answer


1 Answers

Yes, this issue is easily reproducible. I've created a slightly modified version of the documentation example, it loads a video and calls setPlaybackQuality a second later. It is clearly visible that the quality decreases. In fact, the original thumbnail is https://i.ytimg.com/vi/M7lc1UVf-VE/sddefault.jpg, it is being replaced by https://i1.ytimg.com/vi/M7lc1UVf-VE/default.jpg.

While the Flash player is pretty opaque, for the HTML5 player we can take a look at the (pretty obfuscated) source code. This piece of code is particularly interesting (reformatted for readability):

var c;
if (!a.j)
{
  var d = a.element.clientWidth,
      e=a.element.clientHeight;
  if (900 < d || 600 < e)
    c = Av(b, "maxresdefault.jpg");
  !c && (430 < d||320 < e) && (c = Av(b, "sddefault.jpg"))
}
c || (c = Av(b, "default.jpg"));

This indicates that you are indeed not supposed to control thumbnail quality, it is rather set according to viewport size. If width exceeds 900 or height exceeds 600 you get maxresdefault.jpg, if width exceeds 430 or height exceeds 320 you get sddefault.jpg and in all the remaining cases you get default.jpg. This works like that indeed - for the initial load. And this seems to be the intended behavior.

However, that's not what you get for player.cueVideoById() - there it is always default.jpg, presumably because a.j is set (whatever that might be). Edit: Actually, debugging the code has shown that a.j isn't the culprit here. Instead, the Av function returns undefined when called for anything other than "default.jpg" because the data structures (b.La map in particular) aren't completely initialized. To me, this simply looks like a bug, and it seems that it was already reported to Google.

For reference, the source code of function Av:

function Av(a,b)
{
  if (30 == a.O)
  {
    // This branch isn't being entered
    var c = a.La["default.jpg"];
    return c?c:a.videoId?de("//docs.google.com/vt",{id:a.videoId,authuser:a.Wa,authkey:a.Kb}):"//docs.google.com/images/doclist/cleardot.gif"
  }
  b || (b="hqdefault.jpg");
  return (c = a.La[b]) || "sddefault.jpg" == b || "maxresdefault.jpg" == b ?
    c :
    Mt(a.videoId, b)
}

Mt(a.videoId, b) would return the correct URL but the function returns c instead meaning undefined.

Note that the text above applies only to the HTML5 player. Behavior of the Flash player is slightly different and similarly inconsistent.

like image 153
Wladimir Palant Avatar answered Sep 29 '22 14:09

Wladimir Palant