def test_multiple_tasks(self): self.assertEquals(self.c.active_tasks, []) self.assertNotEqual(self.c.source, "") t1 = Task("src", "desc", controller = self.c) self.assertEquals(self.c.source, "src") self.assertEquals(self.c.active_tasks, [t1]) t1.update(0.5) self.assertEquals(self.c.frac, 0.5) t2 = Task("src2", "desc2", controller = self.c) self.assertEquals(self.c.source, _("Active tasks")) self.assertEquals(self.c.frac, 0.25) Task("src3", "desc3", controller = self.c, known_length=False) self.assertAlmostEqual(self.c.frac, 0.5/3) t1.finish() t2.finish() self.assertEquals(self.c.desc, "desc3") self.assertEquals(self.c.frac, None)
def test_multiple_tasks(self): self.assertEquals(self.c.active_tasks, []) self.assertNotEqual(self.c.source, "") t1 = Task("src", "desc", controller=self.c) self.assertEquals(self.c.source, "src") self.assertEquals(self.c.active_tasks, [t1]) t1.update(0.5) self.assertEquals(self.c.frac, 0.5) t2 = Task("src2", "desc2", controller=self.c) self.assertEquals(self.c.source, _("Active tasks")) self.assertEquals(self.c.frac, 0.25) Task("src3", "desc3", controller=self.c, known_length=False) self.assertAlmostEqual(self.c.frac, 0.5 / 3) t1.finish() t2.finish() self.assertEquals(self.c.desc, "desc3") self.assertEquals(self.c.frac, None)
def __add_songs(self, task: Task, songs: Collection[AudioFile], spl: DidlPlaylistContainer): """Generator for copool to add songs to the temp playlist""" assert self.device task_total = float(len(songs)) print_d("Adding %d song(s) to Sonos playlist. " "This might take a while..." % task_total) for i, song in enumerate(songs): if self.__cancel: print_d("Cancelled Sonos export") return lib = self.device.music_library # Exact title gets the best results it seems; some problems with ’ search_term = song("title") assert search_term results = lib.get_tracks(search_term=search_term, max_items=self.MAX_RESULTS_PER_SEARCH) yield total = len(results) if total == 1: track = results[0] elif total > 1: desc = song("~~people~album~title") candidates = [(self._score(t, song), t) for t in results] in_order = sorted(candidates, reverse=True, key=lambda x: x[0]) track = in_order[0][1] print_d(f"From {len(results)} choice(s) for {desc!r}, " f"chose {self.uri_for(track)}") else: print_w("No results for \"%s\"" % search_term) track = None if track: try: self.device.add_item_to_sonos_playlist(track, spl) except SoCoException as e: print_w(f"Couldn't add {track} ({e}, skipping") task.update(float(i) / task_total) yield task.update((task_total - 2) / task_total) yield task.finish() print_d(f"Finished export to {spl.title!r}")
class BufferingWrapper(object): """A wrapper for a Gst.Element (usually GstPlayBin) which pauses the elmement in case buffering is needed, but hides the fact that it does. Probably not perfect... You have to call destroy() before it gets gc'd """ def __init__(self, bin_, player): """ bin_ -- the GstPlaybin instance to wrap player -- the GStreamerPlayer instance used for aborting the buffer process """ self.bin = bin_ self._wanted_state = None self._task = None self._inhibit_play = False self._player = player bus = self.bin.get_bus() bus.add_signal_watch() self.__bus_id = bus.connect('message', self.__message) def __message(self, bus, message): if message.type == Gst.MessageType.BUFFERING: percent = message.parse_buffering() self.__update_buffering(percent) def __getattr__(self, name): return getattr(self.bin, name) def __update_buffering(self, percent): """Call this with buffer percent values from the bus""" if self._task: self._task.update(percent / 100.0) self.__set_inhibit_play(percent < 100) def __set_inhibit_play(self, inhibit): """Change the inhibit state""" if inhibit == self._inhibit_play: return self._inhibit_play = inhibit # task management if inhibit: if not self._task: def stop_buf(*args): self._player.paused = True self._task = Task(_("Stream"), _("Buffering"), stop=stop_buf) elif self._task: self._task.finish() self._task = None # state management if inhibit: # save the current state status, state, pending = self.bin.get_state( timeout=STATE_CHANGE_TIMEOUT) if status == Gst.StateChangeReturn.SUCCESS and \ state == Gst.State.PLAYING: self._wanted_state = state else: # no idea, at least don't play self._wanted_state = Gst.State.PAUSED self.bin.set_state(Gst.State.PAUSED) else: # restore the old state self.bin.set_state(self._wanted_state) self._wanted_state = None def set_state(self, state): if self._inhibit_play: # PLAYING, PAUSED change the state for after buffering is finished, # everything else aborts buffering if state not in (Gst.State.PLAYING, Gst.State.PAUSED): # abort self.__set_inhibit_play(False) self.bin.set_state(state) return self._wanted_state = state else: self.bin.set_state(state) def get_state(self, *args, **kwargs): # get_state also is a barrier (seek/positioning), # so call every time but ignore the result in the inhibit case res = self.bin.get_state(*args, **kwargs) if self._inhibit_play: return (Gst.StateChangeReturn.SUCCESS, self._wanted_state, Gst.State.VOID_PENDING) return res def destroy(self): if self.__bus_id: bus = self.bin.get_bus() bus.disconnect(self.__bus_id) bus.remove_signal_watch() self.__bus_id = None self.__set_inhibit_play(False) self.bin = None
class BufferingWrapper(object): """A wrapper for a Gst.Element (usually GstPlayBin) which pauses the elmement in case buffering is needed, but hides the fact that it does. Probably not perfect... You have to call destroy() before it gets gc'd """ def __init__(self, bin_, player): """ bin_ -- the GstPlaybin instance to wrap player -- the GStreamerPlayer instance used for aborting the buffer process """ self.bin = bin_ self._wanted_state = None self._task = None self._inhibit_play = False self._player = player bus = self.bin.get_bus() bus.add_signal_watch() self.__bus_id = bus.connect('message', self.__message) def __message(self, bus, message): if message.type == Gst.MessageType.BUFFERING: percent = message.parse_buffering() self.__update_buffering(percent) def __getattr__(self, name): return getattr(self.bin, name) def __update_buffering(self, percent): """Call this with buffer percent values from the bus""" if self._task: self._task.update(percent / 100.0) self.__set_inhibit_play(percent < 100) def __set_inhibit_play(self, inhibit): """Change the inhibit state""" if inhibit == self._inhibit_play: return self._inhibit_play = inhibit # task management if inhibit: if not self._task: def stop_buf(*args): self._player.paused = True self._task = Task(_("Stream"), _("Buffering"), stop=stop_buf) elif self._task: self._task.finish() self._task = None # state management if inhibit: # save the current state status, state, pending = self.bin.get_state( timeout=STATE_CHANGE_TIMEOUT) if status == Gst.StateChangeReturn.SUCCESS and \ state == Gst.State.PLAYING: self._wanted_state = state else: # no idea, at least don't play self._wanted_state = Gst.State.PAUSED self.bin.set_state(Gst.State.PAUSED) else: # restore the old state self.bin.set_state(self._wanted_state) self._wanted_state = None def set_state(self, state): if self._inhibit_play: # PLAYING, PAUSED change the state for after buffering is finished, # everything else aborts buffering if state not in (Gst.State.PLAYING, Gst.State.PAUSED): # abort self.__set_inhibit_play(False) self.bin.set_state(state) return self._wanted_state = state else: self.bin.set_state(state) def get_state(self, *args, **kwargs): # get_state also is a barrier (seek/positioning), # so call every time but ignore the result in the inhibit case res = self.bin.get_state(*args, **kwargs) if self._inhibit_play: return (Gst.StateChangeReturn.SUCCESS, self._wanted_state, Gst.State.VOID_PENDING) return res def destroy(self): if self.__bus_id: bus = self.bin.get_bus() bus.disconnect(self.__bus_id) bus.remove_signal_watch() self.__bus_id = None self.__set_inhibit_play(False) self.bin = None