From 9b4e653ae45d15609041efbbd28217cae804eb48 Mon Sep 17 00:00:00 2001 From: Thomas Vander Stichele Date: Thu, 22 Nov 2012 23:20:44 +0000 Subject: [PATCH] * morituri/common/common.py: * morituri/common/program.py: * morituri/image/table.py: * morituri/rip/cd.py: * morituri/test/test_common_common.py: * morituri/test/test_image_toc.py: Handle cases where disc_template and track_template are not in the same directory. --- ChangeLog | 11 ++++++++++ morituri/common/common.py | 29 ++++++++++++++++++++++++ morituri/common/program.py | 2 +- morituri/image/table.py | 10 ++++++--- morituri/rip/cd.py | 34 ++++++++++++++++++++--------- morituri/test/test_common_common.py | 11 ++++++++++ morituri/test/test_image_toc.py | 22 +++++++++++-------- 7 files changed, 96 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index d1bba10..6d5dba5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2012-11-23 Thomas Vander Stichele + + * morituri/common/common.py: + * morituri/common/program.py: + * morituri/image/table.py: + * morituri/rip/cd.py: + * morituri/test/test_common_common.py: + * morituri/test/test_image_toc.py: + Handle cases where disc_template and track_template are not in + the same directory. + 2012-11-19 Thomas Vander Stichele * morituri/test/test_common_encode.py: diff --git a/morituri/common/common.py b/morituri/common/common.py index bf8dd00..a1fa781 100644 --- a/morituri/common/common.py +++ b/morituri/common/common.py @@ -21,10 +21,14 @@ # along with morituri. If not, see . import os +import os.path import math import tempfile import shutil +from morituri.extern.log import log + + SAMPLES_PER_FRAME = 588 WORDS_PER_FRAME = SAMPLES_PER_FRAME * 2 BYTES_PER_FRAME = SAMPLES_PER_FRAME * 4 @@ -334,3 +338,28 @@ def getRealPath(refPath, filePath): return cpath raise KeyError("Cannot find file for %r" % filePath) + +def getRelativePath(targetPath, collectionPath): + """ + Get a relative path from the directory of collectionPath to + targetPath. + + Used to determine the path to use in .cue/.m3u files + """ + log.debug('common', 'getRelativePath: target %r, collection %r' % ( + targetPath, collectionPath)) + + targetDir = os.path.dirname(targetPath) + collectionDir = os.path.dirname(collectionPath) + if targetDir == collectionDir: + log.debug('common', + 'getRelativePath: target and collection in same dir') + return os.path.basename(targetPath) + else: + rel = os.path.relpath( + targetDir + os.path.sep, + collectionDir + os.path.sep) + log.debug('common', + 'getRelativePath: target and collection in different dir, %r' % + rel) + return os.path.join(rel, os.path.basename(targetPath)) diff --git a/morituri/common/program.py b/morituri/common/program.py index e0b8a39..b5bf8b3 100644 --- a/morituri/common/program.py +++ b/morituri/common/program.py @@ -600,7 +600,7 @@ class Program(log.Loggable): self.debug('write .cue file to %s', cuePath) handle = open(cuePath, 'w') # FIXME: do we always want utf-8 ? - handle.write(self.result.table.cue().encode('utf-8')) + handle.write(self.result.table.cue(cuePath).encode('utf-8')) handle.close() self.cuePath = cuePath diff --git a/morituri/image/table.py b/morituri/image/table.py index 2046ce2..702ef42 100644 --- a/morituri/image/table.py +++ b/morituri/image/table.py @@ -503,15 +503,19 @@ class Table(object, log.Loggable): discId1[-1], discId1[-2], discId1[-3], self.getAudioTracks(), discId1, discId2, self.getCDDBDiscId()) - def cue(self, program='Morituri'): + def cue(self, cuePath='', program='Morituri'): """ + @param cuePath: path to the cue file to be written. If empty, + will treat paths as if in current directory. + + Dump our internal representation to a .cue file content. """ lines = [] def writeFile(path): - lines.append('FILE "%s" WAVE' % os.path.basename(path)) - + targetPath = common.getRelativePath(path, cuePath) + lines.append('FILE "%s" WAVE' % targetPath) # header main = ['PERFORMER', 'TITLE'] diff --git a/morituri/rip/cd.py b/morituri/rip/cd.py index 9db5e1c..abb2732 100644 --- a/morituri/rip/cd.py +++ b/morituri/rip/cd.py @@ -58,6 +58,13 @@ filling in the variables and expanding the file extension. Variables are: - %A: album artist - %S: album sort name - %d: disc title + - %y: release year + +Paths to track files referenced in .cue and .m3u files will be made +relative to the directory of the disc files. + +All files will be created relative to the given output directory. +Log files will log the path to tracks relative to this directory. """ def addOptions(self): @@ -69,7 +76,9 @@ filling in the variables and expanding the file extension. Variables are: default=default) self.parser.add_option('-O', '--output-directory', action="store", dest="output_directory", - help="output directory (defaults to current directory)") + help="output directory " + "(defaults to absolute path to current directory) " + ) # FIXME: have a cache of these pickles somewhere self.parser.add_option('-T', '--toc-pickle', action="store", dest="toc_pickle", @@ -107,13 +116,6 @@ filling in the variables and expanding the file extension. Variables are: options.track_template = options.track_template.decode('utf-8') options.disc_template = options.disc_template.decode('utf-8') - slashCountT = len(options.track_template.split(os.path.sep)) - slashCountD = len(options.disc_template.split(os.path.sep)) - if slashCountT != slashCountD: - raise command.CommandError( - "The number of path separators in the templates " \ - "should be the same.") - def do(self, args): prog = program.Program(record=self.getRootCommand().record) runner = task.SyncRunner() @@ -208,14 +210,19 @@ See http://sourceforge.net/tracker/?func=detail&aid=604751&group_id=2171&atid=1 # FIXME: turn this into a method def ripIfNotRipped(number): + self.debug('ripIfNotRipped for track %d' % number) # we can have a previous result trackResult = prog.result.getTrackResult(number) if not trackResult: trackResult = result.TrackResult() prog.result.tracks.append(trackResult) + else: + self.debug('ripIfNotRipped have trackresult, path %r' % + trackResult.filename) path = prog.getPath(prog.outdir, self.options.track_template, mbdiscid, number) + '.' + profile.extension + self.debug('ripIfNotRipped: path %r' % path) trackResult.number = number assert type(path) is unicode, "%r is not unicode" % path @@ -225,6 +232,12 @@ See http://sourceforge.net/tracker/?func=detail&aid=604751&group_id=2171&atid=1 # FIXME: optionally allow overriding reripping if os.path.exists(path): + if path != trackResult.filename: + # the path is different (different name/template ?) + # but we can copy it + self.debug('previous result %r, expected %r' % ( + trackResult.filename, path)) + self.stdout.write('Verifying track %d of %d: %s\n' % ( number, len(itable.tracks), os.path.basename(path).encode('utf-8'))) @@ -326,9 +339,10 @@ See http://sourceforge.net/tracker/?func=detail&aid=604751&group_id=2171&atid=1 handle.write(u'#EXTM3U\n') def writeFile(handle, path, length): - u = u'#EXTINF:%d,%s\n' % (length, os.path.basename(path)) + targetPath = common.getRelativePath(path, m3uPath) + u = u'#EXTINF:%d,%s\n' % (length, targetPath) handle.write(u.encode('utf-8')) - u = '%s\n' % os.path.basename(path) + u = '%s\n' % targetPath handle.write(u.encode('utf-8')) diff --git a/morituri/test/test_common_common.py b/morituri/test/test_common_common.py index e68dbbd..398222f 100644 --- a/morituri/test/test_common_common.py +++ b/morituri/test/test_common_common.py @@ -25,3 +25,14 @@ class FramesTestCase(tcommon.TestCase): class FormatTimeTestCase(tcommon.TestCase): def testFormatTime(self): self.assertEquals(common.formatTime(7202), '02:00:02.000') + + +class GetRelativePathTestCase(tcommon.TestCase): + + def testRelativeOutputDirectory(self): + directory = '.Placebo - Black Market Music (2000)' + cue = './' + directory + '/Placebo - Black Market Music (2000)' + track = './' + directory + '/01. Placebo - Taste in Men.flac' + + self.assertEquals(common.getRelativePath(track, cue), + '01. Placebo - Taste in Men.flac') diff --git a/morituri/test/test_image_toc.py b/morituri/test/test_image_toc.py index fb44a48..8616a5b 100644 --- a/morituri/test/test_image_toc.py +++ b/morituri/test/test_image_toc.py @@ -14,8 +14,9 @@ from morituri.test import common class CureTestCase(common.TestCase): def setUp(self): - self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__), - u'cure.toc')) + self.path = os.path.join(os.path.dirname(__file__), + u'cure.toc') + self.toc = toc.TocFile(self.path) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) @@ -85,7 +86,7 @@ class CureTestCase(common.TestCase): self.toc.table.absolutize() cue = self.toc.table.cue() ref = open(os.path.join(os.path.dirname(__file__), 'cure.cue')).read() - self.assertEquals(cue, ref) + common.diffStrings(cue, ref) # we verify it because it has failed in readdisc in the past self.assertEquals(self.toc.table.getAccurateRipURL(), @@ -109,8 +110,9 @@ class CureTestCase(common.TestCase): class BlocTestCase(common.TestCase): def setUp(self): - self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__), - u'bloc.toc')) + self.path = os.path.join(os.path.dirname(__file__), + u'bloc.toc') + self.toc = toc.TocFile(self.path) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) @@ -160,8 +162,9 @@ class BlocTestCase(common.TestCase): class BreedersTestCase(common.TestCase): def setUp(self): - self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__), - u'breeders.toc')) + self.path = os.path.join(os.path.dirname(__file__), + u'breeders.toc') + self.toc = toc.TocFile(self.path) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) @@ -189,8 +192,9 @@ class BreedersTestCase(common.TestCase): class LadyhawkeTestCase(common.TestCase): def setUp(self): - self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__), - u'ladyhawke.toc')) + self.path = os.path.join(os.path.dirname(__file__), + u'ladyhawke.toc') + self.toc = toc.TocFile(self.path) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) #import code; code.interact(local=locals())