cowbell r36 - in trunk: base gui
- From: btaylor svn gnome org
- To: svn-commits-list gnome org
- Subject: cowbell r36 - in trunk: base gui
- Date: Mon, 2 Jun 2008 04:35:28 +0000 (UTC)
Author: btaylor
Date: Mon Jun 2 04:35:27 2008
New Revision: 36
URL: http://svn.gnome.org/viewvc/cowbell?rev=36&view=rev
Log:
Some work in progress album cover support with MusicBrainz
Modified:
trunk/base/IMetadataProxy.cs
trunk/base/IMetadataProxyService.cs
trunk/base/MetadataProxyService.cs
trunk/base/MusicBrainzMetadataProxy.cs
trunk/base/Utils.cs
trunk/gui/AlbumCoverImage.cs
Modified: trunk/base/IMetadataProxy.cs
==============================================================================
--- trunk/base/IMetadataProxy.cs (original)
+++ trunk/base/IMetadataProxy.cs Mon Jun 2 04:35:27 2008
@@ -28,6 +28,7 @@
public interface IMetadataProxy
{
void Import (MetadataImportCompletedHandler completed_handler);
+ byte[] FetchAlbumArtwork ();
}
public class MetadataImportCompletedArgs : EventArgs
Modified: trunk/base/IMetadataProxyService.cs
==============================================================================
--- trunk/base/IMetadataProxyService.cs (original)
+++ trunk/base/IMetadataProxyService.cs Mon Jun 2 04:35:27 2008
@@ -26,5 +26,6 @@
public interface IMetadataProxyService : IService
{
void FetchMetadata (MetadataImportCompletedHandler import_completed);
+ byte[] FetchAlbumArtwork ();
}
}
Modified: trunk/base/MetadataProxyService.cs
==============================================================================
--- trunk/base/MetadataProxyService.cs (original)
+++ trunk/base/MetadataProxyService.cs Mon Jun 2 04:35:27 2008
@@ -50,6 +50,18 @@
});
}
+ // TODO:
+ public byte[] FetchAlbumArtwork ()
+ {
+ foreach (DictionaryEntry d in proxies)
+ {
+ IMetadataProxy p = (IMetadataProxy)d.Value;
+ return p.FetchAlbumArtwork ();
+ }
+
+ return null;
+ }
+
/**
* Scans all external MetadataServices for matches to the
* current tracks. When finished, import_completed is invoked
Modified: trunk/base/MusicBrainzMetadataProxy.cs
==============================================================================
--- trunk/base/MusicBrainzMetadataProxy.cs (original)
+++ trunk/base/MusicBrainzMetadataProxy.cs Mon Jun 2 04:35:27 2008
@@ -1,6 +1,6 @@
/*
* cowbell
- * Copyright (c) 2005 Brad Taylor
+ * Copyright (c) 2008 Brad Taylor
*
* This file is part of cowbell.
*
@@ -34,30 +34,33 @@
public class MusicBrainzMetadataProxy : IMetadataProxy
{
#region public methods
- public void Import (MetadataImportCompletedHandler completed)
+ public MusicBrainzMetadataProxy ()
{
db_svc = (IDatabaseService)ServiceManager.GetService (
typeof (IDatabaseService));
dispatch_svc = (IDispatchService)ServiceManager.GetService (
typeof (IDispatchService));
-
- Artist a = FindClosestArtist (db_svc.GlobalData.Artist);
- if (a == null) {
+ }
+
+ public void Import (MetadataImportCompletedHandler completed)
+ {
+ Artist artist;
+ Release release;
+ FindClosestAlbumAndRelease (out artist, out release);
+
+ if (artist == null) {
completed (this, new MetadataImportCompletedArgs (
MetadataImportStatus.ArtistNotFound));
return;
- }
-
- Release r = FindClosestRelease (a, db_svc.GlobalData.Album);
- if (r == null) {
+ } else if (release == null) {
completed (this, new MetadataImportCompletedArgs (
MetadataImportStatus.ReleaseNotFound));
return;
}
-
+
int num_matches;
- MatchTracks (a, r, db_svc, out num_matches);
+ MatchTracks (artist, release, db_svc, out num_matches);
if (num_matches == db_svc.Count) {
completed (this, new MetadataImportCompletedArgs (
@@ -68,6 +71,23 @@
completed (this, new MetadataImportCompletedArgs (
MetadataImportStatus.PartialTrackMatch));
}
+
+ public byte[] FetchAlbumArtwork ()
+ {
+ Artist artist;
+ Release release;
+ FindClosestAlbumAndRelease (out artist, out release);
+
+ if (release == null) {
+ return null;
+ }
+
+ string asin = release.GetAsin ();
+ if (String.IsNullOrEmpty (asin))
+ return null;
+
+ return Utils.GetBytesAtUri (String.Format (AMAZON_URI_FORMAT, asin));
+ }
#endregion
#region private delegates
@@ -77,6 +97,11 @@
#region private fields
private IDatabaseService db_svc;
private IDispatchService dispatch_svc;
+
+ private Dictionary<string, Artist> mb_artists_cache = new Dictionary<string, Artist> ();
+ private Dictionary<string, Release> mb_releases_cache = new Dictionary<string, Release> ();
+
+ private const string AMAZON_URI_FORMAT = "http://images.amazon.com/images/P/{0}.01._SCLZZZZZZZ_.jpg";
private const string LUCENE_ARTIST_FORMAT = "artist:{0}";
private const int MAX_TRIES = 5;
private const int ACCEPT_DISTANCE_THRESHOLD = 2;
@@ -154,6 +179,42 @@
}
}
+ private void FindClosestAlbumAndRelease (out Artist artist, out Release release)
+ {
+ artist = null;
+ release = null;
+
+ if (db_svc.GlobalData == null) {
+ return;
+ }
+
+ // TODO: sanitize this somehow?
+ string artist_name = db_svc.GlobalData.Artist;
+
+ if (!mb_artists_cache.ContainsKey (artist_name)) {
+ artist = FindClosestArtist (artist_name);
+ if (artist == null) {
+ return;
+ }
+ mb_artists_cache[artist_name] = artist;
+ }
+
+ artist = mb_artists_cache[artist_name];
+
+ // TODO: sanitize this somehow?
+ string album_name = db_svc.GlobalData.Album;
+
+ if (!mb_releases_cache.ContainsKey (album_name)) {
+ release = FindClosestRelease (artist, album_name);
+ if (release == null) {
+ return;
+ }
+ mb_releases_cache[album_name] = release;
+ }
+
+ release = mb_releases_cache[album_name];
+ }
+
private Release FindClosestRelease (Artist artist, string release_search)
{
int min_distance = Int32.MaxValue;
Modified: trunk/base/Utils.cs
==============================================================================
--- trunk/base/Utils.cs (original)
+++ trunk/base/Utils.cs Mon Jun 2 04:35:27 2008
@@ -20,8 +20,11 @@
*/
using System;
+using System.IO;
+using System.Net;
+using System.Web;
using System.Threading;
-using System.Collections;
+using System.Collections.Generic;
using System.Globalization;
namespace Cowbell.Base
@@ -97,7 +100,7 @@
public static string HumanReadableTimeSpan (TimeSpan span)
{
- ArrayList list = new ArrayList ();
+ List<string> list = new List<string> ();
if (span.Days > 0) {
list.Add (String.Format (Catalog.GetPluralString ("{0} day", "{0} days", span.Days), span.Days));
}
@@ -114,7 +117,7 @@
list.Add (String.Format (Catalog.GetPluralString ("{0} second", "{0} seconds", span.Seconds), span.Seconds));
}
- return String.Join (", ", (string[])list.ToArray (typeof (string)));
+ return String.Join (", ", list.ToArray ());
}
public static string ToTitleCase (string str)
@@ -164,5 +167,48 @@
}
return String.Join (" ", tokens);
}
+
+ public static byte[] GetBytesAtUri (string uri)
+ {
+ try {
+ HttpWebRequest req = (HttpWebRequest)WebRequest.Create (uri);
+ req.UserAgent = "Cowbell";
+ req.KeepAlive = false;
+ req.Timeout = 30000; // 30 sec
+
+ List<byte> bytes = new List<byte> ();
+ using (WebResponse resp = req.GetResponse ()) {
+ // This number won't always be correct,
+ // but it could be a good starting
+ // point, also ignore it if its > 5 MB
+ if (resp.ContentLength < 5242880)
+ bytes.Capacity = (int)resp.ContentLength;
+
+ Stream s = resp.GetResponseStream ();
+
+ byte[] buffer = new byte[8192];
+ int n;
+
+ while ((n = s.Read (buffer, 0, buffer.Length)) != 0) {
+ if (n == 0) {
+ break;
+ }
+
+ if (n < buffer.Length) {
+ // resize the array
+ byte[] tmp = new byte[n];
+ Array.Copy (buffer, tmp, n);
+ buffer = tmp;
+ }
+
+ bytes.AddRange (buffer);
+ }
+ }
+
+ return bytes.ToArray ();
+ } catch (WebException) {
+ return null;
+ }
+ }
}
}
Modified: trunk/gui/AlbumCoverImage.cs
==============================================================================
--- trunk/gui/AlbumCoverImage.cs (original)
+++ trunk/gui/AlbumCoverImage.cs Mon Jun 2 04:35:27 2008
@@ -42,11 +42,13 @@
*/
public class AlbumCoverImage : EventBox
{
- /* public methods */
+#region public methods
public AlbumCoverImage ()
{
db_svc = (IDatabaseService)ServiceManager.GetService (
typeof (IDatabaseService));
+ prx_svc = (IMetadataProxyService)ServiceManager.GetService (
+ typeof (IMetadataProxyService));
pixbuf = null;
UserPixbuf = false;
@@ -120,8 +122,13 @@
}
Refresh ();
} else {
+ // We're already loading
+ if (original == loadingcover) {
+ return;
+ }
+
ShowLoadingCover ();
- dispatch_svc.BackgroundDispatch (new VoidHandler (AmazonDownload));
+ dispatch_svc.BackgroundDispatch (new VoidHandler (ProxyDownload));
}
}
}
@@ -137,75 +144,73 @@
ShowDefaultCover ();
UserPixbuf = false;
}
+#endregion
- /* private fields */
- Gtk.Image image;
+#region private fields
+ private Gtk.Image image;
- static Pixbuf defaultcover;
- static Pixbuf loadingcover;
- Pixbuf pixbuf;
- Pixbuf original;
- string stamp;
+ private static Pixbuf defaultcover;
+ private static Pixbuf loadingcover;
- Hashtable covers;
- Hashtable large_covers;
-
- bool UserPixbuf;
+ private Pixbuf pixbuf;
+ private Pixbuf original;
+ private string stamp;
-// static string DevTag = "1G1CFFX6R1ZWFXDMVJG2";
+ private Hashtable covers;
+ private Hashtable large_covers;
+
+ private bool UserPixbuf;
- static TargetEntry[] CoverDragEntries = new TargetEntry[] {
+ private static TargetEntry[] CoverDragEntries = new TargetEntry[] {
new TargetEntry ("text/uri-list", 0, (uint)TargetType.UriList),
new TargetEntry ("x-special/gnome-icon-list", 0, (uint)TargetType.UriList),
new TargetEntry ("_NETSCAPE_URL", 0, (uint)TargetType.Uri)
};
- static string[] CoverFilenames = {"cover.jpg",
- "Cover.jpg",
- "cover.jpeg",
- "Cover.jpeg",
- "cover.png",
- "Cover.png",
- "cover.gif",
- "Cover.gif",
- "cover.bmp",
- "Cover.bmp",
- "folder.jpg",
- "Folder.jpg",
- "folder.jpeg",
- "Folder.jpeg",
- ".folder.png",
- "folder.png",
- "Folder.png"};
+ private static string[] CoverFilenames = {
+ "cover.jpg", "Cover.jpg", "cover.jpeg",
+ "Cover.jpeg", "cover.png", "Cover.png",
+ "cover.gif", "Cover.gif", "cover.bmp",
+ "Cover.bmp", "folder.jpg", "Folder.jpg",
+ "folder.jpeg", "Folder.jpeg", ".folder.png",
+ "folder.png", "Folder.png"
+ };
- enum TargetType {
+ private enum TargetType {
UriList,
Uri
};
private IDatabaseService db_svc;
+ private IMetadataProxyService prx_svc;
+#endregion
- /* private methods */
+#region private methods
private void ShowLoadingCover ()
{
original = loadingcover;
Refresh ();
}
- private void AmazonDownload ()
+ private void ProxyDownload ()
{
+ byte[] bytes = prx_svc.FetchAlbumArtwork ();
+
try {
- pixbuf = GetCoverFromAmazon ();
+ if (bytes != null && bytes.Length > 0) {
+ pixbuf = new Gdk.Pixbuf (bytes);
+ }
} catch (Exception e) {
pixbuf = null;
Debug.WriteLine (e.Message);
Debug.WriteLine (e.StackTrace);
}
- GLib.Idle.Add (new GLib.IdleHandler (ProcessAmazonDownload));
+
+ GLib.Idle.Add (new GLib.IdleHandler (ProcessCoverDownload));
}
- private bool ProcessAmazonDownload ()
+ private bool ProcessCoverDownload ()
{
lock (this) {
if (pixbuf == null) {
@@ -256,170 +261,6 @@
return border;
}
- /*
- * TODO: Rewrite this code based on AmazonMetadataProxy
- */
- private Pixbuf GetCoverFromAmazon ()
- {
-/*
- Song song = db_svc.GlobalData;
-
- AmazonSearchService search_service = new AmazonSearchService ();
-
- string sane_album_title = SanitizeString (song.Album);
-
- string [] album_title_array = sane_album_title.Split (' ');
- Array.Sort (album_title_array);
-
- * This assumes the right artist is always in Artists [0] *
- string sane_artist = SanitizeString (song.Artist);
-
- * Prepare for handling multi-page results *
- int total_pages = 1;
- int current_page = 1;
- int max_pages = 2; * check no more than 2 pages *
-
- * Create Encapsulated Request *
- ArtistRequest asearch = new ArtistRequest ();
- asearch.devtag = DevTag;
-
- if (!db_svc.MultipleArtists)
- asearch.artist = sane_artist;
- else
- asearch.artist = "Various Artists";
-
- asearch.keywords = sane_album_title;
- asearch.type = "heavy";
- asearch.mode = "music";
- asearch.tag = "webservices-20";
-
- * Use selected Amazon service *
- search_service.Url = "http://soap.amazon.com/onca/soap3";
-
- double best_match_percent = 0.0;
- Pixbuf best_match = null;
-
- while (current_page <= total_pages && current_page <= max_pages)
- {
- asearch.page = Convert.ToString (current_page);
-
- ProductInfo pi;
-
- * Amazon API requires this .. *
- System.Threading.Thread.Sleep (1000);
-
- * Web service calls timeout after 30 seconds *
- search_service.Timeout = 30000;
-
- * This may throw an exception, we catch it in Song.cs in the calling function *
- pi = search_service.ArtistSearchRequest (asearch);
-
- int num_results = pi.Details.Length;
- total_pages = Convert.ToInt32 (pi.TotalPages);
-
- * Work out how many matches are on this page *
- if (num_results < 1)
- return null;
-
- for (int i = 0; i < num_results; i++)
- {
- * Ignore bracketed text on the result from Amazon *
- string sane_product_name = SanitizeString (pi.Details[i].ProductName);
-
- * Compare the two strings statistically *
- string [] product_name_array = sane_product_name.Split (' ');
- Array.Sort (product_name_array);
-
- int match_count = 0;
- foreach (string s in album_title_array)
- {
- if (Array.BinarySearch (product_name_array, s) >= 0)
- match_count++;
- }
-
- double match_percent;
- match_percent = match_count / (double) album_title_array.Length;
-
- if (match_percent >= 0.6) {
- string url = pi.Details[i].ImageUrlMedium;
-
- if (url != null && url.Length > 0) {
- double backward_match_percent = 0.0;
- int backward_match_count = 0;
-
- foreach (string s in product_name_array)
- {
- if (Array.BinarySearch (album_title_array, s) >= 0)
- backward_match_count++;
- }
-
- backward_match_percent = backward_match_count / (double) product_name_array.Length;
-
- double total_match_percent = match_percent + backward_match_percent;
-
- if (total_match_percent > best_match_percent) {
- Pixbuf pix;
-
- try {
- pix = GetCoverFromUrl (url);
- } catch (WebException e) {
- throw e;
- } catch (Exception) {
- pix = null;
- }
-
- if (pix != null) {
- best_match_percent = total_match_percent;
- best_match = pix;
-
- if (best_match_percent == 2.0)
- return best_match;
- }
- }
- // ELSE keep iterating to find a better match
- }
- }
- }
-
- current_page++;
- }
-
- return best_match;
-*/
- return null;
- }
-
- private Pixbuf GetCoverFromUrl (string url)
- {
- Pixbuf cover;
-
- /* read the cover image */
- HttpWebRequest req = (HttpWebRequest) WebRequest.Create (url);
- req.UserAgent = "Cowbell";
- req.KeepAlive = false;
- req.Timeout = 30000; /* Timeout after 30 seconds */
-
- WebResponse resp = null;
-
- /*
- * May throw an exception, but we catch it in the calling
- * function in Song.cs
- */
- resp = req.GetResponse ();
-
- Stream s = resp.GetResponseStream ();
-
- cover = new Pixbuf (s);
-
- resp.Close ();
-
- /* Trap Amazon 1x1 images */
- if (cover.Height == 1 && cover.Width == 1)
- return null;
-
- return cover;
- }
-
private Pixbuf GetCoverLocal (string path)
{
Pixbuf cover;
@@ -433,19 +274,6 @@
return cover;
}
-/*
- private string SanitizeString (string s)
- {
- s = s.ToLower ();
- s = Regex.Replace (s, "\\(.*\\)", "");
- s = Regex.Replace (s, "\\[.*\\]", "");
- s = s.Replace ("-", " ");
- s = s.Replace ("_", " ");
-
- return s;
- }
-*/
-
/* DnD Callbacks mostly stolen from Jorn Baayen */
private void DragDataReceivedCb (object o, DragDataReceivedArgs args)
{
@@ -464,14 +292,18 @@
if (uri.Scheme != "http")
break;
+ success = false;
+
+ byte[] bytes = Utils.GetBytesAtUri (SafeUri.UriToFilename (uri));
+ if (bytes == null || bytes.Length == 0) {
+ break;
+ }
+
try {
- original = GetCoverFromUrl (SafeUri.UriToFilename (uri));
+ original = new Gdk.Pixbuf (bytes);
UserPixbuf = true;
success = true;
- } catch {
- success = false;
- break;
- }
+ } catch { }
break;
@@ -482,14 +314,12 @@
if (path == null)
break;
+ success = false;
try {
original = GetCoverLocal (path);
UserPixbuf = true;
success = true;
- } catch {
- success = false;
- break;
- }
+ } catch { }
break;
}
@@ -511,5 +341,6 @@
}
return "0";
}
+#endregion
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]