javascript - pagina - tag editor para pc
Lea las etiquetas id3 v2.4 con Chrome Javascript/FileReader/DataView nativos (3)
Puedes intentar usar el analizador id3 en github .
Aquí está su violín actualizado que registra el objeto de etiquetas en la consola
Con el id3.js incluido, todo lo que necesita hacer en su código es este:
function readFile(){
id3(this.files[0], function(err, tags) {
console.log(tags);
})
}
document.getElementsByTagName(''input'')[0].addEventListener(''change'',readFile,false);
Y aquí está el objeto de tags
creado por id3
:
{
"title": "Stairway To Heaven",
"album": "Stairway To Heaven",
"artist": "Led Zeppelin",
"year": "1999",
"v1": {
"title": "Stairway To Heaven",
"artist": "Led Zeppelin",
"album": "Stairway To Heaven",
"year": "1999",
"comment": "Classic Rock",
"track": 13,
"version": 1.1,
"genre": "Other"
},
"v2": {
"version": [3, 0],
"title": "Stairway To Heaven",
"album": "Stairway To Heaven",
"comments": "Classic Rock",
"publisher": "Virgin Records"
}
}
¡Espero que esto ayude!
Basado en la respuesta de ebidel , uno puede leer las etiquetas jDataView usando jDataView :
document.querySelector(''input[type="file"]'').onchange = function (e) {
var reader = new FileReader();
reader.onload = function (e) {
var dv = new jDataView(this.result);
// "TAG" starts at byte -128 from EOF.
// See http://en.wikipedia.org/wiki/ID3
if (dv.getString(3, dv.byteLength - 128) == ''TAG'') {
var title = dv.getString(30, dv.tell());
var artist = dv.getString(30, dv.tell());
var album = dv.getString(30, dv.tell());
var year = dv.getString(4, dv.tell());
} else {
// no ID3v1 data found.
}
};
reader.readAsArrayBuffer(this.files[0]);
};
Chrome y otros navegadores ya implementaron DataView (solo estoy interesado en Chrome). Tengo curiosidad si alguien sabe cómo:
- Leer etiquetas usando el DataView nativo
- Lectura de las etiquetas id3 v2.4 (incluida la imagen APIC ''coverart'')
El punto es que no tengo experiencia con archivos binarios, y no sé cómo saltar a la posición correcta de la etiqueta, o qué pequeño endian y endian largo (o lo que sea) son. Solo necesito un ejemplo para una etiqueta, digamos el título, la etiqueta TIT2
, que espero me ayude a comprender cómo saltar a la posición correcta y leer las otras etiquetas también:
function readID3() {
//https://developer.mozilla.org/en-US/docs/Web/API/DataView
//and the position
//http://id3.org/id3v2.4.0-frames
//var id3={};
//id3.TIT2=new DataView(this.result,?offset?,?length?)
/*
?
var a=new DataView(this.result);
console.dir(String.fromCharCode(a.getUint8(0)));
?
*/
}
function readFile() {
var a = new FileReader();
a.onload = readID3;
a.readAsArrayBuffer(this.files[0]);
}
fileBox.addEventListener(''change'', readFile, false);
Aquí está el JSFiddle .
ACTUALIZAR
getString
para poder leer la primera línea y verificar si contiene ID3. Ahora necesito encontrar la posición de la primera etiqueta (TIT2) y la longitud ''variable'' de esa cadena y también verificar si es la versión 2.4.
//Header
//ID3v2/file identifier "ID3"
//ID3v2 version $04 00
//ID3v2 flags (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
//ID3v2 size 4 * %0xxxxxxx
Posibles fuentes externas:
https://developer.mozilla.org/en-US/docs/Web/API/DataView
http://id3.org/id3v2.4.0-frames
http://id3.org/id3v2.4.0-structure
http://blog.nihilogic.dk/2008/08/reading-id3-tags-with-javascript.html
http://ericbidelman.tumblr.com/post/8343485440/reading-mp3-id3-tags-in-javascript
https://github.com/aadsm/JavaScript-ID3-Reader
Estoy usando PHP lib getid3 en este momento ...
Usando el código que encontré aquí: http://www.ulduzsoft.com/2012/07/parsing-id3v2-tags-in-the-mp3-files/ , lo traduje al Javascript aquí: http://jsfiddle.net/eb7rrbw4/
Aquí está el código tal como lo escribí allí:
DataView.prototype.getChar=function(start) {
return String.fromCharCode(this.getUint8(start));
};
DataView.prototype.getString=function(start,length) {
for(var i=0,v='''';i<length;++i) {
v+=this.getChar(start+i);
}
return v;
};
DataView.prototype.getInt=function(start) {
return (this.getUint8(start) << 21) | (this.getUint8(start+1) << 14) | (this.getUint8(start+2) << 7) | this.getUint8(start+3);
};
function readID3(){
var a=new DataView(this.result);
// Parse it quickly
if ( a.getString(0,3)!="ID3" )
{
return false;
}
// True if the tag is pre-V3 tag (shorter headers)
var TagVersion = a.getUint8(3);
// Check the version
if ( TagVersion < 0 || TagVersion > 4 )
{
return false;
}
// Get the ID3 tag size and flags; see 3.1
var tagsize = a.getInt(6)+10;
//(a.getUint8(9) & 0xFF) | ((a.getUint8(8) & 0xFF) << 7 ) | ((a.getUint8(7) & 0xFF) << 14 ) | ((a.getUint8(6) & 0xFF) << 21 ) + 10;
var uses_synch = (a.getUint8(5) & 0x80) != 0 ? true : false;
var has_extended_hdr = (a.getUint8(5) & 0x40) != 0 ? true : false;
var headersize=0;
// Read the extended header length and skip it
if ( has_extended_hdr )
{
var headersize = a.getInt(10);
//(a.getUint8(10) << 21) | (a.getUint8(11) << 14) | (a.getUint8(12) << 7) | a.getUint8(13);
}
// Read the whole tag
var buffer=new DataView(a.buffer.slice(10+headersize,tagsize));
// Prepare to parse the tag
var length = buffer.byteLength;
// Recreate the tag if desynchronization is used inside; we need to replace 0xFF 0x00 with 0xFF
if ( uses_synch )
{
var newpos = 0;
var newbuffer = new DataView(new ArrayBuffer(tagsize));
for ( var i = 0; i < tagsize; i++ )
{
if ( i < tagsize - 1 && (buffer.getUint8(i) & 0xFF) == 0xFF && buffer.getUint8(i+1) == 0 )
{
newbuffer.setUint8(newpos++,0xFF);
i++;
continue;
}
newbuffer.setUint8(newpos++,buffer.getUint8(i));
}
length = newpos;
buffer = newbuffer;
}
// Set some params
var pos = 0;
var ID3FrameSize = TagVersion < 3 ? 6 : 10;
var m_title;
var m_artist;
// Parse the tags
while ( true )
{
var rembytes = length - pos;
// Do we have the frame header?
if ( rembytes < ID3FrameSize )
break;
// Is there a frame?
if ( buffer.getChar(pos) < ''A'' || buffer.getChar(pos) > ''Z'' )
break;
// Frame name is 3 chars in pre-ID3v3 and 4 chars after
var framename;
var framesize;
if ( TagVersion < 3 )
{
framename = buffer.getString(pos,3);
framesize = ((buffer.getUint8(pos+5) & 0xFF) << 8 ) | ((buffer.getUint8(pos+4) & 0xFF) << 16 ) | ((buffer.getUint8(pos+3) & 0xFF) << 24 );
}
else
{
framename = buffer.getString(pos,4);
framesize = buffer.getInt(pos+4);
//(buffer.getUint8(pos+7) & 0xFF) | ((buffer.getUint8(pos+6) & 0xFF) << 8 ) | ((buffer.getUint8(pos+5) & 0xFF) << 16 ) | ((buffer.getUint8(pos+4) & 0xFF) << 24 );
}
if ( pos + framesize > length )
break;
if ( framename== "TPE1" || framename== "TPE2" || framename== "TPE3" || framename== "TPE" )
{
if ( m_artist == null )
m_artist = parseTextField( buffer, pos + ID3FrameSize, framesize );
}
if ( framename== "TIT2" || framename== "TIT" )
{
if ( m_title == null )
m_title = parseTextField( buffer, pos + ID3FrameSize, framesize );
}
pos += framesize + ID3FrameSize;
continue;
}
console.log(m_title,m_artist);
return m_title != null || m_artist != null;
}
function parseTextField( buffer, pos, size )
{
if ( size < 2 )
return null;
var charcode = buffer.getUint8(pos);
//TODO string decoding
/*if ( charcode == 0 )
charset = Charset.forName( "ISO-8859-1" );
else if ( charcode == 3 )
charset = Charset.forName( "UTF-8" );
else
charset = Charset.forName( "UTF-16" );
return charset.decode( ByteBuffer.wrap( buffer, pos + 1, size - 1) ).toString();*/
return buffer.getString(pos+1,size-1);
}
Debería ver el título y el autor en el registro de la consola. Sin embargo, observe la función de análisis de texto, donde la codificación determina la forma de leer la cadena. (buscar TODO). Tampoco lo he probado con los encabezados extendidos o uses_synch true o tag versión 3.
Respuesta parcialmente correcta (correctamente lee utf8 id3v2.4.0 con formato incluida la cubierta)
Las cosas que hice en mi pregunta probablemente funcionen ahora.
Quería un conjunto mínimo de funciones mínimas para manejar solamente id3v2.4.0 y también analizar la imagen adjunta.
Con la ayuda de @Siderite Zackwehdex, cuya respuesta está marcada como correcta, entendí la parte importante del código que faltaba.
Como tenía algo de tiempo para jugar, hice varias modificaciones al código.
Antes que nada, lo siento por el script comprimido, pero tengo una mejor visión general del código general. es más fácil para mí si tiene alguna pregunta sobre el código, solo pregunte.
De todos modos, uses_synch
el uses_synch
... es muy difícil encontrar un archivo que use sincronización. Lo mismo para has_extended_hdr
. También has_extended_hdr
el soporte para id3v2.0.0 a id3v2.2.0. Agregué una verificación de versión, que funciona con todas las subversiones id3v2.
El resultado de la función principal contiene una matriz con todas las etiquetas, dentro también puede encontrar la versión id3v2. Última, pero supongo que útil para expandir, agregué un objeto FRAME personalizado que contiene funciones personalizadas para marcos distintos de textFrames. La función ahora solo dentro convierte la imagen / portada / APIC en una cadena base64 fácil de usar. Al hacerlo, la matriz se puede almacenar como una cadena JSON.
Si bien para algunos de ustedes la compatibilidad es importante, el encabezado o la sincronización anteriorizados son en realidad el problema más pequeño.
PROBLEMAS
La codificación debe ser UTF-8; de lo contrario, se obtienen almohadillas de texto extrañas y algunas imágenes se analizan solo parcialmente. básicamente roto.
Quiero evitar el uso de una biblioteca externa o incluso una función realmente grande solo para eso ... tiene que haber alguna solución inteligente simple para manejar adecuadamente la codificación. ISO-8859-1, UTF-8, UTF-16 .. big endian ... lo que sea ... # 00 vs # 00 00 ...
Si eso se hace, el soporte se puede mejorar exponencialmente.
Espero que algunos de ustedes tengan una solución para eso.
CÓDIGO
DataView.prototype.str=function(a,b,c,d){//start,length,placeholder,placeholder
b=b||1;c=0;d='''';for(;c<b;)d+=String.fromCharCode(this.getUint8(a+c++));return d
}
DataView.prototype.int=function(a){//start
return (this.getUint8(a)<<21)|(this.getUint8(a+1)<<14)|
(this.getUint8(a+2)<<7)|this.getUint8(a+3)
}
var frID3={
''APIC'':function(x,y,z,q){
var b=0,c=['''',0,''''],d=1,e,b64;
while(b<3)e=x.getUint8(y+z+d++),c[b]+=String.fromCharCode(e),
e!=0||(b+=b==0?(c[1]=x.getUint8(y+z+d),2):1);
b64=''data:''+c[0]+'';base64,''+
btoa(String.fromCharCode.apply(null,new Uint8Array(x.buffer.slice(y+z+++d,q))));
return {mime:c[0],description:c[2],type:c[1],base64:b64}
}
}
function readID3(a,b,c,d,e,f,g,h){
if(!(a=new DataView(this.result))||a.str(0,3)!=''ID3'')return;
g={Version:''ID3v2.''+a.getUint8(3)+''.''+a.getUint8(4)};
a=new DataView(a.buffer.slice(10+((a.getUint8(5)&0x40)!=0?a.int(10):0),a.int(6)+10));
b=a.byteLength;c=0;d=10;
while(true){
f=a.str(c);e=a.int(c+4);
if(b-c<d||(f<''A''||f>''Z'')||c+e>b)break;
g[h=a.str(c,4)]=frID3[h]?frID3[h](a,c,d,e):a.str(c+d,e);
c+=e+d;
}
console.log(g);
}
MANIFESTACIÓN