- Significant work on Last.fm code

This commit is contained in:
noisymime 2008-03-07 13:06:44 +00:00
parent b6cf313598
commit 2331c612b0
5 changed files with 162 additions and 66 deletions

View File

@ -1,4 +1,5 @@
import urllib
import xml
from xml.dom import minidom
import pygtk
import gtk
@ -20,34 +21,43 @@ class lastFM_interface:
filehandle = urllib.urlopen(similar_uri)
#We only need the first 2 lines of this file
xml = ""
xml_string = ""
for x in range(2):
xml += filehandle.readline()
xml_string += filehandle.readline()
filehandle.close()
#Check to see if the artist name was found
error_string = "No artist exists with this name: '%s'" % artist
error_string = "No artist exists with this name"
#print "Error String: " + error_string
#print "XML: " + xml
if xml == error_string:
if xml_string[0:len(error_string)] == error_string:
return None
#We make a little manual change to the url, so that we get the BIG pic off last.FM rather than the 160x160 one
xml_string = xml_string.replace("/160/", "/_/")
#Because we only read in 2 lines, we need to manually close the block
xml += "</similarartists>"
dom = minidom.parseString(xml)
element = dom.getElementsByTagName("similarartists")[0]
pic_url = element.getAttribute("picture")
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)
return None
return self.get_pixbuf_from_url(pic_url)
def get_pixbuf_from_url(self, pic_url):
print pic_url
img_handle = urllib.urlopen(pic_url)
img_data = img_handle.read()
img_handle.close()
loader = gtk.gdk.PixbufLoader()
loader.write(img_data)
loader.close()
#loader.close()
return loader.get_pixbuf()

View File

@ -1,31 +1,84 @@
import pygtk
import gtk
import gobject
import os
class album:
artistID, name, image = None
class artist:
artistID = None
name = None
image = None
def __init__(self, music_player):
self.music_player = music_player
def import_from_mythObject(self, mythObject):
try:
self.artistID = mythObject[0]['artist_id']
#self.artistID = mythObject['artist_id']
#self.name = mythObject['artist_name']
#self.image = mythObject['artist_image']
self.artistID = mythObject[0]
self.name = mythObject[1]
self.image = mythObject[2]
if self.image is None: self.image = "unset"
except IndexError, e:
print "Music_Player: Found difference in DB structure for artists. Attempting to continue."
def insert_into_db(self):
if self.image is None:
sql = "ALTER TABLE music_artists ADD image TEXT AFTER artist_name;"
def update_db(self):
print "Music_Player: Looks like this is the first time the Music Player has been started. Attempting to upgrade DB"
sql = "ALTER TABLE music_artists ADD artist_image TEXT AFTER artist_name;"
self.music_player.dbMgr.run_sql(sql)
print "Music_Player: DB Upgrade completed"
def get_image(self):
if not self.image is None:
return gtk.gdk.pixbuf_new_from_file(self.image)
#If image is still equal to None it means that the artist_image column did not exist in the db, we should create it.
if self.image is None:
self.update_db()
self.image = "unset"
#If there was something in self.image, means we've probably already got a pic
if not self.image == "unset":
filename = self.music_player.images_dir + "artists/" + self.image
try:
pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
except gobject.GError, e:
print "Music_Player: Attempted to open file '%s', but it does not exist" % (filename)
return
return pixbuf
#If self.image is a eqaul to 'unset', means the column exists but that the image entry is blank, we should try to find one
else:
return self.get_image_from_lastFM()
pixbuf = self.get_image_from_lastFM()
if not pixbuf is None: self.save_image(pixbuf)
return pixbuf
def get_image_from_lastFM(self):
return self.music_player.lastFM
pixbuf = self.music_player.lastFM.get_artist_image(self.name)
return pixbuf
#Saves an image (pixbuf) to file and updates the Myth db
def save_image(self, pixbuf):
base_dir = self.music_player.images_dir + "artists/"
#Check to make sure the above directory exists
if not os.path.isdir(base_dir):
try:
os.makedirs(base_dir, int('777',8))
except OSError:
print "Music Player Error: Unable to write to music directory '%s'" % (base_dir)
return
self.name = self.name.replace("'","")
filename = base_dir + self.name + ".png"
try:
pixbuf.save(filename, "png")
except gobject.GError:
print "Music_Player: Permission denied trying to save '%s'" % (filename)
return
#Now insert an entry into the db for this
filename_short = self.name + ".png"
sql = "UPDATE music_artists SET artist_image = '%s' WHERE artist_id = '%s'" % (filename_short, self.artistID)
self.music_player.dbMgr.run_sql(sql)

