More screens updated to do background fetching
[jamaendo] / jamaui / player.py
index d860ccb..31211eb 100644 (file)
@@ -27,6 +27,8 @@ import dbus
 
 import jamaendo
 from settings import settings
+from postoffice import postoffice
+from fetcher import Fetcher
 
 log = logging.getLogger(__name__)
 
@@ -65,6 +67,13 @@ class GStreamer(_Player):
         self.volume_multiplier = 1.
         self.volume_property = None
         self.eos_callback = lambda: self.stop()
+        postoffice.connect('settings-changed', self, self.on_settings_changed)
+
+    def on_settings_changed(self, key, value):
+        if key == 'volume':
+            self._set_volume_level(value)
+        #postoffice.disconnect(self)
+
 
     def play_url(self, filetype, uri):
         if None in (filetype, uri):
@@ -100,7 +109,7 @@ class GStreamer(_Player):
             return self.STATES.get(state, 'none')
         return 'none'
 
-    def _get_position_duration(self):
+    def get_position_duration(self):
         try:
             pos_int = self.player.query_position(self.time_format, None)[0]
             dur_int = self.player.query_duration(self.time_format, None)[0]
@@ -114,17 +123,17 @@ class GStreamer(_Player):
 
     def play(self):
         if self.player:
-            log.debug("playing")
             self.player.set_state(gst.STATE_PLAYING)
 
     def pause(self):
         if self.player:
             self.player.set_state(gst.STATE_PAUSED)
 
-    def stop(self):
+    def stop(self, reset = True):
         if self.player:
             self.player.set_state(gst.STATE_NULL)
-            self.player = None
+            if reset:
+                self.player = None
 
     def _maemo_setup_playbin2_player(self, url):
         self.player = gst.parse_launch("playbin2 uri=%s" % (url,))
@@ -150,7 +159,7 @@ class GStreamer(_Player):
         self.filesrc = self.player
         self.filesrc_property = 'uri'
         self.volume_control = self.player
-        self.volume_multiplier = 1.
+        self.volume_multiplier = 10.
         self.volume_property = 'volume'
 
     def _on_decoder_pad_added(self, decoder, src_pad, sink_pad):
@@ -167,23 +176,25 @@ class GStreamer(_Player):
 
         if self.volume_control is not None:
             vol = value * float(self.volume_multiplier)
+            log.debug("Setting volume to %s", vol)
             self.volume_control.set_property( self.volume_property, vol )
 
     def _set_uri_to_be_played(self, uri):
         # Sets the right property depending on the platform of self.filesrc
         if self.player is not None:
             self.filesrc.set_property(self.filesrc_property, uri)
+            log.info("%s", uri)
 
     def _on_message(self, bus, message):
         t = message.type
 
         if t == gst.MESSAGE_EOS:
-            log.info("End of stream")
+            log.debug("Gstreamer: End of stream")
             self.eos_callback()
-        elif t == gst.MESSAGE_STATE_CHANGED:
-            if (message.src == self.player and
-                message.structure['new-state'] == gst.STATE_PLAYING):
-                log.info("State changed to playing")
+        #elif t == gst.MESSAGE_STATE_CHANGED:
+        #    if (message.src == self.player and
+        #        message.structure['new-state'] == gst.STATE_PLAYING):
+        #        log.debug("gstreamer: state -> playing")
         elif t == gst.MESSAGE_ERROR:
             err, debug = message.parse_error()
             log.critical( 'Error: %s %s', err, debug )
@@ -279,6 +290,9 @@ PlayerBackend = GStreamer
 
 class Playlist(object):
     def __init__(self, items = []):
+        self.radio_mode = False
+        self.radio_id = None
+        self.radio_name = None
         if items is None:
             items = []
         for item in items:
@@ -317,6 +331,11 @@ class Playlist(object):
             return self.items[self._current]
         return None
 
+    def jump_to(self, item_id):
+        for c, i in enumerate(self.items):
+            if i.ID == item_id:
+                self._current = c
+
     def current_index(self):
         return self._current
 
