CDDBの日本語文字列取得実験成功。

先日から、CDDBからCDの情報を取得する実験をしていました。
とりあえず、解決しそうなので、中間報告です。

Pythonで実現する一般的な方法は、CDDBとDiscIDをつかって
日本語に対応しているCDDBサーバの情報を取ってくるという方法だと
思います。。。が。。

私の試した結果、アルバムタイトルとアーティスト名は文字化けせずに取得
できるのですが、各トラックの曲名は文字化けしてしまって。。。
エンコードを変換すればいいのかな。。。と思っていろいろやっても
結局だめでした。

頭をかかえながら、ネットで調べてみると、freedb2.org というものが
できているらしいことがわかりました。(TrackType.orgが正式名称かも)

TrackType.orgでは、CDのdisk_idを指定して曲名などを検索する機能があります。
そのページでは日本語が全く化けずに表示されていました。
ためしに、TrackType.orgをCDDBのサーバに指定して、情報をとってきてみました。
でも、症状は変わらず。。。
トラックの曲名は、ASCIIコードのようなデータしか取得できません。。

「ちくしょ。。」
と思いながら、さらにTrackType.orgのnewsというページを呼んでみると、
http経由でテキスト、XML形式のページに直接アクセスできると書かれていました。

たとえば、カテゴリがsoundtrack, disk_idが123456だったとしたら、
(カテゴリ、disk_idはCDDB.query()で取得したもの)

そのCDの情報を取得するには

http://www.freedb2.org/xml/soundtrack/123456

とすればCDの情報を取得できます。

これをPythonでやらせてみよう!!
ということでさっそく作ってみました。

Pythonスクリプトを実行させると、現在挿入されているCDの
情報が画面に表示されます。

# python pyTrackType.py
=============================
artist = オリガ
album = 永遠。
year = 1998
genre = Vocal
track count = 12
1 : Name = 雨
2 : Name = 私の太陽
3 : Name = 遠い日
4 : Name = 忘れな草
5 : Name = 二人の絆
6 : Name = スター
7 : Name = 花の散るとき
8 : Name = 永遠とは
9 : Name = Tam
10 : Name = ピリグリム
11 : Name = こわれた夢
12 : Name = ポーリュシカ・ポーレ

といった感じです。

これを使えば、Exaileの曲名を文字化けなしで取り込む
こともできそうです。

ソースコードはそれほど長くないので、ここにコピペします。
(あとでポケット倉庫@wikiにも置いておきます)
ちなみに、以下のソースはCDが挿入されてなかったり、
ネットワークにつながってない場合のチェックはしていません。ご了承くださいませ。。

import CDDB
import DiscID
import httplib
import xml.sax
from xml.sax.handler import ContentHandler

#
#
class Freedb2XMLHandler(ContentHandler):
    ##
    def __init__(self):
        ContentHandler.__init__(self)

        self.album = ''
        self.artist = ''
        self.year = ''
        self.genre = ''
        self.trackNames = {}

        self.tmpStr = ''
        self.inTrack = False
        self.trackNo = ''
       
        self.tagDict = {'artist': 0, 'title': 1, 'year': 2,
                        'genre': 3, 'track': 4, 'number': 5 }

    ##
    def startElement(self, name, attrs):
        self.tmpStr = ''
        if name in self.tagDict:
            if self.tagDict[name] == self.tagDict['track']:
                self.inTrack = True
                self.trackNo = ''

    ##
    def endElement(self, name):
        if not name in self.tagDict:
            return

        tagType = self.tagDict[name]
        if tagType == self.tagDict['artist']:
            self.artist += self.tmpStr
        elif tagType == self.tagDict['title']:
            if self.inTrack:
                self.trackNames[int(self.trackNo)] = self.tmpStr
            else:
                self.album += self.tmpStr
        elif tagType == self.tagDict['number']:
            self.trackNo += self.tmpStr
        elif tagType == self.tagDict['year']:
            self.year += self.tmpStr
        elif tagType == self.tagDict['genre']:
            self.genre += self.tmpStr

        if tagType == self.tagDict['track']:
            self.inTrack = False

    ##
    def characters(self, content):
        self.tmpStr += content
       
    ##
    def get_track_name(self, trackNo):
        if trackNo in self.trackNames:
            return self.trackNames[trackNo]

        return ''

def get_cd_category_and_discid(cdDevice, serverURL):
    category = ''
    discID = ''
   
    disc = DiscID.open(cdDevice)
    #print disc
    disc_info = DiscID.disc_id(disc)
    #print disc_info
    (status, info) = CDDB.query(disc_info, serverURL)

    # status
    # 200  : success
    # 210  : multiple inexact maches ware found
    # 211  : multiple exact maches ware found
    # other: error
    if status in [210, 211]:
        info = info[0]
        status = 200

    if status == 200:
        category = info['category']
        discID = info['disc_id']

    return (category, discID)

#
#
if __name__ == '__main__':
    (category, discID) = get_cd_category_and_discid('/dev/cdrom',
                                                    'http://tracktype.org:80/~cddb/cddb.cgi')

   
    con = httplib.HTTPConnection('www.freedb2.org')
    con.request('GET','/xml/%s/%s' % (category, discID),
                body='',
                headers={'User-Agent': 'Python/2.5'})

    response = con.getresponse()
    xmldata = response.read()
    #print xmldata

    parser = xml.sax.make_parser()

    handler = Freedb2XMLHandler()
    parser.setContentHandler(handler)
    parser.feed(xmldata)

    print '============================='
    print 'artist = %s' % handler.artist
    print 'album = %s' % handler.album
    print 'year = %s' % handler.year
    print 'genre = %s' % handler.genre

    cnt = len(handler.trackNames)
    print 'track count = %d' % cnt

    for i in range(cnt):
        print '%d : Name = %s' % (i+1, handler.get_track_name(i+1))