Commits

Damián Nohales committed b192e99

Player and PlayList related features already refactorized and some bugs fixed

I also implement a patch to avoid GrooveShark madness requests caused when user press repeatedly the prev and next button by adding a timeout before the song streaming.

  • Participants
  • Parent commits 4c24a82
  • Branches refactoring

Comments (0)

Files changed (5)

File lib/PlayList.py

     
 class PlayList (AbstractSongList):
     def __init__(self, view):
-        playing_song = None
         AbstractSongList.__init__(self, view)
+        self.playing_song = None
     
     def create_model(self):
         # Model: Song, Info, Image, Tooltip, ...
     
     def set_playing_song(self, song):
         if song != None:
-            path = self.get_model().get_song_path(song)
-            self.get_view().scroll_to_path(path, False, 0, 0)
-            self.get_model()[2] = self.create_composited_image(self.get_model()[2])
-        else:
-            if self.playing_song != None:
-                self.get_song_row(self.playing_song)[2] = self.playing_song.get_cover_pixbuf() 
+            path = self.get_song_path(song)
+            if song.get_cover_pixbuf() != None:
+                self.get_model()[path][2] = self.create_composited_image(song.get_cover_pixbuf())
+            self.get_view().scroll_to_path(path, False, 0, 0) 
         
         self.playing_song = song
+        
+        for i in self.range():
+            if self.get_song(i).equals(song) == False:
+                self.get_model()[i][2] = self.get_song(i).get_cover_pixbuf()
     
     def append_song(self, song):
         # Change song local ID to fix the search by song
         return pixbuf
     
     def create_composited_image(self, pixbuf):
+        pixbuf = pixbuf.copy()
         play = gtk.gdk.pixbuf_new_from_file('%s/data/play.png' % env().BASEPATH)
         play.composite(pixbuf, 0, 0, pixbuf.props.width, pixbuf.props.height,
                           0, 0, 1.0, 1.0, gtk.gdk.INTERP_HYPER, 255)
+        return pixbuf

File lib/SharkDown.py

         self.last_iter = None
         self.windowstate = 1
         self.current_song = None
+        self.play_thread = None
         
         init_thread = InitThread(self)
         init_thread.start()
         # Play List definition
         self.sw2 = builder.get_object('scrolledwindow2')
         self.playlist = PlayList(gtk.IconView())
-        self.playlist.get_view().connect('item-activated', self.double_click_start)
+        self.playlist.get_view().connect('item-activated', self.on_playlist_double_click)
         self.playlist.get_view().show()
         self.sw2.add(self.playlist.get_view())
 
             self.playlist.clear()
             self.stop_play()
             self.load_saved_playlist(opendlg.get_filename())
-            self.play_by_index(0)
+            self.play_first_song()
         opendlg.destroy()
 
     def on_window_close(self, widget, data = None):
                 if select_path[0] >= len(self.playlist):
                     select_path = (select_path[0]-1,)
                 self.playlist.get_view().select_path(select_path)
-        
-        
-#        select = self.playlist.get_view().get_selected_items()
-#        if selectiter != None:
-#            next = self.playlist.get_model().iter_next(selectiter)
-#            self.playlist.get_model().remove(selectiter)
-#            if selectiter == self.get_playing_iter():
-#                self.stop_play()
-#            if next != None:
-#                self.playlist.get_view().select_path((select[0][0] + 1,))
+                
+            if self.get_playing_iter() == None:
+                self.stop_play()
 
     def on_clear_playlist(self, widget, data = None):
         """
         Removes all items from the playlist
         """
-        if self.get_current_song() != None:
-            self.stop_play()
+        self.stop_play()
         self.playlist.clear()
 
     def on_toggle_repeat(self, widget, data = None):
         config()['shuffle_playlist'] = int(widget.get_active())
         config().write()
 
-    def double_click_start(self, widget, path, data = None):
+    def on_playlist_double_click(self, widget, path, data = None):
         """
         Starts playling on double click event on the playlist
         treeview.
         """
