2015-11-23 7 views
28

Sto utilizzando l'API di YouTube per caricare video pezzo per pezzo (vedere il codice seguente). Tuttavia, il caricamento a volte fallisce con file più grandi (+ 1 GB), ma non sempre. Il caricamento è mostrato come completo ma possono essere riprodotti solo un paio di minuti e il resto viene troncato. Ho fatto some research ma senza successo apparente. Le mie domande ora:L'API YouTube tronca i video [PHP]

  • C'è la possibilità di contattare direttamente YouTube (vedere i registri di ciò che sta realmente accadendo)?
  • Si tratta di un problema di codifica?
  • L'errore può essere rilevato/rilevato tramite l'API (al momento non viene generata alcuna eccezione)
  • Questo può accadere se si caricano video diversi contemporaneamente (in parallelo, cioè)?
  • Qualcun altro ha riscontrato questo problema?

Qualsiasi aiuto/guida nella giusta direzione è molto apprezzato. Mi piacerebbe anche chiamare fuori una taglia di 500 punti come questo sono io facendo impazzire (appena fatto che ...)

Appendice: Lo script è eseguito su una riga di comando, attraverso un Gearman Server, con set_time_limit(0); set . Il codice/funzione è solo un estratto (e funziona alla grande con file più piccoli, a volte anche fino a 10 GB).

EDIT: Secondo aergistal e di commenti di GeorgeQ sopra, ho cambiato il ciclo while per leggere pezzi direttamente (senza feof() più) e salvare lo stato nel database.

