[SCM] morituri/master: * morituri/test/release.c7d919f4-3ea0-4c4b-a230-b3605f069440.xml: Add release data for Bettie Serveert, Lamprey * morituri/test/test_common_program.py: Add a test for parsing and getting the whole duration. * morituri/common/common.py: Add a method to format time. * morituri/common/program.py: Add duration to tracks and release metadatas. When there are multiple matches, look up the closest in duration. Make sure that multiple matches closest in duration contain same artist and title. Complain about the other ones. * morituri/image/table.py: Add a method to calculate a duration from the table. * morituri/test/test_image_table.py: Add a test for it.

js at users.alioth.debian.org js at users.alioth.debian.org
Sun Oct 19 20:09:34 UTC 2014


The following commit has been merged in the master branch:
commit d43860bdfb52ab30e409853e35e26b4d2e69b4f2
Author: Thomas Vander Stichele <thomas (at) apestaart (dot) org>
Date:   Sun Aug 14 12:18:51 2011 +0000

    	* morituri/test/release.c7d919f4-3ea0-4c4b-a230-b3605f069440.xml:
    	  Add release data for Bettie Serveert, Lamprey
    	* morituri/test/test_common_program.py:
    	  Add a test for parsing and getting the whole duration.
    	* morituri/common/common.py:
    	  Add a method to format time.
    	* morituri/common/program.py:
    	  Add duration to tracks and release metadatas.
    	  When there are multiple matches, look up the closest in duration.
    	  Make sure that multiple matches closest in duration contain same
    	  artist and title.
    	  Complain about the other ones.
    	* morituri/image/table.py:
    	  Add a method to calculate a duration from the table.
    	* morituri/test/test_image_table.py:
    	  Add a test for it.

diff --git a/ChangeLog b/ChangeLog
index c091830..d7f4243 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2011-08-14  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* morituri/test/release.c7d919f4-3ea0-4c4b-a230-b3605f069440.xml:
+	  Add release data for Bettie Serveert, Lamprey
+	* morituri/test/test_common_program.py:
+	  Add a test for parsing and getting the whole duration.
+	* morituri/common/common.py:
+	  Add a method to format time.
+	* morituri/common/program.py:
+	  Add duration to tracks and release metadatas.
+	  When there are multiple matches, look up the closest in duration.
+	  Make sure that multiple matches closest in duration contain same
+	  artist and title.
+	  Complain about the other ones.
+	* morituri/image/table.py:
+	  Add a method to calculate a duration from the table.
+	* morituri/test/test_image_table.py:
+	  Add a test for it.
+
 2011-08-13  Thomas Vander Stichele  <thomas at apestaart dot org>
 
 	* morituri/rip/cd.py:
diff --git a/morituri/common/common.py b/morituri/common/common.py
index e6612ca..406df96 100644
--- a/morituri/common/common.py
+++ b/morituri/common/common.py
@@ -67,6 +67,46 @@ def framesToHMSF(frames):
 
     return "%02d:%02d:%02d.%02d" % (h, m, s, f)
 
+def formatTime(seconds, fractional=3):
+    """
+    Nicely format time in a human-readable format, like
+    HH:MM:SS.mmm
+
+    If fractional is zero, no seconds will be shown.
+    If it is greater than 0, we will show seconds and fractions of seconds.
+    As a side consequence, there is no way to show seconds without fractions.
+
+    @param seconds:    the time in seconds to format.
+    @type  seconds:    int or float
+    @param fractional: how many digits to show for the fractional part of
+                       seconds.
+    @type  fractional: int
+
+    @rtype: string
+    @returns: a nicely formatted time string.
+    """
+    chunks = []
+
+    if seconds < 0:
+        chunks.append(('-'))
+        seconds = -seconds
+
+    hour = 60 * 60
+    hours = seconds / hour
+    seconds %= hour
+
+    minute = 60
+    minutes = seconds / minute
+    seconds %= minute
+
+    chunk = '%02d:%02d' % (hours, minutes)
+    if fractional > 0:
+        chunk += ':%0*.*f' % (fractional + 3, fractional, seconds)
+
+    chunks.append(chunk)
+
+    return " ".join(chunks)
+
 class Persister(object):
     """
     I wrap an optional pickle to persist an object to disk.
diff --git a/morituri/common/program.py b/morituri/common/program.py
index 7ca846f..791f6a7 100644
--- a/morituri/common/program.py
+++ b/morituri/common/program.py
@@ -26,6 +26,7 @@ Common functionality and class for all programs using morituri.
 
 import os
 import urlparse
+import time
 
 from morituri.common import common, log
 from morituri.result import result
@@ -40,6 +41,7 @@ class MusicBrainzException(Exception):
 class TrackMetadata(object):
     artist = None
     title = None
+    duration = None # in ms
 
 class DiscMetadata(object):
     """