-        self.play_view.unselect_all()
-        self.play_by_index(path[0])
+        self.playlist.get_view().unselect_all()
+        self.set_playing_song(self.playlist.get_song(path))
 
     def on_result_row_activated(self, path, column, data = None):
         """
             play_stop_image = gtk.Image()
             play_stop_image.set_from_stock(gtk.STOCK_MEDIA_STOP, gtk.ICON_SIZE_MENU)
             self.staticon.change_playbutton(play_stop_image)
+            self.play_button.set_stock_id(gtk.STOCK_MEDIA_STOP)
 
             self.songinfo.set_markup(
                 _("<b>Playing:</b> {artist} - {title}").format(artist = glib.markup_escape_text(song.get_artist()),
                     "audio-x-generic")
                 n.set_timeout(50)
                 n.show()
+                
+            self.player.set_state(gst.STATE_NULL)
+            
+            if self.play_thread != None:
+                # Avoid the current song streaming
+                self.play_thread.stop()
+                self.play_thread.join();
+            self.play_thread = PlayThread(self, song)
+            self.play_thread.start()
         else:
             self.staticon.change_status_stopped()
             play_stop_image = gtk.Image()
             play_stop_image.set_from_stock(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_MENU)
             self.staticon.change_playbutton(play_stop_image)
+            self.player.set_state(gst.STATE_NULL)
+            self.play_button.set_stock_id(gtk.STOCK_MEDIA_PLAY)
             self.songinfo.set_markup("")
     
-    def play_selected(self, widget, data = None, row = None):
+    def play_first_song(self):
+        if len(self.playlist) > 0:
+            self.set_playing_song(self.playlist.get_song(0))
+    
+    def on_play_selected(self, widget, data = None, row = None):
         """
         Starts the play thread
         """
         if self.get_playing_song() == None:
-            if len(self.playlist):
-                self.set_playing_song(self.playlist.get_song(0))
+            self.play_first_song()
         else:
-            self.set_playing_song(None)
+            self.stop_play()
+            
+    def on_play_next(self, widget, data = None):
+        self.play_next()
+        
+    def on_play_previous(self, widget, data = None):
+        self.play_previous()
     
-    def play_next(self, widget, data = None):
+    def next_shuffled_index(self):
+        path = None
+        
+        if len(self.playlist) == 1:
+            return 0
+        
+        if self.get_playing_song() != None:
+            path = self.playlist.get_song_path(self.get_playing_song())
+            
+        while True:
+            index = random.randint(0, len(self.playlist) - 1)
+            if path == None or index != path[0]:
+                break
+            
+        return index
+    
+    def play_next(self):
         """
         Plays the next item from the playlist
         """
-        if self.get_playing_iter() == None:
-            self.play_by_index(0)
+        if len(self.playlist) == 0:
+            return
+        
+        if self.get_playing_song() == None:
+            self.play_first_song()
         else:
-            index = self.playlist.get_path(self.get_playing_iter())[0] + 1
             if int(config()['shuffle_playlist']) == 1:
-                index = random.randint(0, len(self.playlist) - 1)
+                index = self.next_shuffled_index()
+            else:
+                index = self.playlist.get_song_path(self.get_playing_song())[0] + 1
 
             if index >= len(self.playlist):
                 if int(config()['repeat_playlist']) == 1:
-                    self.play_by_index(0)
+                    index = 0
                 else:
+                    index = None
                     self.stop_play()
-            else:
-                self.play_by_index(index)
-
-    def play_previous(self, widget, data = None):
+            
+            if index != None:
+                self.set_playing_song( self.playlist.get_song((index,)) )
+        
+    def play_previous(self):
         """
         Plays the previous song from the playlist
         """
+        if len(self.playlist) == 0:
+            return
+        
         if self.get_playing_iter() == None:
-            self.play_by_index(0)
+            self.play_first_song()
         else:
-            index = self.playlist.get_path(self.get_playing_iter())[0] - 1
             if int(config()['shuffle_playlist']) == 1:
-                index = random.randint(0, len(self.playlist) - 1)
+                index = self.next_shuffled_index()
+            else:
+                index = self.playlist.get_song_path(self.get_playing_song())[0] - 1
 
             if index < 0:
                 if int(config()['repeat_playlist']) == 1:
-                    self.play_by_index(len(self.playlist) - 1)
+                    index = len(self.playlist) - 1
                 else:
-                    self.play_by_index(0)
-            else:
-                self.play_by_index(index)
-
-    def play_by_index(self, index):
-        """
-        Start the play by an index on playlist.
-        """
-        if index < 0:
-            index = 0
-
-        if index >= len(self.playlist):
-            index = len(self.playlist) - 1
-
-        iter = self.playlist.get_iter((index,))
-
-        if iter != self.get_playing_iter():
-            self.scrobbled = 0
-            for item in self.playlist:
-                item[5] = 400
-            self.playlist[iter][5] = 600
-            self.play_button.set_stock_id(gtk.STOCK_MEDIA_STOP)
-            self.player.set_state(gst.STATE_NULL)
-            song = self.playlist_song(index)
-            self.set_songinfos(song)
-            t = PlayThread(self, song,
-                       int(config()['repeat_playlist']),
-                      self.lastfm)
-            t.start()
+                    index = 0
+            
+            self.set_playing_song( self.playlist.get_song((index,)) )
 
     def stop_play(self):
         """
         Stop current playing
         """
-        for item in self.playlist:
-            item[5] = 400
-        self.player.set_state(gst.STATE_NULL)
-        self.play_button.set_stock_id(gtk.STOCK_MEDIA_PLAY)
-        self.set_songinfos()
+        self.set_playing_song(None)
 
     def on_volume_change(self, widget, data = 0.5):
         """
         return newsong
     
     def equals(self, othersong):
