Día 15: Personalizar reproductor de YouTube con Javascript

La API en Javascript de YouTube nos da la posibilidad de crear un reproductor personalizado para nuestros videos, en flash o en HTML5. Con Javascript, CSS y un poco de tiempo, lograremos crear un reproductor funcional.

Demo

00:00


Código

Primero que nada, necesitaremos incluir en nuestro DOM un tag de script apuntando a la siguiente URL: http://www.youtube.com/player_api. Esto nos permitirá utilizar la API de YouTube en Javascript.

Porfavor, date una buena empapada de los métodos que te brinda la API, te quitarás de muchos dolores de cabeza y te darás cuenta que no es nada complicado. YouTube JavaScript Player API Reference

Como paso siguiente crearemos nuestro video de forma dinámica apuntando hacia un contenedor (div) vacío, en este ejemplo se utiliza el ID «player». La API nos da la posibilidad de detectar cuando esta está cargada, para así comenzar a jugar con ella.

function onYouTubePlayerAPIReady() {
  player = new YT.Player('player', {
    width: '100%',
    height: 'auto',
    videoId: 'WF34N4gJAKE',
    playerVars: {
      controls: 0,
      showinfo: 0,
      iv_load_policy: 3,
      cc_load_policy: 0,
      rel: 0
    },
    events: {
      'onStateChange': videostatus,
      'onReady': playerReady
    }
  });
}

Estamos llamando a dos métodos cuando el reproductor está listo (onReady) y cuando este cambia de estado (onStateChange).

Haremos una pequeña función llamada videostatus para detectar el estado del reproductor.

function videostatus(state) {
  return state["data"];
}

Los valores que te regresará, posiblemente, son:

  • -1: sin iniciar
  • 0: terminado
  • 1: reproduciéndose
  • 2: pausado
  • 3: cargando
  • 5: en fila

Este te ayudará a detectar en qué estado se encuentra el video, para poder jugar con el.

Con motivos ilustrativos de este post, construiremos la barra de progreso del reproductor. Esta se hará con el elemento range input de HTML5 el cual acepta valores min, max, value y step.

Tendremos una variable seeking la cual nos ayudará a detectar si el usuario está moviendo la barra con su cursor.

var seeking = false;

Después, en nuestro range input, asignandole un ID, detectaremos con Javascript cuando el usuario presiona y libera esta barra.

document.getElementById('track').onmousedown = function () {
  seeking = true;
}
document.getElementById('track').onmouseup = function () {
  seekTo(this.value);
  seeking = false;
}

La función seekTo(value) es una función que construiremos para dos cosas: cambiar el tiempo del video según la nueva posición y actualizar la barra de progreso.

function seekTo(seconds) {
  return player.seekTo(seconds, true);
}

Extenderemos nuestra función de status para mostrar actualizar el avance de nuestra barra de progreso.

function videostatus(state) {
  state = state["data"];
  updateProgressBar(state);
  return state;
}

Y nuestra función updateProgressBar(state); funciona básicamente a través de un setInterval. No encontré una mejor manera de hacerlo, si se te ocurre algo, porfavor deja un comentario.

var updater;
function updateProgressBar(state) {
  if (state == 1) {
    updater = setInterval(function () {
      updateSeekTime()
    }, 300);
  } else if (state == 2) {
    clearInterval(updater);
  }
}

Esta última llamará a la función updateSeekTime(); cada 300 milisegundos, esta consta de las siguientes órdenes.

function updateSeekTime() {
  if (!seeking) {
    document.getElementById('track').value = getCurrentTime();
    changetrackcolor();
  }
}

La cual estará llamando a dos funciones: la primera llamada getCurrentTime(); la cuál nos devolverá el timpo actual de reproducción. Tendremos que redondear los valores, ya que la API de YouTube nos devolverá un valor muy exacto, pero no queremos ser tan exactos (¿o si?).

function roundNumber(number, decimalPlaces) {
  decimalPlaces = (!decimalPlaces ? 2 : decimalPlaces);
  return Math.round(number * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPlaces);
}
function getCurrentTime() {
  var currentTime = player.getCurrentTime();
  return roundNumber(currentTime, 3);
}

La segunda función que llama updateSeekTime(); se llama changetrackcolor();. Con ayuda de jQuery y CSS3, lograremos crear la ilusión de una barra de progreso con el range input.

function changetrackcolor() {
    var val = ($("#track").val() - $("#track").attr('min')) / ($("#track").attr('max') - $("#track").attr('min'));
    $("#track").css('background-image',
      '-webkit-gradient(linear, left top, right top, ' +
        'color-stop(' + val + ', #c0392b), ' +
        'color-stop(' + val + ', #cecece)' +
        ')'
    );
}

Y alistamos el range input con un poco de CSS.

 / Track /
#track {
  -webkit-appearance: none;
  -moz-apperance: none;
  border-radius: 6px;
  height: 6px;
  vertical-align: middle;
  background-image: -webkit-gradient(
    linear,
    left top,
    right top,
    color-stop(0, #c0392b),
    color-stop(0, #ecf0f1)
  );
  outline: none;
}

/ Botón del track /
#track::-webkit-slider-thumb {
  -webkit-appearance: none !important;
  background-color: #E9E9E9;
  border: 1px solid #CECECE;
  height: 15px;
  width: 15px;
  border-radius: 50%;
}

Estos últimos dos bloques de código (JS y CSS), los encontré en esta respuesta de Stackoverflow.

Y por último, haremos la función playerReady(); para iniciar y configurar nuestro range input.

function playerReady() {
  setDuration();
  document.getElementById('track').value = getCurrentTime();
  updateSeekTime();
}

La función setDuration(); nos ayudará a asignar un valor máximo a nuestro range input. Recomiendo establecer desde el HTML el step="0.10" para funcionar de una manera mas exacta.

function setDuration() {
  document.getElementById('track').max = player.getDuration() - 1;
}

Y listo. Tendrás una bonita barra de progreso cómo la que pudiste observar en el demo anterior.

El código del reproductor lo puedes ver en el código de fuente de esta página o en los siguientes Gists.

Código Javascript

Código HTML

Código CSS

Dudas o comentarios, en los comentarios de aquí o envíame un tuit.


palabras / Compartir en: Facebook , Twitter o copiar enlace