是否可以使用mutagen将ID3标签添加到m4a文件?

时间:2017-07-03 23:47:06

标签: python python-3.6 mutagen

在编写脚本以使用mutagen标记我的音乐库时遇到问题。 以下代码在处理mp3文件时工作正常,但会破坏m4a文件。

def set_video_tags(video, filepath):
    try:
        tags = ID3(filepath, v2_version=3)
    except ID3NoHeaderError:
        tags = ID3()

    tags.add(TXXX(3, desc='desc:custom_tag',text= video.custom_text))
    tags.save(filepath, v2_version=3)

处理完m4a文件后,可以使用mutagen回读标签,但任何其他播放器都不会检测到标签,音频也不会播放。

我尝试在调用此函数之前从文件中删除MP4标记,但它没有帮助。

我做错了什么?

1 个答案:

答案 0 :(得分:5)

正如我在评论中所说,MP4和MP3是不同的容器,它们使用完全不同的结构来存储元数据。虽然从技术上讲,你可以在MP4元数据中对ID3字段进行编码,但这种情况的使用在很大程度上取决于你的标记器/播放器,因为有很多方法可以做到这一点,而且每个人都认为他们有最好的方式来推动他们自己的结构。

MP3容器的ID3是什么,XMP适用于MP4 / M4A容器(如果你愿意的话,还有许多其他容器,如JPEG,PDF甚至MP3) - 除了XMP是实际的标准ID3是一个事后的想法(它实际上只是MP3文件末尾的一个增加的尾随结构),每个人都参与其中,它的功能主要由当时大受欢迎的玩家决定,如WinAmp,foobar2000等。相比之下,XMP本质上是一种类似原子的结构(这就是为什么你会听到mp4标签被称为'原子甚至他们并不是指同一个东西)元数据还包含元数据所呈现的信息,因此即使是第一次遇到元数据的玩家,理论上也可以从不相关的元数据中辨别相关信息。

当然,在实践中,这也变成了一个玩家/标记器战争,所以他们中的很多人都使用他们自己的自定义'扩展'用于标记 - 目前iTunes对于应该使用哪些字段以及如何以及其他玩家类型的播放方式有着巨大的影响力 - mutagen也是如此。 iTunes将标签分散为MP4结构本身的非视频/音频帧(实际的'原子')而不是单个XMP结构。必须奇怪地命名(二进制名称等),以便它们不会干扰格式本身。虽然这种方法有一些优势(通过流式更改元数据,对实时事件非常有用),但它会使标记变得不必要地复杂化,而且非标准化。

无论如何,出现问题是因为您正在尝试将ID3结构写入MP4容器 - 编写ID3标签时mutagen并未解析整个文件以辨别基础文件是否支持ID3以及在何处/如何编写它,而不是它假定它已经被送入一个普通的MP3文件并以错误的格式写下错误的地方,最好只是在文件的末尾添加一些垃圾(之前,非可流动的ID3版本)或者,最坏的情况是,损坏您的M4A容器。当你读回文件时也是如此 - 它可以读取它之前在可预测位置写入的ID3结构,它并不关心其余数据是什么。

因此,正如我所说,并且正如文档中所示,在处理MP4 / M4A容器时使用mutagen.mp4.MP4(或者更确切地说是底层mutagen.mp4.MP4Tags),因为这些容器是为了与MP4容器。例如,要在您尝试时更改desc代码:

from mutagen.mp4 import MP4

def get_description(filename):
    return MP4(filename).tags.get("desc", [None])[-1]

def set_description(filename, description):
    tags = MP4(filename).tags
    tags["desc"] = description
    tags.save(filename)

注意:我只使用desc函数中的最后一个get_description()条目作为每个'标记的多个条目'支持,因此现有标签作为列表返回。你显然不会在生产环境中使用上述内容。

您可以使用以下方法进行测试:

print("Current description: {}".format(get_description("test.m4a")))
# Current description: None

set_description("test.m4a", "Test description")  # let's add some description
print("Current description: {}".format(get_description("test.m4a")))
# Current description: Test description

# You can also modify the description once set:
set_description("test.m4a", get_description("test.m4a") + " update")
print("Current description: {}".format(get_description("test.m4a")))
# Current description: Test description update

# etc.

支持全套'支持' (或者更确切地说是iTunes,嗯,鼓励)键,您可以查看mutagen.mp4.MP4Tag文档。当然,您可以使用自由形式结构(即----:foo:bar)创建自己的密钥,但不要期望任何其他玩家识别它们。

相关问题