Convertir duración de video de la API v3 de Youtube en PHP

Hace poco me encontré con un problema intentando extraer la duración de un video de la API v3 de Youtube. El formato que nos devuelve la API es algo extraño y tras probar distintas soluciones vistas por la web y sin que ninguna funcionara del todo, intenté hacer mi propia función …

En este artículo vamos a ver tres partes bien diferenciadas:

  • API v3 Youtube => el formato del dato duración en la respuesta de la API.
  • DateInterval  => clase de PHP usada para la transformación de los datos.
  • convertTime  => nuestra función personalizada para ajustar la salida de los datos.

API v3 Youtube

La parte de la respuesta de la API que nos devuelve la duración del video y que viene en JSON es la siguiente:

"contentDetails": {
  "duration": "PT1H8M12S",
  "dimension": "2d",
  "definition": "hd",
  "caption": "false",
  "licensedContent": false,
  "projection": "rectangular"
}
En próximos artículos veremos toda la respuesta de la API de Youtube explicada parte por parte.

El dato que nos interesa aquí es duration y el formato que nos dá la API es PT1H8M12S.
Las dos primeras letras corresponden a Pacific Time (tiempo del pacífico), el resto que es la parte que nos interesa es fácilmente entendible y la traducción sería, en este caso, 1 hora, 8 minutos y 12 segundos. En la siguiente tabla hay algunos ejemplos más:

Formato API Traducción
PT1H38M10S 1 hora, 38 minutos y 10 segundos
PT1H50S 1 hora, 0 minutos y 50 segundos
PT10M1S 10 minutos y 1 segundo
PT9M23S 9 minutos y 23 segundos
PT1M 1 minuto y 0 segundos

DateInterval

La clase DateInterval de PHP sirve para representar un intervalo de fechas en años, meses, días, horas, minutos y segundos. Con esta clase podemos separar los valores 1H 8M 12S separando cada dato con el símbolo : cuando proceda.

$newTime = new DateInterval($youtubeDuration);
$horas = $newTime->h; //extraemos el dato horas
$minutos = $newTime->i; //extraemos el dato minutos
$segundos = $newTime->s; //extraemos el dato segundos
echo $horas.':'.$minutos.':'.$segundos;

Todas las soluciones que probé usaban esta técnica. El problema era el formato que devolvían esas soluciones, a veces quedaba raro dependiendo de la duración del video, y pongo unos ejemplos:

Duración del video Formato Esperado Formato Obtenido
0 horas, 2 minutos y 30 segundos 02:30 0:2:30
1 hora, 2 minutos y 10 segundos 1:02:10 1:2:10
1 hora, 0 minutos y 5 segundos 1:00:05 1:0:5
2 minutos y 7 segundos 2:07 2:7

convertTime

Para crear nuestra propia función con la clase DateInterval ya tenemos casi todo hecho, solo hay que poner un par de condiciones extra para montar el formato final de la duración del video a nuestro gusto.

Las dos cosas que he tenido en cuenta a la hora de crear la función son:

  • Si el dato es menor de 10 hay que poner siempre un 0 delante, excepto en las horas.
  • Si no existe el dato horas y el dato minutos es menor de 10 este no necesita el 0 delante.

Teniendo en cuenta esas dos cosas y tras probar con diferentes videos de diferentes duraciones llegué a una solución que a mi me sirve.

Y así queda la función en PHP con comentarios explicativos:

//pasamos como argumento el valor de duracion de la API
// ejemplo PT20M34S
function convertTime($youtubeDuration) { 
	
  //convertimos la duracion a formato H:i:s
  $newTime = new DateInterval($youtubeDuration);
	
  //HORAS
  $hours = $newTime->h; //extraemos el dato horas
  if($hours > 0){ //si horas es mayor de cero
    $hours .= ':'; //ponemos detras el simbolo :
  } else { //si horas es menor de cero			 
    $hours = ''; //horas estara vacio
  }
	
  //MINUTOS
  $minutes = $newTime->i; //extraemos el dato minutos
  if($hours > 0){ //si horas es mayor de cero
    if($minutes < 10){ //si minutos es menor de diez
      $minutes = '0'.$minutes.':'; //ponemos un cero delante y detras el simbolo :
    } else { //si minutos es 10 o mayor de diez
      $minutes .= ':'; //ponemos detras el simbolo :
    }
  } else { //si horas es menor de cero
    $minutes .= ':'; //ponemos detras de minutos el simbolo :
  }
	
  //SEGUNDOS
  $seconds = $newTime->s; //extraemos el dato segundos
  if($seconds < 10){ //si segundos es menor de diez
    $seconds = '0'.$seconds; //ponemos un cero delante 
  }
	
  //RESULTADO
  return $hours.$minutes.$seconds; //respuesta de la funcion

}

Depurando la función

Siempre podemos (o más bien debemos) depurar la función para que sea más rápida y efectiva. Eliminamos los comentarios, abreviamos las variables y si el código lo permite creamos bucles mientras sea posible. De primeras puede que se entienda bastante peor, pero el funcionamiento es exactamente el mismo que el de la función anterior:

function convertTime($ytd){
  $t=new DateInterval($ytd);
  $h=$t->h; if($h>0){$h.= ':';}else{$h='';}
  $m=$t->i; if($h>0){if($m<10){$m='0'.$m.':';}else{$m.=':';}}else{$m.=':';}
  $s=$t->s; if($s<10){$s='0'.$s;}
  return $h.$m.$s;
}

Lo unico que hay que hacer es pasar el valor recogido de la API como argumento de la función y saldrá transformado en el formato esperado:

Duración del video Formato Recibido Formato Transformado
1 hora, 2 minutos y 10 segundos PT1H2M10S 1:02:10
1 hora, 0 minutos y 5 segundos PT1H5S 1:00:05
36 minutos y 0 segundos PT36M 36:00
2 minutos y 7 segundos PT2M7S 2:07