jueves, marzo 13, 2008

API para el reproductor de YouTube

YouTube acaba de publicar una nueva API que permite interactuar con el reproductor en flash que usa para mostrar sus vídeos. Esto significa que ahora podemos controlar las operaciones básicas del reproductor, y abre múltiples posibilidades; la más obvia crear un reproductor a medida, configurando cualquier aspecto de la interfaz. Seguro que a más de uno se le ocurrirán ideas alucinantes; apuesto a que en breve veremos numerosos ejemplos.

La API permite acceder a las operaciones básicas: reproducir un vídeo, hacer pausa, posicionarse en un momento determinada del vídeo (seek), ajustar el volumen u omitir totalmente el sonido, junto con otras operaciones menos habituales pero aun así útiles.

Veremos en esta entrada una pequeña introducción al API, junto con un ejemplo de la misma.

El ejemplo


Hace poco Frank Taylor creó un vídeo alucinante: Un paseo en caza por los Alpes Suizos. Se trataba de la recreación, mediante el modo simulador de vuelo del Google Earth, de un autentico paseo sobre los Alpes Suizos en un avión de combate. El trabajo que tuvo que hacer para recrear y sincronizar casi a la perfección cada toma es increíble. El vídeo fue luego usado por Eric Schmidt, CEO de Google, para una presentación en la NASA, como se describe en la entrada Crédito de un Gran "Geek". El problema para visualizarlo era que tenías que ir rápido con el ratón, y pulsar lo más rápido posible el "Play" de ambos vídeos para poder comparar.

Gracias a la nueva API, ahora podemos incluir un control externo que reproduzca simultáneamente los dos vídeos con un solo click:

Atención, el ejemplo no se verá a no ser que tengas instalado el plug-in de Flash version 8.0 o superior, y el Javascript habilitado en el navegador.



Veamos primero un poco sobre la API antes de explicar el código del ejemplo.

Empezamos


Para que la nueva API esté disponible, la URL que usaremos para cargar el vídeo debe incluir el parámetro enablejsapi=1, es decir, las URL deben tener la siguiente forma:

http://www.youtube.com/v/VIDEO_ID&enablejsapi=1

Con esto conseguiremos no solo hacer llamadas al reproductor, además, se nos avisará. mediante callbacks, de diversos eventos que nos pueden interesar. Por ejemplo, Cuando está listo el reproductor se llamará automáticamente a la función onYouTubePlayerReady.

Hay otro parámetro, este opcional, que también nos puede ser útil. Si se pasa en el URL del vídeo el parámetro playerapiid con un valor determinado, dicho valor se pasará como primer argumento en la llamada a onYouTubePlayerReady; de esa forma podemos tener varios reproductores en la misma página y saber cuando esta preparado cada uno.

http://www.youtube.com/v/VIDEO_ID&enablejsapi=1&playerapiid=ytplayer

Operaciones


Para poder realizar las llamadas, debemos obtener primero una referencia al reproductor embebido que queremos controlar. La forma más fácil es usar la función getElementById(). Podemos usarla indicando el identificador del div que contienen al reproductor.

Las funciones disponibles son las siguientes:


player.playVideo():Void
Reproduce el vídeo cargado.

player.pauseVideo():Void
Detiene temporalmente la reproducción del vídeo (Pausa).

player.stopVideo():Void
Detiene definitivamente la reproducción del vídeo. También cierra las conexiones de red, por lo que se cancela la descarga del vídeo, si no hubiera terminado, Eso significa que una vez parado definitivamente el vídeo, es necesario recargarlo para volver a reproducirlo.

player.clearVideo():Void
Limpia el reproductor. Es útil si queremos eliminar las escenas restantes que pueden quedar después de parar el vídeo con stopVideo.

player.getVideoBytesLoaded():Number
Devuelve el numero de bytes descargados del vídeo actual.

player.getVideoBytesTotal():Number
Devuelve el tamaño en bytes del vídeo que se este cargando/reproduciendo en ese momento.

player.getVideoStartBytes():Number
Devuelve el número de bytes a partir de donde se empezó a cargar el vídeo. Útil para lo casos en que el usuario haya desplazado el puntero del vídeo a un área que todavía no estuviera cargada.

player.mute():Void
Cancela el sonido.

player.unMute():Void
Restaura el sonido.

player.isMuted():Boolean
Devuelve true si el sonido está cancelado, false en caso contrario.

player.setVolume(volume):Void
Ajusta el volumen. Acepta un número entero en el rango [0..100]

player.getVolume(volume):Void
Devuelve el nivel de volumen actual, lógicamente un número entero entre 0 y 100. Obsérvese que getVolume() devuelve el volumen ajustado aun si el sonido está cancelado.

player.seekTo(seconds, allowSeekAhead):Void
Posiciona el puntero de reproducción en el momento indicado en segundos. El parámetro allowSeekAhead indica si el reproductor debe hacer una nueva petición, en el caso de que la nueva posición está más allá de lo cargado hasta el momento. SeekTo() se posicionará en el fotograma clave más cercano al segundo indicado. Esto implica que, a veces, la reproducción podría empezar justo antes o justo después del segundo indicado; normalmente con un error inferior a los 2 segundos.

player.getPlayerState():Number
Devuelve el estado del reproductor. Los posibles valores son: inicializando (-1), parado/acabado (0), en reproducción (1), en pausa (2), llenando el buffer (3) y vídeo preparado(5).

player.getCurrentTime():Number
Devuelve la posición del vídeo actual, en segundos.

player.getDuration():Number
Devuelve la duración total del vídeo actual, en segundos. getDuration() devolverá 0 hasta que los metadatos del vídeo estén cargados, normalmente justo antes de que comience la reproducción del vídeo.

