添加 ID3 标记 HTML5 文件系统 API
adding id3 tags html5 filesystem api
>我有一个场景,我正在构建一个播客 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
用于上面演示中使用的示例值。
- qoxdoo中的离线存储是否与所有浏览器和本地文件系统兼容
- 内容安全策略指令:;脚本src'self'blob:文件系统:chrome扩展资源:“;获取是否时
- Html 5文件系统API,我得到一个DOMError“;NotSupporteError”;
- 跨浏览器JS文件系统API
- 如何使用chrome文件系统api从chrome应用程序中的url下载图像
- 在文件系统中使用谷歌API
- 声云 API 认证 |NodeWebkit,重定向URI和本地文件系统
- 文件系统API-递归列出从目录拖放文件
- 从HTML5文件系统api上传
- 如何从Deployd(Deployd.com)访问Node.js文件系统API
- 离线应用:使用HTML5文件系统API存储MySQL数据库
- 文件系统API不工作在Chrome v27 &v29
- 文件系统API:文件和文件夹位于哪里
- 如何使用窗口.requestFileSystem的文件系统API
- 使用文件系统api检索所有目录
- Youtube数据API v3文件系统
- 使用 HTML 5 文件系统 API 从字符串路径读取文件
- 添加 ID3 标记 HTML5 文件系统 API
- 在web中同步文件系统API
- JavaScript文件系统API作为象棋Alpha Beta数据存储