How do I get a YouTube video thumbnail from the YouTube API? - php

If I have a YouTube video URL, is there any way to use PHP and cURL to get the associated thumbnail from the YouTube API?

Each YouTube video has four generated images. They are predictably formatted as follows:
https://img.youtube.com/vi/<insert-youtube-video-id-here>/0.jpg
https://img.youtube.com/vi/<insert-youtube-video-id-here>/1.jpg
https://img.youtube.com/vi/<insert-youtube-video-id-here>/2.jpg
https://img.youtube.com/vi/<insert-youtube-video-id-here>/3.jpg
The first one in the list is a full size image and others are thumbnail images. The default thumbnail image (i.e., one of 1.jpg, 2.jpg, 3.jpg) is:
https://img.youtube.com/vi/<insert-youtube-video-id-here>/default.jpg
For the high quality version of the thumbnail use a URL similar to this:
https://img.youtube.com/vi/<insert-youtube-video-id-here>/hqdefault.jpg
There is also a medium quality version of the thumbnail, using a URL similar to the HQ:
https://img.youtube.com/vi/<insert-youtube-video-id-here>/mqdefault.jpg
For the standard definition version of the thumbnail, use a URL similar to this:
https://img.youtube.com/vi/<insert-youtube-video-id-here>/sddefault.jpg
For the maximum resolution version of the thumbnail use a URL similar to this:
https://img.youtube.com/vi/<insert-youtube-video-id-here>/maxresdefault.jpg
All of the above URLs are available over HTTP too. Additionally, the slightly shorter hostname i3.ytimg.com works in place of img.youtube.com in the example URLs above.
Alternatively, you can use the YouTube Data API (v3) to get thumbnail images.

You can use YouTube Data API to retrieve video thumbnails, caption, description, rating, statistics and more. API version 3 requires a key*. Obtain the key and create a videos: list request:
https://www.googleapis.com/youtube/v3/videos?key=YOUR_API_KEY&part=snippet&id=VIDEO_ID
Example PHP Code
$data = file_get_contents("https://www.googleapis.com/youtube/v3/videos?key=YOUR_API_KEY&part=snippet&id=T0Jqdjbed40");
$json = json_decode($data);
var_dump($json->items[0]->snippet->thumbnails);
Output
object(stdClass)#5 (5) {
["default"]=>
object(stdClass)#6 (3) {
["url"]=>
string(46) "https://i.ytimg.com/vi/T0Jqdjbed40/default.jpg"
["width"]=>
int(120)
["height"]=>
int(90)
}
["medium"]=>
object(stdClass)#7 (3) {
["url"]=>
string(48) "https://i.ytimg.com/vi/T0Jqdjbed40/mqdefault.jpg"
["width"]=>
int(320)
["height"]=>
int(180)
}
["high"]=>
object(stdClass)#8 (3) {
["url"]=>
string(48) "https://i.ytimg.com/vi/T0Jqdjbed40/hqdefault.jpg"
["width"]=>
int(480)
["height"]=>
int(360)
}
["standard"]=>
object(stdClass)#9 (3) {
["url"]=>
string(48) "https://i.ytimg.com/vi/T0Jqdjbed40/sddefault.jpg"
["width"]=>
int(640)
["height"]=>
int(480)
}
["maxres"]=>
object(stdClass)#10 (3) {
["url"]=>
string(52) "https://i.ytimg.com/vi/T0Jqdjbed40/maxresdefault.jpg"
["width"]=>
int(1280)
["height"]=>
int(720)
}
}
* Not only that you need a key, you might be asked for billing information depending on the number of API requests you plan to make. However, few thousand requests per day are free.
Source article.

What Asaph said is right. However, not every YouTube video contains all nine
thumbnails. Also, the thumbnails' image sizes depends on the video (the numbers
below are based on one). There are some thumbnails guaranteed to exist:
Width | Height | URL
------|--------|----
120 | 90 | https://i.ytimg.com/vi/<VIDEO ID>/1.jpg
120 | 90 | https://i.ytimg.com/vi/<VIDEO ID>/2.jpg
120 | 90 | https://i.ytimg.com/vi/<VIDEO ID>/3.jpg
120 | 90 | https://i.ytimg.com/vi/<VIDEO ID>/default.jpg
320 | 180 | https://i.ytimg.com/vi/<VIDEO ID>/mq1.jpg
320 | 180 | https://i.ytimg.com/vi/<VIDEO ID>/mq2.jpg
320 | 180 | https://i.ytimg.com/vi/<VIDEO ID>/mq3.jpg
320 | 180 | https://i.ytimg.com/vi/<VIDEO ID>/mqdefault.jpg
480 | 360 | https://i.ytimg.com/vi/<VIDEO ID>/0.jpg
480 | 360 | https://i.ytimg.com/vi/<VIDEO ID>/hq1.jpg
480 | 360 | https://i.ytimg.com/vi/<VIDEO ID>/hq2.jpg
480 | 360 | https://i.ytimg.com/vi/<VIDEO ID>/hq3.jpg
480 | 360 | https://i.ytimg.com/vi/<VIDEO ID>/hqdefault.jpg
Additionally, the some other thumbnails may or may not exist. Their presence is
probably based on whether the video is high-quality.
Width | Height | URL
------|--------|----
640 | 480 | https://i.ytimg.com/vi/<VIDEO ID>/sd1.jpg
640 | 480 | https://i.ytimg.com/vi/<VIDEO ID>/sd2.jpg
640 | 480 | https://i.ytimg.com/vi/<VIDEO ID>/sd3.jpg
640 | 480 | https://i.ytimg.com/vi/<VIDEO ID>/sddefault.jpg
1280 | 720 | https://i.ytimg.com/vi/<VIDEO ID>/hq720.jpg
1920 | 1080 | https://i.ytimg.com/vi/<VIDEO ID>/maxresdefault.jpg
You can find JavaScript and PHP scripts to retrieve thumbnails and other
YouTube information in:
How to get YouTube Video Info with PHP
Retrieve YouTube Video Details using JavaScript - JSON & API v2
You can also use the YouTube Video Information Generator tool to get all
the information about a YouTube video by submitting a URL or video id.

