Los archivos MP3 reservan un espacio para guardar sus etiquetas, algo así como metadatos. En ese espacio se guardan cosas relevantes del audio, por ejemplo el artista, álbum, título, número de pista y esas cosas.
Veamos cómo obtener toda esa información usando el lenguaje de programación PHP combinado con una librería.
Esta información también es conocida como ID3, citando a Wikipedia:
ID3 es un estándar de facto para incluir metadatos (etiquetas) en un archivo contenedor audiovisual, tales como álbum, título o artista. Se utiliza principalmente en ficheros sonoros como MP3.
Aquí dejo una imagen del código, únicamente para adornar el post. Utilicé Polacode con VSCode.
Vamos allá.
La librería está en GitHub, justo aquí. Créditos a su respectivo autor.
Iba a hacer este tutorial pero me interrumpió un pequeño bug en la librería, el cual es explicado y solucionado en un post anterior.
Puedes usar composer para descargar la librería, o simplemente descargar la carpeta data y src, para más tarde incluir el archivo llamado Mp3Info.php dentro de src.
No te preocupes, aquí veremos cómo se hace todo ello.
Yo he optado por descargar las carpetas y ponerlas del siguiente modo, en una carpeta de pruebas llamada extraer_info:
El archivo index.php es uno que yo hice, no lo descargué. En él trabajaremos.
Ahora en el index.php vamos a incluir el archivo de la librería y a indicar que usaremos el espacio de nombres de Mp3Info.
<?php
include_once __DIR__ . "/src/Mp3Info.php";
use wapmorgan\Mp3Info\Mp3Info;
Así lo he hecho yo; tu estructura puede ser distinta o puede que estés usando composer e incluyendo todo con el autoload; da igual, el punto es que incluyas correctamente la librería.
PHP puede ser ejecutado en el navegador a través de un servidor web (por ejemplo XAMPP) o en la consola. En este caso lo ejecutaré en la consola, pero funciona igualmente en el navegador; sólo recuerda ponerlo en el directorio público de tu servidor web.
Las funciones y todo lo que tiene el lenguaje funciona exactamente igual, así que no te preocupes por el lugar de ejecución.
Ahora sí vamos al tutorial.
Comencemos con algo simple, vamos a extraer toda la información de un único archivo MP3. Puede que este archivo tenga etiquetas versión 2, o tal vez únicamente versión 1. Para ello mejor dejamos que la librería nos dé todo lo que encuentre.
La canción que analizaremos será una de León Larregui, llamada Locos. No me culpen; Voluma es uno de los pocos discos que he comprado en play music y que puedo usar para este tutorial para no tener problemas legales.
En fin, esto funcionará para cualquier canción o canciones. Aquí el ejemplo:
<?php
include_once __DIR__ . "/src/Mp3Info.php";
use wapmorgan\Mp3Info\Mp3Info;
$rutaDeLaCancion = __DIR__ . "/01 Locos.mp3";
$informacion = new Mp3Info($rutaDeLaCancion, true);
$tags1 = $informacion->tags1;
$tags2 = $informacion->tags2;
var_dump($tags1);
var_dump($tags2);
Ese es nuestro primer acercamiento a la librería. Creamos una nueva instancia de Mp3Info
pasándole dos argumentos: la ruta de la canción y un booleano indicando si queremos que parsee las etiquetas o no; obviamente SÍ queremos que lo haga.
Cuando parsea, pone los resultados en los miembros públicos de la clase, llamados tags1 y tags2 respectivamente. El primer miembro contiene las etiquetas id3 versión 1, y el segundo las etiquetas versión 2.
Ahorita explico eso, por el momento veamos la salida:
Desde ahí se ve la diferencia. En las tags1
no hay forma de que el unicode funcione (no se ve la ó), en cambio en las tags2
sí.
No vamos a entrar en detalles técnicos; esto es simple… la versión 1 es más antigua, tiene un límite de (me parece) 30 caracteres para los datos, así que si tenemos una canción cuyo título los excede, se cortará. Y por otro lado, no soporta unicode.
Entonces siempre nos vamos a ir por la versión 2, aunque no siempre tendremos la suerte de encontrarla. Sería cosa de hacer un if, pero en resumen te recomiendo siempre elegir la versión 2 en lugar de la versión 1, en caso de estar disponible.
También podemos obtener la duración, peso, bitrate y otras cosas. Todo eso está expuesto cuando instanciamos a la clase Mp3Info. Veamos este ejemplo que imprime:
Queda así:
<?php
include_once __DIR__ . "/src/Mp3Info.php";
use wapmorgan\Mp3Info\Mp3Info;
$rutaDeLaCancion = __DIR__ . "/01 Locos.mp3";
$informacion = new Mp3Info($rutaDeLaCancion, true);
$peso = $informacion->_fileSize;
$duracionEnSegundos = $informacion->duration;
$bitRate = $informacion->bitRate;
$canal = $informacion->channel;
printf("El peso es %f, la duración en segundos es %f, el bitrate es de %d bps y el canal es %s",
$peso, $duracionEnSegundos, $bitRate, $canal);
La salida es: El peso es 7145357.000000, la duración en segundos es 176.640000, el bitrate es de 320000 bps y el canal es stereo
El mismo autor indica que el peso es indicado en bytes, pero muestra el peso del audio, no del archivo. La duración es un flotante; la parte entera representa los segundos y la parte decimal los microsegundos.
De ahí, el bitrate es indicado en bps; por ejemplo, si dice 320000 quiere decir que son 320 KBPS; es una simple división entre 1000. El canal puede ser stereo, mono, dual_mono o joint_stereo.
Ahhh lo olvidaba, el número de pista se saca de distinta manera, dependiendo de la versión de etiquetas. En la versión uno está en $tags1["track"]
y en la versión 2 está en $tags2["TRCK"]
.
Cuando estaba trabajando con esta librería para un proyecto, quise mostrar la duración como se debe, y es en formato MM:SS. Ya sé que fallaría si un audio tuviera más de 60 minutos, pues no muestra horas.
Pero en fin, aquí la dejo por si le sirve a alguien más:
<?php
function convertirAMinutosYSegundos($segundos)
{
$minutos = floor($segundos / 60);
$segundos = $segundos % 60;
return sprintf("%02d:%02d", $minutos, $segundos);
}
Recibe un entero o flotante indicando los segundos (por ejemplo 125) y devuelve un string de esos segundos transformados. Si le pasamos un 125, devuelve 02:05.
En la función se utiliza sprintf.
Sabiendo todo ello, y tomando en cuenta que existen tanto etiquetas versión 2 como versión 1, podemos implementar este código que imprima los detalles más importantes de una canción.
Primero mirará en las etiquetas de la versión 1, y si encuentra que hay etiquetas versión 2 entonces preferirá a esas sobre las anteriores.
<?php
include_once __DIR__ . "/src/Mp3Info.php";
use wapmorgan\Mp3Info\Mp3Info;
function convertirAMinutosYSegundos($segundos)
{
$minutos = floor($segundos / 60);
$segundos = $segundos % 60;
return sprintf("%02d:%02d", $minutos, $segundos);
}
$rutaDeLaCancion = __DIR__ . "/01 Locos.mp3";
$informacion = new Mp3Info($rutaDeLaCancion, true);
$tags1 = $informacion->tags1;
$tags2 = $informacion->tags2;
$titulo = $tags1["song"];
$album = $tags1["album"];
$artista = $tags1["artist"];
$duracion = convertirAMinutosYSegundos($informacion->duration);
$kbps = $informacion->bitRate / 1000;
/**
* Ya extrajimos las etiquetas v1, pero ¿qué tal si hay etiquetas mejoradas en la versión 2?
*/if (!empty($tags2["TIT2"])) {
$titulo = $tags2["TIT2"];
}
if (!empty($tags2["TALB"])) {
$album = $tags2["TALB"];
}
if (!empty($tags2["TPE1"])) {
$artista = $tags2["TPE1"];
}
# Al final, de todos modos imprimimos los datos
printf("Título: %s
Álbum: %s
Artista: %s
Duración: %s
KBPS: %d
", $titulo, $album, $artista, $duracion, $kbps);
Bien pudimos usar el operador de coalescencia nula pero queremos que el código sea legible. Si lo pruebo, sale esto:
Con eso obtenemos la información de un archivo MP3.
Para terminar, veamos cómo podemos obtener la información o etiquetas de todas las canciones en el directorio actual (igual puede cambiarse para que sea otro directorio). Lo que haremos será usar scandir que escaneará el directorio.
Para saber si un archivo es una canción mp3 usamos esta función que me robé por ahí de stackoverflow:
<?php
function endsWith($haystack, $needle)
{
$length = strlen($needle);
if ($length == 0) {
return true;
}
return (substr($haystack, -$length) === $needle);
}
Dicha función nos dice si una cadena termina con determinada cadena. Ya veremos cómo se usa.
Entonces el código queda así:
<?php
include_once __DIR__ . "/src/Mp3Info.php";
use wapmorgan\Mp3Info\Mp3Info;
function endsWith($haystack, $needle)
{
$length = strlen($needle);
if ($length == 0) {
return true;
}
return (substr($haystack, -$length) === $needle);
}
function convertirAMinutosYSegundos($segundos)
{
$minutos = floor($segundos / 60);
$segundos = $segundos % 60;
return sprintf("%02d:%02d", $minutos, $segundos);
}
$archivos = scandir(__DIR__);
$contenido = "";
foreach ($archivos as $archivo) {
if (endsWith($archivo, ".mp3")) {
$rutaDeLaCancion = __DIR__ . DIRECTORY_SEPARATOR . $archivo;
$informacion = new Mp3Info($rutaDeLaCancion, true);
$tags1 = $informacion->tags1;
$tags2 = $informacion->tags2;
$titulo = $tags1["song"];
$album = $tags1["album"];
$artista = $tags1["artist"];
$duracion = convertirAMinutosYSegundos($informacion->duration);
$kbps = $informacion->bitRate / 1000;
/**
* Ya extrajimos las etiquetas v1, pero ¿qué tal si hay etiquetas mejoradas en la versión 2?
*/ if (!empty($tags2["TIT2"])) {
$titulo = $tags2["TIT2"];
}
if (!empty($tags2["TALB"])) {
$album = $tags2["TALB"];
}
if (!empty($tags2["TPE1"])) {
$artista = $tags2["TPE1"];
}
# Al final, de todos modos imprimimos los datos
printf("Título: %s, Álbum: %s, Artista: %s, Duración: %s, KBPS: %d\n",
$titulo, $album, $artista, $duracion, $kbps);
}
}
echo $contenido;
Usamos la función endsWith (terminaCon) para saber si el archivo en el que estamos actualmente es un fichero MP3. En caso de que sí, entonces obtenemos su información y la imprimimos.
Cuando ejecuto este programa, el resultado es este:
Con eso terminamos, ya dimos muchos ejemplos. Y recuerda que siempre puedes ver todo lo que ofrece esta librería aquí.
Hoy te voy a presentar un creador de credenciales que acabo de programar y que…
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Esta web usa cookies.
Ver comentarios
me marca este error
Fatal error: Uncaught Exception: File ../canciones/662ea35f20a69ad9747fcda93e085736.mp3 is not mpeg/audio! in
C:\Users\Luis Martinez\Documents\reproductor\API\Mp3Info-master\src\Mp3Info.php:227
Stack trace:
#0 C:\Users\Luis Martinez\Documents\reproductor\API\api.php(11):
wapmorgan\Mp3Info\Mp3Info->__construct('../canciones/66...', true)
#1 {main}
thrown in C:\Users\Luis Martinez\Documents\reproductor\API\Mp3Info-master\src\Mp3Info.php on line 227<br /
El error le está diciendo la razón