|
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. |
|
16 from warnings import warnpy3k |
|
17 warnpy3k("the cddb module has been removed in Python 3.0", stacklevel=2) |
|
18 del warnpy3k |
|
19 |
|
20 import string, posix, os |
|
21 |
|
22 _cddbrc = '.cddb' |
|
23 _DB_ID_NTRACKS = 5 |
|
24 _dbid_map = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@_=+abcdefghijklmnopqrstuvwxyz' |
|
25 def _dbid(v): |
|
26 if v >= len(_dbid_map): |
|
27 return string.zfill(v, 2) |
|
28 else: |
|
29 return _dbid_map[v] |
|
30 |
|
31 def 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 |
|
60 class 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 ValueError: |
|
114 print 'syntax error in ' + file |
|
115 continue |
|
116 if trackno > ntracks: |
|
117 print 'track number %r in file %s 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 ValueError: |
|
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() |