In YouTube API V3 we can also use these URLs for obtaining thumbnails... They are classified based on their quality.
https://i1.ytimg.com/vi/<insert-youtube-video-id-here>/default.jpg - default
https://i1.ytimg.com/vi/<insert-youtube-video-id-here>/mqdefault.jpg - medium
https://i1.ytimg.com/vi/<insert-youtube-video-id-here>/hqdefault.jpg - high
https://i1.ytimg.com/vi/<insert-youtube-video-id-here>/sddefault.jpg - standard
And for the maximum resolution..
https://i1.ytimg.com/vi/<insert-youtube-video-id-here>/maxresdefault.jpg
One advantage of these URLs over the URLs in the first answer is that these URLs don't get blocked by firewalls.

If you want to get rid of the "black bars" and do it like YouTube does it, you can use:
https://i.ytimg.com/vi_webp/<video id>/mqdefault.webp
And if you can't use the .webp file extension you can do it like this:
https://i.ytimg.com/vi/<video id>/mqdefault.jpg
Also, if you need the unscaled version, use maxresdefault instead of mqdefault.
Note: I'm not sure about the aspect ratio if you're planning to use maxresdefault.

If you want the biggest image from YouTube for a specific video ID, then the URL should be something like this:
http://i3.ytimg.com/vi/SomeVideoIDHere/0.jpg
Using the API, you can pick up the default thumbnail image. Simple code should be something like this:
//Grab the default thumbnail image
$attrs = $media->group->thumbnail[1]->attributes();
$thumbnail = $attrs['url'];
$thumbnail = substr($thumbnail, 0, -5);
$thumb1 = $thumbnail."default.jpg";
// Grab the third thumbnail image
$thumb2 = $thumbnail."2.jpg";
// Grab the fourth thumbnail image.
$thumb3 = $thumbnail."3.jpg";
// Using simple cURL to save it your server.
// You can extend the cURL below if you want it as fancy, just like
// the rest of the folks here.
$ch = curl_init ("$thumb1");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
$rawdata = curl_exec($ch);
curl_close($ch);
// Using fwrite to save the above
$fp = fopen("SomeLocationInReferenceToYourScript/AnyNameYouWant.jpg", 'w');
// Write the file
fwrite($fp, $rawdata);
// And then close it.
fclose($fp);

I made a function to only fetch existing images from YouTube
function youtube_image($id) {
$resolution = array (
'maxresdefault',
'sddefault',
'mqdefault',
'hqdefault',
'default'
);
for ($x = 0; $x < sizeof($resolution); $x++) {
$url = '//img.youtube.com/vi/' . $id . '/' . $resolution[$x] . '.jpg';
if (get_headers($url)[0] == 'HTTP/1.0 200 OK') {
break;
}
}
return $url;
}

YouTube is owned by Google and Google likes to have a reasonable number of images for different screen sizes, hence its images are stored in different sizes. Here is an example of how your thumbnail will be like:
Low quality thumbnail:
http://img.youtube.com/vi/<YouTube_Video_ID_HERE>/sddefault.jpg
Medium quality thumbnail:
http://img.youtube.com/vi/<YouTube_Video_ID_HERE>/mqdefault.jpg
High quality thumbnail:
http://img.youtube.com/vi/<YouTube_Video_ID_HERE>/hqdefault.jpg
Maximum quality thumbnail:
http://img.youtube.com/vi/<YouTube_Video_ID_HERE>/maxresdefault.jpg

You can get the Video Entry which contains the URL to the video's thumbnail. There's example code in the link. Or, if you want to parse XML, there's information here. The XML returned has a media:thumbnail element, which contains the thumbnail's URL.

In YouTube Data API v3, you can get video's thumbnails with the videos->list function. From snippet.thumbnails.(key), you can pick the default, medium or high resolution thumbnail, and get its width, height and URL.
You can also update thumbnails with the thumbnails->set functionality.
For examples, you can check out the YouTube API Samples project. (PHP ones.)

// Get image form video URL
$url = $video['video_url'];
$urls = parse_url($url);
//Expect the URL to be http://youtu.be/abcd, where abcd is the video ID
if ($urls['host'] == 'youtu.be') :
$imgPath = ltrim($urls['path'],'/');
//Expect the URL to be http://www.youtube.com/embed/abcd
elseif (strpos($urls['path'],'embed') == 1) :
$imgPath = end(explode('/',$urls['path']));
//Expect the URL to be abcd only
elseif (strpos($url,'/') === false):
$imgPath = $url;
//Expect the URL to be http://www.youtube.com/watch?v=abcd
else :
parse_str($urls['query']);
$imgPath = $v;
endif;

YouTube is serving thumbnails from 2 servers. You just need to replace <YouTube_Video_ID_HERE> with your own YouTube video id. These days webP is best format for fast loading of images due to small image size.
https://img.youtube.com
https://i.ytimg.com
Examples are with https://i.ytimg.com server just because it’s shorter, no other particular reason. You can use both.
Player Background Thumbnail (480x360):
WebP
https://i.ytimg.com/vi_webp/<YouTube_Video_ID_HERE>/0.webp
JPG
https://i.ytimg.com/vi/<YouTube_Video_ID_HERE>/0.jpg
Video frames thumbnails (120x90)
WebP:
Start: https://i.ytimg.com/vi_webp/<YouTube_Video_ID_HERE>/1.webp
Middle: https://i.ytimg.com/vi_webp/<YouTube_Video_ID_HERE>/2.webp
End: https://i.ytimg.com/vi_webp/<YouTube_Video_ID_HERE>/3.webp
JPG:
Start: https://i.ytimg.com/vi/<YouTube_Video_ID_HERE>/1.jpg
Middle: https://i.ytimg.com/vi/<YouTube_Video_ID_HERE>/2.jpg
End: https://i.ytimg.com/vi/<YouTube_Video_ID_HERE>/3.jpg
Lowest quality thumbnail (120x90)
WebP
https://i.ytimg.com/vi_webp/<YouTube_Video_ID_HERE>/default.webp
JPG
https://i.ytimg.com/vi/<YouTube_Video_ID_HERE>/default.jpg
Medium quality thumbnail (320x180)
WebP
https://i.ytimg.com/vi_webp/<YouTube_Video_ID_HERE>/mqdefault.webp
JPG
https://i.ytimg.com/vi/<YouTube_Video_ID_HERE>/mqdefault.jpg
High quality thumbnail (480x360)
WebP
https://i.ytimg.com/vi_webp/<YouTube_Video_ID_HERE>/hqdefault.webp
JPG
https://i.ytimg.com/vi/<YouTube_Video_ID_HERE>/hqdefault.jpg
Standard quality thumbnail (640x480)
WebP
https://i.ytimg.com/vi_webp/<YouTube_Video_ID_HERE>/sddefault.webp
JPG
https://i.ytimg.com/vi/<YouTube_Video_ID_HERE>/sddefault.jpg
Unscaled thumbnail resolution
WebP
https://i.ytimg.com/vi_webp/<YouTube_Video_ID_HERE>/maxresdefault.webp
JPG
https://i.ytimg.com/vi/<YouTube_Video_ID_HERE>/maxresdefault.jpg

