banshee r4226 - in trunk/banshee: . build src/Core/Banshee.Core src/Core/Banshee.Core/Resources src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Metadata src/Core/Banshee.Services/Banshee.Metadata.LastFM src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz src/Libraries/Lastfm src/Libraries/Lastfm/Lastfm.Data



Author: gburt
Date: Sun Jul 20 20:47:47 2008
New Revision: 4226
URL: http://svn.gnome.org/viewvc/banshee?rev=4226&view=rev

Log:
2008-07-20  Gabriel Burt  <gabriel burt gmail com>

	Patch from Peter de Kraker adding support for fetching cover art from
	Last.fm (BGO #536132), with a few tiny changes (mostly HACKING style
	issues) by me.

	* src/Core/Banshee.Services/Banshee.Metadata/MetadataService.cs:
	Whitespace issues, and add the Lastfm provider.

	* src/Core/Banshee.Services/Banshee.Services.addins:
	* src/Core/Banshee.Services/Makefile.am:
	* src/Core/Banshee.Services/Banshee.Services.mdp:
	* src/Core/Banshee.Services/Banshee.Metadata.LastFM/LastFMMetadataProvider.cs:
	* src/Core/Banshee.Services/Banshee.Metadata.LastFM/LastFMQueryJob.cs: New
	files implementing cover art fetching from Last.fm.

	* src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzQueryJob.cs:
	Whitespace fixes.

	* src/Libraries/Lastfm/Lastfm.mdp:
	* src/Libraries/Lastfm/Makefile.am:
	* src/Libraries/Lastfm/Lastfm.Data/DataEntry.cs:
	* src/Libraries/Lastfm/Lastfm.Data/LastfmAlbumData.cs: Wrap album
	information from Last.fm.

	* src/Core/Banshee.Core/Banshee.Core.mdp:
	* build/build.environment.mk: Banshee.Services now depends on Lastfm.
	Ideally we will move these providers out into extensions at some point.

	* src/Core/Banshee.Core/Resources/contributors.xml: Add Peter and Sandy.



Added:
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.LastFM/
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.LastFM/LastFMMetadataProvider.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.LastFM/LastFMQueryJob.cs
   trunk/banshee/src/Libraries/Lastfm/Lastfm.Data/LastfmAlbumData.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/build/build.environment.mk
   trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp
   trunk/banshee/src/Core/Banshee.Core/Resources/contributors.xml
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzQueryJob.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataService.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Services.addins
   trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
   trunk/banshee/src/Core/Banshee.Services/Makefile.am
   trunk/banshee/src/Libraries/Lastfm/Lastfm.Data/DataEntry.cs
   trunk/banshee/src/Libraries/Lastfm/Lastfm.mdp
   trunk/banshee/src/Libraries/Lastfm/Makefile.am

Modified: trunk/banshee/build/build.environment.mk
==============================================================================
--- trunk/banshee/build/build.environment.mk	(original)
+++ trunk/banshee/build/build.environment.mk	Sun Jul 20 20:47:47 2008
@@ -75,7 +75,7 @@
 LINK_BANSHEE_CORE = -r:$(DIR_BIN)/Banshee.Core.dll
 LINK_BANSHEE_CORE_DEPS = $(REF_BANSHEE_CORE) $(LINK_BANSHEE_CORE)
 
-REF_BANSHEE_SERVICES = $(LINK_SQLITE) $(LINK_BANSHEE_CORE_DEPS) $(LINK_MONO_MEDIA_DEPS)
+REF_BANSHEE_SERVICES = $(LINK_SQLITE) $(LINK_BANSHEE_CORE_DEPS) $(LINK_MONO_MEDIA_DEPS) $(LINK_LASTFM_DEPS)
 LINK_BANSHEE_SERVICES = -r:$(DIR_BIN)/Banshee.Services.dll
 LINK_BANSHEE_SERVICES_DEPS = $(REF_BANSHEE_SERVICES) $(LINK_BANSHEE_SERVICES)
 

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp	Sun Jul 20 20:47:47 2008
@@ -78,6 +78,7 @@
     <ProjectReference type="Gac" localcopy="True" refto="Mono.Posix, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
     <ProjectReference type="Gac" localcopy="True" refto="Mono.Addins, Version=0.3.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
     <ProjectReference type="Gac" localcopy="True" refto="taglib-sharp, Version=2.0.3.0, Culture=neutral, PublicKeyToken=db62eba44689b5b0" />
