1# This file implements a class which forms an interface to the .cddb 2# directory that is maintained by SGI's cdman program. 3# 4# Usage is as follows: 5# 6# import readcd 7# r = readcd.Readcd() 8# c = Cddb(r.gettrackinfo()) 9# 10# Now you can use c.artist, c.title and c.track[trackno] (where trackno 11# starts at 1). When the CD is not recognized, all values will be the empty 12# string. 13# It is also possible to set the above mentioned variables to new values. 14# You can then use c.write() to write out the changed values to the 15# .cdplayerrc file. 16from warnings import warnpy3k 17warnpy3k("the cddb module has been removed in Python 3.0", stacklevel=2) 18del warnpy3k 19 20import string, posix, os 21 22_cddbrc = '.cddb' 23_DB_ID_NTRACKS = 5 24_dbid_map = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@_=+abcdefghijklmnopqrstuvwxyz' 25def _dbid(v): 26 if v >= len(_dbid_map): 27 return string.zfill(v, 2) 28 else: 29 return _dbid_map[v] 30 31def tochash(toc): 32 if type(toc) == type(''): 33 tracklist = [] 34 for i in range(2, len(toc), 4): 35 tracklist.append((None, 36 (int(toc[i:i+2]), 37 int(toc[i+2:i+4])))) 38 else: 39 tracklist = toc 40 ntracks = len(tracklist) 41 hash = _dbid((ntracks >> 4) & 0xF) + _dbid(ntracks & 0xF) 42 if ntracks <= _DB_ID_NTRACKS: 43 nidtracks = ntracks 44 else: 45 nidtracks = _DB_ID_NTRACKS - 1 46 min = 0 47 sec = 0 48 for track in tracklist: 49 start, length = track 50 min = min + length[0] 51 sec = sec + length[1] 52 min = min + sec / 60 53 sec = sec % 60 54 hash = hash + _dbid(min) + _dbid(sec) 55 for i in range(nidtracks): 56 start, length = tracklist[i] 57 hash = hash + _dbid(length[0]) + _dbid(length[1]) 58 return hash 59 60class Cddb: 61 def __init__(self, tracklist): 62 if os.environ.has_key('CDDB_PATH'): 63 path = os.environ['CDDB_PATH'] 64 cddb_path = path.split(',') 65 else: 66 home = os.environ['HOME'] 67 cddb_path = [home + '/' + _cddbrc] 68 69 self._get_id(tracklist) 70 71 for dir in cddb_path: 72 file = dir + '/' + self.id + '.rdb' 73 try: 74 f = open(file, 'r') 75 self.file = file 76 break 77 except IOError: 78 pass 79 ntracks = int(self.id[:2], 16) 80 self.artist = '' 81 self.title = '' 82 self.track = [None] + [''] * ntracks 83 self.trackartist = [None] + [''] * ntracks 84 self.notes = [] 85 if not hasattr(self, 'file'): 86 return 87 import re 88 reg = re.compile(r'^([^.]*)\.([^:]*):[\t ]+(.*)') 89 while 1: 90 line = f.readline() 91 if not line: 92 break 93 match = reg.match(line) 94 if not match: 95 print 'syntax error in ' + file 96 continue 97 name1, name2, value = match.group(1, 2, 3) 98 if name1 == 'album': 99 if name2 == 'artist': 100 self.artist = value 101 elif name2 == 'title': 102 self.title = value 103 elif name2 == 'toc': 104 if not self.toc: 105 self.toc = value 106 if self.toc != value: 107 print 'toc\'s don\'t match' 108 elif name2 == 'notes': 109 self.notes.append(value) 110 elif name1[:5] == 'track': 111 try: 112 trackno = int(name1[5:]) 113 except strings.atoi_error: 114 print 'syntax error in ' + file 115 continue 116 if trackno > ntracks: 117 print 'track number %r in file %r out of range' % (trackno, file) 118 continue 119 if name2 == 'title': 120 self.track[trackno] = value 121 elif name2 == 'artist': 122 self.trackartist[trackno] = value 123 f.close() 124 for i in range(2, len(self.track)): 125 track = self.track[i] 126 # if track title starts with `,', use initial part 127 # of previous track's title 128 if track and track[0] == ',': 129 try: 130 off = self.track[i - 1].index(',') 131 except ValueError: 132 pass 133 else: 134 self.track[i] = self.track[i-1][:off] \ 135 + track 136 137 def _get_id(self, tracklist): 138 # fill in self.id and self.toc. 139 # if the argument is a string ending in .rdb, the part 140 # upto the suffix is taken as the id. 141 if type(tracklist) == type(''): 142 if tracklist[-4:] == '.rdb': 143 self.id = tracklist[:-4] 144 self.toc = '' 145 return 146 t = [] 147 for i in range(2, len(tracklist), 4): 148 t.append((None, \ 149 (int(tracklist[i:i+2]), \ 150 int(tracklist[i+2:i+4])))) 151 tracklist = t 152 ntracks = len(tracklist) 153 self.id = _dbid((ntracks >> 4) & 0xF) + _dbid(ntracks & 0xF) 154 if ntracks <= _DB_ID_NTRACKS: 155 nidtracks = ntracks 156 else: 157 nidtracks = _DB_ID_NTRACKS - 1 158 min = 0 159 sec = 0 160 for track in tracklist: 161 start, length = track 162 min = min + length[0] 163 sec = sec + length[1] 164 min = min + sec / 60 165 sec = sec % 60 166 self.id = self.id + _dbid(min) + _dbid(sec) 167 for i in range(nidtracks): 168 start, length = tracklist[i] 169 self.id = self.id + _dbid(length[0]) + _dbid(length[1]) 170 self.toc = string.zfill(ntracks, 2) 171 for track in tracklist: 172 start, length = track 173 self.toc = self.toc + string.zfill(length[0], 2) + \ 174 string.zfill(length[1], 2) 175 176 def write(self): 177 import posixpath 178 if os.environ.has_key('CDDB_WRITE_DIR'): 179 dir = os.environ['CDDB_WRITE_DIR'] 180 else: 181 dir = os.environ['HOME'] + '/' + _cddbrc 182 file = dir + '/' + self.id + '.rdb' 183 if posixpath.exists(file): 184 # make backup copy 185 posix.rename(file, file + '~') 186 f = open(file, 'w') 187 f.write('album.title:\t' + self.title + '\n') 188 f.write('album.artist:\t' + self.artist + '\n') 189 f.write('album.toc:\t' + self.toc + '\n') 190 for note in self.notes: 191 f.write('album.notes:\t' + note + '\n') 192 prevpref = None 193 for i in range(1, len(self.track)): 194 if self.trackartist[i]: 195 f.write('track%r.artist:\t%s\n' % (i, self.trackartist[i])) 196 track = self.track[i] 197 try: 198 off = track.index(',') 199 except ValuError: 200 prevpref = None 201 else: 202 if prevpref and track[:off] == prevpref: 203 track = track[off:] 204 else: 205 prevpref = track[:off] 206 f.write('track%r.title:\t%s\n' % (i, track)) 207 f.close() 208