Question

I'm trying to update a video thumbnail on YouTube using the YouTube API, with the google-api-php-client library. We're on version 1.0.3-beta.

I've copied/pasted the example, and changed our client_id and client_secret to values which I know work because I can still upload videos using those values right now, I just can't set a thumbnail (on a video I've just uploaded using the same credentials).

This is the error I get:

An client error occurred: Error calling PUT https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId=wL3Rt0sokdI&uploadType=resumable&upload_id=AEnB2UqFI4w1qO1gjoFS-fOlc61OthOht0ngdFAcdG9Nnufds61IyMIUUxf1rAvmoDl77LeEQZb1-HMyqtc9Op3Jg4hRfcyuOQ: (403) Forbidden

Edit - More info: this is a snippet of information I get when printing out the entire exception:

{
    ["errors":protected]=> array(1) 
    {
        [0]=> array(5) { 
            ["domain"]=> string(17) "youtube.thumbnail" 
            ["reason"]=> string(9) "forbidden" 
            ["message"]=> string(9) "Forbidden" 
            ["locationType"]=> string(6) "header" 
            ["location"]=> string(13) "Authorization" 
    } 
}

Here's the script I'm using (it's the same as the example code but I'm putting it here just in case the example URL above goes down):

/**
 * This sample uploads and sets a custom thumbnail for a video.
 *
 * 1. It uploads an image using the "Google_MediaFileUpload" class.
 * 2. It sets the uploaded image as a custom thumbnail to the video by
 *    calling the API's "youtube.thumbnails.set" method
 *
 * @author Ibrahim Ulukaya
*/


// Call set_include_path() as needed to point to your client library.
set_include_path('/path/to/google-api-php-client/src/');
require_once('Google/Client.php');
require_once('Google/Service/YouTube.php');
session_start();

/*
 * You can acquire an OAuth 2.0 client ID and client secret from the
 * Google Developers Console <https://cloud.google.com/console>
 * For more information about using OAuth 2.0 to access Google APIs, please see:
 * <https://developers.google.com/youtube/v3/guides/authentication>
 * Please ensure that you have enabled the YouTube Data API for your project.
 */
$OAUTH2_CLIENT_ID = 'OURCLIENTIDWASHERE';
$OAUTH2_CLIENT_SECRET = 'OURCLIENTSECRETWASHERE';

$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes('https://www.googleapis.com/auth/youtube');
$redirect = filter_var('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'],
    FILTER_SANITIZE_URL);
$client->setRedirectUri($redirect);

// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);

if (isset($_GET['code'])) {
  if (strval($_SESSION['state']) !== strval($_GET['state'])) {
    die('The session state did not match.');
  }

  $client->authenticate($_GET['code']);
  $_SESSION['token'] = $client->getAccessToken();
  header('Location: ' . $redirect);
}

if (isset($_SESSION['token'])) {
  $client->setAccessToken($_SESSION['token']);
}

// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
  try{

    // REPLACE this value with the video ID of the video being updated.
    $videoId = "wL3Rt0sokdI";

    // REPLACE this value with the path to the image file you are uploading.
    $imagePath =     "/path/to/image.jpg";

    // Specify the size of each chunk of data, in bytes. Set a higher value for
    // reliable connection as fewer chunks lead to faster uploads. Set a lower
    // value for better recovery on less reliable connections.
    $chunkSizeBytes = 1 * 1024 * 1024;

    // Setting the defer flag to true tells the client to return a request which can be     called
    // with ->execute(); instead of making the API call immediately.
    $client->setDefer(true);

    // Create a request for the API's thumbnails.set method to upload the image and     associate
    // it with the appropriate video.
    $setRequest = $youtube->thumbnails->set($videoId);

    // Create a MediaFileUpload object for resumable uploads.
    $media = new Google_Http_MediaFileUpload(
        $client,
        $setRequest,
        'image/jpeg',
        null,
        true,
        $chunkSizeBytes
);
$media->setFileSize(filesize($imagePath));


// Read the media file and upload it chunk by chunk.
$status = false;
$handle = fopen($imagePath, "rb");
while (!$status && !feof($handle)) {
  $chunk = fread($handle, $chunkSizeBytes);
  $status = $media->nextChunk($chunk);
}

fclose($handle);

// If you want to make other calls after the file upload, set setDefer back to false
$client->setDefer(false);


$thumbnailUrl = $status['items'][0]['default']['url'];
$htmlBody .= "<h3>Thumbnail Uploaded</h3><ul>";
$htmlBody .= sprintf('<li>%s (%s)</li>',
    $videoId,
    $thumbnailUrl);
$htmlBody .= sprintf('<img src="%s">', $thumbnailUrl);
$htmlBody .= '</ul>';


} catch (Google_ServiceException $e) {
  $htmlBody .= sprintf('<p>A service error occurred: <code>%s</code></p>',
      htmlspecialchars($e->getMessage()));
} catch (Google_Exception $e) {
  $htmlBody .= sprintf('<p>An client error occurred: <code>%s</code></p>',
      htmlspecialchars($e->getMessage()));
}

$_SESSION['token'] = $client->getAccessToken();
} else {
  // If the user hasn't authorized the app, initiate the OAuth flow
  $state = mt_rand();
  $client->setState($state);
  $_SESSION['state'] = $state;

  $authUrl = $client->createAuthUrl();
  $htmlBody = <<<END
  <h3>Authorization Required</h3>
  <p>You need to <a href="$authUrl">authorize access</a> before proceeding.<p>
END;
}
?>

<!doctype html>
<html>
<head>
<title>Claim Uploaded</title>
</head>
<body>
  <?=$htmlBody?>
</body>
</html>
Was it helpful?

Solution

I finally figured out the answer. The YouTube account didn't have permission to upload custom thumbnails (despite being able to "choose" a thumbnail from the YouTube backend.

You can find a list of features enabled on the account at the following URL: http://www.youtube.com/features

In my case, I needed the custom thumbnails permission which wasn't enabled: Custom thumbnails

Apparently verifying your YouTube account grants this permission, as long as your account is in good standing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top