Skip to content

Commit

Permalink
Merge pull request #536 from whipper-team/misc-changes-template
Browse files Browse the repository at this point in the history
This pull request extends the supported template variables. Additions:

- `%B`: release barcode (already included but is now allowed)
- `%C`: release catalog number (already included but is now allowed)
- `%c`: release disambiguation comment
- `%D`: disc title without disambiguation
- `%I`: MusicBrainz Disc ID
- `%M`: total number of discs in the chosen release
- `%N`: number of current disc
- `%T`: medium title

When the relative metadata is available, whipper now adds the `TRACKTOTAL`, `DISCTOTAL` and `DISCNUMBER` metadata tags to the audio tracks.

I've also taken the inspiration from pull request #476.

Resolves #401, resolves #440, resolves #448.
  • Loading branch information
JoeLametta authored May 16, 2021
2 parents 0eaf80c + 9d67144 commit b6338b2
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 31 deletions.
10 changes: 9 additions & 1 deletion man/whipper-cd-rip.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,15 @@ Template schemes
| - %A: release artist
| - %S: release sort name
| - %d: disc title
| - %B: release barcode
| - %C: release catalog number
| - %c: release disambiguation comment
| - %d: release title (with disambiguation)
| - %D: disc title (without disambiguation)
| - %I: MusicBrainz Disc ID
| - %M: total number of discs in the chosen release
| - %N: number of current disc
| - %T: medium title
| - %y: release year
| - %r: release type, lowercase
| - %R: release type, normal case
Expand Down
12 changes: 10 additions & 2 deletions whipper/command/cd.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,15 @@
disc and track template are:
- %A: release artist
- %S: release sort name
- %d: disc title
- %B: release barcode
- %C: release catalog number
- %c: release disambiguation comment
- %d: release title (with disambiguation)
- %D: disc title (without disambiguation)
- %I: MusicBrainz Disc ID
- %M: total number of discs in the chosen release
- %N: number of current disc
- %T: medium title
- %y: release year
- %r: release type, lowercase
- %R: release type, normal case
Expand Down Expand Up @@ -185,7 +193,7 @@ def do(self):
and self.program.metadata.artist \
or 'Unknown Artist'
self.program.result.title = self.program.metadata \
and self.program.metadata.title \
and self.program.metadata.releaseTitle \
or 'Unknown Title'
_, self.program.result.vendor, self.program.result.model, \
self.program.result.release = \
Expand Down
2 changes: 1 addition & 1 deletion whipper/command/mblookup.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def _printMetadata(self, md):
:type md: `DiscMetadata`
"""
print(' Artist: %s' % md.artist.encode('utf-8'))
print(' Title: %s' % md.title.encode('utf-8'))
print(' Title: %s' % md.releaseTitle.encode('utf-8'))
print(' Type: %s' % str(md.releaseType).encode('utf-8'))
print(' URL: %s' % md.url)
print(' Tracks: %d' % len(md.tracks))
Expand Down
4 changes: 2 additions & 2 deletions whipper/common/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'%[^ABCDIMNRSTXcdrxy]', template)
elif kind == 'track':
matches = re.findall(r'%[^ARSXadnrstxy]', template)
matches = re.findall(r'%[^ABCDIMNRSTXacdnrstxy]', template)
if '%' in template and matches:
raise ValueError(kind + ' template string contains invalid '
'variable(s): {}'.format(', '.join(matches)))
Expand Down
43 changes: 32 additions & 11 deletions whipper/common/mbngs.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,25 @@ class DiscMetadata:
:cvar sortName: release artist sort name
:cvar release: earliest release date, in YYYY-MM-DD
:vartype release: str
:cvar title: title of the disc (with disambiguation)
:cvar releaseTitle: title of the release (without disambiguation)
:cvar title: title of the disc (without disambiguation)
:vartype title: str or None
:cvar releaseTitle: title of the release (with disambiguation)
:vartype releasetitle: str or None
:cvar releaseDisambCmt: release disambiguation comment
:vartype releaseDisambCmt: str or None
:cvar mediumTitle: title of the medium
:vartype mediumTitle: str or None
:vartype tracks: list of :any:`TrackMetadata`
:cvar countries: MusicBrainz release countries
:vartype countries: list or None
:cvar discNumber: number of current disc
:vartype discNumber: int or None
:cvar discTotal: total number of discs in the chosen release
:vartype discTotal: int or None
:cvar catalogNumber: release catalog number
:vartype catalogNumber: str or None
:cvar barcode: release barcode
:vartype barcode: str or None
"""

