我有一个场景,其中我正在构建一个播客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/