YouTube API version 3 up and running in 2 minutes
If all you want to do is search YouTube and get associated properties:
Get a public API -- This link gives a good direction
Use below query string. The search query (denoted by q=) in the URL string is stackoverflow for example purposes. YouTube will then send you back a JSON reply where you can then parse for Thumbnail, Snippet, Author, etc.
https://www.googleapis.com/youtube/v3/search?part=id%2Csnippet&maxResults=50&q=stackoverflow&key=YOUR_API_KEY_HERE

Another good alternative would be to use the oEmbed API which is supported by YouTube.
You simply add your YouTube URL to the oEmbed URL and you'll receive a JSON including a thumbnail and the HTML code for embedding.
Example:
http://www.youtube.com/oembed?format=json&url=http%3A//youtube.com/watch%3Fv%3DxUeJdWYdMmQ
Would give you:
{
"height":270,
"width":480,
"title":"example video for 2020",
"thumbnail_width":480,
"html":"...",
"thumbnail_height":360,
"version":"1.0",
"provider_name":"YouTube",
"author_url":"https:\/\/www.youtube.com\/channel\/UCza6VSQUzCON- AzlsrOLwaA",
"thumbnail_url":"https:\/\/i.ytimg.com\/vi\/xUeJdWYdMmQ\/hqdefault.jpg",
"author_name":"Pokics",
"provider_url":"https:\/\/www.youtube.com\/",
"type":"video"
}
Read the documentation for more information.

Use:
https://www.googleapis.com/youtube/v3/videoCategories?part=snippet,id&maxResults=100&regionCode=us&key=**Your YouTube ID**
Above is the link. Using that, you can find the YouTube characteristics of videos. After finding characteristics, you can get videos of the selected category. After then you can find selected video images using Asaph's answer.
Try the above approach and you can parse everything from the YouTube API.

I have used YouTube thumbnails in this way:
$url = 'http://img.youtube.com/vi/' . $youtubeId . '/0.jpg';
$img = dirname(__FILE__) . '/youtubeThumbnail_' . $youtubeId . '.jpg';
file_put_contents($img, file_get_contents($url));
Remember YouTube prevents to include images directly from their server.

You can get the video ID from the YouTube video url using parse_url ,parse_str and then insert in to the predictive urls for images. Thanks to YouTube for the predictive URLs
$videoUrl = "https://www.youtube.com/watch?v=8zy7wGbQgfw";
parse_str( parse_url( $videoUrl, PHP_URL_QUERY ), $my_array_of_vars );
$ytID = $my_array_of_vars['v']; //gets video ID
print "https://img.youtube.com/vi/$ytID/maxresdefault.jpg";
print "https://img.youtube.com/vi/$ytID/mqdefault.jpg";
print "https://img.youtube.com/vi/$ytID/hqdefault.jpg";
print "https://img.youtube.com/vi/$ytID/sddefault.jpg";
print "https://img.youtube.com/vi/$ytID/default.jpg";
You can use this tool to generate YouTube thumbnails
https://youtube-thumbnail-tool.com

I found this nifty tool that allows you to create the image with the YouTube play button placed over the image:
Installed on the server for scripting: https://github.com/halgatewood/youtube-thumbnail-enhancer

Just to add/expand on the solutions given, I feel it is necessary to note that, as I had this problem myself, one can actually grab multiple YouTube videos content, in this case, thumbnails, with one HTTP request:
Using a Rest Client, in this case, HTTPFUL, you can do something like this:
<?php
header("Content-type", "application/json");
//download the httpfull.phar file from http://phphttpclient.com
include("httpful.phar");
$youtubeVidIds= array("nL-rk4bgJWU", "__kupr7KQos", "UCSynl4WbLQ", "joPjqEGJGqU", "PBwEBjX3D3Q");
$response = \Httpful\Request::get("https://www.googleapis.com/youtube/v3/videos?key=YourAPIKey4&part=snippet&id=".implode (",",$youtubeVidIds)."")
->send();
print ($response);
?>

YouTube Data API
YouTube provides us the four generated images for every video through the Data API (v3), for example,
https://i.ytimg.com/vi/V_zwalcR8DU/maxresdefault.jpg
https://i.ytimg.com/vi/V_zwalcR8DU/sddefault.jpg
https://i.ytimg.com/vi/V_zwalcR8DU/hqdefault.jpg
https://i.ytimg.com/vi/V_zwalcR8DU/mqdefault.jpg
Getting access to the images via the API
First get your public API key at Google API Console.
As per YouTube's thumbnail reference in the API documentation, you need to access the resources on snippet.thumbnails.
As per this, you need to phrase your URL like this -
www.googleapis.com/youtube/v3/videos?part=snippet&id=`yourVideoId`&key=`yourApiKey`
Now change your video ID and your API key to the your respective video-id and api-key and its response will be a JSON output providing you the four links in the thumbnails of snippet variable (if all are available).

A simple PHP function I created for the YouTube thumbnail and the types are
default
hqdefault
mqdefault
sddefault
maxresdefault
function get_youtube_thumb($link,$type){
$video_id = explode("?v=", $link);
if (empty($video_id[1])){
$video_id = explode("/v/", $link);
$video_id = explode("&", $video_id[1]);
$video_id = $video_id[0];
}
$thumb_link = "";
if($type == 'default' || $type == 'hqdefault' ||
$type == 'mqdefault' || $type == 'sddefault' ||
$type == 'maxresdefault'){
$thumb_link = 'http://img.youtube.com/vi/'.$video_id.'/'.$type.'.jpg';
}elseif($type == "id"){
$thumb_link = $video_id;
}
return $thumb_link;}

