gloss-mc/modules/music_player/lastFM_interface.py

108 lines
4.4 KiB
Python

import urllib
import xml
from xml.dom import minidom
import pygtk
import gtk
import gobject
from itertools import izip, repeat, chain
class lastFM_interface:
lastFM_base_xml_uri = "http://ws.audioscrobbler.com/1.0/"
lastFM_artist_xml_uri = lastFM_base_xml_uri + "artist/"
lastFM_album_xml_uri = lastFM_base_xml_uri + "album/"
lastFM_track_xml_uri = lastFM_base_xml_uri + "track/"
#Maximum size of images returned
#If images are larger than this, they will be downloaded and resized
max_image_width = 800
max_image_height = 600
def __init__(self):
pass
#Returns a pixbuf with an image of the specified artist
#Returns None if it is unable to get an image
def get_artist_image(self, artist):
artist_clean = artist.replace(" ", "+")
artist_clean = artist_clean.replace("/", "+")
similar_uri = self.lastFM_artist_xml_uri + artist_clean +"/similar.xml"
filehandle = urllib.urlopen(similar_uri)
#We only need the first 2 lines of this file
xml_string = ""
for x in range(2):
xml_string += filehandle.readline()
filehandle.close()
#Check to see if the artist name was found
error_string = "No artist exists with this name"
#print "Error String: " + error_string
#print "XML: " + xml
if xml_string[0:len(error_string)] == error_string:
return None
#We make a little manual change to the url, so that we get a bigger pic off last.FM rather than the 160x160 one
#xml_string = xml_string.replace("/160/", "/_/") #Force use this to get BIG images
xml_string = xml_string.replace("/160/", "/500/") #Attempt to use the 500 size image
#Because we only read in 2 lines, we need to manually close the block
xml_string += "</similarartists>"
try:
dom = minidom.parseString(xml_string)
element = dom.getElementsByTagName("similarartists")[0]
pic_url = element.getAttribute("picture")
except xml.parsers.expat.ExpatError, e:
print "LastFM Error: Could not parse XML '%s'" % (xml_string)
print "LastFM Error: URI Attempted '%s'" % (similar_uri)
return None
#We do a check to see if a 500 size image exists
#If not, fall back onto the _ size image (ie the Biggest Last.fm has)
img_handle = urllib.urlopen(pic_url)
img_size = int(img_handle.info().getheader("Content-Length"))
if img_size == 0:
pic_url = pic_url.replace("/500/", "/_/")
img_handle.close()
return self.get_pixbuf_from_url(pic_url)
def get_pixbuf_from_url(self, pic_url):
chunk_size = 32768
img_handle = urllib.urlopen(pic_url)
img_size = int(img_handle.info().getheader("Content-Length"))
img_data = img_handle.read(img_size)
img_handle.close()
#print pic_url
#print "Img Size: " + str(img_size)
#print "Read size: " + str(len(img_data))
loader = gtk.gdk.PixbufLoader()
try:
#This is a nasty hack to get over GDK Bug: http://bugzilla.gnome.org/show_bug.cgi?id=494667
for chunk in izip(*[chain(img_data, repeat('', chunk_size-1))] * chunk_size):
loader.write(''.join(chunk))
loader.close()
except gobject.GError, e:
print "Last.FM: '%s'" % (e)
#print "Last.FM: Received invalid image file: '%s' " % (pic_url)
pixbuf = loader.get_pixbuf()
#If the image is larger than our maximum size, shrink it down
#This should _generally_ not be needed, but will be used whenver last.fm returns a very large image by mistake
if pixbuf.get_width() > self.max_image_width:
yx_ratio = float(pixbuf.get_height()) / float(pixbuf.get_width())
height = int(self.max_image_width * yx_ratio)
pixbuf = pixbuf.scale_simple(self.max_image_width, height, gtk.gdk.INTERP_HYPER)
elif pixbuf.get_height() > self.max_image_height:
xy_ratio = float(pixbuf.get_width()) / float(pixbuf.get_height())
width = int(self.max_image_height * xy_ratio)
pixbuf = pixbuf.scale_simple(width, self.max_image_height, gtk.gdk.INTERP_HYPER)
return pixbuf