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 inizialetitle   = 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 taggertags = 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,vprint repr(k),repr(v)
###打印结果###TDRC 2011TIT2 ゆりゆららららゆるゆり大事件ゆりゆららららゆるゆり 大事件TRCK 1/4TPE1 七森中☆ごらく部TALB ゆりゆららららゆるゆり大事件TSRC JPPC01101395TCON AnimeTXXX: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'28036204']),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 taggerreload(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 = 0total = 0for 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)continuecount += 1print u"正在处理{percent:.0f}%的歌".format(percent=float(count) / total * 100)process_one_song(filename)

【Python】 获取MP3信息replica相关推荐

  1. python存储mp3信息_【Python】 获取MP3信息replica

    replica 初衷是想要整理iphone中的音乐.IOS(我自己的手机还是IOS8.3,新版本的系统可能有变化了)自带的音乐软件中所有音乐文件都存放在/var/mobile/Media/iTunes ...

  2. python 获取mp3时长(时间长度)

    python 获取mp3时长(时间长度) 第一种方法 import librosa import time def get_mp3_duration(audio_path):""& ...

  3. linux多cpu运行python脚本,linux系统使用python获取cpu信息脚本分享

    linux系统使用python获取cpu信息脚本分享 代码如下: #!/usr/bin/env Python from __future__ import print_function from co ...

  4. python 获取excel信息,下载对应图片

    python 获取excel信息,下载对应图片 import pandas as pd from openpyxl import load_workbook import requests impor ...

  5. Python获取地震信息!能预测地震吗?

    6月17日22分25分,四川省宜宾市长宁县发生了6.0级地震,成都高新减灾研究所与应急管理部门联合建设的大陆地震预警网成功预警本次地震,提前10秒向宜宾市预警,提前61秒向成都预警. 虽然自己还不能写 ...

  6. Python获取电脑信息

    我做了一个Python获取电脑信息的程序,小部分代码是网上找的, 本来想把这个做成一个坑人小程序的 到后面没有灵感了 有想法的可以帮我做一下 私聊发代码给我 代码(pycharm运行通过) # -*- ...

  7. Python获取磁盘使用信息,python获取GPU信息,python根据进程号获取进程信息,pynvml 获取GPU信息,psutil 获取进程信息,系统信息等

    一.工具:psutil模块 psutil是一个跨平台模块,试用相应方法可以直接获取计算机CPU,内存,磁盘,网络等资源使用情况:可以使用我们学习知识与这模块用来做系统监控,性能分析:如果大家熟悉Lin ...

  8. python 获取硬盘信息_使用python获取电脑的磁盘信息方法

    使用Python获取电脑的磁盘信息需要借助于第三方的模块psutil,这个模块需要自己安装,纯粹的CPython下面不具备这个功能. 在iPython交互界面中进行如下演示: 查看电脑的磁盘分区: I ...

  9. python获取交换机信息

    目录 前言 github地址(敲黑板) Python依赖的工具库 核心思路(必看) 兼容性 (必看) 登录,建立一个连接 命令 telnet + 交换机ip 关键代码 注意事项 获取主机名等基础信息 ...

最新文章

  1. 在 ASP.NET 中执行 URL 重写
  2. java urlstreamhandler_获取对Java的默认http(s)URLStreamHandler的引用
  3. oracle 游标小例
  4. 图解当前最强语言模型BERT:NLP是如何攻克迁移学习的?
  5. 构建之法第5词作业(12-15章)
  6. python的文件式如何操作_Python文件操作
  7. EF中Take和Skip的区别
  8. 【数字信号处理】基于DFT的滤波系列3之插值滤波(含MATLAB代码)
  9. 内涝预测过程的噪音_提高人工智能模型准确率的测试过程中需要注意什么?
  10. ionic2+启动白屏问题-------之补充解决之道
  11. QItemSelectionModel——视图选择
  12. Atitit 知识体系概论 attilax著 三大类型 学术型 应用型 职业技术教育 1 附表1、CIP-2000学科群设置情况总表 1 三大层次 分类 学科 专业 2 20个知识大类 2 需
  13. 管理员必须知道的RADIUS认证服务器的部署成本
  14. 淘宝API item_search_similar - 搜索相似的商品
  15. 华为应用市场,浏览器PC版
  16. 第二批鸿蒙手机排名,华为郑重宣布,第二批升级鸿蒙的十款手机,荣耀30系列上榜!...
  17. 设计模式之备忘录模式(Memento Pattern)
  18. 人工智能起源| 阿兰·图灵的《计算机器与智能》
  19. 用mysql触发器做数据统计
  20. 小米手机连接ubuntu adb调试

热门文章

  1. UA MATH571A 一元线性回归II 统计推断1
  2. Java虚拟机垃圾收集器初步学习
  3. VS2010插件编写学习总结
  4. mysqldumpslow基本使用
  5. Windows环境下node.js的安装和配置
  6. 【JavaScript基础】js中关于声明提前的几个误区
  7. SqlHelper简单实现(通过Expression和反射)2.特性和实体设计
  8. 《C与指针》第七章练习
  9. linux tomcat 突然验证码出不来
  10. FileUpload控件实现单按钮图片自动上传并带预览显示