+    <ProjectReference type="Project" localcopy="False" refto="Lastfm" />
   </References>
   <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="True" RelativeMakefileName="./Makefile.am">
     <BuildFilesVar Sync="True" Name="SOURCES" />

Modified: trunk/banshee/src/Core/Banshee.Core/Resources/contributors.xml
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Resources/contributors.xml	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Resources/contributors.xml	Sun Jul 20 20:47:47 2008
@@ -46,7 +46,9 @@
   <contributor>Oscar Forero</contributor>
   <contributor>Patrick van Staveren</contributor> 
   <contributor>Pepijn van de Geer</contributor>
+  <contributor>Peter de Kraker</contributor>
   <contributor>Ruben Vermeersch</contributor>
+  <contributor>Sandy Armstrong</contributor>
   <contributor>Sebastian DrÃge</contributor>
   <contributor>Tim Yamin</contributor>
   <contributor>Trey Ethridge</contributor>

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.LastFM/LastFMMetadataProvider.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.LastFM/LastFMMetadataProvider.cs	Sun Jul 20 20:47:47 2008
@@ -0,0 +1,51 @@
+//
+// LastFMMetadataProvider.cs
+//
+// Author:
+//   Peter de Kraker <peterdk dev umito nl>
+// 
+// Based on RhapsodyMetadataProvider.cs
+//   
+// Copyright (C) 2006-2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+
+using Banshee.Base;
+using Banshee.Metadata;
+using Banshee.Collection;
+
+namespace Banshee.Metadata.LastFM
+{
+    public class LastFMMetadataProvider : BaseMetadataProvider
+    {
+        public LastFMMetadataProvider () : base ()
+        {
+        }
+        
+        public override IMetadataLookupJob CreateJob (IBasicTrackInfo track)
+        {
+            return new LastFMQueryJob (track);
+        }
+    }
+}

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.LastFM/LastFMQueryJob.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.LastFM/LastFMQueryJob.cs	Sun Jul 20 20:47:47 2008
@@ -0,0 +1,132 @@
+// LastFMQueryJob.cs:
+//
+// Author:
+//   Peter de Kraker <peterdk dev umito nl>
+//
+// Based on RhapsodyQueryJob.cs
+//
+// Copyright (C) 2006-2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Net;
+using System.Xml;
+using System.Text;
+using System.Web;
+using System.Collections.Generic;
+
+
+using Hyena;
+using Banshee.Base;
+using Banshee.Collection;
+using Banshee.Metadata;
+using Banshee.Kernel;
+using Banshee.Streaming;
+using Banshee.Networking;
+
+using Lastfm;
+
+namespace Banshee.Metadata.LastFM
+{
+    public class LastFMQueryJob : MetadataServiceJob
+    {        
+        public LastFMQueryJob (IBasicTrackInfo track)
+        {
+            Track = track;                
+        }
+        
+        public override void Run ()
+        {
+            
+            if (Track == null || (Track.MediaAttributes & TrackMediaAttributes.Podcast) != 0) {
+                return;
+            }
+        
+            string artwork_id = Track.ArtworkId;
+
+            if (artwork_id == null || CoverArtSpec.CoverExists (artwork_id) || !NetworkDetect.Instance.Connected) {
+                return;
+            }
+            
+            // Lastfm uses double url-encoding in their current 1.2 api for albuminfo.
+            string lastfmArtist = HttpUtility.UrlEncode (HttpUtility.UrlEncode (Track.AlbumArtist));
+            string lastfmAlbum = HttpUtility.UrlEncode (HttpUtility.UrlEncode (Track.AlbumTitle));
+             
+            Lastfm.Data.LastfmAlbumData album = null;
+            
+            try { 
+                album = new Lastfm.Data.LastfmAlbumData (lastfmArtist, lastfmAlbum);
+            } catch {
+                return;
+            }
+
+            // AllUrls is an array with [small,medium,large] coverart url
+            string [] album_cover_urls = album.AlbumCoverUrls.AllUrls ();              
+
+            // Select the URL for the coverart with highest resolution
+            string best_url = String.Empty;
+            foreach (string url in album_cover_urls) {
+                if (!String.IsNullOrEmpty (url)) {
+                    best_url = url;
+                }
+            }
+
+            // No URL's found
+            if (String.IsNullOrEmpty (best_url) || best_url.Contains ("noimage")) {
+                //string upload_url = String.Format ("http://www.last.fm/music/{0}/{1}/+images";, lastfmArtist, lastfmAlbum);  
+                //Log.DebugFormat ("No coverart provided by lastfm. (you can upload it here: {0}) - {1} ", upload_url, Track.ArtworkId);
+                return;
+            }
+            
+            // Hack: You can get higher resolution artwork by replacing 130X130 with 300x300 in lastfm hosted albumart
+            string high_res_url = null;
+            if (best_url.Contains ("130x130")) {
+                high_res_url = best_url.Replace ("130x130", "300x300");
+            }
+            
+            // Hack: You can get higher resolution artwork from Amazon too (lastfm sometimes uses amazon links)
+            if (best_url.Contains ("MZZZZZZZ")) {                                        
+                high_res_url = best_url.Replace ("MZZZZZZZ", "LZZZZZZZ");
+            }
+                
+            // Download the cover
+            try {
+                if ((high_res_url != null && SaveHttpStreamCover (new Uri (high_res_url), artwork_id, null)) ||
+                   SaveHttpStreamCover (new Uri (best_url), artwork_id, null)) {
+                    if (best_url.Contains ("amazon")) {
+                        Log.Debug ("Downloaded cover art from Amazon", artwork_id);
+                    } else {
+                        Log.Debug ("Downloaded cover art from Lastfm", artwork_id);
+                    }
+
+                    StreamTag tag = new StreamTag ();
+                    tag.Name = CommonTags.AlbumCoverId;
+                    tag.Value = artwork_id;
+                    AddTag (tag);
+                }
+            } catch (Exception e) {
+                Log.Exception ("Cover art found on Lastfm, but downloading it failed. Probably server under high load or dead link", e);
+            }
+        }
+    }
+}

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzQueryJob.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzQueryJob.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzQueryJob.cs	Sun Jul 20 20:47:47 2008
@@ -49,22 +49,22 @@
     
         private string asin;
         
