添加 ID3 标记 HTML5 文件系统 API

adding id3 tags html5 filesystem api

本文关键字:文件系统 API HTML5 标记 ID3 添加      更新时间:2023-09-26

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

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

我确实知道编辑需要在服务器上完成,但如果这一切都可以在浏览器上本地完成,那将非常有帮助。

当然没有现成的库来编辑文件,所以我决定使用 HTML5 文件系统 api,即将文件放入虚拟文件系统中,在那里编辑它,然后将其复制回本地系统。(对于复制,有一个现成的库文件保护程序.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 规范,并将类型化数组与 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 标签大小是扩展
的字节长度的总和 标头、填充和不同步后的帧。
如果 页脚存在,这等于("总大小" - 20)字节,否则 ("总大小" - 10) 字节。

如何构建缓冲区的示例。首先定义一个足够大的缓冲区来容纳所有数据以及一个数据视图:

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

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(此处未显示任何内容,因为答案已超出范围)。

这应该足以让您入门 - 如前所述,您需要研究规格。如果您不熟悉类型化数组,也可以查看这些内容。

另请参阅网站以获取其他资源(框架等)。

同步安全值

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

以下是如何使用JavaScript编码和解码同步安全整数(来自维基百科C/C++来源):

// 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 用于上面演示中使用的示例值。