If you're using the public API, the best way to do it is using if statements.
If the video is public or unlisted, you set the thumbnail using the URL method.
If the video is private you use the API to get the thumbnail.
<?php
if($video_status == 'unlisted'){
$video_thumbnail = 'http://img.youtube.com/vi/'.$video_url.'/mqdefault.jpg';
$video_status = '<i class="fa fa-lock"></i> Unlisted';
}
elseif($video_status == 'public'){
$video_thumbnail = 'http://img.youtube.com/vi/'.$video_url.'/mqdefault.jpg';
$video_status = '<i class="fa fa-eye"></i> Public';
}
elseif($video_status == 'private'){
$video_thumbnail = $playlistItem['snippet']['thumbnails']['maxres']['url'];
$video_status = '<i class="fa fa-lock"></i> Private';
}

https://i.ytimg.com/vi/<--Video ID-->/default.jpg
Image Size Weight 120px Height 90px
https://i.ytimg.com/vi/<--Video ID-->/mqdefault.jpg
Image Size Weight 320px Height 180px
https://i.ytimg.com/vi/<--Video ID-->/hqdefault.jpg
Image Size Weight 480px Height 360px
https://i.ytimg.com/vi/<--Video ID-->/sddefault.jpg
Image Size Weight 640px Height 480px
https://i.ytimg.com/vi/<--Video ID-->/maxresdefault.jpg
Image Size Weight 1280px Height 720px

I think there is a lot of answers for thumbnail, but I want to add some other URLs to get YouTube thumbnail very easily. I am just taking some text from Asaph's answer. Here are some URLs to get YouTube thumbnails:
https://ytimg.googleusercontent.com/vi/<insert-youtube-video-id-here>/default.jpg
For the high quality version of the thumbnail use a URL similar to this:
https://ytimg.googleusercontent.com/vi/<insert-youtube-video-id-here>/hqdefault.jpg
There is also a medium quality version of the thumbnail, using a URL similar to the high quality:
https://ytimg.googleusercontent.com/vi/<insert-youtube-video-id-here>/mqdefault.jpg
For the standard definition version of the thumbnail, use a URL similar to this:
https://ytimg.googleusercontent.com/vi/<insert-youtube-video-id-here>/sddefault.jpg
For the maximum resolution version of the thumbnail use a URL similar to this:
https://ytimg.googleusercontent.com/vi/<insert-youtube-video-id-here>/maxresdefault.jpg

Method 1:
You can find all information for a YouTube video with a JSON page which has even "thumbnail_url",
http://www.youtube.com/oembed?format=json&url={your video URL goes here}
Like final URL look + PHP test code
$data = file_get_contents("https://www.youtube.com/oembed?format=json&url=https://www.youtube.com/watch?v=_7s-6V_0nwA");
$json = json_decode($data);
var_dump($json);
Output
object(stdClass)[1]
public 'width' => int 480
public 'version' => string '1.0' (length=3)
public 'thumbnail_width' => int 480
public 'title' => string 'how to reminder in window as display message' (length=44)
public 'provider_url' => string 'https://www.youtube.com/' (length=24)
public 'thumbnail_url' => string 'https://i.ytimg.com/vi/_7s-6V_0nwA/hqdefault.jpg' (length=48)
public 'author_name' => string 'H2 ZONE' (length=7)
public 'type' => string 'video' (length=5)
public 'author_url' => string 'https://www.youtube.com/channel/UC9M35YwDs8_PCWXd3qkiNzg' (length=56)
public 'provider_name' => string 'YouTube' (length=7)
public 'height' => int 270
public 'html' => string '<iframe width="480" height="270" src="https://www.youtube.com/embed/_7s-6V_0nwA?feature=oembed" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>' (length=171)
public 'thumbnail_height' => int 360
For details, you can also see How to get a YouTube video thumbnail using id
or https://www.youtube.com/watch?v=mXde7q59BI8 video tutorial 1
Method 2:
Using YouTube image link,
https://img.youtube.com/vi/"insert-youtube-video-id-here"/default.jpg
Method 3:
Using browser source code for getting thumbnail using video URL link
-go to video source code and search for thumbnailurl.
Now you can use this URL into
your source code:
{img src="https://img.youtube.com/vi/"insert-youtube-video-id-here"/default.jpg"}
For details you can also see How to get a YouTube video thumbnail using id
or
https://www.youtube.com/watch?v=9f6E8MeM6PI
video tutorial 2

function get_video_thumbnail( $src ) {
$url_pieces = explode('/', $src);
if( $url_pieces[2] == 'dai.ly'){
$id = $url_pieces[3];
$hash = json_decode(file_get_contents('https://api.dailymotion.com/video/'.$id.'?fields=thumbnail_large_url'), TRUE);
$thumbnail = $hash['thumbnail_large_url'];
}else if($url_pieces[2] == 'www.dailymotion.com'){
$id = $url_pieces[4];
$hash = json_decode(file_get_contents('https://api.dailymotion.com/video/'.$id.'?fields=thumbnail_large_url'), TRUE);
$thumbnail = $hash['thumbnail_large_url'];
}else if ( $url_pieces[2] == 'vimeo.com' ) { // If Vimeo
$id = $url_pieces[3];
$hash = unserialize(file_get_contents('http://vimeo.com/api/v2/video/' . $id . '.php'));
$thumbnail = $hash[0]['thumbnail_large'];
} elseif ( $url_pieces[2] == 'youtu.be' ) { // If Youtube
$extract_id = explode('?', $url_pieces[3]);
$id = $extract_id[0];
$thumbnail = 'http://img.youtube.com/vi/' . $id . '/mqdefault.jpg';
}else if ( $url_pieces[2] == 'player.vimeo.com' ) { // If Vimeo
$id = $url_pieces[4];
$hash = unserialize(file_get_contents('http://vimeo.com/api/v2/video/' . $id . '.php'));
$thumbnail = $hash[0]['thumbnail_large'];
} elseif ( $url_pieces[2] == 'www.youtube.com' ) { // If Youtube
$extract_id = explode('=', $url_pieces[3]);
$id = $extract_id[1];
$thumbnail = 'http://img.youtube.com/vi/' . $id . '/mqdefault.jpg';
} else{
$thumbnail = tim_thumb_default_image('video-icon.png', null, 147, 252);
}
return $thumbnail;
}
get_video_thumbnail('https://vimeo.com/154618727');
get_video_thumbnail('https://www.youtube.com/watch?v=SwU0I7_5Cmc');
get_video_thumbnail('https://youtu.be/pbzIfnekjtM');
get_video_thumbnail('http://www.dailymotion.com/video/x5thjyz');

