我有一个场景,其中我正在构建一个播客Web应用程序,该应用程序允许侦听和存储.mp3播客文件。

我正在尝试实现一个基本的Web界面,有人可以从客户端添加整个id3标签(该文件将存储在客户端本地:此客户端与每个客户端都不一样,而只是获得原始播客的家伙文件,最好不要包含任何id3标签)。然后,他在本地托管此页面,在本地添加正确的id3标签,然后将这些.mp3复制到WebDav文件夹中。

我确实知道需要在服务器上进行编辑,但是如果所有这些都可以在浏览器上本地完成,那将真的很有帮助。

当然没有可用的库来编辑文件,所以我决定使用HTML5文件系统api,即将文件拖放到虚拟文件系统中,进行编辑,然后将其复制回本地系统。 (要复制,有一个现成的库FileSaver.js)。

我已经能够做到以下几点:
1)使用webkitGetAsEntry将放置在放置区域的mp3文件与文件系统api相关联

2)然后将此文件复制到文件系统api。

部分代码如下所示:

function onDrop(e)
{
    e.preventDefault();
    e.stopPropagation();

    var items = e.dataTransfer.items;
    var files = e.dataTransfer.files;

    for (var i = 0, item; item = items[i]; ++i)
    {
        // Skip this one if we didn't get a file.
        if (item.kind != 'file') {
            continue;
        }

        var entry = item.webkitGetAsEntry();

        if (entry.isFile)
        {
            // Copy the dropped entry into local filesystem.
            entry.copyTo(cwd, null, function(copiedEntry) {
            //setLoadingTxt({txt: DONE_MSG});
            renderMp3Writer(entry);


我的困惑是如何添加整个id3标签? 。由于不确定,我现在迷路了:

1)我们可以从fileWriter方法将整个id3标签添加到文件中吗?
2)如果是,这将是一个二进制编辑或如何? 。

任何帮助将是有用的。尝试了以下内容,但我想我错了。

var blob1 = new Blob(['ID3hTIT2ga'], {type: 'audio/mp3'});
fileWriter.write(blob1);

最佳答案

您需要构建一个ID3缓冲区,然后创建一个足以容纳ID3和MP3文件的缓冲区,插入ID3并附加MP3数据。

为此,您需要ID3 specification并将带类型的数组与DataView一起使用来构建数组。

ID3的总体结构是这样定义的(请参见上面的链接):

 +-----------------------------+
 |      Header (10 bytes)      |
 +-----------------------------+
 |       Extended Header       |
 | (variable length, OPTIONAL) |
 +-----------------------------+
 |   Frames (variable length)  |
 +-----------------------------+
 |           Padding           |
 | (variable length, OPTIONAL) |
 +-----------------------------+
 | Footer (10 bytes, OPTIONAL) |
 +-----------------------------+


此时,缓冲区长度是未知的,因此您需要分步执行此操作。有几种方法可以执行此操作,您可以为每个字段建立较小的缓冲区段,然后将它们汇总为一个缓冲区。或者,您可以制作一个更大的缓冲区,知道可以容纳要包含的所有字段,并将字段总和从该缓冲区复制到最后一个。

后者往往更简单,并且由于我们正在处理非常小的尺寸,因此这可能是最好的方法(考虑到第一种方法中的每个片段都有其开销)。

因此,您需要做的第一件事就是定义标题。标头是通过以下方式定义的:

ID3v2/file identifier      "ID3"
ID3v2 version              $04 00
ID3v2 flags                %abcd0000  (note: bit-representation)
ID3v2 size             4 * %0xxxxxxx  (note: bit-representation/mask)


ID3和版本是固定值(当然也存在其他版本,但请遵循当前版本)。

通过将它们设置为0,您可能会忽略大多数标志(如果不是全部的话)。但是请检查文档以了解用例,例如,如果要使用扩展标头。

大小定义:


  ID3v2标签大小存储为32位同步安全整数(部分
     6.2),总共产生28个有效位(最多256MB)。
  
  ID3v2标签大小是扩展字节长度的总和
  标头,填充和不同步后的帧。如果一个
  页脚存在,等于('total size'-20)个字节,否则
  (“总大小”-10)字节。


一个如何构建缓冲区的示例。首先定义一个足以容纳所有数据和DataView的缓冲区:

var id3buffer = new ArrayBuffer(1024),    // 1kb "space"
    view = new DataView(id3buffer);


DataView默认为big-endian,这是完美的选择,因此我们现在要做的就是在应有的位置填充数据。我们可以制定一些辅助方法来帮助我们在编写文字的同时移动位置。 DataView的位置是字节绑定的:

 var pos = 0;    // global start position

function setU8(value) {
    view.setUint8(pos++, value)
}

function setU16(value) {
    view.setUint16(pos, value);
    pos += 2;
}

function setU32(value) {
    view.setUint32(pos, value);
    pos += 4;
}


等等。您可以使助手编写文本unicode字符串(例如,参见TextEncoder)等等。

要定义标题,我们可以写“魔术”字ID3。您可以转换一个字符串,或者因为它只有3个字节,也可以直接将其写入。 ID3 = 0x494433以十六进制表示,因此:

setU8(0x49);     // at pos 0
setU8(0x44);     // at pos 1
setU8(0x33);     // at pos 2


因为我们做了包装器,所以我们不必担心缓冲区的位置。

然后写入版本(根据规范v.2.4.0使用0x0400而不使用主要版本(2)):

setU16(0x0400);  // default is big-endian so this works


现在,您可以继续标记和大小(请参阅规格)。

当ID3标头填满后,pos现在将保留总长度。因此,为ID3标签和MP3缓冲区新建一个缓冲区:

var mp3 = new ArrayBuffer(pos + mp3Buffer.byteLength),
    view8 = new Uint8Array(mp3);


view8视图将使我们能够简单地复制到目标:

// create a segment from the tag buffer that will fit target:
var segment = new Uint8Array(view.buffer, 0, n); // replace n with actual length
view8.set(segment, 0);
view8.set(mp3buffer, pos);


如果一切顺利,您现在将拥有一个带有ID3标签的MP3(请记住要检查现有的ID3,您需要扫描到末尾)。

现在,您可以将ArrayBuffer发送到服务器,或者转换为Blob for IndexedDB,或者如果您想提供一个下载链接,则转换为Object-URL(此处未显示,因为答案已超出范围)。

这应该足以让您入门-如前所述,您需要研究规格。如果您不熟悉typed array,请也检查一下。

另请参见站点上的other resources(框架等)。

同步安全值

“ MP3”文件使用以11位开头的帧,所有帧均设置为1。如果标头的size字段恰好包含设置为1的11位,则解码器可能会错误地将其解释为声音数据。为避免这种情况,使用了同步安全整数的概念,确保将每个字节的MSB(最高有效位,位7)始终设置为0。对于ID3,该位向左移动,下一个字节向后移一位。标签4次(因此为4x%01111111)。

以下是使用JavaScript(来自Wikipedia C/C++ source的)对同步安全整数进行编码和解码的方法:



// test values
var value = 0xfffffff,
    sync = intToSyncsafe(value);
document.write("<pre>Original size: 0x" + value.toString(16) + "<br>");
document.write("Synch-safe   : 0x" + sync.toString(16) + "<br>");
document.write("Decoded value: 0x" + syncsafeToInt(sync).toString(16) + "</pre>");


function intToSyncsafe(value) {
    var out, mask = 0x7f;
    while(mask ^ 0x7fffffff) {
        out = value & ~mask;
        out <<= 1;
        out |= value & mask;
        mask = ((mask + 1) << 8) - 1;
        value = out;
    }
    return out
}

function syncsafeToInt(value) {
    var out = 0, mask = 0x7F000000;
    while (mask) {
        out >>= 1;
        out |= value & mask;
        mask >>= 8;
    }
    return out;
}





同步安全值将显示如下位:&b01111111011111110111111101111111为以上演示中使用的示例值。

关于javascript - 添加id3标签html5文件系统api,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30794645/

10-10 19:15