PHP API Youtube Uploads, исключение: Не удалось запустить возобновляемую загрузку, загрузка должна быть отправлена ​​на URL-адрес загрузки

Я пытаюсь создать серверное приложение для загрузки видео на YouTube. В моем серверном приложении пользователь может загружать видео прямо на мой канал YouTube, чтобы сделать его общедоступным.

введите описание изображения здесь

  1. Клиентская часть моего приложения приобретает видео и загружает его на мой сервер.
  2. Затем мой сервер использует YouTube API для загрузки видео на мой канал YouTube.

Чтобы сделать эту работу, я создал фиктивное веб-приложение, которое может захватить обновленный токен, и я сохранил его в файле key.txt

 {"access_token":"MYTOKEN","token_type":"Bearer","expires_in":3600,"created":1435654774} 

Сценарий upload_video.php автоматически обновит файл "key.txt" если access_token устарел. Это код из upload_video.php :

 $key = file_get_contents('key.txt'); $application_name = 'YouTube_Upload'; $client_secret = 'MY_CLIENT_SECRET'; $client_id = 'MY_CLIENT_ID'; $scope = array('https://www.googleapis.com/auth/youtube.upload', 'https://www.googleapis.com/auth/youtube', 'https://www.googleapis.com/auth/youtubepartner'); $videoPath = "Test.f4v"; $videoTitle = "A tutorial video"; $videoDescription = "A video tutorial on how to upload to YouTube"; $videoCategory = "22"; $videoTags = array("youtube", "tutorial"); try{ // Client init $client = new Google_Client(); $client->setApplicationName($application_name); $client->setClientId($client_id); $client->setAccessType('offline'); $client->setAccessToken($key); $client->setScopes($scope); $client->setClientSecret($client_secret); if ($client->getAccessToken()) { /** * Check to see if access token has expired. If so, get a new one and save it to file for future use. */ if($client->isAccessTokenExpired()) { $newToken = json_decode($client->getAccessToken()); $client->refreshToken($newToken->refresh_token); file_put_contents('key.txt', $client->getAccessToken()); } $youtube = new Google_Service_YouTube($client); // Create a snipet with title, description, tags and category id $snippet = new Google_Service_YouTube_VideoSnippet(); $snippet->setTitle($videoTitle); $snippet->setDescription($videoDescription); $snippet->setCategoryId($videoCategory); $snippet->setTags($videoTags); // Create a video status with privacy status. Options are "public", "private" and "unlisted". $status = new Google_Service_YouTube_VideoStatus(); $status->setPrivacyStatus('unlisted'); // Create a YouTube video with snippet and status $video = new Google_Service_YouTube_Video(); $video->setSnippet($snippet); $video->setStatus($status); // Size of each chunk of data in bytes. Setting it higher leads faster upload (less chunks, // for reliable connections). Setting it lower leads better recovery (fine-grained chunks) $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); /** * Video has successfully been upload */ if ($status->status['uploadStatus'] == 'uploaded') { // Actions to perform for a successful upload // ...... } // If want to make other calls after the file upload, set setDefer back to false $client->setDefer(true); } else{ // @TODO Log error echo 'Problems creating the client'; } } catch(Google_Service_Exception $e) { print "Google_Service_Exception ".$e->getCode(). " message is ".$e->getMessage(); print "Stack trace is ".$e->getTraceAsString(); }catch (Exception $e) { print "Exception ".$e->getCode(). " message is ".$e->getMessage(); print "Stack trace is ".$e->getTraceAsString(); } 

Когда скрипт запускается, он вызывает это исключение:

 Exception 0 message is Failed to start the resume-able upload (HTTP 400: global, Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/youtube/v3/videos?part=status,snippet&uploadType=resumable)Stack trace is #0 D:\xampp\htdocs\youtube\src\Google\Http\MediaFileUpload.php(136): Google_Http_MediaFileUpload->getResumeUri() #1 D:\xampp\htdocs\youtube\resumable_upload.php(100): Google_Http_MediaFileUpload->nextChunk('\x00\x00\x00\x1Cftypf4v \x00\x00\x00...') #2 {main} 

исключение getResumeUri() на getResumeUri() (строка 281) в Google_Http_MediaFileUpload , у меня есть var dump ответ из Google

 Google_Http_Request Object ( [batchHeaders:Google_Http_Request:private] => Array ( [Content-Type] => application/http [Content-Transfer-Encoding] => binary [MIME-Version] => 1.0 ) [queryParams:protected] => Array ( [part] => status,snippet [uploadType] => resumable ) [requestMethod:protected] => POST [requestHeaders:protected] => Array ( [content-type] => application/json; charset=UTF-8 [authorization] => Bearer XXXXXXXXXXXXXXXX [content-length] => 187 [x-upload-content-type] => video/* [x-upload-content-length] => 10201286 [expect] => ) [baseComponent:protected] => https://www.googleapis.com//upload [path:protected] => /youtube/v3/videos [postBody:protected] => {"snippet":{"categoryId":"22","description":"A video tutorial on how to upload to YouTube","tags":["youtube","tutorial"],"title":"A tutorial video"},"status":{"privacyStatus":"unlisted"}} [userAgent:protected] => [canGzip:protected] => [responseHttpCode:protected] => 400 [responseHeaders:protected] => Array ( [x-guploader-uploadid] => XXXXXXXXXXXXXXXXXXXXXXXXXX [location] => https://www.googleapis.com/upload/youtube/v3/videos?part=status,snippet&uploadType=resumable [vary] => Origin X-Origin [content-type] => application/json; charset=UTF-8 [content-length] => 468 [date] => Fri, 10 Jul 2015 09:54:30 GMT [server] => UploadServer [alternate-protocol] => 443:quic,p=1 ) [responseBody:protected] => { "error": { "errors": [ { "domain": "global", "reason": "wrongUrlForUpload", "message": "Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/youtube/v3/videos?part=status,snippet&uploadType=resumable" } ], "code": 400, "message": "Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/youtube/v3/videos?part=status,snippet&uploadType=resumable" } } [expectedClass:protected] => Google_Service_YouTube_Video [expectedRaw:protected] => [accessKey] => ) 

Что не так? Спасибо за любую помощь и извините за плохой английский.

Это, похоже, проблема с PHP Client Library API Google. Перейдите в GOOGLE_LIB_PATH / Http / MediaFileUpload.php и замените эту строку:

 $this->request->setBaseComponent($base . '/upload'); 

С этим:

 $this->request->setBaseComponent($base . 'upload'); 

Повторите попытку и поделитесь результатами. Я столкнулся с аналогичной проблемой с API Google Pubsub, где неправильный путь API, установленный библиотекой.

Надеюсь, вам понадобятся возобновляемые загрузки ( https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol )

Затем используйте это без каких-либо изменений.

Также проверьте, поддерживается ли видеоформат с https://support.google.com/youtube/troubleshooter/2888402?hl=ru

Существует метод google для получения токена обновления, поэтому вместо использования json_decode:

 $newToken = json_decode($client->getAccessToken()); $client->refreshToken($newToken->refresh_token); 

Ты можешь сделать :

 $client->refreshToken( $client->getRefreshToken() ); 

Это то, что я до сих пор тестировал и работал нормально.

 $key = trim(file_get_contents('key.txt')); $scope = 'https://www.googleapis.com/auth/youtube';