-        public MusicBrainzQueryJob(IBasicTrackInfo track)
+        public MusicBrainzQueryJob (IBasicTrackInfo track)
         {
             Track = track;
         }
         
-        public MusicBrainzQueryJob(IBasicTrackInfo track, string asin) : this(track)
+        public MusicBrainzQueryJob (IBasicTrackInfo track, string asin) : this (track)
         {
             this.asin = asin;
         }
         
-        public override void Run()
+        public override void Run ()
         {
-            Lookup();
+            Lookup ();
         }
         
-        public bool Lookup()
+        public bool Lookup ()
         {
             if (Track == null || (Track.MediaAttributes & TrackMediaAttributes.Podcast) != 0) {
                 return false;
@@ -72,29 +72,29 @@
             
             string artwork_id = Track.ArtworkId;
             
-            if(artwork_id == null) {
+            if (artwork_id == null) {
                 return false;
-            } else if(CoverArtSpec.CoverExists(artwork_id)) {
+            } else if (CoverArtSpec.CoverExists (artwork_id)) {
                 return false;
-            } else if(!NetworkDetect.Instance.Connected) {
+            } else if (!NetworkDetect.Instance.Connected) {
                 return false;
             }
             
-            if(asin == null) {
-                asin = FindAsin();
-                if(asin == null) {
+            if (asin == null) {
+                asin = FindAsin ();
+                if (asin == null) {
                     return false;
                 }
             }
             
-            if(SaveHttpStreamCover(new Uri(String.Format(AmazonUriFormat, asin)), artwork_id, 
+            if (SaveHttpStreamCover (new Uri (String.Format (AmazonUriFormat, asin)), artwork_id, 
                 new string [] { "image/gif" })) {
                 Log.Debug ("Downloaded cover art from Amazon", artwork_id);
-                StreamTag tag = new StreamTag();
+                StreamTag tag = new StreamTag ();
                 tag.Name = CommonTags.AlbumCoverId;
                 tag.Value = artwork_id;
 
-                AddTag(tag);
+                AddTag (tag);
                 
                 return true;
             }
@@ -106,30 +106,30 @@
         // instead of using the stuff in the MusicBrainz namespace 
         // which sucks and doesn't even appear to work anymore.
         
-        private string FindAsin()
+        private string FindAsin ()
         {
-            Uri uri = new Uri(String.Format("http://musicbrainz.org/ws/1/release/?type=xml&artist={0}&title={1}";,
+            Uri uri = new Uri (String.Format ("http://musicbrainz.org/ws/1/release/?type=xml&artist={0}&title={1}";,
                 Track.ArtistName, Track.AlbumTitle));
 
-            HttpWebResponse response = GetHttpStream(uri);
+            HttpWebResponse response = GetHttpStream (uri);
             if (response == null) {
                 return null;
             }
             
             using (Stream stream = response.GetResponseStream ()) {
-                XmlTextReader reader = new XmlTextReader(stream);
+                XmlTextReader reader = new XmlTextReader (stream);
     
                 bool haveMatch = false;
                 
-                while(reader.Read()) {
-                    if(reader.NodeType == XmlNodeType.Element) {
+                while (reader.Read ()) {
+                    if (reader.NodeType == XmlNodeType.Element) {
                         switch (reader.LocalName) {
                             case "release":
                                 haveMatch = reader["ext:score"] == "100";
                                 break;
                             case "asin":
-                                if(haveMatch) {
-                                    return reader.ReadString();
+                                if (haveMatch) {
+                                    return reader.ReadString ();
                                 }
                             break;
                         default:

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataService.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataService.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataService.cs	Sun Jul 20 20:47:47 2008
@@ -42,8 +42,8 @@
         
         public static MetadataService Instance {
             get {
-                if(instance == null) {
-                    instance = new MetadataService();
+                if (instance == null) {
+                    instance = new MetadataService ();
                 }
                 
                 return instance;
@@ -51,80 +51,81 @@
         }
         
         private Dictionary<IBasicTrackInfo, IMetadataLookupJob> queries 
-            = new Dictionary<IBasicTrackInfo, IMetadataLookupJob>();
-        private List<IMetadataProvider> providers = new List<IMetadataProvider>();
+            = new Dictionary<IBasicTrackInfo, IMetadataLookupJob> ();
+        private List<IMetadataProvider> providers = new List<IMetadataProvider> ();
 
-        public MetadataService()
+        public MetadataService ()
         {
-            AddProvider(new Banshee.Metadata.Embedded.EmbeddedMetadataProvider());
-            AddProvider(new Banshee.Metadata.Rhapsody.RhapsodyMetadataProvider());
-            AddProvider(new Banshee.Metadata.MusicBrainz.MusicBrainzMetadataProvider());
+            AddProvider (new Banshee.Metadata.Embedded.EmbeddedMetadataProvider ());
+            AddProvider (new Banshee.Metadata.Rhapsody.RhapsodyMetadataProvider ());
+            AddProvider (new Banshee.Metadata.MusicBrainz.MusicBrainzMetadataProvider ());
+            AddProvider (new Banshee.Metadata.LastFM.LastFMMetadataProvider ());
             
             Scheduler.JobFinished += OnSchedulerJobFinished;
             Scheduler.JobUnscheduled += OnSchedulerJobUnscheduled;
         }
 
-        public override IMetadataLookupJob CreateJob(IBasicTrackInfo track)
+        public override IMetadataLookupJob CreateJob (IBasicTrackInfo track)
         {
-            return new MetadataServiceJob(this, track);
+            return new MetadataServiceJob (this, track);
         }
         
-        public override void Lookup(IBasicTrackInfo track)
+        public override void Lookup (IBasicTrackInfo track)
         {
-            Lookup(track, JobPriority.Highest);
+            Lookup (track, JobPriority.Highest);
         }
         
-        public void Lookup(IBasicTrackInfo track, JobPriority priority)
+        public void Lookup (IBasicTrackInfo track, JobPriority priority)
         {
-            if(track == null || queries == null) {
+            if (track == null || queries == null) {
                 return;
             }
             
-            lock(((ICollection)queries).SyncRoot) {
-                if(!queries.ContainsKey(track)) {
-                    IMetadataLookupJob job = CreateJob(track);
-                    if(job == null) {
+            lock (((ICollection)queries).SyncRoot) {
+                if (!queries.ContainsKey (track)) {
+                    IMetadataLookupJob job = CreateJob (track);
+                    if (job == null) {
                         return;
                     }
                     
-                    queries.Add(track, job);
-                    Scheduler.Schedule(job, priority);
+                    queries.Add (track, job);
+                    Scheduler.Schedule (job, priority);
                 }
             }
         }
 
-        public void AddProvider(IMetadataProvider provider)
+        public void AddProvider (IMetadataProvider provider)
         {
-            AddProvider(-1, provider);
+            AddProvider (-1, provider);
         }
 
-        public void AddProvider(int position, IMetadataProvider provider)
+        public void AddProvider (int position, IMetadataProvider provider)
         {
-            lock(providers) {
-                if(position < 0) {
-                    providers.Add(provider);
+            lock (providers) {
+                if (position < 0) {
+                    providers.Add (provider);
                 } else {
-                    providers.Insert(position, provider);
+                    providers.Insert (position, provider);
                 }
             }
         }
 
-        public void RemoveProvider(IMetadataProvider provider)
+        public void RemoveProvider (IMetadataProvider provider)
         {
-            lock(providers) {
-                providers.Remove(provider);
+            lock (providers) {
+                providers.Remove (provider);
             }
         }
         
-        private bool RemoveJob(IMetadataLookupJob job)
+        private bool RemoveJob (IMetadataLookupJob job)
         {
-            if(job == null) {
+            if (job == null) {
                 return false;
             }
             
-            lock(((ICollection)queries).SyncRoot) {
-                if(queries.ContainsKey(job.Track)) {
-                    queries.Remove(job.Track);
+            lock (((ICollection)queries).SyncRoot) {
+                if (queries.ContainsKey (job.Track)) {
+                    queries.Remove (job.Track);
                     return true;
                 }
                 
@@ -132,29 +133,29 @@
             }
         }
         
-        private void OnSchedulerJobFinished(IJob job)
+        private void OnSchedulerJobFinished (IJob job)
         {
-            if(!(job is IMetadataLookupJob)) {
+            if (!(job is IMetadataLookupJob)) {
                 return;
             }
             
             IMetadataLookupJob lookup_job = (IMetadataLookupJob)job;
-            if(RemoveJob(lookup_job)) {
-                Banshee.Base.ThreadAssist.ProxyToMain(delegate { 
-                    OnHaveResult(lookup_job.Track, lookup_job.ResultTags); 
+            if (RemoveJob (lookup_job)) {
+                Banshee.Base.ThreadAssist.ProxyToMain (delegate { 
+                    OnHaveResult (lookup_job.Track, lookup_job.ResultTags); 
                 });
             }
         }
         
-        private void OnSchedulerJobUnscheduled(IJob job)
+        private void OnSchedulerJobUnscheduled (IJob job)
         {
-            RemoveJob(job as IMetadataLookupJob);
+            RemoveJob (job as IMetadataLookupJob);
         }
         
         public ReadOnlyCollection<IMetadataProvider> Providers {
             get {
-                lock(providers) {
-                    return new ReadOnlyCollection<IMetadataProvider>(providers);
+                lock (providers) {
+                    return new ReadOnlyCollection<IMetadataProvider> (providers);
                 }
             }
         }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Services.addins
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Services.addins	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Services.addins	Sun Jul 20 20:47:47 2008
@@ -1,5 +1,6 @@
 <Addins>
   <Directory include-subdirs="true">./Backends</Directory>
   <Directory include-subdirs="true">./Extensions</Directory>
+  <Directory include-subdirs="true">./Libraries</Directory>
 </Addins>
 

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp	Sun Jul 20 20:47:47 2008
@@ -172,6 +172,8 @@
     <File name="Banshee.ServiceStack/DBusConnection.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.ServiceStack/DBusCommandService.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.ServiceStack/IDBusObjectName.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Metadata.LastFM/LastFMMetadataProvider.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Metadata.LastFM/LastFMQueryJob.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Hardware/IDiscDuplicator.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Collection.Database/DatabaseImportResultHandler.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Collection.Database/DatabaseQueryFilterModel.cs" subtype="Code" buildaction="Compile" />
@@ -192,6 +194,7 @@
     <ProjectReference type="Gac" localcopy="True" refto="TagLib, Version=0.0.0.0, Culture=neutral" />
     <ProjectReference type="Gac" localcopy="True" refto="NDesk.DBus, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f6716e4f9b2ed099" />
     <ProjectReference type="Gac" localcopy="True" refto="NDesk.DBus.GLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f6716e4f9b2ed099" />
+    <ProjectReference type="Project" localcopy="False" refto="Lastfm" />
   </References>
   <Deployment.LinuxDeployData generateScript="False" />
   <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="True" RelativeMakefileName="Makefile.am">

Modified: trunk/banshee/src/Core/Banshee.Services/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Makefile.am	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Makefile.am	Sun Jul 20 20:47:47 2008
@@ -79,6 +79,8 @@
 	Banshee.MediaProfiles/ProfileConfiguration.cs \
 	Banshee.Metadata.Embedded/EmbeddedMetadataProvider.cs \
 	Banshee.Metadata.Embedded/EmbeddedQueryJob.cs \
+	Banshee.Metadata.LastFM/LastFMMetadataProvider.cs \
+	Banshee.Metadata.LastFM/LastFMQueryJob.cs \
 	Banshee.Metadata.MusicBrainz/MusicBrainzMetadataProvider.cs \
 	Banshee.Metadata.MusicBrainz/MusicBrainzQueryJob.cs \
 	Banshee.Metadata.Rhapsody/RhapsodyMetadataProvider.cs \

Modified: trunk/banshee/src/Libraries/Lastfm/Lastfm.Data/DataEntry.cs
==============================================================================
--- trunk/banshee/src/Libraries/Lastfm/Lastfm.Data/DataEntry.cs	(original)
+++ trunk/banshee/src/Libraries/Lastfm/Lastfm.Data/DataEntry.cs	Sun Jul 20 20:47:47 2008
@@ -211,4 +211,29 @@
     {
         public int Reach                { get { return Get<int>      ("reach"); } }
     }
+    
+    // Album Data
+    public class AlbumData : DataEntry 
+    {            
+        public string Reach             { get { return Get<string>      ("reach"); } }            
+        public string LastfmUrl         { get { return Get<string>      ("url"); } }
+        public DateTime ReleaseDate     { get { return Get<DateTime>    ("releasedate"); } }        
+    }
+    
+    public class AlbumCoverUrls : DataEntry
+    {        
+        public string Small             { get { return Get<string>      ("small"); } }
+        public string Medium            { get { return Get<string>      ("medium"); } }
+        public string Large             { get { return Get<string>      ("large"); } }        
+        public string[] AllUrls() {
+            return (new string[] {Small, Medium, Large});
+        }
+    }
+       
+    public class AlbumTrack : DataEntry
+    {
+        public string Title             { get { return Get<string>      ("title"); } }            
+        public int Reach                { get { return Get<int>         ("reach"); } }
+        public string LastfmUrl         { get { return Get<string>      ("url"); } }
+    }   
 }

Added: trunk/banshee/src/Libraries/Lastfm/Lastfm.Data/LastfmAlbumData.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Lastfm/Lastfm.Data/LastfmAlbumData.cs	Sun Jul 20 20:47:47 2008
@@ -0,0 +1,108 @@
+//
+// LastfmAlbumData.cs
+//
+// Author:
+//   Peter de Kraker <peterdk dev umito nl>
+//
+// Based on LastfmArtistData.cs
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using Hyena;
+
+using System.Collections.Generic;
+
+namespace Lastfm.Data
+{
+    public class LastfmAlbumData
+    {
+        protected Dictionary <string, object> cache = new Dictionary <string, object> ();
+
+        protected string artist;
+        public string Artist {
+            get { return artist; }
+        }
+        
+        protected string album;
+        public string Album {
+            get { return album; }
+        }
+
+        public LastfmAlbumData (string artist, string album) 
+        {
+            this.artist = artist;
+            this.album = album;
+            
+            //Return Exception if the album is not found on Lastfm.
+            try {
+                if (AlbumData != null) {
+                    return;
+                }
+                } catch { throw; } 
+        }
+
+        
+        protected LastfmData<T> Get<T> (string fragment) where T : DataEntry
+        {
+            return Get<T> (fragment, null);
+        }
+
+        protected LastfmData<T> Get<T> (string fragment, string xpath) where T : DataEntry
+        {
+            //using cacheKey because the public methods all use the same fragment but with a different xpath.
+            string cacheKey = fragment + xpath;
+                    
+            if (cache.ContainsKey (cacheKey)) {
+                return (LastfmData<T>) cache [cacheKey];
+            }
+
+            LastfmData<T> obj = new LastfmData<T> (String.Format ("album/{0}/{1}/{2}", artist, album, fragment), xpath);
+            cache [cacheKey] = obj;
+            return obj;
+        }
+        
+        
+#region Public Properties
+//      All these methods use the same fragment, but with a different xpath. This because the info.xml contains lots of different stuff.
+//      Couldn't figure out how to process it otherwise.
+        
+        public AlbumData AlbumData {
+            // We don't need the array, since there is only 1 set of albumdata for any album. Therefore "[0]".
+            get { return (Get<AlbumData> ("info.xml", "/album"))[0]; }
+        }
+        
+        public LastfmData<AlbumTrack> AlbumTracks {
+            get { return Get<AlbumTrack> ("info.xml", "/album/tracks/track"); }
+        }
+        
+        public AlbumCoverUrls AlbumCoverUrls {
+            // We don't need the array, since there is only 1 set of covers for any album. Therefore "[0]".
+            get { return (Get<AlbumCoverUrls> ("info.xml", "/album/coverart"))[0]; }
+        }
+        
+#endregion
+
+    }
+}
+

Modified: trunk/banshee/src/Libraries/Lastfm/Lastfm.mdp
==============================================================================
--- trunk/banshee/src/Libraries/Lastfm/Lastfm.mdp	(original)
+++ trunk/banshee/src/Libraries/Lastfm/Lastfm.mdp	Sun Jul 20 20:47:47 2008
@@ -20,6 +20,7 @@
     <File name="Lastfm.Data/LastfmArtistData.cs" subtype="Code" buildaction="Compile" />
     <File name="Lastfm.Data/LastfmData.cs" subtype="Code" buildaction="Compile" />
     <File name="Lastfm.Data/LastfmUserData.cs" subtype="Code" buildaction="Compile" />
+    <File name="Lastfm.Data/LastfmAlbumData.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

Modified: trunk/banshee/src/Libraries/Lastfm/Makefile.am
==============================================================================
--- trunk/banshee/src/Libraries/Lastfm/Makefile.am	(original)
+++ trunk/banshee/src/Libraries/Lastfm/Makefile.am	Sun Jul 20 20:47:47 2008
@@ -14,7 +14,8 @@
 	Lastfm.Data/DataEntryCollection.cs \
 	Lastfm.Data/LastfmData.cs \
 	Lastfm.Data/LastfmArtistData.cs \
-	Lastfm.Data/LastfmUserData.cs 
+	Lastfm.Data/LastfmUserData.cs \
+	Lastfm.Data/LastfmAlbumData.cs 
 
 include $(top_srcdir)/build/build.mk
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]