* morituri/common/program.py:
Add a retagging command. Add a getMusicBrainz() method. * morituri/rip/cd.py: Use it. * morituri/image/image.py: Add a task to retag an image. * morituri/rip/image.py: Add a command to retag an image.
This commit is contained in:
12
ChangeLog
12
ChangeLog
@@ -1,3 +1,15 @@
|
|||||||
|
2010-04-13 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
|
||||||
|
* morituri/common/program.py:
|
||||||
|
Add a retagging command.
|
||||||
|
Add a getMusicBrainz() method.
|
||||||
|
* morituri/rip/cd.py:
|
||||||
|
Use it.
|
||||||
|
* morituri/image/image.py:
|
||||||
|
Add a task to retag an image.
|
||||||
|
* morituri/rip/image.py:
|
||||||
|
Add a command to retag an image.
|
||||||
|
|
||||||
2010-04-13 Thomas Vander Stichele <thomas at apestaart dot org>
|
2010-04-13 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
|
||||||
* morituri/common/encode.py:
|
* morituri/common/encode.py:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ Common functionality and class for all programs using morituri.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import urlparse
|
||||||
|
|
||||||
from morituri.common import common, log
|
from morituri.common import common, log
|
||||||
from morituri.result import result
|
from morituri.result import result
|
||||||
@@ -71,18 +72,23 @@ def getMetadata(release):
|
|||||||
metadata.artist = release.artist.name
|
metadata.artist = release.artist.name
|
||||||
metadata.sortName = release.artist.sortName
|
metadata.sortName = release.artist.sortName
|
||||||
metadata.release = release.getEarliestReleaseDate()
|
metadata.release = release.getEarliestReleaseDate()
|
||||||
|
metadata.mbid = urlparse.urlparse(release.id)[2].split("/")[-1]
|
||||||
|
metadata.artistMBID = urlparse.urlparse(release.artist.id)[2].split("/")[-1]
|
||||||
|
|
||||||
|
|
||||||
for t in release.tracks:
|
for t in release.tracks:
|
||||||
track = TrackMetadata()
|
track = TrackMetadata()
|
||||||
if isSingleArtist:
|
if isSingleArtist:
|
||||||
track.artist = metadata.artist
|
track.artist = metadata.artist
|
||||||
track.sortName = metadata.sortName
|
track.sortName = metadata.sortName
|
||||||
track.title = t.title
|
track.artistMBID = metadata.artistMBID
|
||||||
else:
|
else:
|
||||||
# various artists discs can have tracks with no artist
|
# various artists discs can have tracks with no artist
|
||||||
track.artist = t.artist and t.artist.name or release.artist.name
|
track.artist = t.artist and t.artist.name or release.artist.name
|
||||||
track.sortName = t.artist.sortName
|
track.sortName = t.artist.sortName
|
||||||
track.title = t.title
|
|
||||||
|
track.title = t.title
|
||||||
|
track.mbid = urlparse.urlparse(t.id)[2].split("/")[-1]
|
||||||
metadata.tracks.append(track)
|
metadata.tracks.append(track)
|
||||||
|
|
||||||
return metadata
|
return metadata
|
||||||
@@ -276,6 +282,34 @@ class Program(log.Loggable):
|
|||||||
|
|
||||||
return os.path.join(outdir, template % v)
|
return os.path.join(outdir, template % v)
|
||||||
|
|
||||||
|
def getMusicBrainz(self, ittoc, mbdiscid):
|
||||||
|
# look up disc on musicbrainz
|
||||||
|
ret = None
|
||||||
|
|
||||||
|
metadatas = None
|
||||||
|
try:
|
||||||
|
metadatas = musicbrainz(mbdiscid)
|
||||||
|
except MusicBrainzException, e:
|
||||||
|
print "Error:", e
|
||||||
|
print 'Continuing without metadata'
|
||||||
|
|
||||||
|
if metadatas:
|
||||||
|
print 'Matching releases:'
|
||||||
|
for metadata in metadatas:
|
||||||
|
print 'Artist : %s' % metadata.artist.encode('utf-8')
|
||||||
|
print 'Title : %s' % metadata.title.encode('utf-8')
|
||||||
|
|
||||||
|
# Select one of the returned releases. We just pick the first one.
|
||||||
|
ret = metadatas[0]
|
||||||
|
else:
|
||||||
|
print 'Submit this disc to MusicBrainz at:'
|
||||||
|
print ittoc.getMusicBrainzSubmitURL()
|
||||||
|
ret = None
|
||||||
|
|
||||||
|
print
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def getTagList(self, number):
|
def getTagList(self, number):
|
||||||
"""
|
"""
|
||||||
Based on the metadata, get a gst.TagList for the given track.
|
Based on the metadata, get a gst.TagList for the given track.
|
||||||
@@ -292,10 +326,15 @@ class Program(log.Loggable):
|
|||||||
if self.metadata:
|
if self.metadata:
|
||||||
artist = self.metadata.artist
|
artist = self.metadata.artist
|
||||||
disc = self.metadata.title
|
disc = self.metadata.title
|
||||||
|
albumMBID = self.metadata.mbid
|
||||||
|
albumArtistMBID = self.metadata.artistMBID
|
||||||
|
|
||||||
if number > 0:
|
if number > 0:
|
||||||
try:
|
try:
|
||||||
artist = self.metadata.tracks[number - 1].artist
|
artist = self.metadata.tracks[number - 1].artist
|
||||||
title = self.metadata.tracks[number - 1].title
|
title = self.metadata.tracks[number - 1].title
|
||||||
|
trackMBID = self.metadata.tracks[number - 1].mbid
|
||||||
|
trackArtistMBID = self.metadata.tracks[number - 1].artistMBID
|
||||||
except IndexError, e:
|
except IndexError, e:
|
||||||
print 'ERROR: no track %d found, %r' % (number, e)
|
print 'ERROR: no track %d found, %r' % (number, e)
|
||||||
raise
|
raise
|
||||||
@@ -342,6 +381,11 @@ class Program(log.Loggable):
|
|||||||
str(date))
|
str(date))
|
||||||
ret[gst.TAG_DATE] = s['date']
|
ret[gst.TAG_DATE] = s['date']
|
||||||
|
|
||||||
|
ret["musicbrainz-trackid"] = trackMBID
|
||||||
|
ret["musicbrainz-artistid"] = trackArtistMBID
|
||||||
|
ret["musicbrainz-albumid"] = albumMBID
|
||||||
|
ret["musicbrainz-albumartistid"] = albumArtistMBID
|
||||||
|
|
||||||
# FIXME: gst.TAG_ISRC
|
# FIXME: gst.TAG_ISRC
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
@@ -404,6 +448,11 @@ class Program(log.Loggable):
|
|||||||
trackResult.peak = t.peak
|
trackResult.peak = t.peak
|
||||||
trackResult.quality = t.quality
|
trackResult.quality = t.quality
|
||||||
|
|
||||||
|
def retagImage(self, runner, taglists):
|
||||||
|
cueImage = image.Image(self.cuePath)
|
||||||
|
t = image.ImageRetagTask(cueImage, taglists)
|
||||||
|
runner.run(t)
|
||||||
|
|
||||||
def verifyImage(self, runner, responses):
|
def verifyImage(self, runner, responses):
|
||||||
"""
|
"""
|
||||||
Verify our image against the given AccurateRip responses.
|
Verify our image against the given AccurateRip responses.
|
||||||
|
|||||||
@@ -200,12 +200,7 @@ class AudioLengthTask(task.Task):
|
|||||||
error, debug = msg.parse_error()
|
error, debug = msg.parse_error()
|
||||||
self.debug('Got GStreamer error: %r, debug: %r' % (
|
self.debug('Got GStreamer error: %r, debug: %r' % (
|
||||||
error.message, debug))
|
error.message, debug))
|
||||||
# give us an exception stack for debugging
|
self.setAndRaiseException(error)
|
||||||
try:
|
|
||||||
raise error
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
self.setException(error)
|
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
class ImageVerifyTask(task.MultiSeparateTask):
|
class ImageVerifyTask(task.MultiSeparateTask):
|
||||||
@@ -300,4 +295,30 @@ class ImageEncodeTask(task.MultiSeparateTask):
|
|||||||
index = track.indexes[1]
|
index = track.indexes[1]
|
||||||
add(index)
|
add(index)
|
||||||
|
|
||||||
|
class ImageRetagTask(task.MultiSeparateTask):
|
||||||
|
"""
|
||||||
|
I retag files in a disk image.
|
||||||
|
"""
|
||||||
|
|
||||||
|
description = "Retagging tracks"
|
||||||
|
|
||||||
|
def __init__(self, image, taglists):
|
||||||
|
task.MultiSeparateTask.__init__(self)
|
||||||
|
|
||||||
|
# here to avoid import gst eating our options
|
||||||
|
from morituri.common import encode
|
||||||
|
|
||||||
|
self._image = image
|
||||||
|
self._taglists = taglists
|
||||||
|
cue = image.cue
|
||||||
|
self._tasks = []
|
||||||
|
self.lengths = {}
|
||||||
|
|
||||||
|
for trackIndex, track in enumerate(cue.table.tracks):
|
||||||
|
self.debug('retagging track %d', trackIndex + 1)
|
||||||
|
index = track.indexes[1]
|
||||||
|
path = image.getRealPath(index.path)
|
||||||
|
assert type(path) is unicode, "%r is not unicode" % path
|
||||||
|
self.debug('schedule retag of %r', path)
|
||||||
|
root, ext = os.path.splitext(os.path.basename(path))
|
||||||
|
taskk = encode.RetagTask(path, taglists[trackIndex])
|
||||||
|
|||||||
@@ -113,26 +113,7 @@ See http://sourceforge.net/tracker/?func=detail&aid=604751&group_id=2171&atid=1
|
|||||||
mbdiscid = ittoc.getMusicBrainzDiscId()
|
mbdiscid = ittoc.getMusicBrainzDiscId()
|
||||||
print "MusicBrainz disc id", mbdiscid
|
print "MusicBrainz disc id", mbdiscid
|
||||||
|
|
||||||
# look up disc on musicbrainz
|
prog.metadata = prog.getMusicBrainz(ittoc, mbdiscid)
|
||||||
metadatas = None
|
|
||||||
try:
|
|
||||||
metadatas = program.musicbrainz(mbdiscid)
|
|
||||||
except program.MusicBrainzException, e:
|
|
||||||
print "Error:", e
|
|
||||||
print 'Continuing without metadata'
|
|
||||||
|
|
||||||
if metadatas:
|
|
||||||
print 'Matching releases:'
|
|
||||||
for metadata in metadatas:
|
|
||||||
print 'Artist : %s' % metadata.artist.encode('utf-8')
|
|
||||||
print 'Title : %s' % metadata.title.encode('utf-8')
|
|
||||||
|
|
||||||
# Select one of the returned releases. We just pick the first one.
|
|
||||||
prog.metadata = metadatas[0]
|
|
||||||
else:
|
|
||||||
print 'Submit this disc to MusicBrainz at:'
|
|
||||||
print ittoc.getMusicBrainzSubmitURL()
|
|
||||||
print
|
|
||||||
|
|
||||||
# now, read the complete index table, which is slower
|
# now, read the complete index table, which is slower
|
||||||
itable = prog.getTable(runner, ittoc.getCDDBDiscId(), device)
|
itable = prog.getTable(runner, ittoc.getCDDBDiscId(), device)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from morituri.common import logcommand, task, accurip, program
|
from morituri.common import logcommand, task, accurip, program, encode
|
||||||
from morituri.image import image, cue
|
from morituri.image import image, cue
|
||||||
from morituri.result import result
|
from morituri.result import result
|
||||||
from morituri.program import cdrdao, cdparanoia
|
from morituri.program import cdrdao, cdparanoia
|
||||||
@@ -97,6 +97,32 @@ class Encode(logcommand.LogCommand):
|
|||||||
outm3u.write('%s' % root)
|
outm3u.write('%s' % root)
|
||||||
outm3u.close()
|
outm3u.close()
|
||||||
|
|
||||||
|
class Retag(logcommand.LogCommand):
|
||||||
|
summary = "retag image files"
|
||||||
|
|
||||||
|
def do(self, args):
|
||||||
|
prog = program.Program()
|
||||||
|
runner = task.SyncRunner()
|
||||||
|
cache = accurip.AccuCache()
|
||||||
|
|
||||||
|
for arg in args:
|
||||||
|
arg = unicode(arg)
|
||||||
|
cueImage = image.Image(arg)
|
||||||
|
cueImage.setup(runner)
|
||||||
|
|
||||||
|
mbdiscid = cueImage.table.getMusicBrainzDiscId()
|
||||||
|
prog.metadata = prog.getMusicBrainz(cueImage.table, mbdiscid)
|
||||||
|
|
||||||
|
# FIXME: this feels like we're poking at internals.
|
||||||
|
prog.cuePath = arg
|
||||||
|
prog.result = result.RipResult()
|
||||||
|
for track in cueImage.table.tracks:
|
||||||
|
path = track.indexes[1].path
|
||||||
|
taglist = prog.getTagList(track.number)
|
||||||
|
self.debug('possibly retagging %r with taglist %r',
|
||||||
|
path, taglist)
|
||||||
|
runner.run(encode.SafeRetagTask(path, taglist))
|
||||||
|
|
||||||
class Verify(logcommand.LogCommand):
|
class Verify(logcommand.LogCommand):
|
||||||
summary = "verify image"
|
summary = "verify image"
|
||||||
|
|
||||||
@@ -128,4 +154,4 @@ class Verify(logcommand.LogCommand):
|
|||||||
class Image(logcommand.LogCommand):
|
class Image(logcommand.LogCommand):
|
||||||
summary = "handle images"
|
summary = "handle images"
|
||||||
|
|
||||||
subCommandClasses = [Encode, Verify, ]
|
subCommandClasses = [Encode, Retag, Verify, ]
|
||||||
|
|||||||
Reference in New Issue
Block a user