@@ -324,49 +343,104 @@ class Playlist(object):
         return len(self.items)
 
     def __repr__(self):
-        return "Playlist(%s)"%(", ".join([str(item.ID) for item in self.items]))
+        return "Playlist(%d of %s)"%(self._current, ", ".join([str(item.ID) for item in self.items]))
 
 class Player(object):
     def __init__(self):
         self.backend = PlayerBackend()
         self.backend.set_eos_callback(self._on_eos)
         self.playlist = Playlist()
+        self.fetcher = None # for refilling the radio
+
+    def get_position_duration(self):
+        return self.backend.get_position_duration()
+
+    def _play_track(self, track, notify='play'):
+        self.backend.play_url('mp3', track.mp3_url())
+        log.debug("playing %s", track)
+        postoffice.notify(notify, track)
+
+    def _refill_radio(self):
+        log.debug("Refilling radio %s", self.playlist)
+        #self.playlist.add(jamaendo.get_radio_tracks(self.playlist.radio_id))
+        self._start_radio_fetcher()
+
+    def _start_radio_fetcher(self):
+        if self.fetcher:
+            self.fetcher.stop()
+            self.fetcher = None
+        self.fetcher = Fetcher(lambda: jamaendo.get_radio_tracks(self.playlist.radio_id),
+                               self,
+                               on_item = self._on_radio_result,
+                               on_ok = self._on_radio_complete,
+                               on_fail = self._on_radio_complete)
+        self.fetcher.has_no_results = True
+        self.fetcher.start()
+
+    def _on_radio_result(self, wnd, item):
+        if wnd is self:
+            self.playlist.add(item)
+            if not self.playing():
+                if self.fetcher.has_no_results:
+                    self.fetcher.has_no_results = False
+                    entry = self.playlist.next()
+                    self._play_track(entry)
+
+    def _on_radio_complete(self, wnd, error=None):
+        if wnd is self:
+            if error:
+                self.stop()
+            self.fetcher.stop()
+            self.fetcher = None
 
     def play(self, playlist = None):
         if playlist:
             self.playlist = playlist
         elif self.playlist is None:
             self.playlist = Playlist()
-        if self.playlist.size():
-            if self.playlist.has_next():
-                entry = self.playlist.next()
-                log.debug("playing %s", entry)
-                self.backend.play_url('mp3', entry.mp3_url())
-
-    def pause(self):
-        self.backend.pause()
-
-    def stop(self):
-        self.backend.stop()
 
-    def playing(self):
-        return self.backend.playing()
+        if self.playlist.current():
+            entry = self.playlist.current()
+            self._play_track(entry)
+        elif self.playlist.has_next():
+            entry = self.playlist.next()
+            self._play_track(entry)
+        elif self.playlist.radio_mode:
+            self._refill_radio()
+            #self.play()
 
     def next(self):
         if self.playlist.has_next():
-            self.stop()
-            self.play()
+            self.backend.stop(reset=False)
+            entry = self.playlist.next()
+            self._play_track(entry, notify='next')
+        elif self.playlist.radio_mode:
+            self._refill_radio()
+            #if self.playlist.has_next():
+            #    self.next()
+            #else:
+            #    self.stop()
         else:
             self.stop()
 
     def prev(self):
         if self.playlist.has_prev():
+            self.backend.stop(reset=False)
             entry = self.playlist.prev()
-            log.debug("playing %s", entry)
-            self.backend.play_url('mp3', entry.mp3_url())
+            self._play_track(entry, 'prev')
+
+    def pause(self):
+        self.backend.pause()
+        postoffice.notify('pause', self.playlist.current())
+
+    def stop(self):
+        self.backend.stop()
+        postoffice.notify('stop', self.playlist.current())
+
+    def playing(self):
+        return self.backend.playing()
 
     def _on_eos(self):
-        log.debug("EOS!")
         self.next()
 
 the_player = Player() # the player instance