cddb.py 6.94 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# This file implements a class which forms an interface to the .cddb
# directory that is maintained by SGI's cdman program.
#
# Usage is as follows:
#
# import readcd
# r = readcd.Readcd()
# c = Cddb(r.gettrackinfo())
#
# Now you can use c.artist, c.title and c.track[trackno] (where trackno
# starts at 1).  When the CD is not recognized, all values will be the empty
# string.
# It is also possible to set the above mentioned variables to new values.
# You can then use c.write() to write out the changed values to the
# .cdplayerrc file.

import string, posix, os

_cddbrc = '.cddb'
_DB_ID_NTRACKS = 5
_dbid_map = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@_=+abcdefghijklmnopqrstuvwxyz'
def _dbid(v):
23 24 25 26
    if v >= len(_dbid_map):
        return string.zfill(v, 2)
    else:
        return _dbid_map[v]
27 28

def tochash(toc):
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
    if type(toc) == type(''):
        tracklist = []
        for i in range(2, len(toc), 4):
            tracklist.append((None,
                      (int(toc[i:i+2]),
                       int(toc[i+2:i+4]))))
    else:
        tracklist = toc
    ntracks = len(tracklist)
    hash = _dbid((ntracks >> 4) & 0xF) + _dbid(ntracks & 0xF)
    if ntracks <= _DB_ID_NTRACKS:
        nidtracks = ntracks
    else:
        nidtracks = _DB_ID_NTRACKS - 1
        min = 0
        sec = 0
        for track in tracklist:
            start, length = track
            min = min + length[0]
            sec = sec + length[1]
        min = min + sec / 60
        sec = sec % 60
        hash = hash + _dbid(min) + _dbid(sec)
    for i in range(nidtracks):
        start, length = tracklist[i]
        hash = hash + _dbid(length[0]) + _dbid(length[1])
    return hash

57
class Cddb:
58 59 60 61 62 63 64
    def __init__(self, tracklist):
        if os.environ.has_key('CDDB_PATH'):
            path = os.environ['CDDB_PATH']
            cddb_path = path.split(',')
        else:
            home = os.environ['HOME']
            cddb_path = [home + '/' + _cddbrc]
65

66
        self._get_id(tracklist)
67

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
        for dir in cddb_path:
            file = dir + '/' + self.id + '.rdb'
            try:
                f = open(file, 'r')
                self.file = file
                break
            except IOError:
                pass
        ntracks = int(self.id[:2], 16)
        self.artist = ''
        self.title = ''
        self.track = [None] + [''] * ntracks
        self.trackartist = [None] + [''] * ntracks
        self.notes = []
        if not hasattr(self, 'file'):
            return
        import re
        reg = re.compile(r'^([^.]*)\.([^:]*):[\t ]+(.*)')
        while 1:
            line = f.readline()
            if not line:
                break
            match = reg.match(line)
            if not match:
                print 'syntax error in ' + file
                continue
            name1, name2, value = match.group(1, 2, 3)
            if name1 == 'album':
                if name2 == 'artist':
                    self.artist = value
                elif name2 == 'title':
                    self.title = value
                elif name2 == 'toc':
                    if not self.toc:
                        self.toc = value
                    if self.toc != value:
                        print 'toc\'s don\'t match'
                elif name2 == 'notes':
                    self.notes.append(value)
            elif name1[:5] == 'track':
                try:
                    trackno = int(name1[5:])
                except ValueError:
                    print 'syntax error in ' + file
                    continue
                if trackno > ntracks:
                    print 'track number %r in file %s out of range' % (trackno, file)
                    continue
                if name2 == 'title':
                    self.track[trackno] = value
                elif name2 == 'artist':
                    self.trackartist[trackno] = value
        f.close()
        for i in range(2, len(self.track)):
            track = self.track[i]
            # if track title starts with `,', use initial part
            # of previous track's title
            if track and track[0] == ',':
                try:
                    off = self.track[i - 1].index(',')
                except ValueError:
                    pass
                else:
                    self.track[i] = self.track[i-1][:off] \
                                    + track
133

134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
    def _get_id(self, tracklist):
        # fill in self.id and self.toc.
        # if the argument is a string ending in .rdb, the part
        # upto the suffix is taken as the id.
        if type(tracklist) == type(''):
            if tracklist[-4:] == '.rdb':
                self.id = tracklist[:-4]
                self.toc = ''
                return
            t = []
            for i in range(2, len(tracklist), 4):
                t.append((None, \
                          (int(tracklist[i:i+2]), \
                           int(tracklist[i+2:i+4]))))
            tracklist = t
        ntracks = len(tracklist)
        self.id = _dbid((ntracks >> 4) & 0xF) + _dbid(ntracks & 0xF)
        if ntracks <= _DB_ID_NTRACKS:
            nidtracks = ntracks
        else:
            nidtracks = _DB_ID_NTRACKS - 1
            min = 0
            sec = 0
            for track in tracklist:
                start, length = track
                min = min + length[0]
                sec = sec + length[1]
            min = min + sec / 60
            sec = sec % 60
            self.id = self.id + _dbid(min) + _dbid(sec)
        for i in range(nidtracks):
            start, length = tracklist[i]
            self.id = self.id + _dbid(length[0]) + _dbid(length[1])
        self.toc = string.zfill(ntracks, 2)
        for track in tracklist:
            start, length = track
            self.toc = self.toc + string.zfill(length[0], 2) + \
                      string.zfill(length[1], 2)
172

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
    def write(self):
        import posixpath
        if os.environ.has_key('CDDB_WRITE_DIR'):
            dir = os.environ['CDDB_WRITE_DIR']
        else:
            dir = os.environ['HOME'] + '/' + _cddbrc
        file = dir + '/' + self.id + '.rdb'
        if posixpath.exists(file):
            # make backup copy
            posix.rename(file, file + '~')
        f = open(file, 'w')
        f.write('album.title:\t' + self.title + '\n')
        f.write('album.artist:\t' + self.artist + '\n')
        f.write('album.toc:\t' + self.toc + '\n')
        for note in self.notes:
            f.write('album.notes:\t' + note + '\n')
        prevpref = None
        for i in range(1, len(self.track)):
            if self.trackartist[i]:
                f.write('track%r.artist:\t%s\n' % (i, self.trackartist[i]))
            track = self.track[i]
            try:
                off = track.index(',')
            except ValueError:
                prevpref = None
            else:
                if prevpref and track[:off] == prevpref:
                    track = track[off:]
                else:
                    prevpref = track[:off]
            f.write('track%r.title:\t%s\n' % (i, track))
        f.close()