artist = None
Expand All @@ -81,6 +95,7 @@ class DiscMetadata:
release = None

releaseTitle = None
releaseDisambCmt = None
releaseType = None

mbid = None
Expand All @@ -91,6 +106,9 @@ class DiscMetadata:
catalogNumber = None
barcode = None
countries = None
discNumber = None
discTotal = None
mediumTitle = None

def __init__(self):
self.tracks = []
Expand Down Expand Up @@ -281,17 +299,20 @@ def _getMetadata(release, discid=None, country=None):
for medium in release['medium-list']:
for disc in medium['disc-list']:
if discid is None or disc['id'] == discid:
title = release['title']
discMD.releaseTitle = title
discMD.title = release['title']
discMD.releaseTitle = releaseTitle = discMD.title
if 'disambiguation' in release:
title += " (%s)" % release['disambiguation']
count = len(release['medium-list'])
if count > 1:
title += ' (Disc %d of %d)' % (
int(medium['position']), count)
discMD.releaseDisambCmt = release['disambiguation']
releaseTitle += " (%s)" % release['disambiguation']
discMD.discNumber = int(medium['position'])
discMD.discTotal = len(release['medium-list'])
if discMD.discTotal > 1:
releaseTitle += ' (Disc %d of %d)' % (
discMD.discNumber, discMD.discTotal)
if 'title' in medium:
title += ": %s" % medium['title']
discMD.title = title
discMD.mediumTitle = medium['title']
releaseTitle += ": %s" % medium['title']
discMD.releaseTitle = releaseTitle
for t in medium['track-list']:
track = TrackMetadata()
trackCredit = _Credit(
Expand Down
43 changes: 31 additions & 12 deletions whipper/common/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,15 @@ def getPath(self, outdir, template, mbdiscid, metadata, track_number=None):
* ``%A``: release artist
* ``%S``: release artist sort name
* ``%d``: disc title
* ``%B``: release barcode
* ``%C``: release catalog number
* ``%c``: release disambiguation comment
* ``%d``: release title (with disambiguation)
* ``%D``: disc title (without disambiguation)
* ``%I``: MusicBrainz Disc ID
* ``%M``: total number of discs in the chosen release
* ``%N``: number of current disc
* ``%T``: medium title
* ``%y``: release year
* ``%r``: release type, lowercase
* ``%R``: release type, normal case
Expand All @@ -187,7 +195,7 @@ def getPath(self, outdir, template, mbdiscid, metadata, track_number=None):
assert isinstance(template, str), "%r is not str" % template
v = {}
v['A'] = 'Unknown Artist'
v['d'] = mbdiscid # fallback for title
v['I'] = v['d'] = v['D'] = mbdiscid # fallback for title
v['r'] = 'unknown'
v['R'] = 'Unknown'
v['B'] = '' # barcode
Expand All @@ -208,9 +216,14 @@ def getPath(self, outdir, template, mbdiscid, metadata, track_number=None):
v['y'] = release[:4]
v['A'] = metadata.artist
v['S'] = metadata.sortName
v['d'] = metadata.title
v['d'] = metadata.releaseTitle
v['D'] = metadata.title
v['B'] = metadata.barcode
v['C'] = metadata.catalogNumber
v['c'] = metadata.releaseDisambCmt
v['M'] = metadata.discTotal
v['N'] = metadata.discNumber
v['T'] = metadata.mediumTitle
if metadata.releaseType:
v['R'] = metadata.releaseType
v['r'] = metadata.releaseType.lower()
Expand Down Expand Up @@ -316,7 +329,7 @@ def getMusicBrainz(self, ittoc, mbdiscid, release=None, country=None,

for metadata in metadatas:
print('\nArtist : %s' % metadata.artist)
print('Title : %s' % metadata.title)
print('Title : %s' % metadata.releaseTitle)
print('Duration: %s' % common.formatTime(
metadata.duration / 1000.0))
print('URL : %s' % metadata.url)
Expand Down Expand Up @@ -356,7 +369,7 @@ def getMusicBrainz(self, ittoc, mbdiscid, release=None, country=None,
if len(metadatas) == 1:
logger.info('picked requested release id %s', release)
print('Artist: %s' % metadatas[0].artist)
print('Title : %s' % metadatas[0].title)
print('Title : %s' % metadatas[0].releaseTitle)
elif not metadatas:
logger.warning("requested release id '%s', but none of "
"the found releases match", release)
Expand All @@ -368,16 +381,16 @@ def getMusicBrainz(self, ittoc, mbdiscid, release=None, country=None,
# If we have multiple, make sure they match
if len(metadatas) > 1:
artist = metadatas[0].artist
releaseTitle = metadatas[0].releaseTitle
discTitle = metadatas[0].title
for i, metadata in enumerate(metadatas):
if not artist == metadata.artist:
logger.warning("artist 0: %r and artist %d: %r are "
"not the same", artist, i,
metadata.artist)
if not releaseTitle == metadata.releaseTitle:
if not discTitle == metadata.title:
logger.warning("title 0: %r and title %d: %r are "
"not the same", releaseTitle, i,
metadata.releaseTitle)
"not the same", discTitle, i,
metadata.title)

if not release and len(list(deltas)) > 1:
logger.warning('picked closest match in duration. '
Expand Down Expand Up @@ -407,13 +420,13 @@ def getTagList(self, number, mbdiscid):
"""
trackArtist = 'Unknown Artist'
releaseArtist = 'Unknown Artist'
disc = 'Unknown Disc'
album = 'Unknown Album'
title = 'Unknown Track'

if self.metadata:
trackArtist = self.metadata.artist
releaseArtist = self.metadata.artist
disc = self.metadata.title
album = self.metadata.title # No disambiguation is proper here
mbidRelease = self.metadata.mbid
mbidReleaseGroup = self.metadata.mbidReleaseGroup
mbidReleaseArtist = self.metadata.mbidArtist
Expand Down Expand Up @@ -445,13 +458,19 @@ def getTagList(self, number, mbdiscid):
tags['ALBUMARTIST'] = releaseArtist
tags['ARTIST'] = trackArtist
tags['TITLE'] = title
tags['ALBUM'] = disc
tags['ALBUM'] = album

tags['TRACKNUMBER'] = '%s' % number

if self.metadata:
if self.metadata.release is not None:
tags['DATE'] = self.metadata.release
if self.metadata.tracks:
tags['TRACKTOTAL'] = str(len(self.metadata.tracks))
if self.metadata.discTotal is not None:
tags['DISCTOTAL'] = str(self.metadata.discTotal)
if self.metadata.discNumber is not None:
tags['DISCNUMBER'] = str(self.metadata.discNumber)

if number > 0:
tags['MUSICBRAINZ_RELEASETRACKID'] = mbidTrack
Expand Down
4 changes: 2 additions & 2 deletions whipper/test/test_common_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def testStandardTemplateFilled(self):
prog = program.Program(config.Config())
md = mbngs.DiscMetadata()
md.artist = md.sortName = 'Jeff Buckley'
md.title = 'Grace'
md.releaseTitle = 'Grace'

path = prog.getPath('/tmp', DEFAULT_DISC_TEMPLATE,
'mbdiscid', md, 0)
Expand All @@ -36,7 +36,7 @@ def testIssue66TemplateFilled(self):
prog = program.Program(config.Config())
md = mbngs.DiscMetadata()
md.artist = md.sortName = 'Jeff Buckley'
md.title = 'Grace'
md.releaseTitle = 'Grace'

path = prog.getPath('/tmp', '%A/%d', 'mbdiscid', md, 0)
self.assertEqual(path,
Expand Down

0 comments on commit b6338b2

Please sign in to comment.