Skip to content
This repository
Browse code

Removed allmusic (for now?); Made some more tests; Fixed lyrics:magis…

…trix; added ainfo:bbcmusic and photos:bbcmusic
  • Loading branch information...
commit fc7feedc11b9380e9f6fc74aa18360d3dc77857b 1 parent 4f0af49
Chris P. authored August 03, 2012
1  .gitignore
@@ -10,6 +10,7 @@ core
10 10
 libglyr.pc
11 11
 doc/doc
12 12
 doc/build
  13
+spec/provider/results/
13 14
 
14 15
 # Ignore documentation, local working directory
15 16
 child/
6  CMakeLists.txt
@@ -143,17 +143,17 @@ SET(LIB_SOURCE_LOCATIONS
143 143
 	"${DIR_INTERN}/guitartabs.c"
144 144
 	"${DIR_INTERN}/backdrops.c"
145 145
 	# extensions
  146
+	"${DIR_INTERN}/common/mbid_lookup.c"
146 147
 	"${DIR_INTERN}/common/google.c"
147 148
 	"${DIR_INTERN}/common/amazon.c"
148 149
 	"${DIR_INTERN}/common/picsearch.c"
149 150
 	"${DIR_INTERN}/common/musicbrainz.c"
150 151
 	"${DIR_AINFO}/lastfm.c"
151  
-	"${DIR_AINFO}/allmusic_com.c"
  152
+	"${DIR_AINFO}/bbcmusic.c"
152 153
 	"${DIR_AINFO}/lyricsreg.c"
153 154
 	"${DIR_SIMILAR}/lastfm.c"
154 155
 	"${DIR_SIMILSO}/lastfm.c"
155 156
 	"${DIR_TRACKLIST}/musicbrainz.c"
156  
-	"${DIR_REVIEW}/allmusic_com.c"
157 157
 	"${DIR_REVIEW}/amazon.c"
158 158
 	"${DIR_REVIEW}/metallum.c"
159 159
 	"${DIR_ALBUMLIST}/musicbrainz.c"
@@ -166,7 +166,6 @@ SET(LIB_SOURCE_LOCATIONS
166 166
 	"${DIR_COVER}/coverhunt.c"
167 167
 	"${DIR_COVER}/lyricswiki.c"
168 168
 	"${DIR_COVER}/albumart.c"
169  
-	"${DIR_COVER}/allmusic_com.c"
170 169
 	"${DIR_COVER}/discogs.c"
171 170
 	"${DIR_COVER}/amazon.c"
172 171
 	"${DIR_COVER}/rhapsody.c"
@@ -192,6 +191,7 @@ SET(LIB_SOURCE_LOCATIONS
192 191
 	"${DIR_PHOTOS}/singerpictures.c"
193 192
 	"${DIR_PHOTOS}/rhapsody.c"
194 193
 	"${DIR_PHOTOS}/picsearch.c"
  194
+	"${DIR_PHOTOS}/bbcmusic.c"
195 195
 	"${DIR_GUITARTABS}/guitaretab.c"
196 196
 	"${DIR_GUITARTABS}/chordie_com.c"
197 197
     "${DIR_BACKDROPS}/htbackdrops.c"
171  lib/intern/ainfo/allmusic_com.c
... ...
@@ -1,171 +0,0 @@
1  
-/***********************************************************
2  
-* This file is part of glyr
3  
-* + a commnadline tool and library to download various sort of musicrelated metadata.
4  
-* + Copyright (C) [2011]  [Christopher Pahl]
5  
-* + Hosted at: https://github.com/sahib/glyr
6  
-*
7  
-* glyr is free software: you can redistribute it and/or modify
8  
-* it under the terms of the GNU General Public License as published by
9  
-* the Free Software Foundation, either version 3 of the License, or
10  
-* (at your option) any later version.
11  
-*
12  
-* glyr is distributed in the hope that it will be useful,
13  
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
14  
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  
-* GNU General Public License for more details.
16  
-*
17  
-* You should have received a copy of the GNU General Public License
18  
-* along with glyr. If not, see <http://www.gnu.org/licenses/>.
19  
-**************************************************************/
20  
-#include "../../stringlib.h"
21  
-#include "../../core.h"
22  
-#include "../../glyr.h"
23  
-
24  
-static const char * ainfo_allmusic_url(GlyrQuery * s)
25  
-{
26  
-	return "http://www.allmusic.com/search/artist/${artist}";
27  
-}
28  
-
29  
-/*-------------------------------------*/
30  
-
31  
-#define IMG_BEGIN "<p class=\"text\">"
32  
-#define IMG_ENDIN "</p>"
33  
-
34  
-static GlyrMemCache * parse_bio_page(GlyrMemCache * to_parse, gchar * url)
35  
-{
36  
-	GlyrMemCache * result = NULL;
37  
-	gchar * text = get_search_value(to_parse->data,IMG_BEGIN,IMG_ENDIN);
38  
-	if(text != NULL)
39  
-	{
40  
-		result = DL_init();
41  
-		result->data = text;
42  
-		result->size = strlen(result->data);
43  
-		result->dsrc = g_strdup(url);
44  
-	}
45  
-	return result;
46  
-}
47  
-
48  
-/*-------------------------------------*/
49  
-
50  
-#define ROOT "<div id=\"tabs\">"
51  
-#define ROOT_URL "http://www.allmusic.com/artist/"
52  
-#define END_OF_ROOT "\">"
53  
-
54  
-static GlyrMemCache * find_long_version(GlyrQuery * s, GlyrMemCache * to_parse)
55  
-{
56  
-	GlyrMemCache * result = NULL;
57  
-	gchar * root = strstr(to_parse->data,ROOT);
58  
-	if(root != NULL)
59  
-	{
60  
-		gchar * url_id = get_search_value(root,ROOT_URL,END_OF_ROOT);
61  
-		if(url_id != NULL)
62  
-		{
63  
-			char * url = g_strdup_printf(ROOT_URL"%s",url_id);
64  
-			if(url != NULL)
65  
-			{
66  
-				GlyrMemCache * dl = download_single(url,s,NULL);
67  
-				if(dl != NULL)
68  
-				{
69  
-					result = parse_bio_page(dl,url);
70  
-					DL_free(dl);
71  
-				}
72  
-				g_free(url);
73  
-			}
74  
-			g_free(url_id);
75  
-		}
76  
-	}
77  
-	return result;
78  
-}
79  
-
80  
-/*-------------------------------------*/
81  
-#define SEARCH_TREE_BEGIN "<table class=\"search-results\""
82  
-#define SEARCH_NODE "<td><a href=\""
83  
-#define SEARCH_DELIM "\">"
84  
-#define END_OF_ARTIST "</a>"
85  
-
86  
-static gboolean approve_content(GlyrQuery * query, gchar * ref)
87  
-{
88  
-	gboolean result = FALSE;
89  
-	if(ref != NULL)
90  
-	{
91  
-		gchar * artist_html = get_search_value(ref,SEARCH_DELIM,END_OF_ARTIST);
92  
-		if(artist_html != NULL)
93  
-		{
94  
-			if(levenshtein_strnormcmp(query,artist_html,query->artist) <= query->fuzzyness)
95  
-			{
96  
-				result = TRUE;
97  
-			}
98  
-			g_free(artist_html);
99  
-		}
100  
-	}
101  
-	return result;
102  
-}
103  
-
104  
-/*-------------------------------------*/
105  
-
106  
-static GList * ainfo_allmusic_parse(cb_object * capo)
107  
-{
108  
-	GList * result_list = NULL;
109  
-
110  
-	/* Are we already on the biopage? */
111  
-	if(strstr(capo->cache->data, "<!--Begin Biography -->"))
112  
-	{
113  
-		GlyrMemCache * info_long = find_long_version(capo->s,capo->cache);
114  
-		if(info_long != NULL)
115  
-		{
116  
-			result_list = g_list_prepend(result_list,info_long);
117  
-		}
118  
-		return result_list;
119  
-	}
120  
-
121  
-	gchar * search_begin = NULL;
122  
-
123  
-	/* Hello, anybody there? */
124  
-	if((search_begin = strstr(capo->cache->data, SEARCH_TREE_BEGIN)) == NULL)
125  
-	{
126  
-		return NULL;
127  
-	}
128  
-
129  
-	gsize nodelen = (sizeof SEARCH_NODE) - 1;
130  
-	gchar * node  = search_begin;
131  
-	while(continue_search(g_list_length(result_list),capo->s) && (node = strstr(node + nodelen,SEARCH_NODE)))
132  
-	{
133  
-		gchar * end_of_url = strstr(node,SEARCH_DELIM);
134  
-		if(approve_content(capo->s,end_of_url) == TRUE)
135  
-		{
136  
-			gchar * url = copy_value(node + nodelen, end_of_url);
137  
-			if(url != NULL)
138  
-			{
139  
-				gchar * biography_url = g_strdup_printf("%s/biography",url);
140  
-				GlyrMemCache * dl_cache = download_single(biography_url,capo->s,NULL);
141  
-				if(dl_cache != NULL)
142  
-				{
143  
-					GlyrMemCache * content = parse_bio_page(dl_cache,biography_url);
144  
-					if(content != NULL)
145  
-					{
146  
-						result_list = g_list_prepend(result_list,content);
147  
-					}
148  
-					DL_free(dl_cache);
149  
-				}
150  
-				g_free(biography_url);
151  
-				g_free(url);
152  
-			}
153  
-		}
154  
-	}
155  
-	return result_list;
156  
-}
157  
-
158  
-/*-------------------------------------*/
159  
-
160  
-MetaDataSource ainfo_allmusic_src =
161  
-{
162  
-	.name      = "allmusic",
163  
-	.key       = 'm',
164  
-	.free_url  = false,
165  
-	.type      = GLYR_GET_ARTISTBIO,
166  
-	.parser    = ainfo_allmusic_parse,
167  
-	.get_url   = ainfo_allmusic_url,
168  
-	.quality   = 70,
169  
-	.speed     = 40,
170  
-	.endmarker = NULL
171  
-};
95  lib/intern/ainfo/bbcmusic.c
... ...
@@ -0,0 +1,95 @@
  1
+/***********************************************************
  2
+ * This file is part of glyr
  3
+ * + a commnadline tool and library to download various sort of musicrelated metadata.
  4
+ * + Copyright (C) [2011]  [Christopher Pahl]
  5
+ * + Hosted at: https://github.com/sahib/glyr
  6
+ *
  7
+ * glyr is free software: you can redistribute it and/or modify
  8
+ * it under the terms of the GNU General Public License as published by
  9
+ * the Free Software Foundation, either version 3 of the License, or
  10
+ * (at your option) any later version.
  11
+ *
  12
+ * glyr is distributed in the hope that it will be useful,
  13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15
+ * GNU General Public License for more details.
  16
+ *
  17
+ * You should have received a copy of the GNU General Public License
  18
+ * along with glyr. If not, see <http://www.gnu.org/licenses/>.
  19
+ **************************************************************/
  20
+
  21
+#include "../../stringlib.h"
  22
+#include "../../core.h"
  23
+#include "../common/mbid_lookup.h"
  24
+
  25
+#define API_ROOT "http://www.bbc.co.uk/music/artists/%s.xml"
  26
+
  27
+/////////////////////////////////
  28
+
  29
+#define CONTENT_BEGIN "<content>"
  30
+#define CONTENT_ENDIN "</content>"
  31
+
  32
+static GlyrMemCache * parse_bbc_xml(GlyrMemCache * input)
  33
+{
  34
+    GlyrMemCache * result = NULL;
  35
+    char * content = get_search_value(input->data, CONTENT_BEGIN, CONTENT_ENDIN);
  36
+    if(content != NULL)
  37
+    {
  38
+        result = DL_init();
  39
+        result->data = content;
  40
+        result->dsrc = g_strdup(input->dsrc);
  41
+        result->size = strlen(content);
  42
+    }
  43
+    return result;
  44
+}
  45
+
  46
+/////////////////////////////////
  47
+
  48
+static const char * ainfo_bbcmusic_url(GlyrQuery * qry)
  49
+{
  50
+    return "http://musicbrainz.org/ws/2/artist?query=artist:${artist}";
  51
+}
  52
+
  53
+/////////////////////////////////
  54
+
  55
+static GList * ainfo_bbcmusic_parse(cb_object * capo)
  56
+{
  57
+    GList * result_list = NULL;
  58
+
  59
+    char * mbid = mbid_parse_data(capo->cache, "artist", capo->s->artist, capo->s);
  60
+
  61
+    if(mbid != NULL)
  62
+    {
  63
+        char * full_url = g_strdup_printf(API_ROOT, mbid);
  64
+        if(full_url != NULL)
  65
+        {
  66
+            GlyrMemCache * bbc_xml = download_single(full_url, capo->s, NULL);
  67
+            if(bbc_xml != NULL)
  68
+            {
  69
+                GlyrMemCache * item = parse_bbc_xml(bbc_xml);
  70
+                if(item != NULL)
  71
+                {
  72
+                    result_list = g_list_prepend(result_list, item);
  73
+                }
  74
+            }
  75
+        }
  76
+    }
  77
+
  78
+    return result_list;
  79
+}
  80
+
  81
+/////////////////////////////////
  82
+
  83
+MetaDataSource ainfo_bbcmusic_src =
  84
+{
  85
+	.name      = "bbcmusic",
  86
+	.key       = 'b',
  87
+	.free_url  = false,
  88
+	.type      = GLYR_GET_ARTISTBIO,
  89
+	.parser    = ainfo_bbcmusic_parse,
  90
+	.get_url   = ainfo_bbcmusic_url,
  91
+	.quality   = 95,
  92
+	.speed     = 85,
  93
+	.endmarker = NULL,
  94
+    .lang_aware = false 
  95
+};
97  lib/intern/common/mbid_lookup.c
... ...
@@ -0,0 +1,97 @@
  1
+/***********************************************************
  2
+ * This file is part of glyr
  3
+ * + a commnadline tool and library to download various sort of musicrelated metadata.
  4
+ * + Copyright (C) [2011]  [Christopher Pahl]
  5
+ * + Hosted at: https://github.com/sahib/glyr
  6
+ *
  7
+ * glyr is free software: you can redistribute it and/or modify
  8
+ * it under the terms of the GNU General Public License as published by
  9
+ * the Free Software Foundation, either version 3 of the License, or
  10
+ * (at your option) any later version.
  11
+ *
  12
+ * glyr is distributed in the hope that it will be useful,
  13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15
+ * GNU General Public License for more details.
  16
+ *
  17
+ * You should have received a copy of the GNU General Public License
  18
+ * along with glyr. If not, see <http://www.gnu.org/licenses/>.
  19
+ **************************************************************/
  20
+
  21
+#include "../../core.h"
  22
+#include "../../stringlib.h"
  23
+
  24
+//////////////////////////////////
  25
+
  26
+char * mbid_parse_data(GlyrMemCache * data, const char * lookup_entity, const char * compre_entity, GlyrQuery * qry)
  27
+{
  28
+    char * key = g_strdup_printf("<%s ", lookup_entity);
  29
+    size_t keylen = strlen(key);
  30
+    char * node = data->data;
  31
+    char * result = NULL;
  32
+
  33
+    while((node = strstr(node + keylen, key)))
  34
+    {
  35
+        char * name = get_search_value(node, "<name>", "</name>");
  36
+        if(name && levenshtein_strnormcmp(qry, name, compre_entity) <= qry->fuzzyness)
  37
+        {
  38
+            result = get_search_value(node, "id=\"", "\"");
  39
+            g_free(name);
  40
+            break;
  41
+        }
  42
+        g_free(name);
  43
+    }
  44
+    g_free(key);
  45
+    return result;
  46
+}
  47
+
  48
+
  49
+//////////////////////////////////
  50
+
  51
+#define LOOKUP_QUERY "http://musicbrainz.org/ws/2/%s?query=%s:%s"
  52
+
  53
+//////////////////////////////////
  54
+
  55
+char * mbid_lookup(const char * query, GLYR_DATA_TYPE type, GlyrQuery * qry)
  56
+{
  57
+    char * result_mbid = NULL;
  58
+    if(query == NULL)
  59
+        return result_mbid;
  60
+
  61
+    const char * lookup_entity = "";
  62
+    const char * compre_entity = qry->artist;
  63
+
  64
+    printf("%d %d\n", GLYR_TYPE_TAG_ARTIST, type);
  65
+    switch(type)
  66
+    {
  67
+        case GLYR_TYPE_TAG_ARTIST:
  68
+            lookup_entity = "artist";
  69
+            compre_entity = qry->artist;
  70
+            break;
  71
+        case GLYR_TYPE_TAG_ALBUM:
  72
+            lookup_entity = "release";
  73
+            compre_entity = qry->album;
  74
+            break;
  75
+        case GLYR_TYPE_TAG_TITLE:
  76
+            lookup_entity = "work";
  77
+            compre_entity = qry->title;
  78
+            break;
  79
+        default:
  80
+            lookup_entity = "artist";
  81
+            compre_entity = qry->artist;
  82
+            break;
  83
+    }
  84
+
  85
+    char * lookup_url = g_strdup_printf(LOOKUP_QUERY, lookup_entity, lookup_entity, query);
  86
+    GlyrMemCache * parseable_data = download_single(lookup_url, qry, NULL);
  87
+    if(parseable_data != NULL)
  88
+    {
  89
+        result_mbid = mbid_parse_data(parseable_data, lookup_entity, compre_entity, qry);
  90
+        DL_free(parseable_data);
  91
+    }
  92
+    
  93
+    g_free(lookup_url);
  94
+    return result_mbid;
  95
+}
  96
+
  97
+//////////////////////////////////
24  lib/intern/common/mbid_lookup.h
... ...
@@ -0,0 +1,24 @@
  1
+/***********************************************************
  2
+ * This file is part of glyr
  3
+ * + a commnadline tool and library to download various sort of musicrelated metadata.
  4
+ * + Copyright (C) [2011]  [Christopher Pahl]
  5
+ * + Hosted at: https://github.com/sahib/glyr
  6
+ *
  7
+ * glyr is free software: you can redistribute it and/or modify
  8
+ * it under the terms of the GNU General Public License as published by
  9
+ * the Free Software Foundation, either version 3 of the License, or
  10
+ * (at your option) any later version.
  11
+ *
  12
+ * glyr is distributed in the hope that it will be useful,
  13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15
+ * GNU General Public License for more details.
  16
+ *
  17
+ * You should have received a copy of the GNU General Public License
  18
+ * along with glyr. If not, see <http://www.gnu.org/licenses/>.
  19
+ **************************************************************/
  20
+
  21
+#include "../../core.h"
  22
+
  23
+char * mbid_lookup(const char * query, GLYR_DATA_TYPE type, GlyrQuery * qry);
  24
+char * mbid_parse_data(GlyrMemCache * data, const char * lookup_entity, const char * compre_entity, GlyrQuery * qry);
139  lib/intern/cover/allmusic_com.c
... ...
@@ -1,139 +0,0 @@
1  
-/***********************************************************
2  
-* This file is part of glyr
3  
-* + a commnadline tool and library to download various sort of musicrelated metadata.
4  
-* + Copyright (C) [2011]  [Christopher Pahl]
5  
-* + Hosted at: https://github.com/sahib/glyr
6  
-*
7  
-* glyr is free software: you can redistribute it and/or modify
8  
-* it under the terms of the GNU General Public License as published by
9  
-* the Free Software Foundation, either version 3 of the License, or
10  
-* (at your option) any later version.
11  
-*
12  
-* glyr is distributed in the hope that it will be useful,
13  
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
14  
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  
-* GNU General Public License for more details.
16  
-*
17  
-* You should have received a copy of the GNU General Public License
18  
-* along with glyr. If not, see <http://www.gnu.org/licenses/>.
19  
-**************************************************************/
20  
-
21  
-#include "../../core.h"
22  
-#include "../../stringlib.h"
23  
-#include "../../glyr.h"
24  
-
25  
-static const char * cover_allmusic_url(GlyrQuery * s)
26  
-{
27  
-	if(s->img_min_size < 200)
28  
-	{
29  
-		return "http://www.allmusic.com/search/album/${album}";
30  
-	}
31  
-	return NULL;
32  
-}
33  
-
34  
-// begin of search results
35  
-#define SEARCH_TREE_BEGIN "<table class=\"search-results\""
36  
-
37  
-//*sole search result */
38  
-#define SEARCH_NODE "<td><a href=\""
39  
-#define SEARCH_DELM "\">"
40  
-
41  
-/* artist */
42  
-#define ARTIST_PART "<td>"
43  
-#define ARTIST_END  "</td>"
44  
-#define IMG_BEGIN "<div class=\"image\"> <img src=\""
45  
-#define IMG_ENDIN "\" alt=\""
46  
-
47  
-#define BAD_URL "/img/pages/site/icons/no_cover_200.gif"
48  
-
49  
-static GlyrMemCache * parse_cover_page(GlyrMemCache * dl_cache)
50  
-{
51  
-	GlyrMemCache * result = NULL;
52  
-	if(dl_cache != NULL)
53  
-	{
54  
-		gchar * img_url = get_search_value(dl_cache->data,IMG_BEGIN,IMG_ENDIN);
55  
-		if(img_url != NULL)
56  
-		{
57  
-			if(strcmp(img_url,BAD_URL) != 0)
58  
-			{
59  
-				result = DL_init();
60  
-				result->data = img_url;
61  
-				result->size = strlen(img_url);
62  
-			}
63  
-			else
64  
-			{
65  
-				g_free(img_url);
66  
-			}
67  
-		}
68  
-	}
69  
-	return result;
70  
-}
71  
-
72  
-/*--------------------------------------*/
73  
-
74  
-#define TITLE_TAG "<a href=\"\">Title</a></th>"
75  
-static GList * cover_allmusic_parse(cb_object * capo)
76  
-{
77  
-	GList * result_list = NULL;
78  
-	if(strstr(capo->cache->data,TITLE_TAG) != NULL)
79  
-	{
80  
-		/* Horray, directly hit the page */
81  
-		GlyrMemCache * result = parse_cover_page(capo->cache);
82  
-		result_list = g_list_prepend(result_list, result);
83  
-		return result_list;
84  
-	}
85  
-
86  
-	gchar * search_begin = NULL;
87  
-	if((search_begin = strstr(capo->cache->data, SEARCH_TREE_BEGIN)) == NULL)
88  
-	{
89  
-		/* No page. Crap. */
90  
-		return NULL;
91  
-	}
92  
-
93  
-	gsize nodelen = (sizeof SEARCH_NODE) - 1;
94  
-	gchar *  node = search_begin;
95  
-	while(continue_search(g_list_length(result_list),capo->s) && (node = strstr(node + nodelen,SEARCH_NODE)))
96  
-	{
97  
-		gchar * url = get_search_value(node,SEARCH_NODE,SEARCH_DELM);
98  
-		if(url != NULL)
99  
-		{
100  
-			/* We have the URL - now check the artist to be the one */
101  
-			gchar * artist = get_search_value(node + nodelen,ARTIST_PART, ARTIST_END); 
102  
-			if(artist != NULL)
103  
-			{
104  
-				if(levenshtein_strnormcmp(capo->s,capo->s->artist,artist) <= capo->s->fuzzyness)
105  
-				{
106  
-					GlyrMemCache * dl_cache = download_single(url,capo->s,"<div class=\"artist\">");
107  
-					if(dl_cache != NULL)
108  
-					{
109  
-						GlyrMemCache * result = parse_cover_page(dl_cache);
110  
-						if(result != NULL && result->data)
111  
-						{
112  
-							result->dsrc = g_strdup(url);
113  
-							result_list = g_list_prepend(result_list,result);
114  
-						}
115  
-						DL_free(dl_cache);
116  
-					}
117  
-				}
118  
-				g_free(artist);
119  
-			}
120  
-			g_free(url);
121  
-		}
122  
-	}
123  
-	return result_list;
124  
-}
125  
-
126  
-/*--------------------------------------*/
127  
-
128  
-MetaDataSource cover_allmusic_src =
129  
-{
130  
-	.name      = "allmusic",
131  
-	.key       = 'm',
132  
-	.parser    = cover_allmusic_parse,
133  
-	.get_url   = cover_allmusic_url,
134  
-	.type      = GLYR_GET_COVERART,
135  
-	.quality   = 65,
136  
-	.speed     = 50,
137  
-	.endmarker = NULL,
138  
-	.free_url  = false
139  
-};
1  lib/intern/cover/lastfm.c
@@ -55,6 +55,7 @@ static GList * cover_lastfm_parse(cb_object *capo)
55 55
     gchar * find  = capo->cache->data;
56 56
     gsize tag_len = strlen(tag_ssize);
57 57
 
  58
+
58 59
     while(continue_search(g_list_length(result_list),capo->s) && (find = strstr(find + tag_len, tag_ssize)) != NULL)
59 60
     {
60 61
         gchar * url = get_search_value(find, (gchar*)tag_ssize, (gchar*)tag_esize);
51  lib/intern/lyrics/magistrix.c
@@ -49,6 +49,50 @@ static GlyrMemCache * parse_lyric_page(GlyrMemCache * cache)
49 49
 
50 50
 ///////////////////////////////////
51 51
 
  52
+#define SEARCH_FIRST_RESULT "<table class='searchresult'>"
  53
+#define SEARCH_LAST_RESULT  "</table>"
  54
+#define SEARCH_NODE "<div class='title'>"
  55
+#define SEARCH_LINK_START "&ndash;\n<a href=\""
  56
+#define SEARCH_LINK_END   "\" class"
  57
+
  58
+static GList * parse_search_result_page(cb_object * capo)
  59
+{
  60
+    GList * result_list = NULL;
  61
+    char * first_result = strstr(capo->cache->data, SEARCH_FIRST_RESULT);
  62
+    if(first_result != NULL) 
  63
+    {
  64
+        char * end_of_results = strstr(first_result + sizeof(SEARCH_FIRST_RESULT), SEARCH_LAST_RESULT);
  65
+        if(end_of_results)
  66
+        {
  67
+            char * node = first_result;
  68
+            while((node = strstr(node + sizeof(SEARCH_NODE), SEARCH_NODE))
  69
+                   && continue_search(g_list_length(result_list), capo->s))
  70
+            {
  71
+                char * new_url = get_search_value(node, SEARCH_LINK_START, SEARCH_LINK_END);
  72
+                if(new_url != NULL) 
  73
+                {
  74
+                    char * full_url = g_strdup_printf("www.magistrix.de%s", new_url);
  75
+                    GlyrMemCache * lyrics_page = download_single(full_url, capo->s, NULL);
  76
+                    if(lyrics_page)
  77
+                    {
  78
+                        GlyrMemCache * item = parse_lyric_page(lyrics_page);
  79
+                        if(item != NULL)
  80
+                        {
  81
+                            result_list = g_list_prepend(result_list, item);
  82
+                        }
  83
+                        DL_free(lyrics_page);
  84
+                    }
  85
+                    g_free(new_url);
  86
+                    g_free(full_url);
  87
+                }
  88
+            }
  89
+        }
  90
+    }
  91
+    return result_list;
  92
+}
  93
+
  94
+///////////////////////////////////
  95
+
52 96
 static GList * lyrics_magistrix_parse (cb_object * capo)
53 97
 {
54 98
     GList * result_list = NULL;
@@ -62,6 +106,11 @@ static GList * lyrics_magistrix_parse (cb_object * capo)
62 106
                 result_list = g_list_prepend(result_list,result);
63 107
             }
64 108
         }
  109
+        else
  110
+        {
  111
+            /* Parse Searchresult page */
  112
+            result_list = parse_search_result_page(capo);
  113
+        }
65 114
     }
66 115
     return result_list;
67 116
 }
@@ -76,7 +125,7 @@ MetaDataSource lyrics_magistrix_src =
76 125
     .get_url   = lyrics_magistrix_url,
77 126
     .type      = GLYR_GET_LYRICS,
78 127
     .quality   = 60,
79  
-    .speed     = 70,
  128
+    .speed     = 75,
80 129
     .endmarker = NULL,
81 130
     .free_url  = false
82 131
 };