Here's the top answer optimized for manual use. The video ID token without separators enables selecting with a double click.
Each YouTube video has four generated images. They are predictably formatted as follows:
https://img.youtube.com/vi/YOUTUBEVIDEOID/0.jpg
https://img.youtube.com/vi/YOUTUBEVIDEOID/1.jpg
https://img.youtube.com/vi/YOUTUBEVIDEOID/2.jpg
https://img.youtube.com/vi/YOUTUBEVIDEOID/3.jpg
The first one in the list is a full size image and others are thumbnail images. The default thumbnail image (ie. one of 1.jpg, 2.jpg, 3.jpg) is:
https://img.youtube.com/vi/YOUTUBEVIDEOID/default.jpg
For the high quality version of the thumbnail use a URL similar to this:
https://img.youtube.com/vi/YOUTUBEVIDEOID/hqdefault.jpg
There is also a medium quality version of the thumbnail, using a URL similar to the HQ:
https://img.youtube.com/vi/YOUTUBEVIDEOID/mqdefault.jpg
For the standard definition version of the thumbnail, use a URL similar to this:
https://img.youtube.com/vi/YOUTUBEVIDEOID/sddefault.jpg
For the maximum resolution version of the thumbnail use a URL similar to this:
https://img.youtube.com/vi/YOUTUBEVIDEOID/maxresdefault.jpg
All of the above URLs are available over HTTP too. Additionally, the slightly shorter hostname i3.ytimg.com works in place of img.youtube.com in the example URLs above.
Alternatively, you can use the YouTube Data API (v3) to get thumbnail images.

Although there are already many answers, but for new visitors I will leave mine with two options for obtaining a thumbnail.
Getting Thumbnail via YouTube Data API
Register your app with Google Cloud Platform and activate YouTube Data API v3 library
Create an API Key in the Credentials section. This way you will get a key to access the API
And send a request for information about the video, including getting a thumbnail.
$api_key = 'YOUR_API_KEY';
$youtube_video_id = 'jNQXAC9IVRw';
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://www.googleapis.com/youtube/v3/videos?key='.$api_key.'&part=snippet&id='.$youtube_video_id,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
));
$response = curl_exec($curl);
curl_close($curl);
$response = json_decode($response,true);
print_r($response); // result with video information and thumbnails
Getting a thumbnail from a direct link without an API
In addition to the API, thumbnails can be obtained via a direct link, like this:
https://i.ytimg.com/vi/jNQXAC9IVRw/hqdefault.jpg
Let's consider this option in detail:
https://i.ytimg.com/vi/<YOUTUBE_VIDEO_ID>/<SIZE_VALUE>.jpg
Where:
YOUTUBE_VIDEO_ID : Your video ID
SIZE_VALUE : Thumbnail size. The variable can contain such values: default, mqdefault, hqdefault, sddefault, maxresdefault
$youtube_video_id = 'jNQXAC9IVRw';
$size = 'hqdefault';
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://i.ytimg.com/vi/{$youtube_video_id}/{$size}.jpg",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
));
$response = curl_exec($curl);
curl_close($curl);
// Write the file
$handle = fopen("image/filename.jpg", 'w'); // set your directory and filename
fwrite($handle, $response);
fclose($handle);

This is my client-side-only no-API-key-required solution.
YouTube.parse('https://www.youtube.com/watch?v=P3DGwyl0mJQ').then(_ => console.log(_))
The code:
import { parseURL, parseQueryString } from './url'
import { getImageSize } from './image'
const PICTURE_SIZE_NAMES = [
// 1280 x 720.
// HD aspect ratio.
'maxresdefault',
// 629 x 472.
// non-HD aspect ratio.
'sddefault',
// For really old videos not having `maxresdefault`/`sddefault`.
'hqdefault'
]
// - Supported YouTube URL formats:
// - http://www.youtube.com/watch?v=My2FRPA3Gf8
// - http://youtu.be/My2FRPA3Gf8
export default
{
parse: async function(url)
{
// Get video ID.
let id
const location = parseURL(url)
if (location.hostname === 'www.youtube.com') {
if (location.search) {
const query = parseQueryString(location.search.slice('/'.length))
id = query.v
}
} else if (location.hostname === 'youtu.be') {
id = location.pathname.slice('/'.length)
}
if (id) {
return {
source: {
provider: 'YouTube',
id
},
picture: await this.getPicture(id)
}
}
},
getPicture: async (id) => {
for (const sizeName of PICTURE_SIZE_NAMES) {
try {
const url = getPictureSizeURL(id, sizeName)
return {
type: 'image/jpeg',
sizes: [{
url,
...(await getImageSize(url))
}]
}
} catch (error) {
console.error(error)
}
}
throw new Error(`No picture found for YouTube video ${id}`)
},
getEmbeddedVideoURL(id, options = {}) {
return `https://www.youtube.com/embed/${id}`
}
}
const getPictureSizeURL = (id, sizeName) => `https://img.youtube.com/vi/${id}/${sizeName}.jpg`
Utility image.js:
// Gets image size.
// Returns a `Promise`.
function getImageSize(url)
{
return new Promise((resolve, reject) =>
{
const image = new Image()
image.onload = () => resolve({ width: image.width, height: image.height })
image.onerror = reject
image.src = url
})
}
Utility url.js:
// Only on client side.
export function parseURL(url)
{
const link = document.createElement('a')
link.href = url
return link
}
export function parseQueryString(queryString)
{
return queryString.split('&').reduce((query, part) =>
{
const [key, value] = part.split('=')
query[decodeURIComponent(key)] = decodeURIComponent(value)
return query
},
{})
}

