Recuperare automaticamente l'immagine di YouTube per la miniatura?
Ho un tipo di post personalizzato che accetta un frammento HTML di embed di YouTube, un titolo e un'immagine in evidenza. Attualmente, devo cercare manualmente un'immagine per l'immagine in evidenza, ma idealmente vorrei poter scaricare e ridimensionare automaticamente il primo fotogramma del video stesso basandomi sull'URL del video durante il processo di salvataggio del post. Se fatto correttamente, il mio tipo di post potrebbe richiedere solo il link e ottenere sia l'immagine che il codice di embed da quello.
Ad esempio, se il link del video è http://www.youtube.com/watch?v=2Jnpi-uBiIg il valore di v verrebbe estratto e utilizzato per scaricare l'immagine all'indirizzo http://img.youtube.com/vi/2Jnpi-uBiIg/0.jpg.
Sono molto nuovo nello sviluppo di WordPress, ma qualcosa mi dice che dovrei guardare agli hook (se li ho capiti correttamente).

Ciao @Jonathan Sampson:
Anche se non è esattamente quello che hai chiesto, potrebbe essere una soluzione valida e gratuita grazie a WordPress.com, come menzionato da @yoast in un tweet stamattina, riferendosi a questo articolo:
In pratica, puoi utilizzare il generatore di screenshot di WordPress.com con un URL in questo formato (che, secondo il blog post, Matt sembra aver approvato per un uso gratuito):
https://s.wordpress.com/mshots/v1/{URL-codificato}?w={larghezza}
Prendendo il tuo URL di esempio:
E codificandolo per l'uso con il generatore di screenshot, ottieni un URL simile a questo (per una larghezza di 400px):
https://s.wordpress.com/mshots/v1/http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D2Jnpi-uBiIg?w=400
Ecco come appare lo screenshot (ho copiato l'immagine per conservarla, quindi non cambierà anche se il servizio WordPress viene modificato, invece di includere un link diretto al servizio per visualizzare l'immagine.) Non sono sicuro del perché abbia catturato solo il video e non l'intera pagina, ma il video è ancora meglio per quello che ti serve:
(fonte: mikeschinkel.com)
Ovviamente, la prima volta che fai una richiesta HTTP GET all'URL, non otterrai lo screenshot perché i server di WordPress.com devono prima acquisire l'immagine, il che richiede troppo tempo per far attendere la tua richiesta. Quindi, alla prima richiesta, verrai reindirizzato a questo URL:
https://s.wordpress.com/wp-content/plugins/mshots/default.gif
E questo URL mostra questa immagine:
Ma se attendi un minuto dopo la prima richiesta e la ripeti, otterrai lo screenshot. Penso che quello che vorrai fare sia richiamarlo per memorizzarlo nella cache, attendere il download e poi conservarlo localmente sul tuo server per ridurre il carico sui server di WordPress.com, evitando che decidano di limitare questo servizio gratuito (o addirittura, se il traffico è sufficiente, potrebbero renderlo a pagamento con funzionalità API aggiuntive!)
P.S. A proposito, per dimostrare che funziona davvero in una pagina web, ecco lo screenshot richiesto direttamente da WordPress.com. Nota che potrebbe essere diverso dall'immagine che ho salvato e linkato sopra, oppure, se è passato molto tempo dall'ultima visualizzazione di questa pagina e la loro cache è stata cancellata, potrebbe mostrare l'immagine "Generating Preview". In tal caso, aspetta un minuto e aggiorna la pagina per visualizzare lo screenshot:

