1 #!/usr/bin/env python2.5
3 from utils import UrllibWrapper
9 LASTFM_APIKEY = "1e1d53528c86406757a6887addef0ace"
10 BASE_LASTFM = "http://ws.audioscrobbler.com/2.0/?method=album.getinfo"
13 BASE_MSN = "http://www.bing.com/images/search?q="
14 MSN_MEDIUM = "+filterui:imagesize-medium"
15 MSN_SMALL = "+filterui:imagesize-medium"
16 MSN_SQUARE = "+filterui:aspect-square"
17 MSN_PHOTO = "+filterui:photo-graphics"
19 CACHE_LOCATION = os.path.join (os.getenv ("HOME"), ".cache", "mussorgsky")
21 # http://www.lastfm.es/api/show?service=290
26 class AADownloadThread (threading.Thread):
28 def __init__ (self, url, artist, album, counter):
29 threading.Thread.__init__ (self, target=self.grab_image, args=(url,))
30 self.counter = counter
31 self.artistName = artist.replace (" ", "_")
32 self.albumName = album.replace (" ", "_")
33 self.image_path = None
34 self.urllib_wrapper = UrllibWrapper ()
36 def grab_image (self, image_url):
37 print "Working", self.counter
38 image = self.urllib_wrapper.get_url (image_url)
40 self.image_path = os.path.join (CACHE_LOCATION, self.artistName + self.albumName + str(self.counter))
41 self.urllib_wrapper.save_content_into_file (image, self.image_path)
43 def get_result (self):
44 return self.image_path
48 class MussorgskyAlbumArt:
51 bus = dbus.SessionBus ()
53 if (not os.path.exists (CACHE_LOCATION)):
54 os.makedirs (CACHE_LOCATION)
56 self.urllib_wrapper = UrllibWrapper ()
58 def get_possible_url (self, artist, album, amount=4):
59 results_page = self.__msn_images (artist, album)
60 return self.__get_url_from_msn_results_page (results_page)
63 def get_album_art (self, albumItem, force=False):
65 Save the first available result as the albumart for that item
67 filename = albumItem.get_aa().get_media_art_path ()
68 if (os.path.exists (filename) and not force):
69 print "Album art already there " + filename
72 results_page = self.__msn_images (albumItem.artist, albumItem.title)
73 for online_resource in self.__get_url_from_msn_results_page (results_page):
74 print "Trying:", online_resource
75 content = self.urllib_wrapper.get_url (online_resource)
77 print "Saved on: %s " % (filename)
78 self.urllib_wrapper.save_content_into_file (content, filename)
79 albumItem.album_art = filename
82 def get_alternatives (self, artist, album, max_alternatives=4):
84 return a list of images in the local disk
86 results_page = self.__msn_images (artist, album)
87 return self.__process_results_page (results_page, artist, album, max_alternatives)
89 def get_alternatives_free_text (self, search_text, max_alternatives=4):
90 results_page = self.__msn_images_free_text (search_text)
91 return self.__process_results_page (results_page, max_alternatives)
93 def __process_results_page (self, results_page, artist, album, max_alternatives):
96 for image_url in self.__get_url_from_msn_results_page (results_page):
98 # Some searches doesn't return anything at all!
101 if (counter >= max_alternatives):
104 t = AADownloadThread (image_url, artist, album, counter)
114 yield t.get_result ()
117 def save_alternative (self, artist, album, img_path, thumb_path):
119 This is done now in the controller
121 if not os.path.exists (img_path) or not os.path.exists (thumb_path):
122 print "**** CRITICAL **** image in path", path, "doesn't exist!"
125 filename = getCoverArtFileName (album)
126 thumbnail = getCoverArtThumbFileName (album)
128 os.rename (img_path, filename)
129 os.rename (thumb_path, thumbnail)
131 return (filename, thumbnail)
133 def reset_alternative (self, artist, album):
135 for filepath in [getCoverArtFileName (album),
136 getCoverArtThumbFileName (album)]:
137 if os.path.exists (filepath):
140 def __msn_images (self, artist, album):
142 good_artist = self.__clean_string_for_search (artist)
143 good_album = self.__clean_string_for_search (album)
145 if (good_album and good_artist):
146 full_try = BASE_MSN + good_album + "+" + good_artist + MSN_MEDIUM + MSN_SQUARE
147 print "Searching (album + artist): %s" % (full_try)
148 result = self.urllib_wrapper.get_url (full_try)
149 if (result and result.find ("no_results") == -1):
153 if (album.lower ().find ("greatest hit") != -1):
154 print "Ignoring '%s': too generic" % (album)
157 album_try = BASE_MSN + good_album + MSN_MEDIUM + MSN_SQUARE
158 print "Searching (album): %s" % (album_try)
159 result = self.urllib_wrapper.get_url (album_try)
160 if (result and result.find ("no_results") == -1):
164 artist_try = BASE_MSN + good_artist + "+CD+music" + MSN_SMALL + MSN_SQUARE + MSN_PHOTO
165 print "Searching (artist CD): %s" % (artist_try)
166 result = self.urllib_wrapper.get_url (artist_try)
167 if (result and result.find ("no_results") == -1):
172 def __msn_images_free_text (self, search_text):
173 full_try = BASE_MSN + self.__clean_string_for_search (search_text) + MSN_MEDIUM + MSN_SQUARE
174 result = self.urllib_wrapper.get_url (full_try)
178 def __get_url_from_msn_results_page (self, page):
182 current_option = None
185 # 500 is just a safe limit
186 for i in range (0, 500):
187 # Iterate until find a jpeg
188 start = page.find ("imgurl:"", starting_at)
191 end = page.find ("&", start + len ("imgurl:""))
192 current_option = page [start + len ("imgurl:""): end].replace ("amp;", "")
193 if (current_option.lower().endswith (".jpg") or
194 current_option.lower().endswith (".jpeg")):
199 def __clean_string_for_search (self, text):
200 if (not text or len (text) < 1):
203 bad_stuff = "_:?\\-~"
206 clean = clean.replace (c, " ")
208 clean.replace ("/", "%2F")
209 clean = clean.replace (" CD1", "").replace(" CD2", "")
210 return urllib.quote(clean)
213 if __name__ == "__main__":
215 from optparse import OptionParser
217 parser = OptionParser()
218 parser.add_option ("-p", "--print", dest="print_paths",
219 action="store_true", default=True,
220 help="Print the destination paths")
221 parser.add_option ("-r", "--retrieve", dest="retrieve",
222 action="store_true", default=False,
223 help="Try to retrieve the online content")
224 parser.add_option ("-m", "--multiple", dest="multiple",
225 action="store_true", default=False,
226 help="Show more than one option")
227 parser.add_option ("-a", "--artist", dest="artist", type="string",
228 help="ARTIST to look for", metavar="ARTIST")
229 parser.add_option ("-b", "--album", dest="album", type="string",
230 help="ALBUM to look for", metavar="ALBUM")
232 (options, args) = parser.parse_args ()
234 if (not options.artist and not options.album):
238 if (options.multiple and options.retrieve):
239 print "Multiple and retrieve are incompatible"
243 if options.print_paths and not options.retrieve:
244 print "Album art:", getCoverArtFileName (options.album)
245 print "Thumbnail:", getCoverArtThumbFileName (options.album)
248 maa = MussorgskyAlbumArt ()
249 maa.get_album_art (options.artist, options.album)
253 maa = MussorgskyAlbumArt ()
254 for (img, thumb) in maa.get_alternatives (options.artist, options.album, 5):