@@ -90,8 +92,12 @@ def getMetadata(release):
     metadata.mbidArtist = urlparse.urlparse(release.artist.id)[2].split("/")[-1]
 
 
+    duration = 0
+
     for t in release.tracks:
         track = TrackMetadata()
+        track.duration = t.duration
+        duration += t.duration
         if isSingleArtist or t.artist == None:
             track.artist = metadata.artist
             track.sortName = metadata.sortName
@@ -106,6 +112,8 @@ def getMetadata(release):
         track.mbid = urlparse.urlparse(t.id)[2].split("/")[-1]
         metadata.tracks.append(track)
 
+    metadata.duration = duration
+
     return metadata
 
 
@@ -159,8 +167,10 @@ def musicbrainz(discid):
 
         md = getMetadata(release)
         if md:
+            log.debug('program', 'duration %r', md.duration)
             ret.append(md)
 
+
     return ret
 
 class Program(log.Loggable):
@@ -345,18 +355,54 @@ class Program(log.Loggable):
         ret = None
 
         metadatas = None
-        try:
-            metadatas = musicbrainz(mbdiscid)
-        except MusicBrainzException, e:
+        for i in range(0, 4):
+            try:
+                metadatas = musicbrainz(mbdiscid)
+            except MusicBrainzException, e:
+                print "Warning:", e
+                time.sleep(5)
+                continue
+
+        if not metadatas:
             print "Error:", e
             print 'Continuing without metadata'
 
         if metadatas:
+            print 'Disc duration: %s' % common.formatTime(
+                ittoc.duration() / 1000.0)
+            print
             print 'Matching releases:'
+            deltas = {}
             for metadata in metadatas:
 
                 print 'Artist  : %s' % metadata.artist.encode('utf-8')
                 print 'Title   : %s' % metadata.title.encode('utf-8')
+                print 'Duration: %s' % common.formatTime(
+                    metadata.duration / 1000.0)
+
+                delta = abs(metadata.duration - ittoc.duration())
+                if not delta in deltas:
+                    deltas[delta] = []
+                deltas[delta].append(metadata)
+
+            # Select the release that most closely matches the duration.
+            lowest = min(deltas.keys())
+
+            # If we have multiple, make sure they match
+            metadatas = deltas[lowest]
+            if len(metadatas) > 1:
+                artist = metadatas[0].artist
+                title = metadatas[0].title
+                for metadata in metadatas:
+                    assert artist == metadata.artist
+                    assert title == metadata.title
+
+                if (len(deltas.keys()) > 1):
+                    print
+                    print 'Picked closest match in duration.'
+                    print 'Others may be wrong in musicbrainz, please correct.'
+                    print 'Artist : %s' % artist
+                    print 'Title :  %s' % title
 
             # Select one of the returned releases. We just pick the first one.
             ret = metadatas[0]
diff --git a/morituri/image/table.py b/morituri/image/table.py
index 9b6522b..725fa7f 100644
--- a/morituri/image/table.py
+++ b/morituri/image/table.py
@@ -427,6 +427,14 @@ class Table(object, log.Loggable):
         return urlparse.urlunparse((
             'http', host, '/bare/cdlookup.html', '', query, ''))
 
