php

Extraer información de archivos MP3 con PHP y Mp3Info

Introducción

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.

Usar Mp3Info y PHP para obtener etiquetas id3 de archivo MP3

Vamos allá.

Sobre la librería

La librería está en GitHub, justo aquí. Créditos a su respectivo autor.

Sobre los nuevos cambios

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.

Archivos necesarios

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.

Incluir archivos

Yo he optado por descargar las carpetas y ponerlas del siguiente modo, en una carpeta de pruebas llamada extraer_info:

Estructura del directorio

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.

Sobre la ejecución del programa

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.

Extraer información de un archivo MP3

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:

Información de ID3 obtenida gracias a MP3 Info

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í.

Diferencia entre versión 1 y 2 de ID3

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.

Otros metadatos

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:

  1. Peso
  2. Duración
  3. Bitrate
  4. Canal

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"].

Convertir segundos a minutos y segundos

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.

Extraer título, álbum, artista, duración y KBPS

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:

Obtener título, álbum, artista, duración y KBPS

Con eso obtenemos la información de un archivo MP3.

Bonus: mostrar información de todo el directorio

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:

Obtener información ID3 de canciones en el directorio actual

Con eso terminamos, ya dimos muchos ejemplos. Y recuerda que siempre puedes ver todo lo que ofrece esta librería aquí.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

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 /

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

1 semana hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 semanas hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 semanas hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 semanas hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 semanas hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

2 semanas hace

Esta web usa cookies.