Skip to content
This repository has been archived by the owner on Dec 3, 2020. It is now read-only.

Commit

Permalink
rewrite getMusicBrainz:
Browse files Browse the repository at this point in the history
- use print directly
- set user agent in method not main
- minor error handling cleanups
- log errors before raising
- simplify release selection logic
  • Loading branch information
RecursiveForest committed Sep 4, 2017
1 parent 3f248bf commit ca33dcf
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 139 deletions.
32 changes: 19 additions & 13 deletions whipper/command/cd.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@
'''


def bye(msg):
logger.critical(msg)
raise RuntimeError(msg)


class _CD(BaseCommand):

"""
Expand Down Expand Up @@ -116,39 +121,40 @@ def do(self):

# already show us some info based on this
self.program.getRipResult(self.ittoc.getCDDBDiscId())
sys.stdout.write("CDDB disc id: %s\n" % self.ittoc.getCDDBDiscId())
print("CDDB disc id: %s" % self.ittoc.getCDDBDiscId())
self.mbdiscid = self.ittoc.getMusicBrainzDiscId()
sys.stdout.write("MusicBrainz disc id %s\n" % self.mbdiscid)

sys.stdout.write("MusicBrainz lookup URL %s\n" %
self.ittoc.getMusicBrainzSubmitURL())
print("MusicBrainz disc id: %s" % self.mbdiscid)
print("MusicBrainz lookup URL: %s" %
self.ittoc.getMusicBrainzSubmitURL())
print('disc duration: %s, %d audio tracks' % (
common.formatTime(self.ittoc.duration() / 1000.0),
self.ittoc.getAudioTracks()))

self.program.metadata = (
self.program.getMusicBrainz(self.ittoc, self.mbdiscid,
release=self.options.release_id,
release_id=self.options.release_id,
country=self.options.country,
prompt=self.options.prompt)
)

if not self.program.metadata:
# fall back to FreeDB for lookup
logger.debug("falling back to freedb")
cddbid = self.ittoc.getCDDBValues()
cddbmd = self.program.getCDDB(cddbid)
logger.debug("freedb id, md: %s, %s", cddbid, cddbmd)
if cddbmd:
sys.stdout.write('FreeDB identifies disc as %s\n' % cddbmd)

# also used by rip cd info
if not getattr(self.options, 'unknown', False):
logger.critical("unable to retrieve disc metadata, "
"--unknown not passed")
return -1
if not self.options.unknown:
bye("unable to retrieve disc metadata, need cd -u to rip "
"unknown disc")

self.program.result.isCdr = cdrdao.DetectCdr(self.device)
if (self.program.result.isCdr and
not getattr(self.options, 'cdr', False)):
logger.critical("inserted disc seems to be a CD-R, "
"--cdr not passed")
return -1
bye("CD-R detected, need cd -r to rip")

# FIXME ?????
# Hackish fix for broken commit
Expand Down
11 changes: 6 additions & 5 deletions whipper/command/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import os
import sys
import pkg_resources
import musicbrainzngs

import whipper

Expand All @@ -19,9 +18,6 @@


def main():
# set user agent
musicbrainzngs.set_useragent("whipper", whipper.__version__,
"https://github.com/JoeLametta/whipper")
# register plugins with pkg_resources
distributions, _ = pkg_resources.working_set.find_plugins(
pkg_resources.Environment([directory.data_path('plugins')])
Expand All @@ -36,8 +32,13 @@ def main():
cmd.options.eject in ('failure', 'always')):
eject_device(e.device)
return 255
except RuntimeError, e:
print(e)
return 1
except KeyboardInterrupt:
return 2
except ImportError, e:
raise ImportError(e)
raise
except task.TaskException, e:
if isinstance(e.exception, ImportError):
raise ImportError(e.exception)
Expand Down
4 changes: 3 additions & 1 deletion whipper/common/mbngs.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
Handles communication with the MusicBrainz server using NGS.
"""

import musicbrainzngs
import urllib2

import logging
Expand Down Expand Up @@ -263,8 +264,9 @@ def musicbrainz(discid, country=None, record=False):
@rtype: list of L{DiscMetadata}
"""
musicbrainzngs.set_useragent("whipper", whipper.__version__,
"https://github.com/JoeLametta/whipper")
logger.debug('looking up results for discid %r', discid)
import musicbrainzngs

ret = []

Expand Down
176 changes: 56 additions & 120 deletions whipper/common/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,17 @@
logger = logging.getLogger(__name__)


# FIXME: should Program have a runner ?

def _prompt_for_key(prompt, items, guess):
while True:
try:
selection = raw_input(prompt % guess)
if not selection:
selection = guess
if selection in items:
return items[selection]
except EOFError:
print('^D')
return

class Program:
"""
Expand Down Expand Up @@ -292,140 +301,67 @@ def getCDDB(self, cddbdiscid):

return None

def getMusicBrainz(self, ittoc, mbdiscid, release=None, country=None,
def getMusicBrainz(self, ittoc, mbdiscid, release_id=None, country=None,
prompt=False):
"""
@type ittoc: L{whipper.image.table.Table}
return metadata from MusicBrainz as mbngs.DiscMetadata
"""
# look up disc on MusicBrainz
self._stdout.write('Disc duration: %s, %d audio tracks\n' % (
common.formatTime(ittoc.duration() / 1000.0),
ittoc.getAudioTracks()))
logger.debug('MusicBrainz submit url: %r',
ittoc.getMusicBrainzSubmitURL())
ret = None

metadatas = None
e = None

# XXX: why retry after MusicBrainzException...?
for _ in range(0, 4):
try:
metadatas = mbngs.musicbrainz(mbdiscid,
country=country,
record=self._record)
releases = mbngs.musicbrainz(mbdiscid,
country=country,
record=self._record)
releases = {r.mbid: r for r in releases}
break
except mbngs.NotFoundException, e:
break
except musicbrainzngs.NetworkError, e:
self._stdout.write("Warning: network error: %r\n" % (e, ))
logger.warning("network error: %r", e)
break
except mbngs.MusicBrainzException, e:
# XXX: ???
self._stdout.write("Warning: %r\n" % (e, ))
time.sleep(5)
continue

if not metadatas:
if e:
self._stdout.write("Error: %r\n" % (e, ))
self._stdout.write('Continuing without metadata\n')

if metadatas:
deltas = {}

self._stdout.write('\nMatching releases:\n')

for metadata in metadatas:
self._stdout.write('\n')
self._stdout.write('Artist : %s\n' %
metadata.artist.encode('utf-8'))
self._stdout.write('Title : %s\n' %
metadata.title.encode('utf-8'))
self._stdout.write('Duration: %s\n' %
common.formatTime(metadata.duration /
1000.0))
self._stdout.write('URL : %s\n' % metadata.url)
self._stdout.write('Release : %s\n' % metadata.mbid)
self._stdout.write('Type : %s\n' % metadata.releaseType)
if metadata.barcode:
self._stdout.write("Barcode : %s\n" % metadata.barcode)
if metadata.catalogNumber:
self._stdout.write("Cat no : %s\n" %
metadata.catalogNumber)

delta = abs(metadata.duration - ittoc.duration())
if delta not in deltas:
deltas[delta] = []
deltas[delta].append(metadata)

lowest = None

if not release and len(metadatas) > 1:
# Select the release that most closely matches the duration.
lowest = min(deltas.keys())

if prompt:
guess = (deltas[lowest])[0].mbid
release = raw_input(
"\nPlease select a release [%s]: " % guess)

if not release:
release = guess

if release:
metadatas = [m for m in metadatas if m.url.endswith(release)]
logger.debug('Asked for release %r, only kept %r',
release, metadatas)
if len(metadatas) == 1:
self._stdout.write('\n')
self._stdout.write('Picked requested release id %s\n' %
release)
self._stdout.write('Artist : %s\n' %
metadatas[0].artist.encode('utf-8'))
self._stdout.write('Title : %s\n' %
metadatas[0].title.encode('utf-8'))
elif not metadatas:
self._stdout.write(
"Requested release id '%s', "
"but none of the found releases match\n" % release)
return
else:
if lowest:
metadatas = deltas[lowest]

# If we have multiple, make sure they match
if len(metadatas) > 1:
artist = metadatas[0].artist
releaseTitle = metadatas[0].releaseTitle
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:
logger.warning("title 0: %r and title %d: %r "
"are not the same" % (
releaseTitle, i,
metadata.releaseTitle))

if (not release and len(deltas.keys()) > 1):
self._stdout.write('\n')
self._stdout.write('Picked closest match in duration.\n')
self._stdout.write('Others may be wrong in MusicBrainz, '
'please correct.\n')
self._stdout.write('Artist : %s\n' %
artist.encode('utf-8'))
self._stdout.write('Title : %s\n' %
metadatas[0].title.encode('utf-8'))

# Select one of the returned releases. We just pick the first one.
ret = metadatas[0]
else:
self._stdout.write(
'Submit this disc to MusicBrainz at the above URL.\n')
ret = None
if not releases:
print('continuing without metadata')
print('please submit this disc to MusicBrainz at the above URL')
return

self._stdout.write('\n')
return ret
print('\nmatching releases:')

for r in releases.values():
print
print('artist : %s' % r.artist.encode('utf-8'))
print('title : %s' % r.title.encode('utf-8'))
print('duration: %s' % common.formatTime(r.duration / 1000.0))
print('URL : %s' % r.url)
print('release : %s' % r.mbid)
print('type : %s' % r.releaseType)
if r.barcode:
print("barcode : %s" % r.barcode)
if r.catalogNumber:
print("cat no : %s" % r.catalogNumber)
print

if release_id:
return releases[release_id]

# Guess the release that most closely matches the duration.
deltas = {}
for r in releases.values():
delta = abs(r.duration - ittoc.duration())
if delta not in deltas:
deltas[delta] = []
deltas[delta].append(r)
release = deltas[min(deltas.keys())][0]

if len(releases) > 1 and prompt:
release = _prompt_for_key("select a release [%s]: ",
releases, release.mbid)
return release

def getTagList(self, number):
"""
Expand Down

0 comments on commit ca33dcf

Please sign in to comment.