* 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.
This commit is contained in:
11
ChangeLog
11
ChangeLog
@@ -1,3 +1,14 @@
|
|||||||
|
2012-11-23 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
|
||||||
|
* 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 <thomas at apestaart dot org>
|
2012-11-19 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
|
||||||
* morituri/test/test_common_encode.py:
|
* morituri/test/test_common_encode.py:
|
||||||
|
|||||||
@@ -21,10 +21,14 @@
|
|||||||
# along with morituri. If not, see <http://www.gnu.org/licenses/>.
|
# along with morituri. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import os.path
|
||||||
import math
|
import math
|
||||||
import tempfile
|
import tempfile
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
from morituri.extern.log import log
|
||||||
|
|
||||||
|
|
||||||
SAMPLES_PER_FRAME = 588
|
SAMPLES_PER_FRAME = 588
|
||||||
WORDS_PER_FRAME = SAMPLES_PER_FRAME * 2
|
WORDS_PER_FRAME = SAMPLES_PER_FRAME * 2
|
||||||
BYTES_PER_FRAME = SAMPLES_PER_FRAME * 4
|
BYTES_PER_FRAME = SAMPLES_PER_FRAME * 4
|
||||||
@@ -334,3 +338,28 @@ def getRealPath(refPath, filePath):
|
|||||||
return cpath
|
return cpath
|
||||||
|
|
||||||
raise KeyError("Cannot find file for %r" % filePath)
|
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))
|
||||||
|
|||||||
@@ -600,7 +600,7 @@ class Program(log.Loggable):
|
|||||||
self.debug('write .cue file to %s', cuePath)
|
self.debug('write .cue file to %s', cuePath)
|
||||||
handle = open(cuePath, 'w')
|
handle = open(cuePath, 'w')
|
||||||
# FIXME: do we always want utf-8 ?
|
# 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()
|
handle.close()
|
||||||
|
|
||||||
self.cuePath = cuePath
|
self.cuePath = cuePath
|
||||||
|
|||||||
@@ -503,15 +503,19 @@ class Table(object, log.Loggable):
|
|||||||
discId1[-1], discId1[-2], discId1[-3],
|
discId1[-1], discId1[-2], discId1[-3],
|
||||||
self.getAudioTracks(), discId1, discId2, self.getCDDBDiscId())
|
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.
|
Dump our internal representation to a .cue file content.
|
||||||
"""
|
"""
|
||||||
lines = []
|
lines = []
|
||||||
|
|
||||||
def writeFile(path):
|
def writeFile(path):
|
||||||
lines.append('FILE "%s" WAVE' % os.path.basename(path))
|
targetPath = common.getRelativePath(path, cuePath)
|
||||||
|
lines.append('FILE "%s" WAVE' % targetPath)
|
||||||
|
|
||||||
# header
|
# header
|
||||||
main = ['PERFORMER', 'TITLE']
|
main = ['PERFORMER', 'TITLE']
|
||||||
|
|||||||
@@ -58,6 +58,13 @@ filling in the variables and expanding the file extension. Variables are:
|
|||||||
- %A: album artist
|
- %A: album artist
|
||||||
- %S: album sort name
|
- %S: album sort name
|
||||||
- %d: disc title
|
- %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):
|
def addOptions(self):
|
||||||
@@ -69,7 +76,9 @@ filling in the variables and expanding the file extension. Variables are:
|
|||||||
default=default)
|
default=default)
|
||||||
self.parser.add_option('-O', '--output-directory',
|
self.parser.add_option('-O', '--output-directory',
|
||||||
action="store", dest="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
|
# FIXME: have a cache of these pickles somewhere
|
||||||
self.parser.add_option('-T', '--toc-pickle',
|
self.parser.add_option('-T', '--toc-pickle',
|
||||||
action="store", dest="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.track_template = options.track_template.decode('utf-8')
|
||||||
options.disc_template = options.disc_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):
|
def do(self, args):
|
||||||
prog = program.Program(record=self.getRootCommand().record)
|
prog = program.Program(record=self.getRootCommand().record)
|
||||||
runner = task.SyncRunner()
|
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
|
# FIXME: turn this into a method
|
||||||
|
|
||||||
def ripIfNotRipped(number):
|
def ripIfNotRipped(number):
|
||||||
|
self.debug('ripIfNotRipped for track %d' % number)
|
||||||
# we can have a previous result
|
# we can have a previous result
|
||||||
trackResult = prog.result.getTrackResult(number)
|
trackResult = prog.result.getTrackResult(number)
|
||||||
if not trackResult:
|
if not trackResult:
|
||||||
trackResult = result.TrackResult()
|
trackResult = result.TrackResult()
|
||||||
prog.result.tracks.append(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,
|
path = prog.getPath(prog.outdir, self.options.track_template,
|
||||||
mbdiscid, number) + '.' + profile.extension
|
mbdiscid, number) + '.' + profile.extension
|
||||||
|
self.debug('ripIfNotRipped: path %r' % path)
|
||||||
trackResult.number = number
|
trackResult.number = number
|
||||||
|
|
||||||
assert type(path) is unicode, "%r is not unicode" % path
|
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
|
# FIXME: optionally allow overriding reripping
|
||||||
if os.path.exists(path):
|
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' % (
|
self.stdout.write('Verifying track %d of %d: %s\n' % (
|
||||||
number, len(itable.tracks),
|
number, len(itable.tracks),
|
||||||
os.path.basename(path).encode('utf-8')))
|
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')
|
handle.write(u'#EXTM3U\n')
|
||||||
|
|
||||||
def writeFile(handle, path, length):
|
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'))
|
handle.write(u.encode('utf-8'))
|
||||||
u = '%s\n' % os.path.basename(path)
|
u = '%s\n' % targetPath
|
||||||
handle.write(u.encode('utf-8'))
|
handle.write(u.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,3 +25,14 @@ class FramesTestCase(tcommon.TestCase):
|
|||||||
class FormatTimeTestCase(tcommon.TestCase):
|
class FormatTimeTestCase(tcommon.TestCase):
|
||||||
def testFormatTime(self):
|
def testFormatTime(self):
|
||||||
self.assertEquals(common.formatTime(7202), '02:00:02.000')
|
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')
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ from morituri.test import common
|
|||||||
class CureTestCase(common.TestCase):
|
class CureTestCase(common.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__),
|
self.path = os.path.join(os.path.dirname(__file__),
|
||||||
u'cure.toc'))
|
u'cure.toc')
|
||||||
|
self.toc = toc.TocFile(self.path)
|
||||||
self.toc.parse()
|
self.toc.parse()
|
||||||
self.assertEquals(len(self.toc.table.tracks), 13)
|
self.assertEquals(len(self.toc.table.tracks), 13)
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ class CureTestCase(common.TestCase):
|
|||||||
self.toc.table.absolutize()
|
self.toc.table.absolutize()
|
||||||
cue = self.toc.table.cue()
|
cue = self.toc.table.cue()
|
||||||
ref = open(os.path.join(os.path.dirname(__file__), 'cure.cue')).read()
|
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
|
# we verify it because it has failed in readdisc in the past
|
||||||
self.assertEquals(self.toc.table.getAccurateRipURL(),
|
self.assertEquals(self.toc.table.getAccurateRipURL(),
|
||||||
@@ -109,8 +110,9 @@ class CureTestCase(common.TestCase):
|
|||||||
class BlocTestCase(common.TestCase):
|
class BlocTestCase(common.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__),
|
self.path = os.path.join(os.path.dirname(__file__),
|
||||||
u'bloc.toc'))
|
u'bloc.toc')
|
||||||
|
self.toc = toc.TocFile(self.path)
|
||||||
self.toc.parse()
|
self.toc.parse()
|
||||||
self.assertEquals(len(self.toc.table.tracks), 13)
|
self.assertEquals(len(self.toc.table.tracks), 13)
|
||||||
|
|
||||||
@@ -160,8 +162,9 @@ class BlocTestCase(common.TestCase):
|
|||||||
class BreedersTestCase(common.TestCase):
|
class BreedersTestCase(common.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__),
|
self.path = os.path.join(os.path.dirname(__file__),
|
||||||
u'breeders.toc'))
|
u'breeders.toc')
|
||||||
|
self.toc = toc.TocFile(self.path)
|
||||||
self.toc.parse()
|
self.toc.parse()
|
||||||
self.assertEquals(len(self.toc.table.tracks), 13)
|
self.assertEquals(len(self.toc.table.tracks), 13)
|
||||||
|
|
||||||
@@ -189,8 +192,9 @@ class BreedersTestCase(common.TestCase):
|
|||||||
class LadyhawkeTestCase(common.TestCase):
|
class LadyhawkeTestCase(common.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__),
|
self.path = os.path.join(os.path.dirname(__file__),
|
||||||
u'ladyhawke.toc'))
|
u'ladyhawke.toc')
|
||||||
|
self.toc = toc.TocFile(self.path)
|
||||||
self.toc.parse()
|
self.toc.parse()
|
||||||
self.assertEquals(len(self.toc.table.tracks), 13)
|
self.assertEquals(len(self.toc.table.tracks), 13)
|
||||||
#import code; code.interact(local=locals())
|
#import code; code.interact(local=locals())
|
||||||
|
|||||||
Reference in New Issue
Block a user