2015-06-30 19 views
18

Sto provando a creare un'applicazione server per il caricamento di video su YouTube. Nella mia applicazione server, l'utente può caricare un video direttamente sul mio canale YouTube per renderlo pubblico.API PHP Uploads di YouTube, eccezione: impossibile avviare il caricamento ripristinabile, il caricamento deve essere inviato all'URL di caricamento

enter image description here

  1. La parte client della mia applicazione acquisisce il video e lo carica al mio server.
  2. Il mio server utilizza quindi l'API di YouTube per caricare il video sul mio canale YouTube.

per fare questo lavoro, ho creato una Web Application fittizio in grado di catturare il token di aggiornamento generato e ho memorizzato in un file key.txt

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

Lo script upload_video.php aggiornerà automaticamente "key.txt" file se access_token è scaduto. Questo è il codice da 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(); 
} 

Quando lo script viene eseguito, sollevare questa eccezione:

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} 

eccezione raise getResumeUri() (linea 281) in Google_Http_MediaFileUpload, ho var scaricare la risposta da parte di 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] => 
) 

Cosa c'è che non va? Grazie per l'aiuto e scusa per il pessimo inglese.

risposta

4

questo sembra essere un problema con PHP libreria client di Google API. Vai a GOOGLE_LIB_PATH/HTTP/MediaFileUpload.php e sostituire questa linea:

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

Con questo:

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

prova di nuovo e condividere i risultati. Ho riscontrato un problema simile con l'API di Google Pubsub in cui il percorso dell'API impostato dalla libreria non era corretto.

+0

perfetto, grazie! – ar099968

+1

corretti negli ultimi commit su github –

1

spero è necessario ripristinabili Upload (https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol)

Quindi utilizzare this senza alcuna modifica.

Controllare anche se il formato video è supportato da https://support.google.com/youtube/troubleshooter/2888402?hl=en

+0

Il mio codice è già ispirato all'esempio resumable_upload.php di google. – ar099968

+0

@ ar099968 Il codice non è in grado di ottenere l'Uri ripristinabile il che significa che non può essere caricato come ripristinabile, come sottolineato da Mithun –

+0

@FurhanShabir Non capisco. Ho utilizzato un esempio riassumibile da google ... – ar099968

1

C'è un metodo di Google per ottenere il token di aggiornamento, quindi invece di utilizzare json_decode:

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

si può fare:

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

grazie per il suggerimento – ar099968

-1

Questo è quello che ho testato finora e che funziona bene.

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