我发现,除了文件名之外,我所有的文件都有错误编码的元数据。
我发现 mp3 文件的 id3 元数据标准只支持 latin1、utf8 和 utf16 编码。
我的文件都包含在 mp3 文件中设置为 latin1 的 CP1251 数据。可能在俄罗斯和西里尔文字国家,所有音乐播放器都将理解 latin1 应该被解释为 CP1251,但对我来说并非如此。
我使用 Python 和 mutagen 来更正元数据。在读取 mp3 元数据时,mutagen 假定数据被编码为 latin1,结果显示乱码。我要做的是得到那些乱码,再次将它们编码成latin1并解码为CP1251,获得unicode。然后我覆盖了 mp3 元数据,然后 mutagen 明白 unicode 应该保存为 utf-8。这样所有的元数据都是正确的。
为了更正文件元数据,我使用了以下 Python 脚本:
from mutagen.easyid3 import EasyID3
def decode_song_metadata(filename):
id3 = EasyID3(filename)
for key in id3.valid_keys:
val = id3.get(key)
if val:
print key
decoded = val[0].encode('latin1').decode('cp1251')
print decoded
id3[key] = decoded
id3.save()
def correct_metadata():
paths = [u'/Users/felipe/Downloads/Songs']
for path in paths:
print 'path: ' + decode_filename(path)
for dirpath, dirnames, filenames in os.walk(path):
for filename in filenames:
try:
decode_song_metadata(os.path.join(dirpath, filename))
except:
print filename
if __name__ == '__main__':
correct_metadata()
这更正了 mp3 元数据,但更正文件名需要不同的技巧,因为它们有不同的编码问题。我认为发生的是原始文件名在 CP1251 中,但是当它们从我的 fat32 格式的 USB 棒复制到我的 Mac 时,macOS 将文件名解释为 latin1。这起源于带有奇怪重音字符的文件名,这些文件名在“正常形式分解”中以 UTF-16 编码,其中每个重音都保存为与主字母不同的 unicode 字符。macOS 还添加了一个污染文件名的 BOM 标记。所以为了纠正这个我不得不做相反的操作:
- 获取文件名。这将返回一个 unicode 字符串,其中分解了范式中的拉丁重音字符。
- 我们必须再次转换为 Normal Form Composed。
- 然后我们用 UTF-16 编码。
- 我们删除 BOM。
- 我们解码解释为 CP1251。
为了解码文件名,我使用了以下脚本:
def decode_filename(filename):
# MacOS filenames are stored in Unicode in "Normal Form Decomposed"
# form, where the accents are saved separated from the main
# character. Because the original characters weren't proper
# accentuated letters, in order to recover them we have to decompose
# the filenames.
# http://stackoverflow.com/a/16467505/212292
norm_filename = unicodedata.normalize('NFC', filename)
utf16 = norm_filename.encode('utf16')
bom = codecs.BOM_UTF16
if utf16.startswith(bom):
# We have to remove the BOM bytes
utf16 = utf16[len(bom):]
cp1251 = utf16.decode('cp1251')
return cp1251
这应该与运行 os.walk() 方法返回的 unicode 一起使用。
虽然上面的脚本有效,但我最终没有使用它来更正文件名。我使用的是启用了“自动管理器”功能的 iTunes。这很棒,因为每次我在 iTunes 上播放歌曲时,它都会获取 mp3 元数据(我已经使用上面的第一个脚本进行了更正)并重命名 mp3 文件以包含歌曲名称,甚至文件夹。我发现这比更正文件名更好,因为这也会正确重命名文件夹并放置对歌曲有意义的文件名。