再次折腾专辑封面

最近 itunes 升级,于是重新在整理音乐文件,看到那些没有专辑封面的 mp3,于是骨子里的不折腾不舒服斯基又发作了,手贱准备再次开始写一个自动工具来搞,上次的折腾记录在这里,根据 ID3 自动补充专辑封面和歌词

上次的失败是因为那个库对于中文的编码支持不是很好,于是最后就出现一些乱码问题,等等,于是这次准备换 python 搞,搜了一下,看到这几篇文章,http://hackerszone.diandian.co…http://www.gracecode.com/posts…http://www.fuchaoqun.com/2010/…http://pipitu.org/2010/05/14/m…,于是我知道手贱的不止我一个,呵呵

他们用的 py 库是http://eyed3.nicfit.net,这次不搞图形界面,于是一通查资料,重新理清了 mp3 tag 的文件格式,按照我的理解,简单来说,是这样的

首先有一个不太成熟的 id3v1,这个东西的做法是把 title,album,artist 这些信息放到文件末尾,格式简单,编码是 ascii,所以不支持中文,而且有一个很大的问题是定长,30 个 char,于是后来演变出另外一种, id3v2,而这个 id3v2 还分为 id3v2.3,这个是目前最多的,也是兼容性最好的,他把这些信息放到文件头部,而且不定长,而且字段不定,所以灵活性很高,可扩展性很强,字符的编码可以是 ascii,或者 utf-8,但是 windows 对于 utf-8 的支持不好,所以如果是用 utf-8 的话,在资源管理器里面是看不出来的,所以 qq 音乐,千千静听这些,默认都是 id3v2.3 的 iso-8859-1,说是 iso-8859-1,其实本质上是 gbk,而 itunes 对于 gbk 和 utf-8 的解码都是没有问题的,所以最皆大欢喜的做法就是用 id3v2.3 的 iso-8859-1(gbk) 来编码,然后嵌入图形文件当作封面,这个 id3v2 还有一个 id3v2.4,这个比较新,所以不怎么广泛,他的优势是标签信息可以在文件头,也可以在文件尾,在文件头的劣势显而易见,每次改写都要重写整个文件,磁盘读写量很大,除了 id3v2,还有一种格式叫做 apev2,这个也比较先进,可惜的是普及率也不高。

方针路线定了,接下来就是实干了,照着前面几篇博客的代码,敲敲打打的得到下面这个代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 2012.12.3

'''根据豆瓣自动补全专辑封面'''

import os, sys, re, time, urllib, eyeD3

import logging
logging.basicConfig(filename = 'log%s.txt' % time.time(), 
                    filemode = 'w', 
                    format = '[%(levelname)s] [%(asctime)s] %(message)s', 
                    level = logging.DEBUG)

def fillCover(filename):
    logging.info('processing %s' % filename)
    t = eyeD3.Tag()

    try:
        t.link(filename)
    except:
        logging.error('can not open file')
        return False

    images = t.getImages()
    if len(images) > 0:
        logging.info('alreay has cover images')
        return True

    title = t.getTitle()
    album = t.getAlbum()
    artist = t.getArtist()
    logging.debug('title is %s' % title)
    logging.debug('album is %s' % album)
    logging.debug('artist is %s' % artist)

    if title and artist:
        keyword = ' '.join([title, artist])
        keyword = keyword.encode('utf-8')
    else:
        logging.debug('no id3 tags')
        keyword = filename.split('\')[-1].split('.')[0]
        keyword = keyword.encode('gbk')
    logging.debug('keyword is %s' % keyword)

    doubanSearchAPI = 'http://api.douban.com/v2/music/search?q={0}'
    request = doubanSearchAPI.format(urllib.quote(keyword))
    logging.debug('request is %s' % request)
    result = urllib.urlopen(request).read()
    logging.debug('result is %s' % result)

    # 豆瓣 API 限制是每分钟 10 次请求
    # http://developers.douban.com/wiki/?title=api_v2
    #logging.warn('sleep for 6 sec')
    #time.sleep(6)

    if not result:
        return False
    doubanCoverPattern = 's(d+).jpg'
    doubanCoverURL = 'http://img3.douban.com/lpic/s{0}.jpg'
    match = re.search(doubanCoverPattern, result, re.IGNORECASE)
    if match:
        coverFileURL = doubanCoverURL.format(match.groups()[0])
        logging.debug('cover image url is %s' % coverFileURL)
    else:
        logging.debug('no cover image url matched')
        return False

    try:
        logging.debug('downloading cover image file')
        coverFileName = ' - '.join([artist, album])+'.jpg'
        f = file(coverFileName, 'wb')
        f.write(urllib.urlopen(coverFileURL).read())
        f.close()
        logging.debug('download finished')
    except:
        logging.error('download error')

    try:
        logging.debug('adding image')
        t.addImage(3, coverFileName, u'')
        t.update()
        logging.info('successfully add image')
        return True
    except:
        logging.error('add image error')
        return False


def main():
    if len(sys.argv) < 2:
        print 'usage: %s /path/to/your/music/folder/' % __file__
        return False
    for i in os.listdir(sys.argv[1]):
        fillCover(os.path.join(sys.argv[1], i))

if __name__ == '__main__':
    main()

这份代码在英文歌曲下,基本没有问题,可以比较顺利的跑,但是,中文,又是恶心的编码问题,由于现有的歌曲中,id3v2.3 的编码方式有些是 gbk ,有些是 utf-8,这个就比较麻烦了,不过千千静听有一个批量编辑文件属性的功能,可以在那里面,把所有文件的编码方式统一,可惜的是,这个 py 库到目前我发现他只支持 utf-8,对于 gbk 会乱码,于是我现在对于中文歌曲的处理方法是,全部拖进千千静听,转成 id3v2.3 的 utf-8,然后用这份代码去跑,跑完了,事实上图片已经钱嵌进去了,但是在 windows 的资源管理器中看不到,在 itunes 中可以,在 airplay 中也可以,但是如果这个时候再用千千静听把所有的编码都转换回 gbk,就会丢失了专辑封面,这个就很麻烦,目前就卡在这里

接下来的话,最理想的情况当然是研究清楚这个 py 库,然后让他可以处理 gbk 的标签,然后用千千静听把所有的标签转成 gbk,再用这份代码去下载封面,这样就你好我好大家好了

One thought on “再次折腾专辑封面

  1. Pingback: Python eyeD3 库的乱码问题初步 | ZRJ

Leave a Reply

Your email address will not be published. Required fields are marked *