【Python】 获取MP3信息replica
replica
初衷是想要整理iphone中的音乐。IOS(我自己的手机还是IOS8.3,新版本的系统可能有变化了)自带的音乐软件中所有音乐文件都存放在/var/mobile/Media/iTunes_Control里面。不过很令人抓狂的是首先这个目录被分隔成了从F00-Fxx的多个子目录,我的手机上总共到F49,mp3文件都放在这些子目录中。其次,mp3文件名全部都被点窜了,是看起来毫无规律的随机四位大写字母。每隔一段时间我都想从手机中把音乐备份出来然后放到电脑上,但是不知道文件名的话维护起来很麻烦。所以需要一个小程序来根据mp3的信息改变文件名。
程序的目标非常简单,就是首先提取MP3文件中的信息,主要提取其歌名和演唱者两个字段,然后把这个文件重命名成 “歌名 - 演唱者.mp3”这种格式。
■ 关于mp3信息的提取方法
mp3除了音频信息的部分外,在文件的某些地方还会存放有关于这个音频的一些基本信息比如作者,创作时间,专辑名,曲序号,专辑图片等等。这些信息被统称为ID3标签。ID3标签被分成两代,第一代ID3v1只存储一些很简单的信息,占用文件末尾的128个字节(下面的直接读文件的就是默认是ID3v1的情况)。而ID3v2位于文件的开头,并且包含很全的信息比如加上一张专辑插图。
网上搜到最多的使用ID3或者类似的一些模块进行提取,也有很多人根据mp3的文件结构特征直接对文件进行读取操作然后过滤出信息。因为我手上的资源很杂而且试了一下第二种方法发现很多文件提取信息都不全或者错误,所以还是用了第一种方法。下面这个是从网上摘来的,某种比较简洁的第二种方法示例:这个函数读取一个文件,然后从文件内容的特定位置解析出tag信息并返回一个字典。
def getID3(filename):
fp = open(filename, 'r')
fp.seek(-128, 2) fp.read(3) # TAG iniziale
title = fp.read(30)
artist = fp.read(30)
album = fp.read(30)
anno = fp.read(4)
comment = fp.read(28) fp.close() return {'title':title, 'artist':artist, 'album':album, 'anno':anno}
和网上很多人用ID3或者eyed3之类的模块不同,我用了个相对比较冷门的replica,他一共就只有三个模块文件cli.py , tagger.py , cloner.py。我们用到的主要是tagger。基本用法如下:
from replica import tagger tags = tagger.get_tags("PATH.mp3") #获取一个mp3文件的ID3标签信息 tagger.set_tags(tags,"ANOTHER.mp3")
get_tags方法得到的是一个mutagen的MP3对象(replica是基于mutagen的,mutagen是更基本一些的音频处理模块)。这个对象所属的类应该实现了__getattr__方法,所以你可以像一个字典一样去访问这个对象中的一些键值。而如果打印这个这个对象看到的就是一个字典:
for k,v in tags.items():
if k == u"APIC:": #跳过U'APIC:'这个键是因为这个键的值是专辑图片,如果用字符来表示的话太大了这里显示不下
continue
print k,v
print repr(k),repr(v)
###打印结果###
TDRC 2011
TIT2 ゆりゆららららゆるゆり大事件
ゆりゆららららゆるゆり 大事件
TRCK 1/4
TPE1 七森中☆ごらく部
TALB ゆりゆららららゆるゆり大事件
TSRC JPPC01101395
TCON Anime
TXXX:DISCID 28036204 ###repr结果###
'TDRC' TDRC(encoding=<Encoding.LATIN1: 0>, text=[u'2011'])
'TIT2' TIT2(encoding=<Encoding.UTF16: 1>, text=[u'\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a\u5927\u4e8b\u4ef6'])
u'USLT::eng' USLT(encoding=<Encoding.UTF16: 1>, lang='eng', desc=u'', text=u'\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a\r\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a\r\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a \u5927\u4e8b\u4ef6\r\u3066\u3093\u3066\u3053\u307e\u3044\u306e\u4eca\u65e5\u660e\u65e5\u5927\u7206\u767a\r\u305d\u3093\u3067\u8eab\u9577\u4f38\u3073\u306a\u3044\u3084\u3042\u3042\u3069\u3046\u3057\u3088\r\u7518\u3044\u3082\u306e\u98df\u3079\u3059\u304d\u30c6\u30fc\u30de\u30d0\u30fc\u30af\r\u307b\u3044\u3058\u3083\u96a0\u305b\u3088\u4e59\u5973\u3067\u3069\u3046\u3058\u3083\u308d\r\u90e8\u6d3b\u52d5\u672c\u756a\r\u3057\u3081\u3057\u3081\u7121\u9045\u523b\r\u672c\u696d\u5b78\u696d\u306a\u306b\u305d\u308c\r\u305d\u3093\u306a\u306e\u305c\u3093\u305c\u3093\u305c\u3093\u305c\u3093\u305c\u3093\u305c\u3093\u98df\u3079\u308c\u306a\u3044\r\u685c\u54b2\u304d \uff08\u685c\u54b2\u304d\uff09\r\u685c\u6563\u308a \uff08\u685c\u6563\u308a\uff09\r\u660e\u65e5\u3082\u3044\u3044\u65e5\u3068\u6b4c\u3046\u3088\r\u541b\u304c\u597d\u304d \uff08\u541b\u304c\u597d\u304d\uff09\r\u541b\u304c\u3044\u3044 \uff08\u541b\u304c\u3044\u3044\uff09\r\u660e\u65e5\u3082\u3044\u305f\u3044\u3068\u601d\u3046\u3088\r\u6700\u7d42\u624b\u6bb5\u3067\u5c40\u7720\u308a\r\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a\r\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a\r\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a \u5927\u4e8b\u4ef6(\u3060\u3044\u3058\u3051\u3093)\r\u3044\u308d\u306f\u306b\u307b\u3078\u3068\u3067\u304a\u307f\u304f\u3058Get you\uff01\u3042\u308a\u3089\u3073\u3085\u30fc\r\u306b\u3083\u3093\uff01\u306b\u3083\u3093\uff01\u8001\u306b\u3083\u3093\uff01\u82e5\u306b\u3083\u3093\uff01\u7537\u306b\u3083\uff01\u5973\u3093\uff01\r\u5fc5\u6b7b\u306b\u5bc6\u66f8\u3092\u767a\u5c04\u3067\u5fc5\u4e2d\u6388\u696d\u4e2d\r\u3067\u3082\u306d\u3042\u3089\u3089\u3089\u30c1\u30e7\u30fc\u30af\u304c\u30df\u30b5\u30a4\u30eb\r\u864e\u7a74\u306b\u5165\u3089\u306a\u3044\r\u96e8\u306a\u3089\u30cf\u30ec\u30eb\u30e4\r\u30ab\u30e9\u30aa\u30b1\u5272\u9ad8\u306a\u306b\u305d\u308c\r\u305d\u3093\u306a\u306e\u305c\u3063\u305f\u3044\u305c\u3063\u305f\u3044\u305c\u3063\u305f\u3044\u98df()\u3079\u308c\u306a\u3044\uff01\uff01\r\u685c\u54b2\u304d \uff08\u685c\u54b2\u304d\uff09\r\u685c\u6563\u308a \uff08\u685c\u6563\u308a\uff09\r\u660e\u65e5\u3082\u3044\u3044\u65e5\u3068\u6b4c\u3046\u3088\r\u541b\u304c\u597d\u304d \uff08\u541b\u304c\u597d\u304d\uff09\r\u541b\u304c\u3044\u3044 \uff08\u541b\u304c\u3044\u3044\uff09\r\u660e\u65e5\u3082\u3044\u305f\u3044\u3068\u601d\u3046\u3088\r\u8fd1\u6240\u306e\u30ef\u30f3\u30b3\u3068\u683c\u95d8\r\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a\r\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a\r\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a \u5927\u4e8b\u4ef6\r\u30c1\u30e3\u30a4\u30e0\u304c\u76ee\u899a\u307e\u3057\rKIRA\u2606KIRA\u2606TSUN-DELE\r\u751f\u30af\u30ea\u30fc\u30e0\u60d1\u661f \u306a\u306b\u305d\u308c\r\u305d\u308c\u306a\u3089\u307b\u3093\u3068\u306b\u307b\u3093\u3068\u306b\u307b\u3093\u3068\u306b\u3084\u3081\u308c\u306a\u3044\uff01\u3084\u3081\u308c\u306a\u3044\uff01\uff01\r\u685c\u54b2\u304d \uff08\u685c\u54b2\u304d\uff09\r\u685c\u6563\u308a \uff08\u685c\u6563\u308a\uff09\r\u660e\u65e5\u3082\u3044\u3044\u65e5\u3068\u6b4c\u3046\u3088\r\u541b\u304c\u597d\u304d \uff08\u541b\u304c\u597d\u304d\uff09\r\u541b\u304c\u3044\u3044 \uff08\u541b\u304c\u3044\u3044\uff09\r\u660e\u65e5\u3082\u3044\u305f\u3044\u3068\u601d\u3046\u3088\r\u6700\u7d42\u624b\u6bb5(\u3067\u5c40\u7720\u308a\r\u8fd1\u6240\u306e\u30ef\u30f3\u30b3\u3068\u683c\u95d8\r\u9769\u547d\u8d77\u3053\u3057\u3066\u5352\u696d\r\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a\r\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a\r\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a \u5927\u4e8b\u4ef6\r')
'TRCK' TRCK(encoding=<Encoding.LATIN1: 0>, text=[u'1/4'])
'TPE1' TPE1(encoding=<Encoding.UTF16: 1>, text=[u'\u4e03\u68ee\u4e2d\u2606\u3054\u3089\u304f\u90e8'])
'TALB' TALB(encoding=<Encoding.UTF16: 1>, text=[u'\u3086\u308a\u3086\u3089\u3089\u3089\u3089\u3086\u308b\u3086\u308a\u5927\u4e8b\u4ef6'])
'TSRC' TSRC(encoding=<Encoding.UTF16: 1>, text=[u'JPPC01101395'])
'TCON' TCON(encoding=<Encoding.UTF16: 1>, text=[u'Anime'])
u'TXXX:DISCID' TXXX(encoding=<Encoding.UTF16: 1>, desc=u'DISCID', text=[u'28036204'])
字典本身打印出来是这样:
{u'APIC:':'关于图片信息的内容','TSRC': TSRC(encoding=<Encoding.UTF16: 1>, text=[u'JPPC01101395']), 'TCON': TCON(encoding=<Encoding.UTF16: 1>, text=[u'Anime']), u'TXXX:DISCID': TXXX(encoding=<Encoding.UTF16: 1>, desc=u'DISCID', text=[u'']),xxxx还有一些,意思一下。。}
结合各个键的值大概就可以猜出来这个键是什么意思了。对于没有设置某个标签信息的文件而言,它的tags对象中就不会有相关的键。值其实是一些对象,比如标题标签的键是TIT2,值就是一个TIT2对象,其有两个关键的属性,分别是TIT2.encoding和TIT2.text分别指出了显示标题时用的编码格式和标题文本组成的单个元素的列表。
这些对象的全图鉴可以参见mutagen/id3/_frames.py的源码。只是关于如何改变或创建这些对象,改变一个既有的MP3的标签信息这一方面还有待研究(其实是mutagen的内容了)
其实就论replica这个模块的用法的话就是以上了,然而我在之后的编写过程中又遇到了各种各样的坑,比如编码问题,windows系统对于文件名的要求等等,所以打算继续写下去。
■ 关于文本信息的编码
在tag信息的对象中,大多承载文字信息的对象都有encoding和text两个属性,且text属性中是一个单unicode元素的列表。其实这两个属性联合起来就表示了这个unicode应该用哪种编码进行encode才能成为原本的信息。
首先来看encoding这属性。这个属性其实是维护了一个mutagen中的Encoding对象,这个对象可以在源码中看到(位于mutagen/id3/_specs.py),把四种编码分别用了一个数字表示,在知道了对应关系之后我们可以在自己的脚本里添加一个同样的字典使得使用更加方便:
ENCODING = {0: "latin1", 1: "utf16", 2: "utf16be", 3: "utf8"}
因为从相关对象中取到的属性本质就是一个数,比如TIT2.Encoding其实就是1.
在四种编码格式中,比较特殊的是latin1这种格式。latin1就是ISO-8859-1,之前在en/decode以及print探索那篇文章中也提到过,被latin1 decode出来的unicode只能被latin1 encode成str,并且encode得到的东西的编码格式和最原先的是一样的。
■ windows中文件名的规则
windows中的文件名不能含有字符 \/:*?"<>| 中的任意一个。如果含有这些错误的话在运用os.rename或者其他类似的重命名手段的时候会报错WindowsError123。另一方面,如果同目录下已经有相同名字文件存在时重命名会报错WindowsError183。
一般而言,对windows上的文件进行命名的时候我们可以直接用unicode类型的字符串(如果愿意,也可以用gb这个系列的编码格式的字符串进行命名,不过能用unicode的情况下应该尽量用通用性更加好的unicode)。但是就这个程序而言,我们碰到了很多由latin1编码格式得到的unicode,很遗憾在处理如果用这些unicode直接去命名文件,会出现乱码。目前我能想到的解决办法是在进行命名之前进行一个判断,如果这个文本信息的编码格式是latin1的,那么在将其输出成文件名的一部分之前先把它encode("latin1"),如果不是,那么可以直接把它作为文件名的一部分去rename。
■ 关于其他一些小改善
至此整个小程序基本功能已经实现了,接下来就是一些业务逻辑的改善了。比如tag信息不全时怎么办,重命名失败时怎么办,增加处理进度提示,对于目录中非mp3文件的处理等等。最后整个脚本如下:
#!/usr/bin/env python
# coding=utf8
import os
import sys
import logging
import re
from replica import tagger reload(sys)
sys.setdefaultencoding("gb18030") ENCODING = {0: "latin1", 1: "utf16", 2: "utf16be", 3: "utf8"} logging.basicConfig(filename="mp3.log", level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s ") def modify_textual(string):
return re.sub(u'[\\\/:\*\?"<>\|]', " ", string) def process_one_song(songName):
mp3 = tagger.get_tags(u"{songname}".format(songname=songName))
try:
artist = mp3.get("TPE1").text[0]
enco_form = ENCODING.get(mp3.get("TPE1").encoding)
if enco_form == "latin1":
artist = artist.encode("latin1")
except AttributeError as e:
artist = u"未知艺术家"
try:
name = mp3.get("TIT2").text[0]
enco_form = ENCODING.get(mp3.get("TIT2").encoding)
if enco_form == "latin1":
name = name.encode("latin1")
except AttributeError as e:
name = u"未知曲名"
name = modify_textual(name)
artist = modify_textual(artist)
logging.info(u"{songname}".format(songname=songName) +
u"{filename}.mp3".format(
filename=os.path.dirname(songName) + os.sep.decode("utf8") + name + u"-" + artist))
try:
os.rename(u"{songname}".format(songname=songName), u"{filename}.mp3".format(
filename=os.path.dirname(songName) + os.sep.decode("utf8") + name + u"-" + artist))
except WindowsError as windowserror:
logging.error(
"error processing {name} for windows error [{error}]".format(name=songName, error=str(windowserror))) def main():
try:
rootpath = sys.argv[1]
except IndexError as e:
rootpath = 'mp3'
if not os.path.isdir(rootpath):
print u"输入目录不存在"
sys.exit(1)
count = 0
total = 0
for root, dir, files in os.walk(rootpath):
total += len(files)
for root, dir, files in os.walk(rootpath):
for file in files:
filename = os.path.join(root.decode("gb18030"), file.decode("gb18030"))
if os.path.splitext(file)[1] != '.mp3':
os.remove(filename)
continue
count += 1
print u"正在处理{percent:.0f}%的歌".format(percent=float(count) / total * 100)
process_one_song(filename)
【Python】 获取MP3信息replica的更多相关文章
- python 获取对象信息
当我们拿到一个对象的引用时,如何知道这个对象是什么类型.有哪些方法呢? 使用type() 首先,我们来判断对象类型,使用type()函数: 基本类型都可以用type()判断: >>> ...
- Python 获取车票信息
提示:该代码仅供学习使用,切勿滥用!!! 先来一个git地址:https://gitee.com/wang_li/li_wang 效果图: 逻辑: 1.获取Json文件的内容 2.根据信息生成URL ...
- 用python获取服务器硬件信息[转]
#!/usr/bin/env python # -*- coding: utf-8 -*- import rlcompleter, readline readline.parse_and_bind(' ...
- 用python获取ip信息
1.138网站 http://user.ip138.com/ip/首次注册后赠送1000次请求,API接口请求格式如下,必须要有token值 import httplib2 from urllib.p ...
- python获取对象信息
获取对象信息 拿到一个变量,除了用 isinstance() 判断它是否是某种类型的实例外,还有没有别的方法获取到更多的信息呢? 例如,已有定义: class Person(object): def ...
- python获取机器信息脚本(网上寻找的)
获取机器信息(待测试) # -*- coding: UTF-8 -*- import psutil import json import os import socket import struct ...
- python获取的信息列表微信公共平台和用户头像
转载注明原文地址:http://blog.csdn.net/btyh17mxy/article/details/25207889 只写模拟登陆的方式获取微信从信息和头像库列表公共平台, - 相关后,功 ...
- 关于Python 获取windows信息收集
收集一些Python操作windows的代码 (不管是自带的or第三方库)均来自网上 1.shutdown 操作 定时关机.重启.注销 #!/usr/bin/python #-*-coding:utf ...
- Python - 获取帮助信息
1- Python Manuals 自带CHM格式的Python Manuals存放在\Python<x.x>\Doc\目录下.可以在IDLE界面下按F1键或点击help选项下Python ...
随机推荐
- 6.2 PowerPC处理器如何处理MSI中断请求
PowerPC处理器使用OpenPIC中断控制器或者MPIC中断控制器,处理外部中断请求.其中MPIC中断控制器基于OpenPIC中断控制器,但是作出了许多增强,目前Freescale新推出的Powe ...
- 2.3 PCI桥与PCI设备的配置空间
PCI设备都有独立的配置空间,HOST主桥通过配置读写总线事务访问这段空间.PCI总线规定了三种类型的PCI配置空间,分别是PCI Agent设备使用的配置空间,PCI桥使用的配置空间和Cardbus ...
- 4.2 PCIe体系结构的组成部件
PCIe总线作为处理器系统的局部总线,其作用与PCI总线类似,主要目的是为了连接处理器系统中的外部设备,当然PCIe总线也可以连接其他处理器系统.在不同的处理器系统中,PCIe体系结构的实现方法略有不 ...
- 用dd实现linux硬盘备份
一个去年的老本,500G硬盘,空间各种捉急,准备迁移到公司的台式机上,却发现Linux上迁移环境没有Windows下那么方便,只能复制整块硬盘了. 从公司拿了一块1T的硬盘,插入移动硬盘盒(淘宝上搞的 ...
- hi3531串口波特率计算
波特率配置 通过配置寄存器UART_IBRD 和UART_FBRD 可以设置UART 工作的波特率,波特率 计算公式为: 当前波特率=UART 参考时钟频率(1/2 总线时钟频率)/(16 x 分频系 ...
- freemarker写select组件(三)
freemarker写select组件 1.宏定义 <#macro select id datas value="" key="" text=" ...
- Nethogs - 网络流量监控工具
命令iftop来检查带宽使用情况.netstat用来查看接口统计报告.还有其他的一些工具Bandwidthd.Speedometer.Nethogs.Darkstat.jnettop.ifstat.i ...
- javascript右键菜单分析
右键菜单 思路 1.遮蔽原来的默认右键菜单 2.新建右键菜单跟随鼠标移动 3.注意边界处的位置变化 4.自定义右键内容的具体效果 具体 这样的事件涉及到有关contextmenu事件,阻止默认事件,获 ...
- Java虚拟机的锁优化
1 锁偏向.当现成请求一个对象锁时,如果获得锁,则该对象锁进入偏向模式,当该线程再次请求该对象的锁时,无需再做任何同步操作. 可通过在Java虚拟机中开启参数-XX:+UseBasedLock开启偏向 ...
- 用Java实现栈结构
栈是一种先进后出的数据结构,出栈入栈都是操作的栈顶元素,下面是利用Java语言实现的一个简单的栈结构 class MyStack{ private int size;//栈大小 private Obj ...