97  lib/intern/photos/bbcmusic.c
... ...
@@ -0,0 +1,97 @@
  1
+/***********************************************************
  2
+ * This file is part of glyr
  3
+ * + a commnadline tool and library to download various sort of musicrelated metadata.
  4
+ * + Copyright (C) [2011]  [Christopher Pahl]
  5
+ * + Hosted at: https://github.com/sahib/glyr
  6
+ *
  7
+ * glyr is free software: you can redistribute it and/or modify
  8
+ * it under the terms of the GNU General Public License as published by
  9
+ * the Free Software Foundation, either version 3 of the License, or
  10
+ * (at your option) any later version.
  11
+ *
  12
+ * glyr is distributed in the hope that it will be useful,
  13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15
+ * GNU General Public License for more details.
  16
+ *
  17
+ * You should have received a copy of the GNU General Public License
  18
+ * along with glyr. If not, see <http://www.gnu.org/licenses/>.
  19
+ **************************************************************/
  20
+
  21
+#include "../../stringlib.h"
  22
+#include "../../core.h"
  23
+#include "../common/mbid_lookup.h"
  24
+
  25
+#define API_ROOT "http://www.bbc.co.uk/music/artists/%s.xml"
  26
+
  27
+/////////////////////////////////
  28
+
  29
