diff --git a/whipper/command/cd.py b/whipper/command/cd.py index daa11f0f..767538c1 100644 --- a/whipper/command/cd.py +++ b/whipper/command/cd.py @@ -54,6 +54,10 @@ disc and track template are: - %A: release artist - %S: release sort name + - %D: release title + - %T: medium title + - %N: medium position + - %M: medium count - %d: disc title - %y: release year - %r: release type, lowercase @@ -126,6 +130,9 @@ def do(self): logger.critical("unable to retrieve disc metadata, " "--unknown argument not passed") return -1 + elif self.program.metadata.mediumCount != '1': + self.options.track_template = self.options.track_template_mdisc + self.options.disc_template = self.options.disc_template_mdisc self.program.result.isCdr = cdrdao.DetectCdr(self.device) if (self.program.result.isCdr and @@ -278,10 +285,18 @@ def add_arguments(self): action="store", dest="track_template", default=DEFAULT_TRACK_TEMPLATE, help="template for track file naming") + self.parser.add_argument('--track-template-mdisc', + action="store", dest="track_template_mdisc", + help="template for track file naming " + "for a multidisc collection") self.parser.add_argument('--disc-template', action="store", dest="disc_template", default=DEFAULT_DISC_TEMPLATE, help="template for disc file naming") + self.parser.add_argument('--disc-template-mdisc', + action="store", dest="disc_template_mdisc", + help="template for disc file naming " + "for a multidisc collection") self.parser.add_argument('-U', '--unknown', action="store_true", dest="unknown", help="whether to continue ripping if " @@ -291,6 +306,11 @@ def add_arguments(self): help="whether to continue ripping if " "the disc is a CD-R", default=False) + self.parser.add_argument('--on-log-found', + action="store", dest="log_found", + help="what to do if a log file already exists", + choices=['stop', 'ask', 'continue'], + default='stop') self.parser.add_argument('-C', '--cover-art', action="store", dest="cover_art", help="fetch cover art and save it as " @@ -313,8 +333,16 @@ def handle_arguments(self): self.options.track_template = self.options.track_template validate_template(self.options.track_template, 'track') + if self.options.track_template_mdisc: + validate_template(self.options.track_template_mdisc, 'track') + else: + self.options.track_template_mdisc = self.options.track_template self.options.disc_template = self.options.disc_template validate_template(self.options.disc_template, 'disc') + if self.options.disc_template_mdisc: + validate_template(self.options.disc_template_mdisc, 'disc') + else: + self.options.disc_template_mdisc = self.options.disc_template if self.options.offset is None: raise ValueError("Drive offset is unconfigured.\n" @@ -362,7 +390,15 @@ def doCommand(self): if logs: msg = ("output directory %s is a finished rip" % dirname) logger.debug(msg) - raise RuntimeError(msg) + if self.options.log_found == 'stop': + raise RuntimeError(msg) + else: + print("Found log files in %s, this may be a finished rip" + % dirname) + print(logs) + if self.options.log_found == 'ask': + if input('Continue anyway? [y/n] ').lower() != 'y': + raise RuntimeError(msg) else: logger.info("creating output directory %s", dirname) os.makedirs(dirname) diff --git a/whipper/common/common.py b/whipper/common/common.py index 9a5f5235..c9f2323d 100644 --- a/whipper/common/common.py +++ b/whipper/common/common.py @@ -277,9 +277,9 @@ def getRelativePath(targetPath, collectionPath): def validate_template(template, kind): """Raise exception if disc/track template includes invalid variables.""" if kind == 'disc': - matches = re.findall(r'%[^ARSXdrxy]', template) + matches = re.findall(r'%[^ADMNRSTXdrxy]', template) elif kind == 'track': - matches = re.findall(r'%[^ARSXadnrstxy]', template) + matches = re.findall(r'%[^ADMNRSTXadnrstxy]', template) if '%' in template and matches: raise ValueError(kind + ' template string contains invalid ' 'variable(s): {}'.format(', '.join(matches))) diff --git a/whipper/common/mbngs.py b/whipper/common/mbngs.py index a36f5367..bd6f6337 100644 --- a/whipper/common/mbngs.py +++ b/whipper/common/mbngs.py @@ -92,6 +92,10 @@ class DiscMetadata: barcode = None countries = None + mediumPosition = None + mediumCount = None + mediumTitle = None + def __init__(self): self.tracks = [] @@ -289,7 +293,13 @@ def _getMetadata(release, discid=None, country=None): if count > 1: title += ' (Disc %d of %d)' % ( int(medium['position']), count) + discMD.mediumCount = str(count) + if 'position' in medium: + discMD.mediumPosition = medium['position'] + else: + discMD.mediumPosition = '1' if 'title' in medium: + discMD.mediumTitle = medium['title'] title += ": %s" % medium['title'] discMD.title = title for t in medium['track-list']: diff --git a/whipper/common/program.py b/whipper/common/program.py index 9269c9d9..3231b8b8 100644 --- a/whipper/common/program.py +++ b/whipper/common/program.py @@ -201,6 +201,10 @@ def getPath(self, outdir, template, mbdiscid, metadata, track_number=None): * ``%A``: release artist * ``%S``: release artist sort name + * ``%D``: release title + * ``%T``: medium title + * ``%N``: medium positon + * ``%M``: medium count * ``%d``: disc title * ``%y``: release year * ``%r``: release type, lowercase @@ -217,6 +221,8 @@ def getPath(self, outdir, template, mbdiscid, metadata, track_number=None): v['R'] = 'Unknown' v['B'] = '' # barcode v['C'] = '' # catalog number + v['N'] = '1' + v['M'] = '1' v['x'] = 'flac' v['X'] = v['x'].upper() v['y'] = '0000' @@ -234,8 +240,13 @@ def getPath(self, outdir, template, mbdiscid, metadata, track_number=None): v['A'] = self._filter.filter(metadata.artist) v['S'] = self._filter.filter(metadata.sortName) v['d'] = self._filter.filter(metadata.title) + v['D'] = self._filter.filter(metadata.releaseTitle) + if metadata.mediumTitle: + v['T'] = self._filter.filter(metadata.mediumTitle) v['B'] = metadata.barcode v['C'] = metadata.catalogNumber + v['M'] = metadata.mediumCount + v['N'] = metadata.mediumPosition if metadata.releaseType: v['R'] = metadata.releaseType v['r'] = metadata.releaseType.lower() @@ -250,6 +261,13 @@ def getPath(self, outdir, template, mbdiscid, metadata, track_number=None): # htoa defaults to disc's artist v['a'] = self._filter.filter(metadata.artist) + if 'S' not in v: + v['S'] = v['A'] + if 'D' not in v: + v['D'] = v['d'] + if 'T' not in v: + v['T'] = '%0*d' % (len(v['M']), int(v['N'])) + template = re.sub(r'%(\w)', r'%(\1)s', template) return os.path.join(outdir, template % v) @@ -470,6 +488,13 @@ def getTagList(self, number, mbdiscid): if self.metadata.release is not None: tags['DATE'] = self.metadata.release + if self.metadata.mediumCount: + tags['DISCNUMBER'] = self.metadata.mediumPosition + tags['DISCTOTAL'] = self.metadata.mediumCount + + if self.metadata.tracks: + tags['TRACKTOTAL'] = str(len(self.metadata.tracks)) + if number > 0: tags['MUSICBRAINZ_RELEASETRACKID'] = mbidTrack tags['MUSICBRAINZ_TRACKID'] = mbidRecording