Il mio generatore di post per video blog (http://v.leau.co/) fa questo ma non in contesto WordPress.
Fornisci una query ad esempio "superman" (poi aspetti (senza alcuna notifica che sta facendo qualcosa) (dato che sono l'unico utente)), poi clicchi i video che vuoi postare, clicchi su genera codice e ottieni il codice dove le miniature sono ospitate sul mio sito perché nel frattempo le ha scaricate. Questo codice può essere copiato e incollato in un post.
In altre parole, se mettessi il codice in una funzione restituirebbe il pezzo di codice ad esempio un tag a con un link al video che viene aggiunto al contenuto oppure ad esempio il link all'immagine in evidenza che viene scaricata localmente.
È questo il codice che stai cercando? Penso che il nucleo sia:
Una funzione per recuperare più risultati (quindi se vuoi visualizzare più di 1 video nel codice risultante invece di 1 specifico):
function retrieveMoreResults($key, $q, $start, $cache) {
$url = "http://ajax.googleapis.com/ajax/services/search/video?v=1.0&q=" . $q . "&rsz=large&start=" . $start. "&key=" . $key;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_REFERER, $referer);
$body = curl_exec($ch);
curl_close($ch);
$responseData = json_decode($body, true);
$tempOutputString .= display($responseData, $cache, $q);
return $tempOutputString;
}
Una funzione per ottenere la pagina iniziale dei risultati:
function retrieveResults($key, $q, $cache) {
# prima chiamata
$url = "http://ajax.googleapis.com/ajax/services/search/video?v=1.0&q=" . $q . "&rsz=large&key=" . $key;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_REFERER, $referer);
$body = curl_exec($ch);
curl_close($ch);
$responseData = json_decode($body, true);
$tempOutputString = "";
$tempOutputString .= display($responseData, $cache, $q);
$boolFirstRequest = true;
foreach ($responseData["responseData"]["cursor"]["pages"] as $GsearchResultClass) {
$start = $GsearchResultClass["start"];
if ($boolFirstRequest) {
$boolFirstRequest = false;
} else {
$tempOutputString .= retrieveMoreResults($key, $q, $start, $cache);
}
}
return $tempOutputString;
}
Una funzione per visualizzare e scaricare le miniature in una certa directory (variabile) e per restituire un pezzo di codice da inserire nel post:
function display($responseData, $cache, $tag) {
$strBuffer="";
foreach ($responseData["responseData"]["results"] as $GsearchResultClass) {
#
# ci sono URL di YouTube e anche URL di Google Video, sono entrambi diversi
# quello di Google video contiene la parola "ThumbnailServer"
# esempio:
# youtube: http://1.gvt0.com/vi/6jKzr143K8U/default.jpg
# video.google: http://3.gvt0.com/ThumbnailServer2?app=vss&contentid=7efbd69963e4cc67&offsetms=30000&itag=w160&hl=en&sigh=J6N1fv_It6H5jJWX51fKt-eYqNk
#
$thumbId="";
$imageThumb=$GsearchResultClass["tbUrl"];
if (strstr($imageThumb, 'ThumbnailServer')) {
$imgStringBits = explode('&',$imageThumb);
$parsedImgStr=strstr($imgStringBits[1],'=');
$parsedImgStr = substr($parsedImgStr,1);
$thumbId = $parsedImgStr;
} else {
$imgStringBits = explode('/',$imageThumb);
$thumbId = $imgStringBits[4];
}
$imgFile=$cache . "/" . $thumbId . ".jpg";
#
# Ora che abbiamo il nome del file immagine controlliamo se già esiste nella cache:
# - se esiste NON cancellarlo mai (perché dovremmo?)
# - se non esiste... beh, recuperiamolo via curl
#
if (!file_exists($imgFile)) {
$ch = curl_init ();
$timeout = 5;
curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9) Gecko/2008052906 Firefox/3.0');
curl_setopt ($ch, CURLOPT_AUTOREFERER, true);
curl_setopt ($ch, CURLOPT_URL, $imageThumb);
curl_setopt ($ch, CURLOPT_HEADER, false);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($ch, CURLOPT_BINARYTRANSFER, true);
curl_setopt ($ch, CURLOPT_VERBOSE, 1);
$rawdata = curl_exec ($ch);
curl_close ($ch);
if($rawdata) {
$fp = fopen($imgFile, 'w');
fwrite($fp, $rawdata);
fclose($fp);
} else {
#
# Se la nostra azione Curl non recupera nulla allora usa l'immagine predefinita
#
$imgfile="images/default.jpg";
}
}
#
# Ora che abbiamo l'URL dell'immagine creiamo un div (hmm.. potremmo spostare lo
# stile successivamente in un CSS separato) contenente la miniatura del video, il link
# e la descrizione. Se ti piace puoi aggiungere tutti gli altri
# parametri che Google restituisce come durata ecc...
#
$strBuffer .= "<div style=\"float:left;width:125px;height:130px;font-size:8px;font-family:arial;\" class=\"thumb\"><div>";
$strBuffer .= "<a href=\"#\" class=\"del\" id=\"$thumbId\"> AGGIUNGI</a><br />";
$strBuffer .= "<a href=\"" . $GsearchResultClass["playUrl"] . "\" target=\"_blank\">";
$strBuffer .= "<img src=\"" . $imgFile . "\" alt=\"" . $GsearchResultClass["title"] . "\" border=\"0\" width=\"120\">";
$strBuffer .= "</a><br />\n";
#
# Nota che aggiungiamo anche un'opzione per eliminare, per ora rimuove solo dalla pagina
# ma nella prossima versione dovrebbe fare una chiamata AJAX per scrivere l'ID da qualche parte
# così che non lo vedremo più.
#
$strBuffer .= $GsearchResultClass["titleNoFormatting"] . "<br />";
$strBuffer .= "</div></div>\n";
}
return $strBuffer;
}
Una funzione per chiamare le precedenti:
function moviePage($tag, $cacheName, $cacheTime, $key) {
$cache = $cacheName . "/" . $tag;
checkCache($cache);
cleanCacheHTML($cache);
$filename = $tag . ".html";
$spFile=$cache . "/" . $filename;
if (file_exists($spFile) && filemtime($spFile) > $cacheTime ) {
$strBuffer = file_get_contents($spFile) . "<!-- " . $spFile . " from cache -->";
} else {
$strBuffer = retrieveResults($key, $tag, $cache);
}
$strBuffer .= "<br clear=\"all\">";
$fp = fopen($spFile, 'w');
fwrite($fp, $strBuffer);
fclose($fp);
return $strBuffer;
}
(la $key è la tua chiave API di Google) (http://code.google.com/intl/it-IT/more/)
IMHO penso che il resto sia più che altro "prendere il codice restituito e aggiungerlo al contenuto di un post + impostare la miniatura scaricata nella cache come immagine in evidenza?
P.S. IMHO è sempre meglio postare una miniatura in un video quando si fa riferimento a video di YouTube poiché spesso i video più vecchi vengono rimossi da YouTube e lasciano brutti post come risultato. Con le tue miniature almeno l'immagine rimane lì per sempre così che in seguito hai un'idea di cosa avevi postato originariamente.

ottima risposta! E se creassi un campo personalizzato per permettere all'utente di inserire l'URL sorgente del video e facessi eseguire il download dell'immagine/collegamento all'immagine locale al momento del salvataggio del post? Un ultimo passo sarebbe che quando aggiorni il post con un nuovo URL, la vecchia immagine viene eliminata e quella nuova viene aggiunta/collegata. Se potessi estendere il tuo codice con questa funzionalità penso che sarebbe molto utile per i lettori.

Non sono sicuro di aver capito esattamente cosa intendi, ma ho trovato questa soluzione alternativa:
http://wpworks.wordpress.com/2010/12/23/display-youtube-thumbnail-with-wordpress-custom-field/
Saluti

Funzione per visualizzare l'immagine basata sull'URL? È questo il tipo di cosa che avevi in mente?
function get_youtube_screen( $url = '', $type = 'default', $echo = true ) {
if( empty( $url ) )
return false;
if( !isset( $type ) )
$type = '';
$url = esc_url( $url );
preg_match("|[\\?&]v=([^&#]*)|",$url,$vid_id);
if( !isset( $vid_id[1] ) )
return false;
$img_server_num = 'i'. rand(1,4);
switch( $type ) {
case 'large':
$img = "<img src=\"http://{$img_server_num}.ytimg.com/vi/{$vid_id[1]}/0.jpg\" alt=\"Anteprima grande del video YouTube\" title=\"Anteprima video YouTube\" />";
break;
case 'first':
// Anteprima del primo frame
$img = "<img src=\"http://{$img_server_num}.ytimg.com/vi/{$vid_id[1]}/1.jpg\" alt=\"Primo frame del video YouTube\" title=\"Primo frame video YouTube\" />";
break;
case 'small':
// Anteprima di un frame successivo (non sono sicuro di come determinino quale)
$img = "<img src=\"http://{$img_server_num}.ytimg.com/vi/{$vid_id[1]}/2.jpg\" alt=\"Anteprima piccola del video YouTube\" title=\"Anteprima piccola video YouTube\" />";
break;
case 'default':
case '':
default:
$img = "<img src=\"http://{$img_server_num}.ytimg.com/vi/{$vid_id[1]}/default.jpg\" alt=\"Anteprima predefinita del video YouTube\" title=\"Anteprima video YouTube\" />";
break;
}
if( $echo )
echo $img;
else
return $img;
}
// Esempi di chiamata
get_youtube_screen( "http://www.youtube.com/watch?v=dZfmPREbTd8", 'default' );
get_youtube_screen( "http://www.youtube.com/watch?v=dZfmPREbTd8", 'large' );
get_youtube_screen( "http://www.youtube.com/watch?v=dZfmPREbTd8", 'small' );
get_youtube_screen( "http://www.youtube.com/watch?v=dZfmPREbTd8", 'first' );
YouTube sembra servire le immagini da alcuni server per le miniature..
iN.ytimg.com
Dove N è solitamente un valore numerico da 1 a 4 (a volte 5, ma non era coerente nei test).
Usano anche img.youtube.com
ma mi piaceva l'idea di recuperare da server alternativi, quindi ho codificato la funzione per scegliere casualmente uno tra 4 server da cui visualizzare l'immagine.
NOTA: Non c'è sempre un'immagine per ogni dimensione per ogni video, alcune potrebbero essere vuote, tuttavia l'immagine predefinita sembra funzionare costantemente negli URL video che ho testato.
Fammi sapere se questo ti aiuta..

Ottima risposta, +1. Questa era una domanda fantastica; 4 risposte completamente diverse e tutte apparentemente soluzioni molto valide. Adoro WA!

Ho esaminato la classe embed e i filtri disponibili, ma non ho trovato un modo semplice per trasportare l'immagine dall'oggetto embed (che in realtà contiene l'URL dell'immagine) alle funzioni degli shortcode che generano l'HTML, l'oggetto embed attualmente (per quanto ho potuto vedere) non passa i dati necessari ai filtri/hook disponibili. Non sono sicuro del perché la classe embed non trasmetta le informazioni sull'immagine (che possiede), avrebbe senso farlo...
