def __ensure_book_object_is_up_to_date(self): # Racecondition: Sometimes the "track-changed" event is fired in playback_speed first before titlebar. Then it might happen, that the current_book is None or not uptodate. # Only way to fix this is having a global truth that is accessed from everywhere. # TODO if player.get_current_track() and ( not self.current_book or player.get_current_track() and self.current_book.id != player.get_current_track().book.id): self.update_track_ui()
def update_ui_time(self, widget): """ Displays the value of the progress slider in the text boxes as time. """ val = int(self.progress_scale.get_value()) if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): label_text = tools.seconds_to_str(val, display_zero_h=True) else: label_text = tools.seconds_to_str(val) self.current_label.set_markup("<tt><b>" + label_text + "</b></tt>") track = player.get_current_track() if track: if tools.get_glib_settings().get_boolean( "titlebar-remaining-time"): total = self.progress_scale.get_adjustment().get_upper() remaining_secs: int = int((total - val)) self.remaining_label.set_markup( "<tt><b>-" + tools.seconds_to_str(remaining_secs, display_zero_h=True) + "</b></tt>") else: remaining_secs: int = int((track.length / self.ui.speed.get_speed()) - val) self.remaining_label.set_markup( "<tt><b>-" + tools.seconds_to_str( remaining_secs, display_zero_h=False) + "</b></tt>") if self.ui.book_overview.book and self.current_book.id == self.ui.book_overview.book.id: self.ui.book_overview.update_time()
def on_close(self, widget, data=None): """ Close and dispose everything that needs to be when window is closed. """ log.info("Closing.") self.titlebar.close() self.fs_monitor.close() if self.sleep_timer.is_running(): self.sleep_timer.stop() # save current position when still playing if player.get_gst_player_state() == Gst.State.PLAYING: Track.update(position=player.get_current_duration()).where( Track.id == player.get_current_track().id).execute() player.stop() player.dispose() close_db() report.close() log.info("Closing app.") self.app.quit() log.info("App closed.")
def update_ui_time(self, widget): """ Displays the value of the progress slider in the text boxes as time. """ track = player.get_current_track() if not track: log.debug("update_ui_time: track was None.") return val = int(self.progress_scale.get_value()) if self._application_settings.titlebar_remaining_time: total = self.progress_scale.get_adjustment().get_upper() remaining_secs: int = int((total - val)) current_text = seconds_to_str(val, total) remaining_text = seconds_to_str(remaining_secs, total) else: remaining_secs = int((track.length / self.ui.speed.get_speed()) - val) remaining_text = seconds_to_str(remaining_secs, track.length) current_text = seconds_to_str(val, track.length) self.current_label.set_markup("<tt><b>" + current_text + "</b></tt>") self.remaining_label.set_markup("<tt><b>-" + remaining_text + "</b></tt>") if self.ui.book_overview.book and self.current_book.id == self.ui.book_overview.book.id: self.ui.book_overview.update_time()
def __load_last_book(self): """ Loads the last book into the player """ player.load_last_book() if player.get_current_track(): self.titlebar.load_last_book()
def _play_chapter(self, book: Book, chapter: Chapter): current_track = player.get_current_track() book.last_played = int(time.time()) if current_track and current_track.file == chapter.file: player.play_pause(None) else: player.load_file(chapter._db_object) player.play_pause(None, True)
def __update_progress_scale_range(self): """ Update the progress scale range including the current playback speed. """ if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): total = db.get_book_duration( self.current_book) / self.ui.speed.get_speed() else: total = player.get_current_track().length / self.ui.speed.get_speed() self.progress_scale.set_range(0, total)
def set_title_cover(self, pixbuf, size): """ Sets the cover in the title bar. """ if pixbuf: surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, self.ui.window.get_scale_factor(), None) self.cover_img.set_from_surface(surface) self.cover_img.set_tooltip_text(player.get_current_track().book.name) else: self.cover_img.set_from_icon_name("book-open-variant-symbolic", Gtk.IconSize.MENU) self.cover_img.props.pixel_size = size
def loaded_chapter(self) -> Optional[Chapter]: current_track = player.get_current_track() if not current_track: return None chapter = None for c in self._library.chapters: if c.id == current_track.id: chapter = c return chapter
def __init_components(self): self.titlebar = Titlebar() self.sleep_timer = SleepTimer() self.speed = PlaybackSpeed() player.init() self.titlebar.activate() if player.get_current_track() is None: self.block_ui_buttons(True) self._importer.add_listener(self._on_importer_event)
def loaded_book(self) -> Optional[Book]: current_track = player.get_current_track() if not current_track: return None track_id = current_track.id book = None for b in self._library.books: if any(chapter.id == track_id for chapter in b.chapters): book = b break return book
def track_changed(self): """ The track loaded in the player has changed. Refresh the currently playing track and mark it in the track overview popover. """ # also reset the book playing state if self.current_book_element: self.current_book_element.set_playing(False) curr_track = player.get_current_track() self.current_book_element = next( filter(lambda x: x.book.id == curr_track.book.id, self.book_box.get_children()), None) self.block_ui_buttons(False, True)
def __init_components(self): self.titlebar = Titlebar() self.sleep_timer = SleepTimer() self.speed = PlaybackSpeed() self.settings = Settings() self.book_overview = BookOverview() self.fs_monitor = fs_monitor.FilesystemMonitor() self.offline_cache = offline_cache.OfflineCache() player.init() self.titlebar.activate() if player.get_current_track() is None: self.block_ui_buttons(True)
def __update_progress_scale_range(self): """ Update the progress scale range including the current playback speed. """ current_track = player.get_current_track() if not current_track or not self.current_book: return if self._application_settings.titlebar_remaining_time: total = get_book_duration( self.current_book) / self.ui.speed.get_speed() else: total = current_track.length / self.ui.speed.get_speed() self.progress_scale.set_range(0, total)
def __player_changed(self, event, message): """ Listen to and handle all gst player messages that are important for the ui. """ if event == "stop": if self.__inhibit_cookie: self.app.uninhibit(self.__inhibit_cookie) self.is_playing = False self.stop() self.titlebar.stop() self.sleep_timer.stop() elif event == "play": self.is_playing = True self.play() self.titlebar.play() self.sleep_timer.start() self.book_overview.select_track(None, True) self.refresh_recent() self.__inhibit_cookie = self.app.inhibit( self.window, Gtk.ApplicationInhibitFlags.SUSPEND, "Playback of audiobook") elif event == "pause": if self.__inhibit_cookie: self.app.uninhibit(self.__inhibit_cookie) self.is_playing = False self.pause() self.titlebar.pause() self.sleep_timer.stop() self.book_overview.select_track(None, False) elif event == "track-changed": self.track_changed() if self.sort_stack.props.visible_child_name == "recent": self.book_box.invalidate_filter() self.book_box.invalidate_sort() elif event == "error": if self.dialog_open: return if "Resource not found" in str(message): current_track = player.get_current_track() if db.is_external(current_track.book): player.stop() player.unload() player.emit_event("stop") else: self.dialog_open = True dialog = FileNotFoundDialog( current_track.file) dialog.show()
def __on_button_press(self, eventbox, event): """ Play the selected track. """ current_track = player.get_current_track() if current_track and current_track.id == self.track.id: player.play_pause(None) if player.get_gst_player_state() == Gst.State.PLAYING: player.jump_to_ns(Track.select().where( Track.id == self.track.id).get().position) else: player.load_file( Track.select().where(Track.id == self.track.id).get()) player.play_pause(None, True) Book.update(position=self.track).where( Book.id == self.track.book.id).execute()
def __on_play_clicked(self, event): """ Play button clicked. Start/pause playback. """ track = get_track_for_playback(self.book) current_track = player.get_current_track() if current_track and current_track.book.id == self.book.id: player.play_pause(None) if player.get_gst_player_state() == Gst.State.PLAYING: player.jump_to_ns(track.position) else: player.load_file(track) player.play_pause(None, True) return True
def load_last_book(self): if Settings.get().last_played_book: self.update_track_ui() self.update_ui_time(self.progress_scale) cur_m, cur_s = player.get_current_duration_ui() self.__set_progress_scale_value(cur_m * 60 + cur_s) pos = int(player.get_current_track().position) if tools.get_glib_settings().get_boolean("replay"): log.info("Replaying the previous 30 seconds.") amount = 30 * 1000000000 if (pos < amount): pos = 0 else: pos = pos - amount self.__set_progress_scale_value( int(pos / 1000000000 / self.ui.speed.get_speed()))
def switch_to_playing(self): """ Switch the UI state back to playing. This enables all UI functionality for the user. """ self.titlebar.switch_to_playing() if self.main_stack.props.visible_child_name != "book_overview" and self.main_stack.props.visible_child_name != "nothing_here" and self.main_stack.props.visible_child_name != "no_media": self.main_stack.props.visible_child_name = "main" if self.main_stack.props.visible_child_name != "no_media" and self.main_stack.props.visible_child_name != "book_overview": self.category_toolbar.set_visible(True) if player.get_current_track(): self.block_ui_buttons(False, True) else: # we want to only block the player controls self.block_ui_buttons(False, True) self.block_ui_buttons(True, False) self.window.props.window.set_cursor(None)
def get_playback_start_position(self): """ Returns the position where to start playback of the current track. This checks for the automatic replay option. :return: Position in ns """ pos = player.get_current_track().position if self.first_play: self.first_play = False if tools.get_glib_settings().get_boolean("replay"): amount = 30 * 1000000000 if pos < amount: pos = 0 else: pos = pos - amount return pos
def _on_play_button_press(self, widget, event): """ Play this book. """ if event.type == Gdk.EventType.BUTTON_PRESS and event.button != 1: return track = db.get_track_for_playback(self.book) current_track = player.get_current_track() if current_track and current_track.book.id == self.book.id: player.play_pause(None) if player.get_gst_player_state() == Gst.State.PLAYING: player.jump_to_ns(track.position) else: player.load_file(track) player.play_pause(None, True) return True
def __player_changed(self, event, message): """ React to player changes. """ if self.book is None or self.ui.titlebar.current_book is None or self.ui.titlebar.current_book.id != self.book.id: return if event == "play": self.play_book_button.set_image(self.pause_img) self.current_track_element.set_playing(True) self.last_played_label.set_text( tools.past_date_to_human_readable(message.book.last_played)) elif event == "pause": self.play_book_button.set_image(self.play_img) self.current_track_element.set_playing(False) elif event == "stop": self._mark_current_track() elif event == "track-changed": track = player.get_current_track() self._set_active_track(track, player.is_playing())
def __on_progress_clicked(self, widget, sender): """ Jump to the slided time and release the progress scale update lock. """ value = self.progress_scale.get_value() * self.ui.speed.get_speed() if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): track, time = get_track_from_book_time(self.current_book, value) if track.id == player.get_current_track().id: player.jump_to(time) else: player.load_file(track) player.play_pause(None, True) self.__set_progress_scale_value(time / self.ui.speed.get_speed()) player.jump_to(time) else: player.jump_to(value) self.progress_scale_clicked = False return False
def __on_rewind_clicked(self, button): """ """ seconds = 30 * self.ui.speed.get_speed() if self.ui.first_play: ns = seconds * 1000000000 track = player.get_current_track() pos = track.position if (pos > ns): pos -= ns else: pos = 0 player.save_current_track_position(pos=pos, track=track) else: player.rewind(seconds) # we want to see the jump imediatly therefore we apply the new time manually if self.progress_scale.get_value() > 30: self.progress_scale.set_value(self.progress_scale.get_value() - 30) else: self.progress_scale.set_value(0)
def update_track_ui(self): # set data of new stream in ui track = player.get_current_track() if track is None: return self.title_label.set_text(track.book.name) self.subtitle_label.set_text(track.name) self.block_ui_buttons(False) self.progress_scale.set_sensitive(True) self.progress_scale.set_visible(True) # only change cover when book has changed if self.current_book is not track.book: self.current_book = track.book if tools.is_elementary(): size = 28 else: size = 40 self.set_title_cover( artwork_cache.get_cover_pixbuf( track.book, self.ui.window.get_scale_factor(), size), size) self.current_remaining = db.get_book_remaining(self.current_book, False) self.current_elapsed = db.get_book_progress(self.current_book, False) self.__update_progress_scale_range() if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): self.progress_scale.set_value(self.current_elapsed / self.ui.speed.get_speed()) else: self.progress_scale.set_value(0) self.update_ui_time(None) self.current_label.set_visible(True) self.remaining_label.set_visible(True)
def __init_components(self): if player.get_current_track() is None: self.block_ui_buttons(True) self._importer.add_listener(self._on_importer_event)