Save this code in empty.php file and test it.
<img src="<?php echo youtube_img_src('9bZkp7q19f0', 'high');?>" />
<?php
// Get a YOUTUBE video thumb image's source url for IMG tag "src" attribute:
// $ID = YouYube video ID (string)
// $size = string (default, medium, high or standard)
function youtube_img_src ($ID = null, $size = 'default') {
switch ($size) {
case 'medium':
$size = 'mqdefault';
break;
case 'high':
$size = 'hqdefault';
break;
case 'standard':
$size = 'sddefault';
break;
default:
$size = 'default';
break;
}
if ($ID) {
return sprintf('https://img.youtube.com/vi/%s/%s.jpg', $ID, $size);
}
return 'https://img.youtube.com/vi/ERROR/1.jpg';
}
There are some thumbnails guaranteed to exist:
Width | Height | URL
------|--------|----
120 | 90 | https://i.ytimg.com/vi/<VIDEO ID>/1.jpg
120 | 90 | https://i.ytimg.com/vi/<VIDEO ID>/2.jpg
120 | 90 | https://i.ytimg.com/vi/<VIDEO ID>/3.jpg
120 | 90 | https://i.ytimg.com/vi/<VIDEO ID>/default.jpg
320 | 180 | https://i.ytimg.com/vi/<VIDEO ID>/mq1.jpg
320 | 180 | https://i.ytimg.com/vi/<VIDEO ID>/mq2.jpg
320 | 180 | https://i.ytimg.com/vi/<VIDEO ID>/mq3.jpg
320 | 180 | https://i.ytimg.com/vi/<VIDEO ID>/mqdefault.jpg
480 | 360 | https://i.ytimg.com/vi/<VIDEO ID>/0.jpg
480 | 360 | https://i.ytimg.com/vi/<VIDEO ID>/hq1.jpg
480 | 360 | https://i.ytimg.com/vi/<VIDEO ID>/hq2.jpg
480 | 360 | https://i.ytimg.com/vi/<VIDEO ID>/hq3.jpg
480 | 360 | https://i.ytimg.com/vi/<VIDEO ID>/hqdefault.jpg
Thanks.

Related

Determine if YouTube video is widescreen?

