add new my script - pyscreenlist - python+pil and calling mplayer
[archive.git] / Minstrell / cue.py
blob1d5d4653e898a0cb3c8d40da09348b4901c18c44
1 import re, sys
3 WS = '[ \t]'
4 NONWS = '[^ \t]'
5 LB = '^'+WS+'*'
6 LE = WS+'*$'
7 SWS = WS+'+'
8 STRING = "('([^']|\\')*'|\"([^\"]|\\\")*\"|("+NONWS+'+))'
9 NUMBER = '([0-9]+)'
10 FILE_FORMAT = '(BINARY|MOTOROLA|AIFF|WAVE|MP3)'
11 TRACK_MODE = '(AUDIO|MODE1_2048|MODE1_2352|MODE2_2048|MODE2_2332|MODE2_2336|MODE2_2342|MODE2_2352)'
12 TRACK_FLAG = '(PRE|DCP|FOUR_CH|SCMS)'
13 TRACK_FLAGS = '('+TRACK_FLAG+WS+')*'+TRACK_FLAG
14 TIME = '('+NUMBER+':'+NUMBER+':'+NUMBER+')'
16 REM = re.compile(LB+'REM.*$')
17 EMPTY = re.compile('^'+WS+'*$')
18 CATALOG = re.compile(LB+'CATALOG' +WS+STRING+LE)
19 CDTEXTFILE = re.compile(LB+'CDTEXTFILE'+WS+STRING+LE)
21 TITLE = re.compile(LB+'TITLE' +WS+STRING+LE)
22 PERFORMER = re.compile(LB+'PERFORMER' +WS+STRING+LE)
23 SONGWRITER = re.compile(LB+'SONGWRITER'+WS+STRING+LE)
24 COMPOSER = re.compile(LB+'COMPOSER' +WS+STRING+LE)
25 ARRANGER = re.compile(LB+'ARRANGER' +WS+STRING+LE)
26 MESSAGE = re.compile(LB+'MESSAGE' +WS+STRING+LE)
27 DISC_ID = re.compile(LB+'DISC_ID' +WS+STRING+LE)
28 GENRE = re.compile(LB+'GENRE' +WS+STRING+LE)
29 TOC_INFO1 = re.compile(LB+'TOC_INFO1' +WS+STRING+LE)
30 TOC_INFO2 = re.compile(LB+'TOC_INFO2' +WS+STRING+LE)
31 UPC_EAN = re.compile(LB+'UPC_EAN' +WS+STRING+LE)
32 ISRC = re.compile(LB+'ISRC' +WS+STRING+LE)
33 SIZE_INFO = re.compile(LB+'SIZE_INFO' +WS+STRING+LE)
35 FILE = re.compile(LB+'FILE'+WS+STRING+WS+FILE_FORMAT+LE)
37 TRACK = re.compile(LB+'TRACK'+WS+NUMBER+WS+TRACK_MODE+LE)
38 FLAGS = re.compile(LB+'FLAGS'+WS+TRACK_FLAGS+LE)
39 TRACK_ISRC = re.compile(LB+'TRACK_ISRC'+WS+STRING+LE)
40 PREGAP = re.compile(LB+'PREGAP'+WS+TIME+LE)
41 INDEX = re.compile(LB+'INDEX'+WS+NUMBER+WS+TIME+LE)
42 POSTGAP = re.compile(LB+'POSTGAP'+WS+TIME+LE)
44 class CREUser:
45 def match(self, cre, s):
46 self.m = cre.match(s)
47 return self.m
49 class CueTime:
50 minutes = 0
51 seconds = 0
52 frames = 0
53 def __init__(self, m, s, f):
54 self.minutes = m
55 self.seconds = s
56 self.frames = f
57 def is_zero(self):
58 return minutes == 0 and seconds == 0 and frames == 0
59 def __str__(self)
60 return '%02d:%02d:%02d' % (self.minutes, self.seconds, self.frames)
62 class CueCommonData:
63 title = ''
64 performer = ''
65 songwriter = ''
66 composer = ''
67 arranger = ''
68 message = ''
69 disc_id = ''
70 genre = ''
71 toc_info1 = ''
72 toc_info2 = ''
73 upc_ean = ''
74 isrc = ''
75 size_info = ''
76 file = ''
77 file_format = ''
78 def __to_string_list(self):
79 ss = []
80 if self.title:
81 ss.append('TITLE "%s"' % self.title)
82 if self.performer:
83 ss.append('PERFORMER "%s"' % self.performer)
84 if self.songwriter:
85 ss.append('SONGWRITER "%s"' % self.songwriter)
86 if self.composer:
87 ss.append('COMPOSER "%s"' % self.composer)
88 if self.arranger:
89 ss.append('ARRANGER "%s"' % self.arranger)
90 if self.message:
91 ss.append('MESSAGE "%s"' % self.message)
92 if self.disc_id:
93 ss.append('DISC_ID "%s"' % self.disc_id)
94 if self.genre:
95 ss.append('GENRE "%s"' % self.genre)
96 if self.toc_info1:
97 ss.append('TOC_INFO1 "%s"' % self.toc_info1)
98 if self.toc_info2:
99 ss.append('TOC_INFO2 "%s"' % self.toc_info2)
100 if self.upc_ean:
101 ss.append('UPC_EAN "%s"' % self.upc_ean)
102 if self.isrc:
103 ss.append('ISRC "%s"' % self.isrc)
104 if self.size_info:
105 ss.append('SIZE_INFO "%s"' % self.size_info)
106 if self.file and self.file_format:
107 ss.append('FILE "%s" %s' % (self.file, self.file_format))
108 return ss
110 class CueTrack(CueCommonData):
111 track_isrc = ''
112 pregap = CueTime(0,0,0)
113 postgap = CueTime(0,0,0)
114 flags = []
115 indexes = []
116 def __init__(self, num, mode):
117 self.num = num
118 self.mode = mode
119 def add_flag(self, flag):
120 self.flags.append(flag)
121 def add_index(self, num, time):
122 self.indexes.append((num, time))
123 def __to_string_list(self):
124 ss = []
125 ss.append('TRACK %02d %s' % (self.num, self.mode))
126 if self.track_isrc:
127 ss.append('TRACK_ISRC "%s"' % self.track_isrc)
128 if not self.pregap.is_zero():
129 ss.append('PREGAP '+str(self.pregap))
130 if not self.postgap.is_zero():
131 ss.append('POSTGAP '+str(self.postgap))
132 if self.flags:
133 ss.append('FLAGS '+self.flags.join(' '))
134 if self.indexes:
135 for index in self.indexes:
136 ss.append('INDEX %02d %s' % (index[0], str(index[1])))
137 ss = ss + self.CueCommonData.__to_string_list()
138 return ss
140 class CueSheet(CueCommonData):
141 catalog = ''
142 cdtextfile = ""
143 tracks = []
144 def add_track(self, track):
145 self.tracks.append(track)
146 def to_string(self, sep):
147 ss = []
148 if self.catalog:
149 ss.append('CATALOG '+self.catalog)
150 if self.cdtextfile:
151 ss.append('CDTEXTFILE '+self.cdtextfile)
152 ss = ss + self.__to_string_list('')
153 for track in tracks:
154 ss = ss + track.__to_string_list()
155 return ss.join(sep)
157 def match_cdtext(s, o):
158 u = CREUser()
159 if u.match(TITLE, s):
160 o.title = u.m.group(1)
161 elif u.match(PERFORMER, s):
162 o.performer = u.m.group(1)
163 elif u.match(SONGWRITER, s):
164 o.songwriter = u.m.group(1)
165 elif u.match(COMPOSER, s):
166 o.composer = u.m.group(1)
167 elif u.match(ARRANGER, s):
168 o.arranger = u.m.group(1)
169 elif u.match(MESSAGE, s):
170 o.message = u.m.group(1)
171 elif u.match(DISC_ID, s):
172 o.disc_id = u.m.group(1)
173 elif u.match(GENRE, s):
174 o.genre = u.m.group(1)
175 elif u.match(TOC_INFO1, s):
176 o.toc_info1 = u.m.group(1)
177 elif u.match(TOC_INFO2, s):
178 o.toc_info2 = u.m.group(1)
179 elif u.match(UPC_EAN, s):
180 o.upc_ean = u.m.group(1)
181 elif u.match(ISRC, s):
182 o.isrc = u.m.group(1)
183 elif u.match(SIZE_INFO, s):
184 o.size_info = u.m.group(1)
185 else:
186 return False
187 return True
189 def match_file(s, o):
190 u = CREUser()
191 if u.match(FILE, s):
192 o.file = u.m.group(1)
193 o.file_format = u.m.group(2)
194 else:
195 return False
196 return True
198 def parse_string_list(slist):
199 sheet = CueSheet()
200 global_part = True
201 u = CREUser()
202 for s in slist:
203 if global_part:
204 if u.match(CATALOG, s):
205 sheet.catalog = u.m.group(1)
206 elif u.match(CDTEXTFILE, s):
207 sheet.cdtextfile = u.m.group(1)
208 elif match_cdtext(s, sheet):
209 pass
210 elif match_file(s, sheet):
211 pass
212 elif u.match(TRACK, s):
213 global_part = False
214 track = CueTrack(int(u.m.group(1)), u.m.group(2))
215 elif u.match(REM, s):
216 pass
217 elif u.match(EMPTY, s):
218 pass
219 else:
220 print 'global error at %s' % s
221 else:
222 if u.match(TRACK, s):
223 sheet.add_track(track)
224 track = CueTrack(int(u.m.group(1)), u.m.group(2))
225 elif match_cdtext(s, track):
226 pass
227 elif u.match(FLAGS, s):
228 track.add_flag(u.m.group(1))
229 elif u.match(TRACK_ISRC, s):
230 track.track_isrc = u.m.group(1)
231 elif u.match(PREGAP, s):
232 track.pregap(CueTime(u.m.group(1)))
233 elif u.match(INDEX, s):
234 time = CueTime(int(u.m.group(3)),int(u.m.group(4)),int(u.m.group(5)))
235 track.add_index(int(u.m.group(1)), time)
236 elif u.match(POSTGAP, s):
237 track.postgap = CueTime(u.m.group(1))
238 elif match_file(s, track):
239 pass
240 elif u.match(REM, s):
241 pass
242 elif u.match(EMPTY, s):
243 pass
244 else:
245 print 'track error at %s' % s
246 return sheet
248 def parse_file(filename,encoding):
249 f = open(filename, 'r')
250 data = f.read()
251 udata = unicode(data, encoding)
252 return parse_string_list(re.split('\r|\n', udata))