tag para pagina oficial mp3tag etiquetas descargar javascript filereader dataview id3

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:

  1. Leer etiquetas usando el DataView nativo
  2. 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

http://jsfiddle.net/s492L/3/

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

http://getid3.sourceforge.net/

http://getid3.sourceforge.net/source2/module.tag.id3v2.phps


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

https://jsfiddle.net/2awq6pz7/