I would like to know with certainty if a YouTube video is widescreen or not using the v3 API. There are many old videos that have a 4:3 ratio, so I need to detect this.
This was possible with API v2, but it is officially retired now. Here are the API v3 docs.
An API call looks something like this:
https://www.googleapis.com/youtube/v3/videos?id=[VIDEOID]&part=snippet&key=[DEVELOPERKEY]
Also, the thumbnail data always returns dimensions of 4:3, so that doesn't help. Here is an example:
[thumbnails] => Array
(
[default] => Array
(
[url] => https://i.ytimg.com/vi/nnnnnnnnn/default.jpg
[width] => 120
[height] => 90
)
...
)
Any ideas?
(I'm currently hacking this by analyzing pixels in the thumbnails where tell-tale black bars on 4:3 videos will be.)
Here is a sample video in 4:3 ratio:
https://www.youtube.com/watch?v=zMJ-Dl4eJu8 (old martial arts video)
and one in 16:9:
https://www.youtube.com/watch?v=7O2Jqi-LhEI (a new workout video)
Update: One promising suggestion was to explore fileDetails.videoStreams[].aspectRatio but it seems that this is only available to the video owner. Otherwise requesting fileDetails results in
The request cannot access user rating information. This error may occur because the request is not properly authorized
If you're open to using a different method other than V3 of the API, then I believe it is possible via the oEmbed API.
http://www.youtube.com/oembed?url={VIDEO_URL}&format=json
Like so:
http://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=zMJ-Dl4eJu8&format=json
Would produce:
{
"provider_url":"https:\/\/www.youtube.com\/",
"thumbnail_url":"https:\/\/i.ytimg.com\/vi\/zMJ-Dl4eJu8\/hqdefault.jpg",
"thumbnail_height":360,
"height":344,
"type":"video",
"version":"1.0",
"html":"\u003ciframe width=\"459\" height=\"344\" src=\"https:\/\/www.youtube.com\/embed\/zMJ-Dl4eJu8?feature=oembed\" frameborder=\"0\" allowfullscreen\u003e\u003c\/iframe\u003e",
"author_name":"hadronica2",
"width":459,
"provider_name":"YouTube",
"author_url":"https:\/\/www.youtube.com\/user\/hadronica2",
"title":"Aikido - Kazuo Chiba sensei - 1\u00ba part",
"thumbnail_width":480
}
In the examples you've given, the output was as follows:
http://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=zMJ-Dl4eJu8&format=json
Width: 459
Height: 344
Ratio: w/h = 1.3343 = 4:3 (ish)
http://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=zMJ-Dl4eJu8&format=json
Width: 480
Height: 270
Ratio: w/h = 1.7777 = 16/9
This appears to work in the examples you've provided.
Here is the abridged version that I have been using since v2 of the API retired.
It tests a few points on the top and bottom of the default.jpg thumbnail image of a given video where black bars might be. A vertically opposite point from a top point is tested to see if those pixels are similar to each other to within some delta. This is repeated for a few more points.
function isWidescreen($video = null) {
// LOGIC:
// 4:3 videos will have default.jpg with no top black bars
// 16:9 videos will have black top and bottom borders on default.jpg
// Get the default thumbnail (may have black bars on top and bottom)
$response = self::accessCurlObj()->get("https://i.ytimg.com/vi/{$video}/default.jpg");
$defaultImgRes = imagecreatefromstring($response);
$samplePoints = array(array(20,2), array(40,4), array(60,6), array(80,8));
// Scan a few points for equality between top and bottom
$height = imagesy($defaultImgRes);
foreach($samplePoints as $point) {
// Top
$rgbTop = imagecolorat($defaultImgRes, $point[0], $point[1]);
$colorsTop = imagecolorsforindex($defaultImgRes, $rgbTop);
// Bottom
$rgbBottom = imagecolorat($defaultImgRes, $point[0], $height - $point[1]);
$colorsBottom = imagecolorsforindex($defaultImgRes, $rgbBottom);
// If these arrays are not close, then let's call this 4:3 aspect
if(!$this->areArraysClose($colorsTop, $colorsBottom, 20)) {
return false;
}
}
// Default to widescreen
return true;
}
// Determine if the numeric values in the RGBA array are within some delta from each other
function areArraysClose(&$a, &$b, $delta = 10) {
foreach($a as $key => $val) {
if(abs($val - $b[$key]) > $delta) {
return false;
}
}
return true;
}
This seems to be working sufficiently enough. An obvious improvement is to check if the pixels are close to black, or apply some image processing to remove black bars automatically then check the dimensions of the remaining image.
However, my hope was that a domain-knowledgeable SO member would have a better solution before going deeper down this rabbit hole... and someone came through.

How to Download Images from new RETS CRMLS

I am trying to download images from new RETS CRMLS
$photos = $rets->SearchQuery("Media","Media",$lid, array('Limit' => 'none', 'Select' => "MediaOrder,MediaURL"));
foreach ($photos as $photo)
{
if ($photo['Success'] == true)
{
file_put_contents("../images/{$photo['Content-ID']}-{$photo['Object-ID']}.jpg", $photo['Data']);
$count++;
}
}
this is not working
If you want to download the images from the Property class, you can use this rets function
$rets->GetObject("Property", "Photo", $listingId, "*", 1);
This will return the array of images associated with the particular listingId as image url.
If you want to download as binary image files then you can use the last parameter as '0', instead of '1'. [ '1' is for getting public image Urls]
If the image is to be downloaded from the Media class then you can use the same function with Media as the class. And you should first get the listing Id from the Property class.
Your "file_put_contents" function appears to be attempting to parse the info headers within a multipart/mime response from a GetObject query. Rather, you'd want to do a straight http download of the MediaUrls. I'm not a php wizard, but you'd do something more like:
$photoUrls = $rets->SearchQuery("Media","Media",$lid, array('Limit' => 'none', 'Select' => "MediaOrder,MediaURL"));
while ($photo = $rets->FetchRow($photoUrls)) {
file_put_contents("../images/{$lid}-{$photo['MediaOrder']}.jpg", file_get_contents($photo['MediaURL']));
}
$rets->FreeResult($photoUrls);
Also, you probably want to limit your search to MediaTypes of "Image" so you don't get other binary data or documents, like virtual tour URLs or PDFs (see google group for this MLS that you also posted within).

Transparency with GifCreator php class not working

I try to use the Gifcreator php class to create an animated GIF image from 10 PNG images.
The animated image is created but transparency of original images is lost. I have a black bakground.
The documentation says that the transparency is determinated by first loaded image. The 10 images have a transparent background. I loaded htem in Paint whicj says that it is based on white.
Has anoyone a solution to this ?
Thanks,
The class is here : https://github.com/Sybio/GifCreator
My script here : http://www.egloff.eu/rsmaptest/slideshow.php
The first image here : http://www.egloff.eu/rsmaptest/images/image0.png
The code :
<?php
// Include the class
require_once('./testcreator/GifCreator.php');
// Instanciate the class (uses default options with the addition of width/height specified)
$gif = new GifCreator(0, 2, array(0, 0, 0),550,550);
// Add each frame to the animation
$gif->addFrame(file_get_contents('images/image9.png'), 100, true);
$gif->addFrame(file_get_contents('images/image8.png'), 100, true);
$gif->addFrame(file_get_contents('images/image7.png'), 100, true);
$gif->addFrame(file_get_contents('images/image6.png'), 100, true);
$gif->addFrame(file_get_contents('images/image5.png'), 100, true);
$gif->addFrame(file_get_contents('images/image4.png'), 100, true);
$gif->addFrame(file_get_contents('images/image3.png'), 100, true);
$gif->addFrame(file_get_contents('images/image2.png'), 100, true);
$gif->addFrame(file_get_contents('images/image1.png'), 100, true);
$gif->addFrame(file_get_contents('images/image0.png'), 500, true);
// Output the animated gif
header('Content-type: image/gif');
echo $gif->getAnimation();
?>
I found an answer to my own question, and it might help some others using the same library or other libraries based on the same original work by László Zsidi.
In the class, you have to replace the following part that appears in one or another place in 2 lines :
$Locals_ext = "!\xF9\x04" . chr ( ( $this->DIS << 2 ) + 0 ) .
by this one
$Locals_ext = "!\xF9\x04" . chr ((( $this->DIS << 2 )) | 1 + 0 ) .
That solved my problem and transparency works now OK. i tried in 3 differents classes i've found are all based on the same work.
I hope this can help.

Get Image ICC Profile with PHP or Imagick

I have been struggling all day with this issue and surprised that can't find any documentation!
I am uploading images to a website & would like to extract the name of each images ICC profile & use it in the image description. So far, standard PHP produces no results. I have checked the images with Photoshop, Bridge & Exiftool & each has identified the profile embedded.
<?php
$info = exif_read_data($image);
echo 'ICC Profile: '.$info['ICC_Profile'].'<br>';
echo 'ICC Profile: '.$info['CurrentICCProfile'].'<br>';
echo 'ICC Profile: '.$info['ColorSpace'].'<br>';
?>
Imagick produced the best results with:
$imagick = new Imagick();
$imagick->readImage($image);
print_r ($imagick->getImageProfiles("icc",true));
Generating an array that actually mentions the profile but not a usable string. Any help appreciated.
I'm using these versions:
PHP Version 5.2.17 - imagick module version 3.0.1 - ImageMagick version 6.7.6-8
And print_r returns (for 'ProPhoto RGB' ICC profile):
Array ( [icc] => �KCMSmntrRGB XYZ � :acspMSFTKODAROMM���+KODAcprtHdesc\�wtpt�rTRC�gTRC�bTRC�rXYZgXYZbXYZ,dmnd#ndmdd��mmod�(textCopyright (c) Eastman Kodak Company, 1999, all rights reserved.desc ProPhoto RGB��ProPhoto RGB ProPhoto RGBXYZ ���,curv�XYZ �4I�XYZ "��>XYZ �-descKODAK��KODAKKODAKdesc'Reference Output Medium Metric(ROMM) (��Reference Output Medium Metric(ROMM) 'Reference Output Medium Metric(ROMM) mmod���;� )
in full (from Exiftool):
Profile CMM Type : KCMS
Profile Version : 2.1.0
Profile Class : Display Device Profile
Color Space Data : RGB
Profile Connection Space : XYZ
Profile Date Time : 1998:12:01 18:58:21
Profile File Signature : acsp
Primary Platform : Microsoft Corporation
CMM Flags : Not Embedded, Independent
Device Manufacturer : KODA
Device Model : ROMM
Device Attributes : Reflective, Glossy, Positive, Color
Rendering Intent : Perceptual
Connection Space Illuminant : 0.9642 1 0.82487
Profile Creator : KODA
Profile ID : 0
Profile Copyright : Copyright (c) Eastman Kodak Company, 1999, all rights reserved.
Profile Description : ProPhoto RGB
Media White Point : 0.9642 1 0.82489
Red Tone Reproduction Curve : (Binary data 14 bytes, use -b option to extract)
Green Tone Reproduction Curve : (Binary data 14 bytes, use -b option to extract)
Blue Tone Reproduction Curve : (Binary data 14 bytes, use -b option to extract)
Red Matrix Column : 0.79767 0.28804 0
Green Matrix Column : 0.13519 0.71188 0
Blue Matrix Column : 0.03134 9e-005 0.82491
Device Mfg Desc : KODAK
Device Model Desc : Reference Output Medium Metric(ROMM)
Make And Model : (Binary data 40 bytes, use -b option to extract)
I'm not too sure, if this is the case for all images. At least the images i have, have this information in their "Properties". Thus to get a printable profile name it should work like this:
$imagick = new imagick('/some/filename');
$profile = $imagick->getImageProperties('icc:model', true);
/**
* If the property 'icc:model' is set $profile now should be:
* array( 'icc:model' => 'ICC model name')
*/
If you would like to see all the properties, which are set for an image, you could probe the image manually with identify -verbose /some/filename. There you will have to look for "Properties:", the ICC name should be set there.
The above is the easy way to obtain the ICC profile name. If you really need the ICC name from the icc profile you might want to take a look at the ICC Profile Format Specification
In short:
The first 128 bytes are the header. Then follows a tag table, where the first 4 bytes are the size of the table.
Each tag consists of 4 byte triplets. The first 4 byts are the name of the tag. The next four bytes are the offset of the data in the icc file. The next four bytes define the size of the tags data.
We are interested in the 'desc' tag (see page 63 in the specification).
The description itself starts again with 'desc' then four bytes are reserved. The next four bytes define the size of the ICC profiles name.
In code it works like this:
$image = new imagick('/path/to/img');
try {
$existingICC = $image->getImageProfile('icc');
} catch (ImagickException $e) {
// Handle it
$existingICC = null;
}
if($existingICC) {
// Search the start of the description tag in the tag table.:
// We are not looking in the 128 bytes for the header + 4 bytes for the size of the table
$descTagPos = stripos( $existingICC, 'desc', 131 );
if( $descTagPos === false) {
// There is no description, handle it.
} else {
// This is the description Tag ( 'desc'|offset|size each with a size of 4 bytes
$descTag = substr( $existingICC, $descTagPos, 12 );
// Get the offset out of the description tag, unpack it from binary to hex and then from hex to decimal
$descTagOffset = substr ( $descTag, 4, 4 );
$descTagOffset = unpack( 'H*', $descTagOffset );
$descTagOffset = hexdec( $descTagOffset[1] );
// Same for the description size
$descTagSize = substr ( $existingICC, $descTagPos + 8, 4 );
$descTagSize = unpack('H*', $descTagSize);
$descTagSize = hexdec( $descTagSize[1] );
// Here finally is the descripton
$iccDesc = substr( $existingICC, $descTagOffset, $descTagSize );
// See page 63 in the standard, here we extract the size of the ICC profile name string
$iccNameSize = substr( $iccDesc, 8, 4 );
$iccNameSize = unpack( 'H*', $iccNameSize);
$iccNameSize = hexdec( $iccNameSize[1]);
// Finally got the name.
$iccName = substr( $iccDesc, 12, $iccNameSize );
echo "ICC name: $iccName\n";
}
}

using regex to separate local, youtube or vimeo video

I am making a video playback website and I need to use a html5 video player to play local videos and youtube api and vimeo api to play vimeo videos. THE problem is I want to filter the link entered by the user for all 3 conditions. I tried some regex as I never used it before but was not successful. Can anyone help me giving a example showing how to separate those links for making 3 conditions
taking out the word "youtube" out of a youtube link so that i could make a condition statement
same way taking out .mp4 and .ogg extension from the local video so that it can be used to be played in a html5 video player
same way extract the word "vimeo" from a vimeo link so that I can use a vimeo api to play vimeo videos.
Can anyone help?
For example we input a youtube link
http://www.youtube.com/watch?v=example
Then how to get the word "youtube" out of this link?
And I uploaded a local video with file name
example.mp4
Then how can I get the extensoon mp4 from that?
This is adapated from a php class I wrote some times ago :
<?php
function identifyService ( $url )
{
$url = preg_replace('#\#.*$#', '', trim($url));
$services_regexp = array(
"#^\w+\.(?P<format>[a-zA-Z0-9]{2,5})#" => 'local',
'#vimeo\.com\/(?P<id>[0-9]*)[\/\?]?#i' => 'vimeo',
'#youtube\.[a-z]{0,5}/.*[\?&]?v(?:\/|=)?(?P<id>[^&]*)#i' => 'youtube'
);
foreach ( $services_regexp as $pattern => $service ) {
if ( preg_match ( $pattern, $url, $matches ) ) {
return ( $service === 'local' ) ? $matches['format'] : $service;
}
}
return false;
}
$url = "foo.ogg";
// $url = "bar.mp4";
// $url = "http://www.youtube.com/watch?v=_rqR8_mOp_A";
// $url = "http://vimeo.com/39044814";
$service = identifyService( $url );
var_dump( $service );
?>
Hope it helps.

Categories