+// TODO: Make this and photos:bbcmusic more general.
  30
+
  31
+#define CONTENT_BEGIN "<image><src>"
  32
+#define CONTENT_ENDIN "</src></image>"
  33
+
  34
+static GlyrMemCache * parse_bbc_xml(GlyrMemCache * input)
  35
+{
  36
+    GlyrMemCache * result = NULL;
  37
+    char * content = get_search_value(input->data, CONTENT_BEGIN, CONTENT_ENDIN);
  38
+    if(content != NULL)
  39
+    {
  40
+        result = DL_init();
  41
+        result->data = content;
  42
+        result->dsrc = g_strdup(input->dsrc);
  43
+        result->size = strlen(content);
  44
+    }
  45
+    return result;
  46
+}
  47
+
  48
+/////////////////////////////////
  49
+
  50
+static const char * photos_bbcmusic_url(GlyrQuery * qry)
  51
+{
  52
+    return "http://musicbrainz.org/ws/2/artist?query=artist:${artist}";
  53
+}
  54
+
  55
+/////////////////////////////////
  56
+
  57
+static GList * photos_bbcmusic_parse(cb_object * capo)
  58
+{
  59
+    GList * result_list = NULL;
  60
+
  61
+    char * mbid = mbid_parse_data(capo->cache, "artist", capo->s->artist, capo->s);
  62
+
  63
+    if(mbid != NULL)
  64
+    {
  65
+        char * full_url = g_strdup_printf(API_ROOT, mbid);
  66
+        if(full_url != NULL)
  67
+        {
  68
+            GlyrMemCache * bbc_xml = download_single(full_url, capo->s, NULL);
  69
+            if(bbc_xml != NULL)
  70
+            {
  71
+                GlyrMemCache * item = parse_bbc_xml(bbc_xml);
  72
+                if(item != NULL)
  73
+                {
  74
+                    result_list = g_list_prepend(result_list, item);
  75
+                }
  76
+            }
  77
+        }
  78
+    }
  79
+
  80
+    return result_list;
  81
+}
  82
