From 5411fffd4b0281fea414115e7daac6f9f2eb2ed6 Mon Sep 17 00:00:00 2001 From: Thomas Vander Stichele Date: Sun, 3 May 2009 09:55:36 +0000 Subject: [PATCH] * morituri/program/cdrdao.py: Add a task to read the Table. --- ChangeLog | 5 ++ morituri/program/cdrdao.py | 125 ++++++++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 10380e3..2f054c2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-05-03 Thomas Vander Stichele + + * morituri/program/cdrdao.py: + Add a task to read the Table. + 2009-05-02 Thomas Vander Stichele * morituri/common/task.py: diff --git a/morituri/program/cdrdao.py b/morituri/program/cdrdao.py index 0fe9280..8bbf5ff 100644 --- a/morituri/program/cdrdao.py +++ b/morituri/program/cdrdao.py @@ -27,7 +27,7 @@ import subprocess import tempfile from morituri.common import task, log -from morituri.image import toc +from morituri.image import toc, table from morituri.extern import asyncsub states = ['START', 'TRACK', 'LEADOUT', 'DONE'] @@ -35,12 +35,12 @@ states = ['START', 'TRACK', 'LEADOUT', 'DONE'] _ANALYZING_RE = re.compile(r'^Analyzing track (?P\d+).*') _TRACK_RE = re.compile(r""" ^(?P[\d\s]{2})\s+ # Track - \w+\s+ # Mode + (?P\w+)\s+ # Mode; AUDIO \d\s+ # Flags \d\d:\d\d:\d\d # Start in HH:MM:FF \((?P.+)\)\s+ # Start in frames \d\d:\d\d:\d\d # Length in HH:MM:FF - \(.+\) # Length in frames + \((?P.+)\) # Length in frames """, re.VERBOSE) _LEADOUT_RE = re.compile(r""" ^Leadout\s @@ -201,3 +201,122 @@ class ReadTOCTask(task.Task): self._track = track #self.setProgress(float(track - 1) / self._tracks) #print 'analyzing', track + +class ReadTableTask(task.Task): + """ + I am a task that reads the TOC of a CD, without pregaps. + """ + + description = "Reading TOC..." + + + def __init__(self): + self._buffer = "" # accumulate characters + self._lines = [] # accumulate lines + self._errors = [] # accumulate error lines + self._lineIndex = 0 # where we are + self._state = 'START' + self._frames = None # number of frames + self._starts = [] # start of each track, in frames + self._track = None # which track are we analyzing? + self._toc = None # path to temporary .toc file + self._table = table.Table() + + self.toc = None # result + + def start(self, runner): + task.Task.start(self, runner) + + # FIXME: create a temporary file instead + (fd, self._toc) = tempfile.mkstemp(suffix='.morituri') + os.close(fd) + os.unlink(self._toc) + + bufsize = 1024 + self._popen = asyncsub.Popen(["cdrdao", "read-toc", "--fast-toc", + self._toc], + bufsize=bufsize, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, close_fds=True) + + self.runner.schedule(1.0, self._read, runner) + + def _read(self, runner): + ret = self._popen.recv_err() + self.log(ret) + if not ret: + # could be finished now + self.runner.schedule(1.0, self._poll, runner) + return + + self._buffer += ret + + # parse buffer into lines if possible, and parse them + if "\n" in self._buffer: + lines = self._buffer.split('\n') + if lines[-1] != "\n": + # last line didn't end yet + self._buffer = lines[-1] + del lines[-1] + else: + self._buffer = "" + for line in lines: + self.log('Parsing %s', line) + if line.startswith('ERROR:'): + self._errors.append(line) + + self._parse(lines) + self._lines.extend(lines) + + self.runner.schedule(1.0, self._read, runner) + + def _poll(self, runner): + if self._popen.poll() is None: + self.runner.schedule(1.0, self._poll, runner) + return + + self._done() + + def _done(self): + self.setProgress(1.0) + if self._popen.returncode != 0: + if self._errors: + print "\n".join(self._errors) + else: + print 'ERROR: exit code %r' % self._popen.returncode + else: + self.table = self._table + os.unlink(self._toc) + + self.stop() + return + + def _parse(self, lines): + for line in lines: + methodName = "_parse_" + self._state + getattr(self, methodName)(line) + + def _parse_START(self, line): + if line.startswith('Track'): + self.debug('Found possible track line') + if line == "Track Mode Flags Start Length": + self.debug('Found track line, moving to TRACK state') + self._state = 'TRACK' + + def _parse_TRACK(self, line): + if line.startswith('---'): + return + + m = _TRACK_RE.search(line) + if m: + self._tracks = int(m.group('track')) + start = int(m.group('start')) + self._starts.append(start) + mode = m.group('mode') + length = int(m.group('length')) + self.debug('Found track %d', self._tracks) + track = table.Track(self._tracks, start, start + length - 1, + mode == "AUDIO") + self.debug('Track %d, start offset %d, length %d', + self._tracks, start, length) + self._table.tracks.append(track)