- Significant work on Last.fm code
This commit is contained in:
parent
b6cf313598
commit
2331c612b0
|
@ -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()
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
"""
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue