Introducción
Esta mañana justamente estaba planeando un tutorial sobre cómo extraer la información de una canción MP3 que usa el formato Id3 o algo así. Para ello estaba usando la magnífica librería llamada Mp3Info y el lenguaje de programación PHP.
Todo iba bien, hasta que noté algo extraño. Extraje la información de una canción pero regresaba los datos con un carácter de menos. Por ejemplo, si el artista era León Larregui, mostraba León Larregu. O si el nombre de la canción era Locos, mostraba Loco.
Aquí una imagen que lo comprueba:
Entonces me puse a depurar y depurar por un montón de tiempo hasta que di con la solución que justo ahora vengo a exponer
Resumen nivel 5
Bueno, al final sólo fue agregar el carácter NUL al final de la cadena.
Hice un fork del repositorio aquí, el cual soluciona este bug citado en el repositorio original.
Arreglar bug de Mp3Info que remueve el último carácter
Probé de todo, primero imprimí la cadena y la analicé. Vi que decía algo como “V o l u m a”, así con espacios. Supuse que es porque usa dos bytes para representar los caracteres unicode o esas cosas, pero tenían un espacio porque el segundo carácter no era usado, ya que todo cabía en un byte.
Luego intenté decodificar la cadena con todos los formatos que devolviera mb_list_encodings
usando mb_convert_encoding
, pero todo salía feo; con caracteres raros, signos de interrogación y esas cosas.
Más tarde recorrí la cadena y fui imprimiendo su representación ASCII usando la función ord
con este código, (no está muy bonito pero estaba depurando, no programando):
<?php
echo "Vamos con '" . $data["information"] . "'\n";
$l = strlen($data["information"]);
for($x = 0; $x < $l; $x++){
echo ord($data["information"][$x]) . "\n";
}
Comenzaba mostrando el 255 y 254, supongo que son unos bytes que indican otra cosa que desconozco (tal vez algo como un encabezado).
Lo que realmente importaba era que después imprimía el 86 y más tarde el 0; el 86 representaba la V de Voluma. ¿Y ese cero? Así que (y me vengo a dar cuenta de la posible explicación al escribir este post) usaba dos caracteres para representar una letra, por cosas del unicode como lo mencioné anteriormente.
Dejaba ese carácter nulo porque no lo necesitaba, ya que la V se puede representar con un byte. La salida era así:
Y fue ahí cuando me di cuenta de que faltaba un cero al final, ya que cada letra llevaba su representación y un 0, o el carácter nulo si hablamos del código ASCII.
Yo creo que PHP, al convertir la codificación, detectaba el 97 como un carácter que estorbaba, porque no usaba 2 bytes, sólo uno; era el sobrante que no tenía pareja.
Así que lo que hice fue agregar al final de la cadena el carácter nulo:
$data["information"] .= chr(0);
La función chr complementa a ord, dado un número devuelve su representación ASCII. Y entonces la salida ahora era distinta:
Después del 97 ahora sí salía un cero. Si borraba todo mi código de depuración y dejaba todo limpio, la función ahora se veía así:
<?php
private function handleTextFrame($frameSize, $raw)
{
$data = unpack('C1encoding/A' . ($frameSize - 1) . 'information', $raw);
if ($data['encoding'] == 0x00) # ISO-8859-1
return mb_convert_encoding($data['information'], 'utf-8', 'iso-8859-1');
else{ # utf-16
# Fix the missing last char of the info bug
# Add NUL character at the end of the string.
# Don't ask, just enjoy. Idk why it works, but it works!
$data["information"] .= chr(0);
return mb_convert_encoding($data['information'], 'utf-8', 'utf-16');
}
}
Simplemente agregué una concatenación. Se ve simple, pero llevó horas escribir esa maldita línea. Y si probaba…
Ahora ya devolvía toda la información. Me pregunto qué pasa si el último carácter de la cadena es multibyte, supongo que habría que comprobar si su último byte es NUL y si no entonces concatenar.
El punto es que quedó arreglado y ahora sí continuaré escribiendo el tutorial.
Muy buenas parzibyte,
Te estoy escribiendo porque estoy interesado en esta librería para implementarla en mi sitio web, te cuento que estoy haciendo un script web el cual contendrá una lista de reproducción de mp3 y hasta ahora puedo extraer todos los datos excepto uno. me refiero a la imagen de portada que trae el Mp3 el cual aparece en los reproductores cuando se esta reproduciendo el archivo de audio.
llevo varios días buscando información sobre esto pero no encuentro nada que me solucione mi busqueda.
Me gustaría saber si con esta librería sería capaz de extraer esa imagen de portada que lleva cada mp3.
Un cordial saludo y espero me puedas responder, si puedes por un correo directo gracias.
Att: Jose Peguero