+
  83
+/////////////////////////////////
  84
+
  85
+MetaDataSource photos_bbcmusic_src =
  86
+{
  87
+	.name      = "bbcmusic",
  88
+	.key       = 'b',
  89
+	.free_url  = false,
  90
+	.type      = GLYR_GET_ARTIST_PHOTOS,
  91
+	.parser    = photos_bbcmusic_parse,
  92
+	.get_url   = photos_bbcmusic_url,
  93
+	.quality   = 80,
  94
+	.speed     = 60,
  95
+	.endmarker = NULL,
  96
+    .lang_aware = false 
  97
+};
133  lib/intern/review/allmusic_com.c
... ...
@@ -1,133 +0,0 @@
1  
-/***********************************************************
2  
-* This file is part of glyr
3  
-* + a commnadline tool and library to download various sort of musicrelated metadata.
4  
-* + Copyright (C) [2011]  [Christopher Pahl]
5  
-* + Hosted at: https://github.com/sahib/glyr
6  
-*
7  
-* glyr is free software: you can redistribute it and/or modify
8  
-* it under the terms of the GNU General Public License as published by
9  
-* the Free Software Foundation, either version 3 of the License, or
10  
-* (at your option) any later version.
11  
-*
12  
-* glyr is distributed in the hope that it will be useful,
13  
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
14  
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  
-* GNU General Public License for more details.
16  
-*
17  
-* You should have received a copy of the GNU General Public License
18  
-* along with glyr. If not, see <http://www.gnu.org/licenses/>.
19  
-**************************************************************/
20  
-#include "../../stringlib.h"
21  
-#include "../../core.h"
22  
-
23  
-// begin of search results
24  
-#define SEARCH_TREE_BEGIN "<table class=\"search-results\""
25  
-
26  
-// sole search result
27  
-#define SEARCH_NODE "<td><a href=\""
28  
-#define SEARCH_DELM "\">"
29  
-
30  
-// artist
31  
-#define ARTIST_PART "<td>"
32  
-#define ARTIST_END  "</td>"
33  
-
34  
-/*---------------------------------*/
35  
-
36  
-static const gchar * review_allmusic_url(GlyrQuery * s)
37  
-{
38  
-    return "http://www.allmusic.com/search/album/${album}";
39  
-}
40  
-
41  
-#define TEXT_BEGIN "<p class=\"text\">"
42  
-#define TEXT_ENDIN "</p>"
43  
-
44  
-/*---------------------------------*/
45  
-
46  
-static GlyrMemCache * parse_text(GlyrMemCache * to_parse)
47  
-{
48  
-    GlyrMemCache * return_cache = NULL;
49  
-    gchar * text = get_search_value(to_parse->data,TEXT_BEGIN,TEXT_ENDIN);
50  
-
51  
-    if(text != NULL)
52  
-    {
53  
-	    return_cache = DL_init();
54  
-	    return_cache->data = text;
55  
-	    return_cache->size = strlen(text);
56  
-	    return_cache->dsrc = g_strdup(to_parse->dsrc);
57  
-    }
58  
-    return return_cache;
59  
-}
60  
-
61  
-/*---------------------------------*/
62  
-
63  
-#define TITLE_BEGIN  "<a href=\"\">Title</a></th>"
64  
-#define SINGLE_ENDMARK "<div id=\"tracks\">"
65  
-
66  
-static GList * review_allmusic_parse(cb_object * capo)
67  
-{
68  
-	GList * result_list = NULL;
69  
-	if(strstr(capo->cache->data,TITLE_BEGIN) != NULL)
70  
-	{
71  
-		/* We're directly on the start site :-( */
72  
-		GlyrMemCache * result = parse_text(capo->cache);
73  
-		result_list = g_list_prepend(result_list, result);
74  
-		return result_list;
75  
-	}
76  
-
77  
-	gchar * search_begin = NULL;
78  
-	if( (search_begin = strstr(capo->cache->data, SEARCH_TREE_BEGIN)) == NULL)
79  
-	{
80  
-		/* Oh, nothing found :-( */
81  
-		return NULL;
82  
-	}
83  
-
84  
-	gsize nodelen = (sizeof SEARCH_NODE) - 1;
85  
-	gchar *  node = search_begin;
86  
-	while(continue_search(g_list_length(result_list),capo->s) && (node = strstr(node + nodelen,SEARCH_NODE)))
87  
-	{
88  
-		gchar * url = copy_value(node + nodelen,strstr(node,SEARCH_DELM));
89  
-		if(url != NULL)
90  
-		{
91  
-			/* We have the URL - now check the artist to be the one we want */
92  
-			gchar * artist = get_search_value(node + nodelen, ARTIST_PART, ARTIST_END);
93  
-			if(artist != NULL)
94  
-			{
95  
-				if(levenshtein_strnormcmp(capo->s,capo->s->artist,artist) <= capo->s->fuzzyness)
96  
-				{
97  
-					gchar * review_url = g_strdup_printf("%s/review",url);
98  
-					if(review_url != NULL)
99  
-					{
100  
-						GlyrMemCache * dl = download_single(review_url,capo->s,SINGLE_ENDMARK);
101  
-						if(dl != NULL)
102  
-						{
103  
-							GlyrMemCache * result = parse_text(dl);
104  
-							if(result != NULL)
105  
-							{
106  
-								result_list = g_list_prepend(result_list,result);
107  
-							}
108  
-							DL_free(dl);
109  
-						}
110  
-						g_free(review_url);
111  
-					}
112  
-				}
113  
-				g_free(artist);
114  
-			}
115  
-			g_free(url);
116  
-		}
117  
-	}
118  
-	return result_list;
119  
-}
120  
-
121  
-/*--------------------------------------------------------*/
122  
-
123  
-MetaDataSource review_allmusic_src =
124  
-{
125  
-	.name = "allmusic",
126  
-	.key  = 'm',
127  
-	.parser    = review_allmusic_parse,
128  
-	.get_url   = review_allmusic_url,
129  
-	.quality   = 75,
130  
-	.speed     = 40,
131  
-	.free_url  = false,
132  
-	.type      = GLYR_GET_ALBUM_REVIEW
133  
-};
12  lib/register_plugins.c
@@ -51,12 +51,11 @@ extern MetaDataFetcher glyrFetcher_backdrops;
51 51
 