+    def duration(self):
+        """
+        Get an estimate of the duration in ms.
+        """
+        values = self._getMusicBrainzValues()
+        leadout = values[2]
+        first = values[3]
+        return ((leadout - first) * 1000) / common.FRAMES_PER_SECOND
 
     def _getMusicBrainzValues(self):
         """
diff --git a/morituri/test/release.c7d919f4-3ea0-4c4b-a230-b3605f069440.xml b/morituri/test/release.c7d919f4-3ea0-4c4b-a230-b3605f069440.xml
new file mode 100644
index 0000000..346c677
--- /dev/null
+++ b/morituri/test/release.c7d919f4-3ea0-4c4b-a230-b3605f069440.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- gotten from get "http://www.musicbrainz.org/ws/1/release/c7d919f4-3ea0-4c4b-a230-b3605f069440?type=xml&inc=tracks+release-events+artist"
+     -->
+<metadata xmlns="http://musicbrainz.org/ns/mmd-1.0#" >
+    <release type="Album Official" id="c7d919f4-3ea0-4c4b-a230-b3605f069440">
+        <title>Lamprey</title><text-representation script="Latn" language="ENG" />
+        <asin>B00000581T</asin>
+        <artist id="89e4aade-fc77-4a18-8d0c-3554cc9b8c54">
+            <name>Bettie Serveert</name><sort-name>Bettie Serveert</sort-name>
+        </artist>
+        <track-list>
+            <track id="a89c2320-1eae-4f2d-8b0e-6dfac4ae1451">
+                <title>Keepsake</title><duration>378693</duration>
+            </track>
+            <track id="730df656-f504-4866-b5d0-c59ee01524a3">
+                <title>Ray Ray Rain</title><duration>262106</duration>
+            </track>
+            <track id="62ff731e-3cec-4f7c-a614-72adb062fd6c">
+                <title>D. Feathers</title><duration>332626</duration>
+            </track>
+            <track id="e2702c6e-1dae-4a5d-ab16-aed1be105f94">
+                <title>Re-Feel-It</title><duration>238240</duration>
+            </track>
+            <track id="8bc5865e-6286-4cf2-83c8-94061cf4e25f">
+                <title>21 Days</title><duration>203826</duration>
+            </track>
+            <track id="484f7bc6-51bd-44dd-bac6-b8218602d3f0">
+                <title>Cybor*D</title><duration>241800</duration>
+            </track>
+            <track id="e0f2ce29-392e-499d-8ff9-f573e01fb3dc">
+                <title>Tell Me, Sad</title><duration>318333</duration>
+            </track>
+            <track id="a6d4d047-fef8-41f8-88c0-ed077de875a8">
+                <title>Crutches</title><duration>292373</duration>
+            </track>
+            <track id="8a05d376-b09f-4f92-b0d4-10cf177df0f3">
+                <title>Something So Wild</title><duration>171466</duration>
+            </track>
+            <track id="8b3402bd-aa83-4c01-961b-8fd01cf47228">
+                <title>Totally Freaked Out</title><duration>250893</duration>
+            </track>
+            <track id="b5628295-f5be-438e-ae89-6213666fd552">
+                <title>Silent Spring</title><duration>272533</duration>
+            </track>
+        </track-list>
+        <release-event-list>
+            <event country="US" format="CD" date="1995-04-16" barcode="075679250421" catalog-number="OLE-121-2" />
+        </release-event-list>
+    </release>
+</metadata>
diff --git a/morituri/test/test_common_program.py b/morituri/test/test_common_program.py
index 1c72b01..3a5d0b3 100644
--- a/morituri/test/test_common_program.py
+++ b/morituri/test/test_common_program.py
@@ -110,3 +110,17 @@ class PathTestCase(unittest.TestCase):
         self.assertEquals(path,
             u'/tmp/Jeff Buckley/Grace')
   
+class MetadataLengthTestCase(unittest.TestCase):
+    def testLamprey(self):
+        from musicbrainz2 import wsxml
+
+        path = os.path.join(os.path.dirname(__file__),
+            'release.c7d919f4-3ea0-4c4b-a230-b3605f069440.xml')
+        handle = open(path, "rb")
+
+        reader = wsxml.MbXmlParser()
+        wsMetadata = reader.parse(handle)
+        release = wsMetadata.getRelease()
+        metadata = progam.getMetadata(release)
+
+        self.assertEquals(metadata.duration, 2962889)
diff --git a/morituri/test/test_image_table.py b/morituri/test/test_image_table.py
index 7c810f3..43e59b2 100644
--- a/morituri/test/test_image_table.py
+++ b/morituri/test/test_image_table.py
@@ -52,6 +52,9 @@ class LadyhawkeTestCase(tcommon.TestCase):
         self.assertEquals(self.table.getAccurateRipURL(),
         "http://www.accuraterip.com/accuraterip/a/5/d/dBAR-012-0013bd5a-00b8d489-c60af50d.bin")
 
+    def testDuration(self):
+        self.assertEquals(self.table.duration(), 2609413)
+
 class MusicBrainzTestCase(tcommon.TestCase):
     # example taken from http://musicbrainz.org/doc/DiscIDCalculation
     # disc is Ettella Diamant

-- 
morituri packaging



More information about the pkg-multimedia-commits mailing list