2
votes

I use a PHP script to upload some daily videos to a Youtube channel (based on this code sample: https://developers.google.com/youtube/v3/code_samples/php#resumable_uploads)

The problem is after this loop:

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

Normally the $status variable has the video id ($status['id']) after the upload is complete but since mid January all the uploads failed with one of this errors:

  • $status variable value stills as "false"
  • Inside the catch, the Google_Service_Exception message is like "A service error occurred: Error calling PUT https://www.googleapis.com/upload/youtube/v3/videos?part=status%2Csnippet&uploadType=resumable&upload_id=xxx: (400) Invalid request. The number of bytes uploaded is required to be equal or greater than 262144, except for the final request (it's recommended to be the exact multiple of 262144). The received request contained nnn bytes, which does not meet this requirement.", where nnn is less than 262144 and seems to be the last request.

When I access the Youtube channel I can see the new videos with a status "Preparing upload" or stuck with a fixed percentage.

My code has not changed for months but now I can't upload any new video.

Anyone can please help me to know what's wrong? Thanks in advance!

2
You may check this thread. Maybe the error is because of the library gcs-resumable-upload. It creates/re-uses a JSON file to store the progress of the resumable upload. Try to check ~/.config/configstore/gcloud-node.json then remove it to see if works.abielita
Thanks for your answer! I think the PHP library (github.com/google/google-api-php-client/tree/1.1.6) hasn't that file, that thread looks like a solution for npm package.Astor

2 Answers

1
votes

Maybe you can try like that and then let MediaFileUpload cut the chunk itself:

$media = new \Google_Http_MediaFileUpload(
   $client,
   $insertRequest,
   'video/*',
   file_get_contents($pathToFile),  <== put file content instead of null
   true,
   $chunkSizeBytes
);
$media->setFileSize($size);

$status = false;
while (!$status) {
   $status = $media->nextChunk();
}
2
votes

The solution proposed by @pom (thanks by the way) doesn't really solve this issue if you need to implement a progress indicator.

I'm facing the same problem than @astor; after calling ->nextChunk for the final chunk i get:

The number of bytes uploaded is required to be equal or greater than 262144, except for the final request (it's recommended to be the exact multiple of 262144). The received request contained 38099 bytes, which does not meet this requirement.

See this log file :

The code is copy-paste from the google/google-api-php-client doc. The log file shows the size of the first chunk being a bit superior to the others (except the last one) which i couldn't explain. Another "strange" thing is that its size changes test after test. The size of the last chunk seems correct, and at the end all bytes should have been uploaded. However, uploading the remaining bytes in the last chunk ->nextChunk($chunk) throws this error.

One important precision is that my source file is on AWS S3. File operations (filesize, fread, fopen) are done with the Amazon S3 Stream Wrapper. It may add some headers or IDK that causes the problem. EDIT: I don't have such problem with local files

Has anyone run into the same problem? ?

...
  $chunkSizeBytes = 5 * 1024 * 1024;
  $client->setDefer(true);
  $request = $service->files->create($file);

  $media = new Google_Http_MediaFileUpload(
      $client,
      $request,
      'text/plain',
      null,
      true,
      $chunkSizeBytes
  );
  $media->setFileSize(filesize(TESTFILE));
  // Upload the various chunks. $status will be false until the process is
  // complete.
  $status = false;
  $handle = fopen(TESTFILE, "rb");
  while (!$status && !feof($handle)) {
    // read until you get $chunkSizeBytes from TESTFILE
    // fread will never return more than 8192 bytes if the stream is read buffered and it does not represent a plain file
    // An example of a read buffered file is when reading from a URL
    $chunk = readVideoChunk($handle, $chunkSizeBytes);
    $status = $media->nextChunk($chunk);
  }
  // The final value of $status will be the data from the API for the object
  // that has been uploaded.
  $result = false;
  if ($status != false) {
    $result = $status;
  }
  fclose($handle);
}
function readVideoChunk ($handle, $chunkSize)
{
    $byteCount = 0;
    $giantChunk = "";
    while (!feof($handle)) {
        // fread will never return more than 8192 bytes if the stream is read buffered and it does not represent a plain file
        $chunk = fread($handle, 8192);
        $byteCount += strlen($chunk);
        $giantChunk .= $chunk;
        if ($byteCount >= $chunkSize)
        {
            return $giantChunk;
        }
    }
    return $giantChunk;
}