Async album art showing thumbnails
authorIvan Frade <ivan.frade@gmail.com>
Tue, 25 Aug 2009 20:54:28 +0000 (23:54 +0300)
committerIvan Frade <ivan.frade@gmail.com>
Tue, 25 Aug 2009 20:54:28 +0000 (23:54 +0300)
Async retrieval of the album art. Showing thumbnails instead
of full images. Show 5 images instead of 4 in the dialog

src/aa_selection_dialog.py
src/album_art.py
src/album_art_panel.py

index 47086d1..b22ecc0 100644 (file)
@@ -17,6 +17,7 @@ class AlbumArtSelectionDialog (gtk.Dialog):
         self.artist = artist
         self.album = album
         self.size = size
+        self.paths = []
         self.__create_view (size)
 
         if (downloader):
@@ -29,6 +30,7 @@ class AlbumArtSelectionDialog (gtk.Dialog):
         self.selection_thumb = None
         hildon.hildon_gtk_window_set_progress_indicator (self, 1)
 
+
     def __create_view (self, size):
         hbox = gtk.HBox (homogeneous=True)
 
@@ -50,23 +52,27 @@ class AlbumArtSelectionDialog (gtk.Dialog):
         self.vbox.add (hbox)
 
     def __get_alternatives_async (self):
-        self.paths = self.downloader.get_alternatives (self.album, self.artist, 4)
-        self.__populate (self.paths)        
+        counter = 0
+        for (path, thumb) in self.downloader.get_alternatives (self.album, self.artist, self.size):
+            self.paths.insert (counter, (path, thumb))
+            self.images[counter].set_from_file (thumb)
+            self.event_boxes [counter].set_sensitive (True)
+            counter += 1
+            while (gtk.events_pending()):
+                gtk.main_iteration()
+
+        while (counter < self.size):
+                self.images[counter].set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
+                counter += 1
+                
         hildon.hildon_gtk_window_set_progress_indicator (self, 0)
 
-    def __populate (self, paths):
-
-        for i in range (0, self.size):
-            if (len(paths) > i):
-                self.images[i].set_from_file (paths[i])
-                self.event_boxes[i].set_sensitive (True)
-            else:
-                self.images[i].set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
 
     def click_on_img (self, widget, event, position):
+        img, thumb = self.paths[position]
         self.selection_img, self.selection_thumb = self.downloader.save_alternative (self.artist,
                                                                                      self.album,
-                                                                                     self.paths[position])
+                                                                                     img, thumb)
         self.response (position)
 
     def get_selection (self):
@@ -79,12 +85,16 @@ if __name__ == "__main__":
     import time
     class MockDownloader:
         def __init__ (self):
-            self.alt = ["../hendrix.jpeg", "../hoover.jpeg", "../dylan.jpeg"]
+            self.alt = [("../hendrix.jpeg", "../hendrix-thumb.jpeg"),
+                        ("../hoover.jpeg", "../hoover-thumb.jpeg"),
+                        ("../backbeat.jpeg", "../backbeat-thumb.jpeg"),
+                        ("../dylan.jpeg", "../dylan-thumb.jpeg")]
         def get_alternatives (self, album, artist, amount):
-            time.sleep (5)
-            return self.alt [0:amount]
-        def save_alternative (self, artist, album, img):
-            return ("/home/user/.cache/media-art/" + img, "/home/user/.thumbnails/normal/" + img)
+            for a in self.alt:
+                time.sleep (1)
+                yield a
+        def save_alternative (self, artist, album, img, thumb):
+            return ("/home/user/.cache/media-art/" + img, "/home/user/.thumbnails/normal/" + thumb)
                               
 
     def clicked_button (self):
index 72cf1db..7f81061 100755 (executable)
@@ -14,10 +14,9 @@ except ImportError:
 try:
     import PIL
     import Image
-    pil_available = True
 except ImportError:
-    pil_available = False
-
+    print "Please install python-imaging package"
+    sys.exit (-1)
 
 # Set socket timeout
 import socket
@@ -49,15 +48,7 @@ class MussorgskyAlbumArt:
         if (not os.path.exists (CACHE_LOCATION)):
             os.makedirs (CACHE_LOCATION)
             