52 52
 
53 53
 /* Externalized sourceprovider vars, add yours here */
54  
-extern MetaDataSource ainfo_allmusic_src;
55 54
 extern MetaDataSource ainfo_lastfm_src;
56 55
 extern MetaDataSource ainfo_lyricsreg_src;
  56
+extern MetaDataSource ainfo_bbcmusic_src;
57 57
 extern MetaDataSource albumlist_musicbrainz_src;
58 58
 extern MetaDataSource cover_albumart_src;
59  
-extern MetaDataSource cover_allmusic_src;
60 59
 extern MetaDataSource cover_amazon_src;
61 60
 extern MetaDataSource cover_coverhunt_src;
62 61
 extern MetaDataSource cover_discogs_src;
@@ -87,8 +86,8 @@ extern MetaDataSource photos_singerpictures_src;
87 86
 extern MetaDataSource photos_discogs_src;
88 87
 extern MetaDataSource photos_rhapsody_src;
89 88
 extern MetaDataSource photos_picsearch_src;
  89
+extern MetaDataSource photos_bbcmusic_src;
90 90
 extern MetaDataSource relations_musicbrainz_src;
91  
-extern MetaDataSource review_allmusic_src;
92 91
 extern MetaDataSource review_amazon_src;
93 92
 extern MetaDataSource review_metallum_src;
