--- plugins/artdisplay/artdisplay/__init__.py	2007/01/19 01:33:29	1.1
+++ plugins/artdisplay/artdisplay/__init__.py	2007/01/19 01:37:05
@@ -233,6 +233,20 @@ class FadingImage (gtk.Misc):
 gobject.type_register (FadingImage)
 
 
+class ArtDisplayWidget (FadingImage):
+	def __init__ (self, missing_image):
+		super (ArtDisplayWidget, self).__init__ (missing_image)
+		self.set_padding (0, 5)
+		self.current_entry, self.working = None, False
+		self.current_pixbuf, self.current_uri = None, None
+	
+	def set (self, entry, pixbuf, uri, working):
+		self.current_entry = entry
+		self.current_pixbuf = pixbuf
+		self.current_uri = uri
+		self.set_current_art (pixbuf, working)
+
+
 class ArtDisplayPlugin (rb.Plugin):
 	def __init__ (self):
 		rb.Plugin.__init__ (self)
@@ -244,14 +258,12 @@ class ArtDisplayPlugin (rb.Plugin):
 		self.pc_id = sp.connect ('playing-changed', self.playing_changed)
 		db = shell.get_property ("db")
 		self.eemr_art_id = db.connect_after ('entry-extra-metadata-request::rb:coverArt', self.cover_art_request)
-		self.art_widget = FadingImage (self.find_file (ART_MISSING_ICON + ".svg"))
-		self.art_widget.set_padding (0, 5)
+		self.eemn_art_id = db.connect_after ('entry-extra-metadata-notify::rb:coverArt', self.cover_art_notify)
+		self.art_widget = ArtDisplayWidget (self.find_file (ART_MISSING_ICON + ".svg"))
 		shell.add_widget (self.art_widget, rb.SHELL_UI_LOCATION_SIDEBAR)
 		self.art_db = CoverArtDatabase ()
-		self.current_entry = None
-		self.current_pixbuf = None
-		entry = sp.get_playing_entry ()
-		self.playing_entry_changed (sp, entry)
+		self.current_entry, self.current_pixbuf = None, None
+		self.playing_entry_changed (sp, sp.get_playing_entry ())
 	
 	def deactivate (self, shell):
 		self.shell = None
@@ -259,6 +271,7 @@ class ArtDisplayPlugin (rb.Plugin):
 		sp.disconnect (self.pc_id)
 		db = shell.get_property ("db")
 		db.disconnect (self.eemr_art_id)
+		db.disconnect (self.eemn_art_id)
 		shell.remove_widget (self.art_widget, rb.SHELL_UI_LOCATION_SIDEBAR)
 		self.art_widget.disconnect_handlers ()
 		self.art_widget = None
@@ -272,29 +287,43 @@ class ArtDisplayPlugin (rb.Plugin):
 		self.set_entry(entry)
 
 	def set_entry (self, entry):
-		if entry != self.current_entry and entry is not None:
-			db = self.shell.get_property ("db")
+		if entry == self.current_entry:
+			return
+		db = self.shell.get_property ("db")
 
-			self.art_widget.set_current_art (None, True)
-			self.art_widget.show ()
-			# Intitates search in the database (which checks art cache, internet etc.)
-			self.current_entry = entry
-			self.current_pixbuf = None
-			self.art_db.get_pixbuf(db, entry, self.on_get_pixbuf_completed)
+		self.art_widget.set (entry, None, None, True)
+		self.art_widget.show ()
+		# Intitates search in the database (which checks art cache, internet etc.)
+		self.current_entry = entry
+		self.current_pixbuf = None
+		self.art_db.get_pixbuf(db, entry, self.on_get_pixbuf_completed)
 
-	def on_get_pixbuf_completed(self, entry, pixbuf):
+	def on_get_pixbuf_completed(self, entry, pixbuf, uri):
 		# Set the pixbuf for the entry returned from the art db
-		if entry == self.current_entry:
-			self.art_widget.set_current_art (pixbuf, False)
-			if pixbuf:
-				db = self.shell.get_property ("db")
-				# This might be from a playing-changed signal, 
-				# in which case consumers won't be ready yet.
-				def idle_emit_art():
-					db.emit_entry_extra_metadata_notify (entry, "rb:coverArt", pixbuf)
-					return False
-				gobject.idle_add(idle_emit_art)
-	
+		if entry != self.current_entry:
+			return
+		self.current_pixbuf = pixbuf
+		self.art_widget.set (entry, pixbuf, uri, False)
+		if pixbuf:
+			db = self.shell.get_property ("db")
+			# This might be from a playing-changed signal, 
+			# in which case consumers won't be ready yet.
+			def idle_emit_art():
+				db.emit_entry_extra_metadata_notify (entry, "rb:coverArt", pixbuf)
+				return False
+			gobject.idle_add(idle_emit_art)
+
 	def cover_art_request (self, db, entry):
 		if entry == self.current_entry:
 			return self.current_pixbuf
+
+	def cover_art_notify (self, db, entry, field, metadata):
+		if entry != self.current_entry:
+			return
+		if not isinstance (metadata, gtk.gdk.Pixbuf):
+			return
+		self.art_db.cancel_get_pixbuf (entry)
+		if self.current_pixbuf == metadata:
+			return
+		self.art_widget.set (entry, metadata, None, False)
+
--- plugins/artdisplay/artdisplay/CoverArtDatabase.py	2007/01/19 01:33:32	1.1
+++ plugins/artdisplay/artdisplay/CoverArtDatabase.py	2007/01/19 01:33:54
@@ -20,6 +20,7 @@
 import rhythmdb, rb
 import os
 import gtk