player.addEventListener(event, listener):Void
Añade una función de respuesta ante un determinado evento.

player.getVideoUrl():String
Devuelve el URL de YouTube.com del vídeo un carga/reproducción.

player.getVideoEmbedCode():String
Retorna el código embebido para el vídeo un carga/reproducción.

Eventos



onStateChange
Se dispara cuando cambia el estado del reproductor. Los posibles valores son: inicializando (-1), parado/acabado (0), en reproducción (1), en pausa (2), llenando el buffer (3) y vídeo preparado (5). En la carga inicial, se emite un mensaje de inicializando (-1) seguido de un mensaje de vídeo preparado (5).
onError
Se dispara cuando ocurre algún error en el reproductor. En la actualidad, solo hay un código de error: 100, que significa "Vídeo no disponible". Puede producirse porque la URL esté mal, porque el vídeo haya sido borrado (por cualquier razón) o que haya sido marcado como privado o no embebible por el autor del mismo.

Eventos especiales



onYouTubePlayerReady(playerid)
Se llama automáticamente a esta función una vez que el reproductor esté totalmente cargado y la API lista para aceptar llamadas. Si se ha pasado un parámetro playerapiid en la URL del vídeo, el valor pasado será usado como argumento de la función. La función debe estar implementada en la misma página Html que contenga el reproductor.

El ejemplo comentado


Para el ejemplo presentado se ha usado la librería swfobject, que presenta la ventaja de poder controlar la versión de flash necesaria para que el navegador acepte la API. Concretamente, hace falta que la versión del plug-in de Flash sea la ocho o superior.

Cualquiera que haya ido un paso más allá del "hola, mundo" en javascript sabe que necesita un framework que aisle su código de las diferencias entre navegadores, o corre el riesgo de acabar cortándose las venas. Yo estoy utilizando jQuery (Su lema es: Haz más escribiendo menos). El código de inicialización es el siguiente:

function main() {
var params = { allowScriptAccess: "always" };
var URL1 = "http://www.youtube.com/v/IDbMCM_2Zuc&border=0&enablejsapi=1&playerapiid=player1";
swfobject.embedSWF(URL1, "player1"
, "320", "270", "8"
, null, null
, params
, { id: "player1" }
);
var URL2 = "http://www.youtube.com/v/P7RJhQQGya8&border=0&enablejsapi=1&playerapiid=player2";
swfobject.embedSWF(URL2, "player2"
, "320", "270", "8"
, null, null
, params
, { id: "player2" }
);
jQuery('#play2').click(play_vids);
jQuery('#pause2').click(pause_vids);
}

jQuery(document).ready(main);

Creamos ambos reproductores con la llamada swfobject.embedSWF. En estas llamadas pasamos, en primer lugar, la URL del vídeo (Obsérvese que el URL tiene codificados los valores especiales enablejsapi y playerapiid) y el identificador del elemento HTML que lo contendrá. Dentro de la página, por tanto, tengo que tener algo como esto:

<div id="player1" class="reproductor">
You need Flash player 8+ and JavaScript enabled to view this video.
</div>
<div id="player2" class="reproductor">
You still need Flash player 8+ and JavaScript enabled to view this video.
</div>

Los siguientes 3 parámetros también nos interesan; son: Ancho y alto del reproductor y versión mínima de Flash (320, 270 y 8 respectivamente). El valor de params (penúltimo argumento) habilita el acceso al reproductor mediante javascript. El último de los parámetros se usa para incluir un identificador de cada reproductor. Aquí, imaginativamente, los hemos llamado Player1 y Player2.

Las últimas líneas de la función principal sirven para asociar, usando jQuery, el evento click de los botones de reproducción y pausa con las funciones play_vids y pause_vids respectivamente.

Como vimos antes, el propio API nos avisa de que esta preparada mediante una llamada a la función onYouTubePlayerReady. En nuestro ejemplo, usamos esta llamada para guardar en dos variables globales las referencias a ambos reproductores.

function onYouTubePlayerReady(player_id) {
if (player_id == 'player1') {
Player1 = document.getElementById("player1");
}
if (player_id == 'player2') {
Player2 = document.getElementById("player2");
}
}

Como hay dos reproductores en la página, se realizarán dos llamadas a esta función, una para cada uno de ellos. Quizá ahora se entienda más la necesidad de usar el parámetro playerapiid; si no lo hubiéramos hecho no podríamos distinguir entre las dos llamadas. Como hemos tenido la precaución de usarlo, codificándolo en la URL de cada video, ahora se nos devuelve como argumento de la función, permitiéndonos saber de que reproductor se trata en cada caso.

Una vez que las variables globales Player1 y Player2 están apuntando a cada reproductor, y que este está preparado, las funciones que controlan la reproducción simultanea son elementales:

function play_vids() {
if (Player1) { Player1.playVideo(); }
if (Player2) { Player2.playVideo(); }
}

La función de pausa es equivalente:

function pause_vids() {
if (Player1) { Player1.pauseVideo(); }
if (Player2) { Player2.pauseVideo(); }
}


Lamento la extensión de esta entrada. No he tenido tiempo de hacerla más corta.

Más información sobre este tema:

co.mments.comdel.icio.usmeneamefresquidiggYahooMyWeb

3 comentarios:

Jose Frechín dijo...

Impresionante, Fran Taylor de Google Earth Blog, ha escrito un post sobre este experimento con la API de Youtube.

trocolo dijo...

Excelente, es justo lo que estaba buscando. XD

GuimelGMC dijo...

no importa lo largo de la entra esta muy bien explicada en este momento intentare hacer algo parecido a lo que hiciste gracias...