-        if (pil_available):
-            self.thumbnailer = LocalThumbnailer ()
-        else:
-            try:
-                self.thumbnailer = bus.get_object ('org.freedesktop.thumbnailer',
-                                                   '/org/freedesktop/thumbnailer/Generic')
-            except dbus.exceptions.DBusException:
-                print "No thumbnailer available"
-                self.thumbnailer = None
+        self.thumbnailer = LocalThumbnailer ()
 
     def get_album_art (self, artist, album, force=False):
         """
@@ -95,37 +86,41 @@ class MussorgskyAlbumArt:
         return (filename, thumbnail)
 
 
-    def get_alternatives (self, artist, album, no_alternatives):
+    def get_alternatives (self, artist, album, max_alternatives=4):
         """
         return a list of paths of possible album arts
         """
+        counter = 0
         results_page = self.__msn_images (artist, album)
-        valid_images = []
         for image_url in self.__get_url_from_msn_results_page (results_page):
             if (not image_url):
                 # Some searches doesn't return anything at all!
                 break
+
+            if (counter >= max_alternatives):
+                break
             
             image = self.__get_url (image_url)
             if (image):
-                image_path = os.path.join (CACHE_LOCATION, "alternative-" + str(len(valid_images)))
+                image_path = os.path.join (CACHE_LOCATION, "alternative-" + str(counter))
+                thumb_path = os.path.join (CACHE_LOCATION, "alternative-" + str(counter) + "thumb")
                 self.__save_content_into_file (image, image_path)
-                valid_images.append (image_path)
-                if (len (valid_images) > no_alternatives):
-                    return valid_images
-        return valid_images
+                self.thumbnailer.create (image_path, thumb_path)
+                counter += 1
+                yield (image_path, thumb_path)
 
-    def save_alternative (self, artist, album, path):
-        if not os.path.exists (path):
+
+    def save_alternative (self, artist, album, img_path, thumb_path):
+        if not os.path.exists (img_path) or not os.path.exists (thumb_path):
             print "**** CRITICAL **** image in path", path, "doesn't exist!"
             return (None, None)
         
         filename = getCoverArtFileName (album)
         thumbnail = getCoverArtThumbFileName (album)
 
-        os.rename (path, filename)
-        if (not self.__request_thumbnail (filename)):
-            print "Something wrong creating the thumbnail!"
+        os.rename (img_path, filename)
+        os.rename (thumb_path, thumbnail)
+
         return (filename, thumbnail)
 
     def __last_fm (self, artist, album):
@@ -162,7 +157,7 @@ class MussorgskyAlbumArt:
             full_try = BASE_MSN + good_album + "+" + good_artist + MSN_MEDIUM + MSN_SQUARE
             print "Searching (album + artist): %s" % (full_try)
             result = self.__get_url (full_try)
-            if (result.find ("no_results") == -1):
+            if (result and result.find ("no_results") == -1):
                 return result
 
         if (album):
@@ -173,14 +168,14 @@ class MussorgskyAlbumArt:
                 album_try = BASE_MSN + good_album + MSN_MEDIUM + MSN_SQUARE
                 print "Searching (album): %s" % (album_try)
                 result = self.__get_url (album_try)
-                if (result.find ("no_results") == -1):
+                if (result and result.find ("no_results") == -1):
                     return result
             
         if (artist):
             artist_try = BASE_MSN + good_artist + "+CD+music"  + MSN_SMALL + MSN_SQUARE + MSN_PHOTO
             print "Searching (artist CD): %s" % (artist_try)
             result = self.__get_url (artist_try)
-            if (result.find ("no_results") == -1):
+            if (result and result.find ("no_results") == -1):
                 return result
         
         return None
@@ -206,7 +201,6 @@ class MussorgskyAlbumArt:
                 current_option.lower().endswith (".jpeg")):
                 yield current_option
             starting_at = end
-        yield None
         
 
     def __clean_string_for_search (self, text):
@@ -237,12 +231,8 @@ class MussorgskyAlbumArt:
             return None
 
     def __request_thumbnail (self, filename):
-        if (not self.thumbnailer):
-            print "No thumbnailer available"
-            return
-        uri = "file://" + filename
-        handle = time.time ()
-        return self.thumbnailer.Queue ([uri], ["image/jpeg"], dbus.UInt32 (handle))
+        thumbFile = get_thumb_filename_for_path (fullCoverFileName)
+        return self.thumbnailer.create (filename, thumbFile)
             
 
 
@@ -250,20 +240,16 @@ class LocalThumbnailer:
     def __init__ (self):
         self.THUMBNAIL_SIZE = (124,124)
 
-    def Queue (self, uris, mimes, handle):
-        for i in range (0, len(uris)):
-            uri = uris[i]
-            fullCoverFileName = uri[7:]
-            if (os.path.exists (fullCoverFileName)):
-                thumbFile = get_thumb_filename_for_path (fullCoverFileName)
-                try:
-                    image = Image.open (fullCoverFileName)
-                    image = image.resize (self.THUMBNAIL_SIZE, Image.ANTIALIAS )
-                    image.save( thumbFile, "JPEG" )
-                    print "Thumbnail: " + thumbFile
-                except IOError, e:
-                    print e
-                    return False
+    def create (self, fullCoverFileName, thumbFile):
+        if (os.path.exists (fullCoverFileName)):
+            try:
+                image = Image.open (fullCoverFileName)
+                image = image.resize (self.THUMBNAIL_SIZE, Image.ANTIALIAS )
+                image.save (thumbFile, "JPEG")
+                print "Thumbnail: " + thumbFile
+            except IOError, e:
+                print e
+                return False
         return True
             
 
@@ -308,6 +294,6 @@ if __name__ == "__main__":
 
     if options.multiple:
         maa = MussorgskyAlbumArt ()
-        alt = maa.get_alternatives (options.artist, options.album, 5)
-        for a in alt:
-            print a
+        for (img, thumb) in  maa.get_alternatives (options.artist, options.album, 5):
+            print img
+            print thumb
index cbb7074..f98feb3 100644 (file)
@@ -68,7 +68,7 @@ class MussorgskyAlbumArtPanel (hildon.StackableWindow):
         album = treeview.get_model ().get_value (it, 3)
         artist = treeview.get_model ().get_value (it, 2)
 
-        dialog = AlbumArtSelectionDialog (self, artist, album, 4)
+        dialog = AlbumArtSelectionDialog (self, artist, album, 5)
         dialog.show_all ()
         
         response = dialog.run ()