From 0bf69cb3e3ea33e78e98663af1060d9f88c1283b Mon Sep 17 00:00:00 2001 From: bjschuma Date: Wed, 1 Jul 2009 13:41:33 +0000 Subject: [PATCH] New icon (thanks Andrew), began last.fm code git-svn-id: file:///home/anna/Desktop/ocarina-legacy/mithos/ocarina@40 1daee41c-8060-4895-b1f0-2197c00d777a --- trunk/images/ocarina.png | Bin 2173 -> 4089 bytes trunk/src/GuiObjects/controlPanel.py | 3 +- trunk/src/GuiObjects/infoView.py | 2 +- trunk/src/GuiObjects/plistView.py | 55 +++++++++++++++++---------- trunk/src/GuiObjects/scrobbler.py | 53 ++++++++++++++++++++++++++ trunk/src/ocarina.py | 3 +- trunk/src/saveddata.py | 1 + trunk/src/song.py | 22 +++-------- trunk/src/window.py | 21 ++++++++-- 9 files changed, 115 insertions(+), 45 deletions(-) create mode 100644 trunk/src/GuiObjects/scrobbler.py diff --git a/trunk/images/ocarina.png b/trunk/images/ocarina.png index 7835d24c50e34d50768d167c6190082534e122ff..e8ec887912b5637cf9b6958fefd56a7c8409d5cd 100644 GIT binary patch delta 4074 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 0: self.data.curSong = self.qlist[0][0] self.data.curQ.pop(self.data.curQ.index(self.data.curSong)) + self.qtime -= self.data.library.files[self.data.curSong].duration + self.changedTab(None,None,1) self.qlist.remove(self.qlist.get_iter(0)) self.data.playingQ = True self.setTabText("queue") @@ -208,7 +209,6 @@ class PlistView(gtk.Notebook): self.data.curSong = random.randint(0,len(self.data.curList)) else: next = self.plist[0][0] - #self.data.curSong = self.plist[0][0] for i in range(len(self.plist)-1): if self.plist[i][0]==self.data.curSong: next = self.plist[i+1][0] @@ -216,9 +216,13 @@ class PlistView(gtk.Notebook): self.data.curSong = next if self.data.curSong >= len(self.data.curList): self.data.curSong = 0 + self.loadSong(True) - if not((self.data.song.playing==False) ^ (self.status==PAFTER)): + pause = (self.status == PAFTER) + + if pause == False: self.controls.plause(None,None) + self.controls.changeImg() self.status = CONTINUE @@ -228,7 +232,7 @@ class PlistView(gtk.Notebook): return if self.data.song: self.data.song.close() - self.data.song.passInfo(self.data.library.files[self.data.curSong]) + self.data.song = Song(self.data.library.files[self.data.curSong],self.next) if scroll == True: self.gotoCurSong() @@ -246,17 +250,26 @@ class PlistView(gtk.Notebook): self.ptreesel.select_path(i) - - + # A callback to show the right click menu def clicked(self,widget,data): if data.button == 3: self.prcmenu.popup(None,None,None,data.button,data.time) + # Called when songs are queued def enqueue(self,widgit,func,data): (model,pathlist) = self.ptreesel.get_selected_rows() for path in pathlist: q = self.plist[path] self.data.curQ+=[q[0]] self.qlist.append([q[0],q[1],q[2],q[3],q[4],q[5]]) + self.qtime+=self.data.library.files[q[0]].duration self.setTabText("queue") + + + # Update the total time label when a tab is changed + def changedTab(self,widgit,page,pagenum): + if pagenum == 0: + self.label.set_text(self.makeTimeLabel(self.ptime)) + else: + self.label.set_text(self.makeTimeLabel(self.qtime)) diff --git a/trunk/src/GuiObjects/scrobbler.py b/trunk/src/GuiObjects/scrobbler.py new file mode 100644 index 00000000..fbaf6bab --- /dev/null +++ b/trunk/src/GuiObjects/scrobbler.py @@ -0,0 +1,53 @@ +import urllib2 +import pygtk +pygtk.require('2.0') +import gtk +import webbrowser +import thread + +import xml.dom +from xml.dom import minidom + + +class Scrobbler(gtk.VBox): + def __init__(self,data): + gtk.VBox.__init__(self,False,0) + self.data = data + self.url = "http://ws.audioscrobbler.com/2.0/" + self.key = "api_key=2c76f85a6704efd74b5a358821284ef9" + self.token = "token=" + + # Run these in new thread so we can keep loading other things while waiting + thread.start_new_thread(self.setup,("setup",None)) + #self.fetchToken() + #self.authorize() + + #self.makeRequest() + self.show() + + + def setup(self,widgit,data): + self.fetchToken() + self.authorize() + + + def addMethod(self,method): + return self.url+"?method="+method + + def authorize(self): + url = "http://www.last.fm/api/auth/?" + url+=self.key+"&"+self.token + webbrowser.open(url) + + + def fetchToken(self): + url = self.addMethod("auth.gettoken")+"&"+self.key + req = urllib2.Request(url) + req.add_header('User-Agent','Ocarina') + status = minidom.parse(urllib2.urlopen(req)).documentElement + + attr = status.getAttributeNode("status") + if attr.value != "ok": + return + self.token += status.firstChild.nextSibling.firstChild.data + print self.token diff --git a/trunk/src/ocarina.py b/trunk/src/ocarina.py index ae39d3ab..b387bdd7 100644 --- a/trunk/src/ocarina.py +++ b/trunk/src/ocarina.py @@ -24,7 +24,8 @@ class main: self.options.verbose = True # Load saved data (or create new data) self.data = SavedData(self.options) - self.data.song = Song(self.quit) + #self.data.song = Song(self.quit) + self.data.quit = None self.window = Window(self.quit,self.options,self.data) gtk.main() diff --git a/trunk/src/saveddata.py b/trunk/src/saveddata.py index 12ffd49b..0b2347d5 100644 --- a/trunk/src/saveddata.py +++ b/trunk/src/saveddata.py @@ -22,6 +22,7 @@ class SavedData: self.path = path self.song = None self.random = False + self.quit = None if os.path.exists(path): try: diff --git a/trunk/src/song.py b/trunk/src/song.py index 1f164c15..d7411a99 100644 --- a/trunk/src/song.py +++ b/trunk/src/song.py @@ -7,13 +7,13 @@ import gst class Song(): #def __init__(self,info,exitFunc,prnt): - def __init__(self,exitFunc): - self.quit=exitFunc - # initialize player pipeline - self.next = None - self.info = None + def __init__(self,info,next): + self.next = next + self.info = info self.player = gst.Pipeline("player") self.bin = gst.element_factory_make("playbin",None) + self.bin.set_property("uri","file://"+self.info.filename) + self.bin.set_state(gst.STATE_PAUSED) self.player.add(self.bin) # initialize bus @@ -43,8 +43,6 @@ class Song(): # Toggle between play and pause def plause(self): - if self.hasFile == False: - return if self.playing == False: self.player.set_state(gst.STATE_PLAYING) self.playing = True @@ -55,8 +53,6 @@ class Song(): # Stop playback def stop(self): - if self.hasFile == False: - return self.player.set_state(gst.STATE_PAUSED) self.playing = False self.current = 0 @@ -65,7 +61,6 @@ class Song(): # Close the song def close(self): - self.playing = False self.player.set_state(gst.STATE_NULL) @@ -74,10 +69,3 @@ class Song(): if self.playing == False: return (False,False) return (True, self.player.query_position(self.time_format,None)[0]) - - - # Use to load a file path - def passInfo(self,info): - self.info = info - self.bin.set_property("uri","file://"+self.info.filename) - self.hasFile = True diff --git a/trunk/src/window.py b/trunk/src/window.py index 28387132..139d1355 100644 --- a/trunk/src/window.py +++ b/trunk/src/window.py @@ -9,6 +9,7 @@ from GuiObjects.libView import LibView from GuiObjects.plistView import PlistView from GuiObjects.controlPanel import ControlPanel from GuiObjects.infoView import InfoView +from GuiObjects.scrobbler import Scrobbler class Window(gtk.Window): @@ -96,10 +97,23 @@ class Window(gtk.Window): self.contentPane.add(self.divider) self.divider.show() + leftPane = gtk.Notebook() + leftPane.show() + leftPane.set_tab_pos(gtk.POS_LEFT) + self.libview = LibView(self.data) self.libview.show() - self.divider.add1(self.libview) + libLabel = gtk.Label("Library") + libLabel.set_angle(90) + leftPane.append_page(self.libview,libLabel) + scrobbler = Scrobbler(self.data) + scrobLabel = gtk.Label("Last.fm") + scrobLabel.set_angle(90) + leftPane.append_page(scrobbler,scrobLabel) + + self.divider.add1(leftPane) + rightPane=gtk.VBox(False,0) infoview = InfoView(self.data) @@ -117,12 +131,11 @@ class Window(gtk.Window): def makeBottomRow(self,vbox): box = gtk.HBox(False,0) - #box.pack_end(self.libview.label,False,False,10) + box.show() controls = ControlPanel(self.data,self.plistview) self.plistview.controls = controls vbox.pack_start(controls,False,False,0) - box.pack_end(self.plistview.plabel) - box.show() + box.pack_end(self.plistview.label) align = gtk.Alignment(1,1,0,0) align.add(box) align.show()