Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/380.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/laravel/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用本机Chrome Javascript/FileReader/DataView读取id3 v2.4标记_Javascript_Filereader_Dataview_Id3 - Fatal编程技术网

使用本机Chrome Javascript/FileReader/DataView读取id3 v2.4标记

使用本机Chrome Javascript/FileReader/DataView读取id3 v2.4标记,javascript,filereader,dataview,id3,Javascript,Filereader,Dataview,Id3,根据的答案,可以通过以下方式读取id3v1标签: Chrome和其他浏览器现在已经实现了DataView(我只对Chrome感兴趣)。我很好奇是否有人知道如何: 使用本机数据视图读取标记 读取id3 v2.4标记(包括APIC图像“coverart”) 关键是我没有使用二进制文件的经验,完全不知道如何跳转到正确的标记位置,也不知道little endian和long endian(或其他什么)是什么。我只需要一个标签的例子,比如标题,TIT2标签,我希望它能帮助我理解如何跳转到正确的位置,以及如

根据的答案,可以通过以下方式读取id3v1标签:

Chrome和其他浏览器现在已经实现了DataView(我只对Chrome感兴趣)。我很好奇是否有人知道如何:

  • 使用本机数据视图读取标记
  • 读取id3 v2.4标记(包括APIC图像“coverart”)
  • 关键是我没有使用二进制文件的经验,完全不知道如何跳转到正确的标记位置,也不知道little endian和long endian(或其他什么)是什么。我只需要一个标签的例子,比如标题,
    TIT2
    标签,我希望它能帮助我理解如何跳转到正确的位置,以及如何阅读其他标签:

    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);
    
    这是你的电话号码


    更新

    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);
    }
    

    我添加了
    getString
    ,以便读取第一行并检查它是否包含ID3。 现在我需要找到第一个标记(TIT2)的位置和该字符串的“可变”长度&还要检查它是否是版本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
    

    可能的外部来源:

    我现在正在使用PHP getid3库

    您可以尝试使用

    包括后,您只需在代码中执行以下操作:

    function readFile(){
       id3(this.files[0], function(err, tags) {
           console.log(tags);
       })
    }
    document.getElementsByTagName('input')[0].addEventListener('change',readFile,false);
    
    下面是由
    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"
      }
    }
    

    希望这有帮助

    使用我在这里找到的代码:,我在这里将其翻译成Javascript:

    下面是我在那里写的代码:

    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);
    }
    
    DataView.prototype.getChar=函数(开始){
    返回字符串.fromCharCode(this.getUint8(start));
    };
    DataView.prototype.getString=函数(开始,长度){
    
    对于(var i=0,v='';i部分正确答案(正确读取utf8格式的id3v2.4.0,包括封面)

    我在问题中提出的问题现在可能有效了

    我想要一个非常粗糙的最小函数集,只处理id3v2.4.0&并解析附加的图像

    在@Siderite Zackwehdex的帮助下,答案被标记为正确,我理解了代码中缺失的重要部分

    由于我有一些时间来使用它,我对代码进行了各种修改

    首先,对于压缩后的脚本,我感到很抱歉,但我对整个代码有了更好的了解。这对我来说更容易。如果您对代码有一些问题,请提问

    无论如何,我删除了
    uses\u synch
    …很难找到使用synch的文件。同样的
    扩展了\u hdr
    。我还删除了对id3v2.0.0到id3v2.2.0的支持。我添加了一个版本检查,该检查适用于所有id3v2子版本

    主函数输出包含一个包含所有标记的数组,在里面你也可以找到id3v2版本。最后,但我想这对扩展很有用,我添加了一个自定义框架对象,其中包含除textFrames之外的其他框架的自定义函数。现在唯一的内部函数将image/cover/APIC转换为易于使用的base64字符串。这样,数组可以存储为JSON字符串

    对你们中的一些人来说,兼容性很重要,但上面提到的exended头或sync实际上是最小的问题

    问题

    编码需要是UTF-8,否则会出现奇怪的文本填充和 有些图像只被部分解析,基本上被破坏了

    我想避免使用外部库,甚至是一个非常大的函数…需要一些智能的简单解决方案来正确处理编码。 ISO-8859-1,UTF-8,UTF-16..大端…不管什么…#00对#00

    如果做到这一点,支持能力将得到指数级的提高

    我希望你们中的一些人能找到解决办法

    代码

    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);
    }
    
    DataView.prototype.str=函数(a,b,c,d){//开始,长度,占位符,占位符
    
    b=b | | 1;c=0;d='';代表(;C能否提供此帮助?我正在搜索本机函数…反物质使用了大量的多边形填充…这使得它非常缓慢和不稳定。它在许多浏览器上都很好用…但我只需要chrome就可以了。我只想在ajax filereader dataview等重要函数中使用最新的js 1.7+。反物质的代码适用于一个文件…但是如果你需要处理多个文件这不是一个好主意。另外,使用chrome,你可以使用持久性存储,因此可以处理大文件。wich,有了更多的知识,还可以让你将这些标记写入文件。想想mp4格式。我在Node.js中使用了它,并取得了很大成功,也许你可以通过browserify?运行它,因为它期望一个可读的流,你必须找到一种方法将数据打包成一个可读的流。你可以使用XHR获取mp3,并将responseType设置为“arraybuffer”以处理原始字节。这方面的好处是它可以在客户端运行…如果客户端可以这样做,为什么要使用服务器上的节点进行计算???我希望我们可以改进我希望我们能进一步改进这个极小函数