View File

@ -2,6 +2,8 @@ import pygtk
import gtk
import clutter
from modules.music_player.music_objects.song import song
from modules.music_player.music_objects.artist import artist
from modules.music_player.music_objects.album import album
from modules.music_player.lastFM_interface import lastFM_interface
from ui_elements.image_row import ImageRow
@ -14,20 +16,38 @@ class Module():
self.dbMgr = dbMgr
self.setup_ui()
self.albums = []
self.artists = []
self.songs = []
self.imageRow = ImageRow(self.glossMgr, self.stage.get_width(), 100, 10)
self.lastFM = lastFM_interface()
self.base_dir = self.dbMgr.get_setting("MusicLocation")
self.images_dir = self.get_images_dir()
print "Music Base Dir: " + self.base_dir
self.is_playing = False
self.load_albums()
#self.load_albums()
self.load_artists()
self.lastFM = lastFM_interface()
#lastFM.get_artist_image("Jason Marazdsgds")
def setup_ui(self):
self.menu_image = self.glossMgr.themeMgr.get_texture("music_menu_image", None, None)
#Get the images dir setting our of the DB
#But also creates the setting if it doesn't already exist
def get_images_dir(self):
images_dir = self.dbMgr.get_setting("GlossMusicImgLocation")
if images_dir is None:
#We need to create the setting
#Default value is the same as the music base_dir + covers
images_dir = self.base_dir + "/.images/"
images_dir = images_dir.replace("//", "/") #Just a silly little check
self.dbMgr.set_setting("GlossMusicImgLocation", images_dir)
return images_dir
#Action to take when menu item is selected
def action(self):
return self
@ -56,8 +76,16 @@ class Module():
self.backdrop_behaviour.apply(self.backdrop)
timeline_backdrop.start()
self.stage.add(self.tmpImage)
self.tmpImage.show()
for artist in self.artists:
pixbuf = artist.get_image()
if not pixbuf is None:
tmpImage = clutter.Texture()
tmpImage.set_pixbuf(pixbuf)
self.imageRow.add_texture_group(tmpImage)
self.stage.add(self.imageRow)
self.imageRow.show()
def stop(self):
pass
@ -69,41 +97,9 @@ class Module():
pass
def load_albums(self):
"""
if not os.path.isdir(dirPath):
print "ERROR VideoPlayer: Invalid video path"
return None
final_file_list = []
new_file_list = os.listdir(dirPath)
#Videos and Directories
for dir_entry in new_file_list:
if os.path.isdir(dirPath + "/" + dir_entry) and not ( dir_entry[0] == "."):
cover_viewer.add_folder(dir_entry)
#print dir_entry
else:
final_file_list.append(dir_entry)
#Check if we're empty
if len(final_file_list) == 0:
return
#Make sure the dirPath ends in "/"
if not dirPath[-1] == "/":
dirPath = dirPath + "/"
"""
#Generate some SQL to retrieve videos that were in the final_file_list
#Load the videos into the cover viewer
sql = "SELECT * FROM music_songs" # WHERE filename IN ("
"""
for filename in final_file_list:
filename = dirPath + filename
sql = sql + "\"" + filename + "\", "
sqlLength = int(len(sql) - 2)
sql = sql[:sqlLength]
sql = sql + ")"
"""
if self.glossMgr.debug: print "Music SQL: " + sql
results = self.dbMgr.run_sql(sql)
@ -135,4 +131,35 @@ class Module():
self.tmpImage = clutter.Texture()
self.tmpImage.set_pixbuf(pixbuf)
def load_artists(self):
#Generate some SQL to retrieve videos that were in the final_file_list
#Load the videos into the cover viewer
sql = "SELECT * FROM music_artists" # WHERE filename IN ("
if self.glossMgr.debug: print "Music Artist SQL: " + sql
results = self.dbMgr.run_sql(sql)
#Check for null return
if results == None:
print "MusicPlayer: No connection to DB or no artists found in DB"
return None
pixbuf = None
#Else add the entries in
for record in results:
tempArtist = artist(self)
tempArtist.import_from_mythObject(record)
self.artists.append(tempArtist)
"""
if not tempArtist.get_image()is None:
pixbuf = tempArtist.get_image()
break
"""
#print filename
#tempSong.set_file(filename)
"""
if not pixbuf is None:
self.tmpImage = clutter.Texture()
self.tmpImage.set_pixbuf(pixbuf)
"""

