使用 eyed3 从 mp3 文件名获取歌曲名设置 ID3 属性

需求

近期有朋友拜托弄一批 mp3 放 U 盘里面以便开车的时候听,于是下载了一批歌曲,都整理成 歌曲名-歌唱者.mp3 这样的文件名。可是有些播放器会优先使用 ID3(即 mp3 文件的一个自带的信息段。顺便吐槽一下,官方网站 https://id3.org 居然打不开,提示 500 错误?!) 来罗列歌单,而不是文件名,这些 mp3 本身的 ID3 属性良莠不齐,到时候就乱套了。因此需要逐个将文件名上面的歌曲、歌者信息写入 mp3 文件的 ID3 属性内。

实战

此类日常事务,最方便的自然是 python 了。查了一下,python 下的音频文件处理模块有 eyed3、pydub、pyAudio 等。其中的 eyed3 最为小巧便捷。完整代码如下

python 复制代码
import  os
import eyed3


def main(path):
    files= os.listdir(path)
    counter = 0
    for mp3 in files:
        if mp3[-3:] != 'mp3' :
            continue

        title, artist = get_title_artist_from_filename(mp3)
        
        # 调用 eyed3 模块,写入歌曲信息
        try:
            audio = eyed3.load(path + '/' + mp3)
            print(f'[eyed3] load {mp3} success,', end=' ')
        except:
            print(f'[error] {mp3} load fail!')
            continue
        if(audio.tag == None): # 部分歌曲 ID3 信息缺失
            audio.tag = eyed3.id3.tag.Tag()
        audio.tag.title = title
        audio.tag.artist = artist
        print(f'ready to write ID3: {title} {artist}')
        audio.tag.save(version=eyed3.id3.ID3_V2_4, encoding = "utf8") # 指定使用 ID3 V2.4,确保支持中文,ref: ..\lib\site-packages\eyed3\id3
        counter += 1
    
    print(f'共处理了 {counter} 个 mp3 文件')


def get_title_artist_from_filename(filename):
    '''通过文件名获取歌曲信息,文件名样式:歌曲名 - 歌唱人员.mp3'''
    prefix = filename.split('.')[0]
    msg = prefix.split('-') 
    title = msg[0].strip()
    artist = msg[1].strip()
    return (title, artist)


if __name__ == '__main__':
    mp3 = 'd:/temp/经典老歌'
    main(mp3)

踩坑

这里最大的坑有两个:

  1. 低版本 ID3 不支持 unicode,导致写入的中文会变成一串的 ?
  2. 部分歌曲本身不带 ID3 属性,此时需要自行添加之。

下面逐一解释

指定 ID3 版本

有些歌曲自带的 ID3 属性是 v1.0 版本的,只支持英文字母,强行写入中文会导致乱码,或者干脆显示成一串的 ?????

解决这个问题的办法,就在 eyed3.id3.tag.Tag.save()里面,官方文档说,给 save() 函数加上 version=... 的参数,确保使用高版本的 ID3 就可以支持 unicode。可是文档到这里就没了,也没告诉我这个版本具体要怎么指定。

没办法,只能打开下载的 eyed3 源代码,找到函数定义,发现 ID3 版本号都定义在 site_packages\eyed3\id3\__init__.py 里面,直接取用即可。如下

python 复制代码
# Version 1, 1.0 or 1.1
ID3_V1 = (1, None, None)
# Version 1.0, specifically
ID3_V1_0 = (1, 0, 0)
# Version 1.1, specifically
ID3_V1_1 = (1, 1, 0)
# Version 2, 2.2, 2.3 or 2.4
ID3_V2 = (2, None, None)
# Version 2.2, specifically
ID3_V2_2 = (2, 2, 0)
# Version 2.3, specifically
ID3_V2_3 = (2, 3, 0)
# Version 2.4, specifically
ID3_V2_4 = (2, 4, 0)

因此我们使用 tag.save(version=eyed3.id3.ID3_V2_4, encoding = "utf8") 即可确保中文不乱码。

添加 ID3 属性

有些 mp3 文件本身不自带 ID3 属性,此时 eyed3 调用 tag 属性就会出错。

运行一个 python 的交互界面,手动生成一个 eyed3 对象,检查 __dict__ 属性,大致如下:

python 复制代码
>>> import eyed3
>>> a = eyed3.load('d:/temp/a/q.mp3')
>>> a.__dict__
{'_tag_version': None, 
'_path': 'd:\\temp\\a\\q.mp3', 
'type': 1, 
'_info': Mp3AudioInfo(time_secs=316.78, size_bytes=5056888), 
'_tag': None}

可以看到 _tag 属性为 None。解决办法就是自行生成一个 Tag 对象,手动赋值即可。即代码中的 audio.tag = eyed3.id3.tag.Tag() 这句

参考

相关推荐
Main. 243 分钟前
Linux进程观:简单性如何成就强大性(六)
linux·运维·服务器
CODE-boy17 分钟前
利用8个参数定义一个汽轮机,然后根据这8个参数生成汽轮机性能试验时的测点清单-pycharm-源代码(适用所有类型汽轮机)
ide·python·pycharm·汽轮机·性能试验
丶重明9 分钟前
【Go每日一练】实现简单的控制台计算器
服务器·算法·golang
西域编娃12 分钟前
Hadoop 集群部署与配置详解
大数据·linux·运维·hadoop·分布式
紫气东来,茉上花开12 分钟前
java如何在linux服务器创建文件excel并把循环插入每一行的后端查出来的数据,每天新建一个excel带时间的
java·linux·服务器
2301_8010670915 分钟前
Web服务器配置、虚拟主机配置、访问权限控制
运维·服务器·php·apache
追寻向上32 分钟前
《JMeter自动化测试实战指南:从环境搭建到Python集成(进阶篇)》
开发语言·python·jmeter
Start_Present34 分钟前
Pytorch 第十回:卷积神经网络——DenseNet模型
pytorch·python·深度学习·神经网络·分类·cnn
猫头虎41 分钟前
阿里云操作系统控制台评测:国产AI+运维 一站式运维管理平台
运维·服务器·人工智能·阿里云·aigc·ai编程·ai写作
沉到海底去吧Go44 分钟前
图片OCR多区域识别并重命名图片文件,基于Python和阿里云的实现方案
python·阿里云·云计算·ocr·pdf信息提取到表格·多个区域内容提取信息到表格·批量pdf多个区域内容保存表格