/* 
    Uploads one file to youtube chunk by chunk 
*/ 
function uploadFile($dbfile) { 
    $client = $this->client; 
    $youtube = new Google_Service_YouTube($client); 
    $htmlBody = ""; 

    try { 
     // 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("SO Example"); 

     // 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 = "private"; 

     // 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($dbfile->localfile)); 

     // Read the media file and upload it chunk by chunk. 
     $status = false; 
     $handle = fopen($dbfile->localfile, "rb"); 

     while (!$status && ($chunk = (fread($handle, $chunkSizeBytes))) !== FALSE) { 
      $status = $media->nextChunk($chunk); 
      $data = array("filename" => $dbfile->localfile, "status" => print_r($status, true)); 
      $db->saveLog($data); 
     } 

     /* the old code 
     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); 

     $log = array("success" => true, "snippet_id" => $status["id"]); 
    } catch (Google_ServiceException $e) { 
     $log = array("success" => false, "errormsg" => $e->getMessage()); 
    } catch (Google_Exception $e) { 
     $log = array("success" => false, "errormsg" => $e->getMessage()); 
    } 

    return $log; 
} 
+1

come sono in esecuzione il sceneggiatura? Attraverso un browser o una riga di comando? – DaImTo

+0

@DaImTo Riga di comando, server Gearman. Ho cambiato la domanda per riflettere le informazioni aggiuntive. – Jan

+1

Come nota a margine [Perché è male usare feof() per controllare un loop] (http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong). È anche possibile creare un ciclo infinito se il puntatore del file è per qualche motivo non valido. – aergistal

risposta

8

C'è la possibilità di contattare direttamente su YouTube (che vedono tronchi di ciò che sta realmente accadendo)?

Bene, questa è una missione impossibile. È necessario inviare loro numerose mail per (forse) ottenere una risposta. Ho provato alcune volte, ma nessuna risposta da parte loro.

Si tratta di un problema di codifica?

Sì, questo è un problema di codifica. Se stai cercando di caricare un video HD, e se viene troncato o abbreviato o di qualsiasi tipo, si tratta di un problema di codifica. YouTube li ha periodicamente.

Può l'errore di essere catturati/rilevata tramite l'API (al momento, non fa eccezione viene lanciata)

No, non può. Devi vedere il video quando viene caricato per visualizzare un errore. Non c'è eccezione nel mezzo del processo o in qualsiasi parte del caricamento.

Questo può accadere se si stanno caricando video diversi contemporaneamente (nel parallelo )?

Non importa. Se stai caricando un video o due, tre, cinque video contemporaneamente, non importa. È solo un upload. Solo la cosa negativa che potrebbe accadere nel processo è una perdita di connessione. Ogni video va nella sua stessa direzione. È come quando copi più file da una cartella all'altra.

Qualcun altro ha riscontrato questo problema?

Sì. Tu, io e un sacco di altri caricatori. È un problema di YouTube. È il loro bug o qualche codifica/rendering/transcodifica, qualunque sia il loro problema. Tutto dipende dalle scelte di elaborazione di YouTube.

Quando è successo a me, la mia soluzione era usare HTTPS/SSL quando ho caricato il video. E ha funzionato. Non c'era nessun problema di taglio, ritaglio, transcodifica, codifica/rendering.

+2

Questo odora di vincere la taglia :-) Risposta buona e dettagliata. Mentre sto caricando i video a livello di codice, come garantire di utilizzare HTTPS tramite l'SDK? – Jan

+1

Basta configurare il certificato e funzionerà. Ecco un ottimo inizio per entrare nello stesso paniere con ssl. -> http://developer.android.com/training/articles/security-ssl.html –

2

sembra che lo script sia scaduto. provare questo codice nella prima riga: set_time_limit(0);

+1

No, l'ho già impostato. Il codice sopra è solo un estratto. – Jan

+0

@Jan Immagino che volesse solo "rubare" la taglia ;-) –

+1

@MarkusSafar: Ma non sul mio orologio ;-) Sinceramente, se funzionasse, darei volentieri la taglia, ma fino ad ora, non è purtroppo. – Jan

2

Il caricamento è completo ma è possibile riprodurre solo un paio di minuti e il resto viene troncato. Ho fatto delle ricerche ma senza un evidente successo.

Si tratta di un problema di codifica?

Ok .. si sta utilizzando il caricamento "Chunked". In altre parole: è un caricamento "ripristinabile" come descritto nello YT Upload API.

La mia prima ipotesi: è un problema di intestazione content-range (di una delle richieste). Tutte le parti devono essere perfettamente allineate a byte sul lato server YT, altrimenti si finirà con solo la prima parte del file binario. Riferimento: Upload Chunks e si prega di notare la casella blu su Content Range Header.

Il google-api-php-client deve gestirlo correttamente. Ma a livello di bug potrebbe essere qualsiasi cosa: API out-of-sync con il client, problema di configurazione cURL, intestazione non impostata, intervallo non calcolato correttamente.

Può l'errore di essere catturati/rilevata tramite l'API (al momento, non viene generata un'eccezione)

test del client non è il tuo lavoro. Si dovrebbe abilitare GuzzleHttp\RequestOptions::DEBUG per vedere se tutte le intestazioni sono corrette. Quindi potresti provare a tirare lo stato del caricamento in parallelo al caricamento stesso (seconda richiesta di guzzle).

C'è la possibilità di contattare direttamente YouTube (vedere i registri di ciò che sta realmente accadendo)?

Sì, si sta utilizzando Google_Http_MediaFileUpload e fa parte di Google-API-PHP-client.

Basta aprire un problema nel corso al loro repo GitHub: https://github.com/google/google-api-php-client/issues


Il mio suggerimento è:

  • lasciare la cipolla PHP PHP(ext_curl(libcurl))) + yourscript(google-api-client(guzzle)))
    • PHP cipolla significa: lo script usa google-api-client, che usa guzzle, che usa php_ext_curl, che usa libc url internamente
    • si dispone di più livelli e gli errori possono capitare a tutti loro
    • bottom-line: consente semplicemente di bypassare lo stack PHP per il test dalla CLI
  • provare a riprodurre il problema di upload chunked sulla CLI utilizzando cURL
  • uso una seconda console di richiesta di stato del caricamento attiva tra pezzi caricati
  • poi, nel caso del caricamento da CLI
    • fallisce: indicherebbe un problema del server di YT
    • riesce: confronta le intestazioni dalla CLI contro lo script PHP (guzzle in modalità debug) per avvicinarsi al problema
+0

Grazie per aver esaminato questo. Tuttavia, non capisco completamente cosa intendi con la tua prima opzione (lascia la cipolla PHP) - cosa significa questa parte? – Jan

+0

Ok, ho aggiornato la mia risposta per spiegarlo un po '. (boxcon ... bel progetto!) –