Titles/Album 超过 30 个字节的名称

Titles/Album names that are longer than 30 bytes

不知道这是不是正确的地方。

我正在尝试读取 ID3V1 标签的元数据,有些标题超过 30 个字节,其他程序读取完整标题没有问题。我检查了 id3.org 但没能找到任何有用的信息。我该如何阅读完整的标题?

#!/usr/bin/python3

from os import listdir
from os.path import isfile, join

path = "/media/Music/RZ"
files = [join(path, f) for f in listdir(path) if isfile(join(path, f)) and f.endswith("mp3")]

for f in files:
    with open(f, "rb") as f:
        f.seek(-128, 2)
        data = f.read()

        if data[:3] == b"TAG":
            title = data[3:33].decode("UTF-8")
            artist = data[33:63].decode("UTF-8")
            album = data[63:93].decode("UTF-8")

打印标题结果为

Super-Doom-Hex-Gloom Part One
Get Your Boots On ! That's The
Wurdalak
In The Age Of The Consegrated 
A Hearse That Overturns With T
Well, Everybody's Fucking In A
Satanic Cyanide ! The Killer R
The Life And Times Of A Teenag
The Last Of The Demons Defeate
Medication For The Melancholy
The Hideous Exhibitions Of A D
In The Bone Pile

正如 PeterCo 在他们的评论中所说,就 ID3v1 标签所知,您 正在 阅读完整的标题。该标准有一些非官方扩展,允许稍长的字段(“extended tag" being slightly better-known than ID3v1.2 or ID3v1.3”),但其中 none 很常见——如果您的测试文件我会感到惊讶包括它们。我的猜测是显示完整标题的程序实际上是从 ID3v2 标签中获取的,该标签(尽管名称)与 ID3v1 几乎没有共同之处。

如果您只是想要一些东西来确保正确的文件在更大的程序中遵循正确的路径,那么我建议您坚持使用现有的东西;它清晰轻巧。如果您 关心 ID3v1 标签,则相同。但是,如果您 正在使用完整标题做某事,那么到目前为止,您最好的选择是使用 existing libraries 之一。实际上,我发现实施该规范很有趣,但无可争议的是,它本身就是一个完整的项目。


就是说,如果您知道除了标题(或其他 near-ubiquitous 文本字段的可预测的、有限的选择)之外您永远不会想要任何东西,您可以天真地扫描文件以查找正确的 headers,如下所述。我希望你能原谅我没有编写实际代码,但我已经有一段时间没写 Python 了。如果您这样做,我真的建议您查看 official specifications 以更好地了解您将跳过的内容。

您要做的第一件事是检查文件的前三个字节。如果它们不是 49 44 33(ASCII 中的 ID3),那么它可能没有 ID3v2 标签(或者格式不正确),您也可以使用 ID3v1。当您在此处时,您可能需要检查第四个字节 – 它将是 0304,具体取决于文件使用的版本。一旦我们读到文本,它们之间可能会出现一些差异,但现在只需确保之后的 second 字节(文件中的第六个字节)小于128,尤其是版本字节为 03 时;你不想处理反向不同步,相信我。

一旦你验证了这一点,就开始 运行 浏览文件,直到你找到序列 54 49 54 32TIT2 代表 "Text tITle 2" 实际上是数字我们想要;或者,您可能希望为艺术家匹配 54 50 45 31 TPE1 或为专辑匹配 54 41 4C 42 TALB,或者在规范中查找其他 ID)。这不是一个特别常见的序列,但只是为了确保您不会 运行 进入任何已保存在评论或任何内容中的内容,您可能需要确保接下来的几个字节跟在 00 00 0_ __ _0 00 之后– 即使这样也不是万无一失的。无论如何,前四个字节是大小,虽然 技术上 可能顶部 two-and-a-half 不会是 00 00 0,但这需要一个长得离谱的字符串文本(超过 2047 字节)或填充过多;最后两个表示该字段的特殊属性,虽然零也有可能实际上不是零,但这意味着该字段的编码方式并不简单,如果您尝试处理它,您可能会考虑实施整个标准。

读取下一个字节。它指示文本的编码方式:00 表示 ISO-8859-101 表示以 byte-order-marker 开头的 UTF-16,02 是 big-endian UTF -16 没有字节标记,03 是 UTF-8。您可以忽略任何您不想处理的内容,但 ID3v2.3 仅支持前两个,如果您已经识别带有 BOM 的 UTF-16(并且编写了足够多的程序),则忽略 UTF-16BE 并没有任何好处编码中的标签,你会想要捕捉它),或者如果你识别 ISO-8859-1,则为 UTF-8。

之后才是版本字节真正发挥作用的地方。如果你在 ID3v2.3 中,你只需要读取到第一个空字符(不是字节;仅对于 UTF-16 编码,这意味着寻找两个连续的 00 字节)。如果您使用的是 ID3v2.4,则需要在采用简单方法还是完全支持新版本支持的多个值之间做出选择。我推荐第一个,因为——信不信由你——我试图让这个实现简洁,但为了完整性,另一个需要记住两个段落的大小字节,将第三个(第一个 half-blank)向左移动通过 7 位(或乘以 128)加上第四位(全空格),读取那么多字节(不是字符),根据上一段解码,拆分字符串在空字符(不是字节)上。

最后,您获得了完整的头衔。如果你想继续寻找另一个文本标签(比如我在上面放弃的作者​​或专辑),那么你需要继续扫描文件的其余部分以找到他们的 headers。否则,只需跳转到 ID3v1 标签并陶醉于如何 siple 它是为了获得 t运行 指定的值。