Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to upload Video to YouTube using Google API PHP Client Library and Youtube API V3?

Trying to simply upload video using Google API PHP Client (latest release 1.1.6), but code in Youtube API V3 is not working and giving 500 internal server error.

What is wrong with code below when I am not using any bleeding edge beta version, I have just masked 3 parameters below otherwise it is copied form Youtube API V3.

  require_once 'google-api-php-client/src/Google/Client.php';
  require_once 'google-api-php-client/src/Google/Service/YouTube.php';

  session_start();

  $OAUTH2_CLIENT_ID = 'CHANGE1-0osfh0p5h80o9ol2uqtsjq5i7r1jun.apps.googleusercontent.com';
  $OAUTH2_CLIENT_SECRET = 'CHANGE2azMpt__VdSt9';

  $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 path to the file you are uploading.
      $videoPath = "/CHANGE3/videos/test.mp4";

      // Create a snippet with title, description, tags and category ID
      // Create an asset resource and set its snippet metadata and type.
      // This example sets the video's title, description, keyword tags, and
      // video category.
      $snippet = new Google_Service_YouTube_VideoSnippet();
      $snippet->setTitle("Test title");
      $snippet->setDescription("Test description");
      $snippet->setTags(array("tag1", "tag2"));

      // Numeric video category. See
      // https://developers.google.com/youtube/v3/docs/videoCategories/list 
      $snippet->setCategoryId("22");

      // Set the video's status to "public". Valid statuses are "public",
      // "private" and "unlisted".
      $status = new Google_Service_YouTube_VideoStatus();
      $status->privacyStatus = "public";

      // Associate the snippet and status objects with a new video resource.
      $video = new Google_Service_YouTube_Video();
      $video->setSnippet($snippet);
      $video->setStatus($status);

      // 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 videos.insert method to create and upload the video.
      $insertRequest = $youtube->videos->insert("status,snippet", $video);

      // Create a MediaFileUpload object for resumable uploads.
      $media = new Google_Http_MediaFileUpload(
          $client,
          $insertRequest,
          'video/*',
          null,
          true,
          $chunkSizeBytes
      );
      $media->setFileSize(filesize($videoPath));


      // Read the media file and upload it chunk by chunk.
      $status = false;
      $handle = fopen($videoPath, "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);


      $htmlBody .= "<h3>Video Uploaded</h3><ul>";
      $htmlBody .= sprintf('<li>%s (%s)</li>',
          $status['snippet']['title'],
          $status['id']);

      $htmlBody .= '</ul>';

    } catch (Google_Service_Exception $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;
  }
  echo $htmlBody;

A service error occurred: Error calling PUT https://www.googleapis.com/upload/youtube/v3/videos?part=status%2Csnippet&uploadType=resumable&upload_id=AEnB2UpXd4UQ0dt-v2_8YLzDp4KAywZQUIgUEm3Lxyv7nV_ZLAHghu6RiNE0e82xMMGx9ztQvTdYGFwvSNP5yJiOdffS0CuG-Q: (400) Failed to parse Content-Range header.

Don't mark it duplicate of very old and deprecated questions below, as you can see other questions even included files in their code that are not present in latest Google API PHP Client library or are referring to dead Google Code Project. Similar outdated question 1, 2, 3, 4, 5

like image 416
XIMRX Avatar asked Jan 22 '16 19:01

XIMRX


2 Answers

Strangely a very small tweak in code fixes the problem.

Instead of just $videoPath = "/path/to/file.mp4"; using DOCUMENT_ROOT solves the issue. Other than that code of documentation is perfect.

$videoPath = $_SERVER["DOCUMENT_ROOT"] . "/mapapp/videos/test.mp4";
like image 122
XIMRX Avatar answered Oct 13 '22 15:10

XIMRX


for other whoe comes around and deal with "Failed to parse Content-Range header"

I was searching for 3 days and finaly i found my solution...

my file was bigger then 4gb and xampp on windows (my webserver tool) is just 32bit so the fopen() command could not read my big files.

I installaed apache 64bit and php7 64bit by my own and it is gone

At this moment my script finaly loads chunks on big files

794 - 07:14:15 - 832569344
795 - 07:14:16 - 833617920
796 - 07:14:17 - 834666496
797 - 07:14:18 - 835715072
798 - 07:14:19 - 836763648
799 - 07:14:19 - 837812224
800 - 07:14:20 - 838860800
801 - 07:14:21 - 839909376
802 - 07:14:22 - 840957952
803 - 07:14:23 - 842006528
804 - 07:14:24 - 843055104

allready 804 chunks ^^ no truncate nothign :D just uploading flawless

like image 37
Daniel Knuth Avatar answered Oct 13 '22 15:10

Daniel Knuth