+        if othersong == None:
+            return False
+        
         return self.local_id == othersong.local_id
     
     def get_data(self):

File lib/guihelpers.py

             prefs = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
             prefs.connect("activate", instance.on_open_preferences)
             self.playbut = gtk.ImageMenuItem(gtk.STOCK_MEDIA_PLAY)
-            self.playbut.connect("activate", instance.play_selected)
+            self.playbut.connect("activate", instance.on_play_selected)
             prebut = gtk.ImageMenuItem(gtk.STOCK_MEDIA_PREVIOUS)
-            prebut.connect("activate", instance.play_previous)
+            prebut.connect("activate", instance.on_play_previous)
             ffbut = gtk.ImageMenuItem(gtk.STOCK_MEDIA_NEXT)
-            ffbut.connect("activate", instance.play_next)
+            ffbut.connect("activate", instance.on_play_next)
 
             updimg = gtk.Image()
             updimg.set_from_icon_name('system-software-update',
         prefs = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
         prefs.connect("activate", self.instance.on_open_preferences)
         playbut = gtk.ImageMenuItem(gtk.STOCK_MEDIA_PLAY)
-        playbut.connect("activate", self.instance.play_selected)
+        playbut.connect("activate", self.instance.on_play_selected)
         prebut = gtk.ImageMenuItem(gtk.STOCK_MEDIA_PREVIOUS)
-        prebut.connect("activate", self.instance.play_previous)
+        prebut.connect("activate", self.instance.on_play_previous)
         ffbut = gtk.ImageMenuItem(gtk.STOCK_MEDIA_NEXT)
-        ffbut.connect("activate", self.instance.play_next)
+        ffbut.connect("activate", self.instance.on_play_next)
 
         updimg = gtk.Image()
         updimg.set_from_icon_name('system-software-update',

File lib/tfuncs.py

 
 class PlayThread(threading.Thread):
 
-    def __init__(self, _window, _song, _conf, _lastfm):
+    def __init__(self, app, song):
         """
         Start the player thread with the following parameters:
-        @param _window : The main window, to work with in the 
-                         main class that would be self
-        @param _song : The song information that we get from the search
-        @param _conf : The information if the track is to be repeated
-        @param _lastfm : The LastFM instance
+        @param app: The application instance
+        @param song: The song to play
         """
         threading.Thread.__init__(self)
-        self.win = _window
-        self.songid = _song["SongID"]
-        self.song = _song
-        self.repeat = _conf
-        self.lastfm = _lastfm
+        self.app = app
+        self.song = song
+        self._stop = threading.Event()
 
     def run(self):
+        # This avoid madness when user press repeatedly the prev and next button
+        # The song streaming begins if the thread is not canceled in one second
+        self._stop.wait(1)
+        if self.stopped():
+            return
+        
         try:
-            key = groove.getStreamKeyFromSongIDEx(self.songid)
+            key = groove.getStreamKeyFromSongIDEx(self.song.get_id())
         except Exception, e:
             print e
         playurls = "http://%s/stream.php?streamKey=%s"
-        play_url = playurls % (key["result"]["%s" % self.songid]["ip"],
-                               key["result"]["%s" % self.songid]["streamKey"])
-        self.win.player.set_property('uri', play_url)
-        self.win.player.set_state(gst.STATE_PLAYING)
-        self.win.play_button.set_stock_id(gtk.STOCK_MEDIA_STOP)
-        if self.lastfm != "":
-            if self.win.scrobbled == 0:
-                self.lastfm.scrobble(self.song['ArtistName'],
-                                    self.song['SongName'],
+        play_url = playurls % (key["result"]["%s" % self.song.get_id()]["ip"],
+                               key["result"]["%s" % self.song.get_id()]["streamKey"])
+        print "[Playing]", self.song.get_id(), play_url
+        self.app.player.set_property('uri', play_url)
+        self.app.player.set_state(gst.STATE_PLAYING)
+        if self.app.lastfm != "":
+            if self.app.scrobbled == 0:
+                self.lastfm.scrobble(self.song.get_artist(),
+                                    self.song.get_title(),
                                     int(time.time()))
-                self.lastfm.update_now_playing(self.song['ArtistName'],
-                                              self.song['SongName'])
-                self.win.scrobbled = 1
+                self.lastfm.update_now_playing(self.song.get_artist(),
+                                              self.song.get_title())
+                self.app.scrobbled = 1
             else:
                 pass
-        bus = self.win.player.get_bus()
+        bus = self.app.player.get_bus()
         bus.enable_sync_message_emission()
         bus.add_signal_watch()
 # I will leave this commented out just till it's confirmed that
         sets state gst.STATE_NULL and calls the play_next 
         method.
         """
-        self.win.player.set_state(gst.STATE_NULL)
-        self.win.play_button.set_stock_id(gtk.STOCK_MEDIA_STOP)
-        self.win.play_next(self.win.ff_button)
+        gobject.idle_add(self.app.play_next)
 
 #    def update_buttons(self, state):
 #        if state == gst.STATE_NULL:
 #        else:
 #            self.win.play_button.set_stock_id(gtk.STOCK_MEDIA_STOP)
 
+    def stop(self):
+        self._stop.set()
+
+    def stopped(self):
+        return self._stop.isSet()
+
 
 class KeyListenerThread(threading.Thread):
 
-    def __init__(self, _window):
+    def __init__(self, app):
         """
         A thread to listen for multimedia key press
         Accepts as parameter:
         @param _window : The main window, to interact with
         """
         threading.Thread.__init__(self)
-        self.win = _window
+        self.app = app
 
     def run(self):
         """
         """
         if what in ['Stop', 'Play', 'Next', 'Previous']:
             if what == 'Stop':
-                self.win.play_selected(self.win.play_button)
+                self.app.on_play_selected(self.app.play_button)
             elif what == 'Play':
-                self.win.play_selected(self.win.play_button)
+                self.app.on_play_selected(self.app.play_button)
             elif what == 'Next':
-                self.win.play_next(self.win.ff_button)
+                self.app.play_next()
             elif what == 'Previous':
-                self.win.play_previous(self.win.prev_button)
+                self.app.play_previous()
 
 class SearchThread(threading.Thread):