+import itertools
 
 from AmazonCoverArtSearch import AmazonCoverArtSearch
 from LocalCoverArtSearch import LocalCoverArtSearch
@@ -27,17 +28,58 @@ from LocalCoverArtSearch import LocalCov
 ART_SEARCHES_LOCAL = [LocalCoverArtSearch]
 ART_SEARCHES_REMOTE = [AmazonCoverArtSearch]
 ART_FOLDER = '~/.gnome2/rhythmbox/covers'
+ART_CACHE_EXTENSION = 'jpg'
+ART_CACHE_FORMAT = 'jpeg'
+ART_CACHE_SETTINGS = {"quality": "100"}
+
+class TicketSystem:
+	def __init__ (self):
+		self.counter = itertools.count ()
+		self.hash = {}
+		self.dead = set ()
+
+	def get (self, item):
+		ticket = self.counter.next ()
+		self.hash.setdefault (item, set ()).add (ticket)
+		return ticket
+
+	def bury (self, ticket):
+		try:
+			self.dead.remove (ticket)
+			return True
+		except KeyError:
+			return False
+
+	def forget (self, item, ticket):
+		try:
+			self.hash[item].remove (ticket)
+			return True
+		except KeyError:
+			self.dead.remove (ticket)
+			return False
+
+	def purge (self, item):
+		self.dead.update (self.hash.pop (item, set ()))
+
+	def release (self, item, ticket):
+		try:
+			self.dead.update (self.hash.pop (item) - set([ticket]))
+			return True
+		except KeyError:
+			self.dead.remove (ticket)
+			return False
 
 class CoverArtDatabase (object):
 	def __init__ (self):
 		self.loader = rb.Loader()
+		self.ticket = TicketSystem ()
 
-	def build_art_cache_filename (self, album, artist, extension):
+	def build_art_cache_filename (self, db, entry, extension):
+		artist = db.entry_get (entry, rhythmdb.PROP_ARTIST)
+		album = db.entry_get (entry, rhythmdb.PROP_ALBUM)
 		art_folder = os.path.expanduser (ART_FOLDER)
 		if not os.path.exists (art_folder):
 			os.mkdir (art_folder)
-		if extension is None:
-			extension = "jpg"
 
 		# FIXME: the following block of code is messy and needs to be redone ASAP
 		return art_folder + '/%s - %s.%s' % (artist.replace ('/', '-'), album.replace ('/', '-'), extension)	
@@ -48,10 +90,13 @@ class CoverArtDatabase (object):
 		for Engine in ART_SEARCHES_REMOTE:
 			if Engine.__name__ not in blist:
 				yield Engine (self.loader), Engine.__name__, True
+	
+	def cancel_get_pixbuf (self, entry):
+		self.ticket.purge (entry)
   
 	def get_pixbuf (self, db, entry, callback):
 		if entry is None:
-			callback (entry, None)
+			callback (entry, None, None)
 			return
             
 		st_artist = db.entry_get (entry, rhythmdb.PROP_ARTIST) or _("Unknown")
@@ -66,16 +111,18 @@ class CoverArtDatabase (object):
 		rb.Coroutine (self.image_search, db, st_album, st_artist, entry, callback).begin ()
 
 	def image_search (self, plexer, db, st_album, st_artist, entry, callback):
-		art_location = self.build_art_cache_filename (st_album, st_artist, "jpg")
-		blist_location = self.build_art_cache_filename (st_album, st_artist, "rb-blist")
+		art_location = self.build_art_cache_filename (db, entry, ART_CACHE_EXTENSION)
+		blist_location = self.build_art_cache_filename (db, entry, "rb-blist")
 
 		# Check local cache
 		if os.path.exists (art_location):
+			self.ticket.purge (entry)
 			pixbuf = gtk.gdk.pixbuf_new_from_file (art_location)	
-			callback (entry, pixbuf)
+			callback (entry, pixbuf, art_location)
 			return
 
 		blist = self.read_blist (blist_location)
+		ticket = self.ticket.get (entry)
 		for engine, engine_name, engine_remote in self.engines (blist):
 			plexer.clear ()
 			engine.search (db, entry, plexer.send ())
@@ -89,17 +136,28 @@ class CoverArtDatabase (object):
 					_, (data, ) = plexer.receive ()
 					pixbuf = self.image_data_load (data)
 					if pixbuf:
-						if engine_remote:
-							pixbuf.save (art_location, "jpeg", {"quality": "100"})
+						if self.ticket.release (entry, ticket):
+							if engine_remote:
+								pixbuf.save (art_location, ART_CACHE_FORMAT, ART_CACHE_SETTINGS)
+								uri = art_location
+							else:
+								uri = str (url)
+							callback (entry, pixbuf, uri)
 						self.write_blist (blist_location, blist)
-						callback (entry, pixbuf)
 						return
 				if not engine.search_next ():
 					if engine_remote:
 						blist.append (engine_name)
 					break
+				if self.ticket.bury (ticket):
+					self.write_blist (blist_location, blist)
+					return
+			if self.ticket.bury (ticket):
+				self.write_blist (blist_location, blist)
+				return
+		if self.ticket.forget (entry, ticket):
+			callback (entry, None, None)
 		self.write_blist (blist_location, blist)
-		callback (entry, None)
 
 	def read_blist (self, blist_location):
 		if os.path.exists (blist_location):