94 93
 extern MetaDataSource similar_artist_lastfm_src;
@@ -138,12 +137,11 @@ void plugin_add_to_list(GList ** list, void * data)
138 137
 
139 138
 static void register_provider_plugins(void)
140 139
 {
141  
-    plugin_add_to_list(&glyrMetaDataSourceList,&ainfo_allmusic_src);
142 140
     plugin_add_to_list(&glyrMetaDataSourceList,&ainfo_lastfm_src);
143 141
     plugin_add_to_list(&glyrMetaDataSourceList,&ainfo_lyricsreg_src);
  142
+    plugin_add_to_list(&glyrMetaDataSourceList,&ainfo_bbcmusic_src);
144 143
     plugin_add_to_list(&glyrMetaDataSourceList,&albumlist_musicbrainz_src);
145 144
     plugin_add_to_list(&glyrMetaDataSourceList,&cover_albumart_src);
146  
-    plugin_add_to_list(&glyrMetaDataSourceList,&cover_allmusic_src);
147 145
 
148 146
     // FIXME: Silly amazon requires to be a Seller to use their API
149 147
     // WTF?! God I hate thos Just-for-the-paying-people-salesmen dudes
@@ -176,7 +174,7 @@ static void register_provider_plugins(void)
176 174
     // FIXME: Chartlyrics reacts very slowly, and often not at all
177 175
     // add again when running again ( :( - good api though)    
178 176
     // 28.1.2012: Seems to be on again, API fails too often though still.
179  
-    // plugin_add_to_list(&glyrMetaDataSourceList,&lyrics_chartlyrics_src);
  177
+    plugin_add_to_list(&glyrMetaDataSourceList,&lyrics_chartlyrics_src);
180 178
     plugin_add_to_list(&glyrMetaDataSourceList,&photos_flickr_src);
181 179
     plugin_add_to_list(&glyrMetaDataSourceList,&photos_google_src);
182 180
     plugin_add_to_list(&glyrMetaDataSourceList,&photos_lastfm_src);
@@ -184,8 +182,8 @@ static void register_provider_plugins(void)
184 182
     plugin_add_to_list(&glyrMetaDataSourceList,&photos_singerpictures_src);
185 183
     plugin_add_to_list(&glyrMetaDataSourceList,&photos_rhapsody_src);
186 184
     plugin_add_to_list(&glyrMetaDataSourceList,&photos_picsearch_src);
  185
+    plugin_add_to_list(&glyrMetaDataSourceList,&photos_bbcmusic_src);
187 186
     plugin_add_to_list(&glyrMetaDataSourceList,&relations_musicbrainz_src);
188  
-    plugin_add_to_list(&glyrMetaDataSourceList,&review_allmusic_src);
189 187
 
190 188
     // FIXME: Silly amazon requires to be a Seller to use their API
191 189
     // WTF?! God I hate thos Just-for-the-paying people-salesmen
6  spec/provider/current.txt
@@ -12,7 +12,7 @@ Running: tests.similarsongs :
12 12
 .--------------+-------------+-----------+----------------------------.
13 13
 | O/P          | Equilibrium | In Flames | The band they called Horse |
14 14
 +--------------+-------------+-----------+----------------------------+
15  
-| lastfm       | X           | X         | Y                          |
  15
+| lastfm       | Y           | Y         | Y                          |
16 16
 '--------------+-------------+-----------+----------------------------'
17 17
 
18 18
 
@@ -31,7 +31,7 @@ Running: tests.lyrics :
31 31
 | O/P          | Die Apokalyptischen Reiter | The band they called Horse | Lady Gaga | Knorkator | In Flames | Excrementory Grindfuckers | Amy Whitehouse | Equilibrium | Annihilator |
32 32
 +--------------+----------------------------+----------------------------+-----------+-----------+-----------+---------------------------+----------------+-------------+-------------+
33 33
 | metrolyrics  | Y                          | Y                          | #         | #         | #         | #                         | #              | #           | #           |
34  
-| magistrix    | #                          | Y                          | X         | Y         | #         | #                         | #              | #           | #           |
  34
+| magistrix    | #                          | Y                          | Y         | Y         | #         | #                         | #              | #           | #           |
35 35
 | lyrdb        | #                          | Y                          | #         | #         | #         | #                         | #              | #           | #           |
36 36
 | lipwalk      | #                          | Y                          | #         | Y         | Y         | #                         | #              | #           | #           |
37 37
 | lyricswiki   | #                          | Y                          | #         | #         | #         | Y                         | #              | #           | #           |
@@ -121,7 +121,7 @@ Running: tests.albumlist :
121 121
 .--------------+----------------------+-------------.
122 122
 | O/P          | Benele Banga Baracka | Equilibrium |
123 123
 +--------------+----------------------+-------------+
124  
-| musicbrainz  | Y                    | X           |
  124
+| musicbrainz  | Y                    | Y           |
125 125
 '--------------+----------------------+-------------'
126 126
 
127 127
 
4  spec/provider/executor.py
@@ -63,7 +63,9 @@ def test_by_dictionary(testcases, includes=[], colored=True):
63 63
     # Wait for all of them to join, and remove them eventually.
64 64
     for thread in THREAD_LIST:
65 65
         thread.join()
66  
-        THREAD_LIST.remove(thread)
  66
+
  67
+    # Make sure to be reentrant
  68
+    THREAD_LIST = []
67 69
 
68 70
     # Render the table
69 71
     block = canvas.draw()
4  spec/provider/tests/albumlist.py
@@ -11,9 +11,9 @@
11 11
         'options': {
12 12
             'get_type': 'albumlist',
13 13
             'artist': 'Equilibrium',
14  
-            'number': 13
  14
+            'number': 4
15 15
             },
16  
-        'expect': lambda r: len(r) == 13
  16
+        'expect': lambda r: len(r) == 4
17 17
         }, {
18 18
         'options':  {
19 19
             'get_type': 'tracklist',
15  spec/provider/tests/albumreview.py
@@ -11,21 +11,6 @@
11 11
 
12 12
 TESTCASES = [{
13 13
     # {{{
14  
-    'name': 'allmusic',
15  
-    'data': [{
16  
-        'options': {
17  
-            'get_type': 'albumreview',
18  
-            'artist': '36 Crazyfists',
19  
-            'album': 'Rest Inside the Flames'
20  
-            },
21  
-        'expect': len_greater_0
22  
-        }, {
23  
-        'options': not_found_options,
24  
-        'expect': len_equal_0
25  
-        }],
26  
-    }, {
27  
-    # }}}
28  
-    # {{{
29 14
     'name': 'metallum',
30 15
     'data': [{
31 16
         'options': {
56  spec/provider/tests/artistbio.py
... ...
@@ -0,0 +1,56 @@
  1
+#!/usr/bin/env python
  2
+# encoding: utf-8
  3
+
  4
+from tests.__common__ import *
  5
+
  6
+not_found_options = {
  7
+        'get_type': 'artistbio',
  8
+        'artist': 'The band they called Horse',
  9
+        'album': 'The album you all know.'
  10
+        }
  11
+
  12
+TESTCASES = [{
  13
+    # {{{
  14
+    'name': 'lastfm',
  15
+    'data': [{
  16
+        'options': {
  17
+            'get_type': 'artistbio',
  18
+            'artist': 'Die Ärzte',
  19
+            'language': 'de'
  20
+            },
  21
+        'expect': lambda r: len(r) == 1 and r[0].size > 35000
  22
+        }, {
  23
+        'options': not_found_options,
  24
+        'expect': len_equal_0
  25
+        }],
  26
+    }, {
  27
+    # }}}
  28
+    # {{{
  29
+    'name': 'lyricsreg',
  30
+    'data': [{
  31
+        'options': {
  32
+            'get_type': 'artistbio',
  33
+            'artist': 'Adele'
  34
+            },
  35
+        'expect': lambda r: len(r) == 1 and r[0].size > 1000
  36
+        }, {
  37
+        'options': not_found_options,
  38
+        'expect': len_equal_0
  39
+        }],
  40
+    }, {
  41
+    # }}}
  42
+    # {{{
  43
+    'name': 'bbcmusic',
  44
+    'data': [{
  45
+        'options': {
  46
+            'get_type': 'artistbio',
  47
+            'artist': 'The Rolling Stones'
  48
+            },
  49
+        'expect': lambda r: len(r) == 1 and r[0].size > 1500
  50
+        }, {
  51
+        'options': not_found_options,
  52
+        'expect': len_equal_0
  53
+        }],
  54
+    }
  55
+    # }}}
  56
+]
14  spec/provider/tests/artistphoto.py
@@ -12,6 +12,20 @@
12 12
 
13 13
 TESTCASES = [{
14 14
     # {{{
  15
+    'name': 'bbcmusic',
  16
+    'data': [{
  17
+        'options': {
  18
+            'get_type': 'artistphoto',
  19
+            'artist': 'The Rolling Stones'
  20
+            },
  21
+        'expect': len_greater_0
  22
+        }, {
  23
+        'options': not_found_options,
  24
+        'expect': len_equal_0
  25
+        }],
  26
+    }, {
  27
+    # }}}
  28
+    # {{{
15 29
     'name': 'discogs',
16 30
     'data': [{
17 31
         'options': {
15  spec/provider/tests/cover.py
@@ -43,21 +43,6 @@
43 43
     }, {
44 44
     # }}}
45 45
     # {{{
46  
-    'name': 'allmusic',
47  
-    'data': [{
48  
-        'options': {
49  
-            'get_type': 'cover',
50  
-            'artist': 'Adele',
51  
-            'album': '19',
52  
-            },
53  
-        'expect': len_greater_0
54  
-        }, {
55  
-        'options': not_found_options,
56  
-        'expect': len_equal_0
57  
-        }]
58  
-    }, {
59  
-    # }}}
60  
-    # {{{
61 46
     'name': 'discogs',
62 47
     'data': [{
63 48
         'options': {
6  spec/provider/tests/similarsongs.py
@@ -6,7 +6,7 @@
6 6
 not_found_options = {
7 7
         'get_type': 'similarsongs',
8 8
         'artist': 'The band they called Horse',
9  
-        'album': 'The album you all know.'
  9
+        'title': 'The album you all know.'
10 10
         }
11 11
 
12 12
 TESTCASES = [{
@@ -16,14 +16,14 @@
16