ポケット倉庫@ Wiki

オーディオプレーヤ "Exaile"のCD情報取得プラグイン

最終更新:

kani_3

- view
メンバー限定 登録/ログイン

オーディオプレーヤ "Exaile"の曲情報取得プラグイン(pyGrabCDInfo)


Exaileのプラグインを作ってみました。(Linux環境でのみ動作確認を行っています)

pyGrabCDInfo.pyというファイルのみです。
pyGrabCDInfo.pyを ~/.exaile/plugins/に置き、Exaileを再起動してください。

Exaile起動後、PluginManagerを開いて、Enableチェックボックスを
ONにすることで有効になります。

このプラグインが有効になっている状態でExaileが起動すると、
Exaileのウインドウに”grabCDDB”というボタンが追加されています。

ネットワークに接続されている状態で、PCにCDをトレイに挿入し、
CDの曲名を表示してください(FileメニューのOpenDiscを選択)。

CDの情報がExaileのウインドウに表示された後、もし文字化けが
あった場合には、grabCDDBボタンをおせば、ネットワーク経由で情報を
再取得し、文字化けを解消してくれます。(きっと)

実行するためには、以下のものが必要です。
  • exaile
  • python
  • pygtk
  • CDDB
  • DiscID
  • httplib
  • xml.sax


ソースコードは以下の通りです。
(実際のスクリプトファイルはこのページの一番下に添付してあります)


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


PLUGIN_NAME = 'CD InfoGraber'
PLUGIN_AUTHORS = ['kani <jkani4@gmail.com>']
PLUGIN_VERSION = '0.1'
PLUGIN_ENABLED = False
PLUGIN_DESCRIPTION = r'''Get CD Information such as album name from freedb2.org.'''


b = gtk.Button()
PLUGIN_ICON = b.render_icon(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_MENU)
b.destroy()

URL_CDDB_TRACKTYPE_ORG = 'http://tracktype.org:80/~cddb/cddb.cgi'
URL_FREEDB2_ORG = 'www.freedb2.org'

CONNS = plugins.SignalContainer()


##
def get_conf_str(name, defStr):
    return APP.settings.get_str(name,
                               default=defStr,
                               plugin=plugins.name(__file__))

##
def set_conf_str(name, someStr):
   APP.settings.set_str(name,
                        someStr,
                        plugin=plugins.name(__file__))

#
#
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 count_tracks(self):
        return len(self.trackNames)

    ##
    def get_track_name(self, trackNo):
        if trackNo in self.trackNames:
            return self.trackNames[trackNo]

        return ''

    ##
    def get_track_name_dict(self):
        return self.trackNames
    
    ##
    def get_artist(self):
        return self.artist

    ##
    def get_album(self):
        return self.album

    ##
    def get_year(self):
        return self.year

    ##
    def get_genre(self):
        return self.genre

#
#
def showErrorMsg(msgStr):
    if len(msgStr) == 0:
        return
    dialog = gtk.MessageDialog(APP.window, buttons=gtk.BUTTONS_OK,
                               type=gtk.MESSAGE_INFO,
                               message_format=msgStr)
    dialog.run()
    dialog.destroy()

#
#
def update_track_info(trackList, artist, album, year, genre, trackNames):
    if trackList == None:
        return
   
    trkCnt = len(trackNames)
   
    if trkCnt == 0:
        showErrorMsg('Current playlist has no tracks..')
        return

    songs = trackList.get_songs()
    if songs == None:
        return

    if len(songs) != trkCnt:
        showErrorMsg("The number of track in the current playlist is different from CDDB's one ")
        return
    
    for i in range(trkCnt):
        songs[i].title = trackNames[i+1]
        songs[i].album = album
        songs[i].artist = artist
        songs[i].year = year
        songs[i].genre = genre

    trackList.set_songs(songs)

#
#
def get_cd_category_and_discid(cdDevice, serverURL):
    category = ''
    discID = ''
    try:
        disc = DiscID.open(cdDevice)
        disc_info = DiscID.disc_id(disc)
        (status, info) = CDDB.query(disc_info, serverURL)
    except:
        showErrorMsg('can not get cddb information. ')
        return (category, discID)

    # 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)


#
#
def grab_cd_info(widget, app):
    if app == None:
        return

    if app.tracks == None or len(app.tracks.get_songs()) == 0:
        showErrorMsg('There are no tracks selected.')
        return

    #
    # Get categroy and disc_id of CD that is in the cd drive.
    #
    device = APP.settings.get_str('cd_device', '/dev/cdrom')
    try:
        (category, discID) = get_cd_category_and_discid(device,
                                                        URL_CDDB_TRACKTYPE_ORG)
        if category == '' or discID == '':
            raise -1
    except:
        showErrorMsg('Can not get category or disc_id.')
        progWind.close()
        return
    
    #
    # Connect to www.freedb2.org, and get cd information in  xml format.
    #
    try:
        con = httplib.HTTPConnection(URL_FREEDB2_ORG)
        con.request('GET','/xml/%s/%s' % (category, discID),
                    body='',
                    headers={'User-Agent': 'Python/2.5'})
    except:
        showErrorMsg('Can not get xml from www.freedb2.org')
        progWind.close()
        return

    #
    # Parse xml
    #
    try:
        handler = Freedb2XMLHandler()

        response = con.getresponse()
        xmldata = response.read()
        parser = xml.sax.make_parser()
        parser.setContentHandler(handler)
        parser.feed(xmldata)
    except:
        showErrorMsg('Can not parse xml.')
        progWind.close()
        return

    if handler.count_tracks() == 0:
        showErrorMsg('there is no tracks.')
        progWind.close()
        return

    #
    # Update the current playlist with grabbed information.
    #
    update_track_info(app.tracks,
                      handler.get_artist(),
                      handler.get_album(),
                      handler.get_year(),
                      handler.get_genre(),
                      handler.get_track_name_dict())



###
#
# Below describes functions for exaile plugin.
#
###

gToolBar = None
gCnvButton = None
#
#
def initialize():
    '''
       Called when the plugin is enabled.
    '''
    #
    # Append custom button to reload  audio cd track information
    # from CDDB
    global gToolBar
    global gCnvButton
    if gCnvButton == None:
        gToolBar = APP.xml.get_widget('play_toolbar')
        gCnvButton = gtk.Button('grabCDDB')
        gToolBar.pack_start(gCnvButton, True, False, 0)
        gToolBar.show_all()

        gCnvButton.connect('clicked', grab_cd_info, APP)

    return True


#
#
def destroy():
    '''
       Called when the plugin is disabled.
    '''
    pass
添付ファイル
記事メニュー
目安箱バナー