View File

@ -78,7 +78,14 @@ class mythDB():
# get the resultset as a tuple
return data[0][1]
def set_setting(self, setting, value):
if not self.connected:
print "Error: Could not establish connection to SQL server. Unable to obtain setting '" + setting_name + "'"
return None
sql = "INSERT INTO settings VALUES('%s', '%s', '%s')" % (setting, value, self.localHost)
self.cursor.execute(sql)
#Gets the backend server details, which, in theory, can be different from the SQL server details and/or default port
def get_backend_server(self):

View File

@ -27,7 +27,6 @@ class ImageRow(clutter.Group):
self.images_width = int(width * self.images_size_percent)
self.images_height = int(height * self.images_size_percent)
self.num_visible_rows = rows
self.num_columns = columns
self.image_size = int(self.images_width / self.num_columns) #A cover will be cover_size * cover_size (X * Y)
@ -40,7 +39,7 @@ class ImageRow(clutter.Group):
#And setup the clip size and position
scale_amount = int(self.image_size * self.scaleFactor - self.image_size)
clip_width = (self.image_size*columns) + scale_amount #Width is the cover size by the number of colums, plus the additional amount required for scaling
clip_height = (self.image_size*rows) + scale_amount
clip_height = (height) + scale_amount
self.images_group_clip.set_clip(-(scale_amount/2), -(scale_amount/2), clip_width, clip_height)
@ -57,13 +56,13 @@ class ImageRow(clutter.Group):
#Setup the current min and max viewable rows
self.min_visible_columns = 0
self.max_visible_columns = self.num_visible_columns
self.max_visible_columns = columns
self.currentSelection = 0
self.add(self.images_group_clip)
covers_x = int(width * (1-self.covers_size_percent)/2)
covers_y = int(height * (1-self.covers_size_percent)/2)
covers_x = int(width * (1-self.images_size_percent)/2)
covers_y = int(height * (1-self.images_size_percent)/2)
#self.images_group.set_position(covers_x, covers_y)
#self.images_group.set_depth(1) #self.image_size)
self.images_group.show()
@ -78,19 +77,19 @@ class ImageRow(clutter.Group):
self.textureLibrary.append(tempGroup)
x = self.num_covers * self.image_size + ( self.num_covers * self.cover_gap)
x = self.num_images * self.image_size + ( self.num_images * self.image_gap)
y = 0#(self.cover_gap + self.image_size) * (self.num_covers/self.num_columns)
tempGroup.set_position(x, y)
#If we're past the maximum rows, make the pics invistible
if self.num_covers > (self.num_columns * self.num_visible_rows)-1:
if self.num_images > (self.num_columns-1):
tempGroup.set_opacity(0)
else:
self.images_group.add(tempGroup)
tempGroup.show()
self.num_covers = self.num_covers +1
self.num_images += 1
def select_item(self, incomingItem, outgoingItem):