diff --git a/lazy_player/__init__.py b/lazy_player/__init__.py index 1e6a7f4..e4503f5 100644 --- a/lazy_player/__init__.py +++ b/lazy_player/__init__.py @@ -70,24 +70,24 @@ class MainWindow(Gtk.ApplicationWindow): self.video_widget.set_vexpand(True) self.video_widget.set_hexpand(True) - overlay_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - overlay_box.set_name("black-overlay") - overlay_box.set_vexpand(True) - overlay_box.set_hexpand(True) + video_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + video_box.set_name("black-overlay") + video_box.set_vexpand(True) + video_box.set_hexpand(True) # Create an overlay container overlay = Gtk.Overlay() overlay.set_child(self.video_widget) overlay.add_overlay(self.overlay_label) - overlay_box.append(overlay) + video_box.append(overlay) # Setup video player self.video_player = VideoPlayer(self.video_widget) # Add both main menu and overlay to stack self.stack.add_named(main_box, "menu") - self.stack.add_named(overlay_box, "overlay") + self.stack.add_named(video_box, "player") self.stack.set_visible_child_name("menu") # Create a grid to handle the 1:2 ratio @@ -139,8 +139,9 @@ class MainWindow(Gtk.ApplicationWindow): # Start playing the video track = file_item.load_attribute("subtitle_track", -2) self.video_player.play(file_item.full_path, position, track) + self.last_position_save = self.now - self.stack.set_visible_child_name("overlay") + self.stack.set_visible_child_name("player") self.show_overlay_text(f"Playing: {file_item.name}") self.list_view.connect("activate", on_activate) @@ -271,7 +272,7 @@ class MainWindow(Gtk.ApplicationWindow): """Toggle between play and pause states""" self.video_player.toggle_play_pause() - def _on_video_key_pressed( + def _on_player_key_pressed( self, keyval: int, keycode: int, @@ -313,8 +314,16 @@ class MainWindow(Gtk.ApplicationWindow): return True elif keyval == Gdk.keyval_from_name("j"): - msg = self.video_player.cycle_subtitles() - self.show_overlay_text(msg) + has_subs, index, lang = self.video_player.cycle_subtitles() + + if has_subs: + if index: + self.show_overlay_text(f"Subtitles #{index} ({lang})") + else: + self.show_overlay_text("Subtitles turned off") + else: + self.show_overlay_text("No subtitles available") + return True return False @@ -368,8 +377,8 @@ class MainWindow(Gtk.ApplicationWindow): state: Gdk.ModifierType, ) -> bool: # Handle keys differently based on which view is active - if self.stack.get_visible_child_name() == "overlay": - return self._on_video_key_pressed(keyval, keycode, state) + if self.stack.get_visible_child_name() == "player": + return self._on_player_key_pressed(keyval, keycode, state) else: return self._on_menu_key_pressed(keyval, keycode, state) diff --git a/lazy_player/style.css b/lazy_player/style.css index 9249466..a1411a1 100644 --- a/lazy_player/style.css +++ b/lazy_player/style.css @@ -28,7 +28,7 @@ listview > row { color: white; font-size: 24px; font-family: monospace; - background-color: rgba(64, 64, 64, 0.25); + background-color: rgba(32, 32, 32, 0.5); padding: 24px; border-radius: 8px; margin: 32px; diff --git a/lazy_player/video_player.py b/lazy_player/video_player.py index 4e697a7..e0e8502 100644 --- a/lazy_player/video_player.py +++ b/lazy_player/video_player.py @@ -7,16 +7,21 @@ import gi gi.require_version("Gtk", "4.0") gi.require_version("Gst", "1.0") -from gi.repository import Gst, Gtk # NOQA: E402 +gi.require_version("GObject", "2.0") +from gi.repository import GObject, Gst, Gtk # NOQA: E402 # NOQA: E402 -class VideoPlayer: +class VideoPlayer(GObject.Object): pipeline: Gst.Pipeline playbin: Gst.Element - is_playing: bool + + __gtype_name__ = "VideoPlayer" + + is_playing = GObject.Property(type=bool, default=False) + is_paused = GObject.Property(type=bool, default=True) def __init__(self, picture: Gtk.Picture): - self.is_playing = False + super().__init__() self.pipeline = Gst.Pipeline.new("video-player") @@ -55,11 +60,11 @@ class VideoPlayer: flags &= ~0x00000004 # TEXT flag self.playbin.set_property("flags", flags) - if position: - # Pause and wait for it to complete - self.pipeline.set_state(Gst.State.PAUSED) - self.pipeline.get_state(Gst.CLOCK_TIME_NONE) + # Pause and wait for it to complete + self.pipeline.set_state(Gst.State.PAUSED) + self.pipeline.get_state(Gst.CLOCK_TIME_NONE) + if position: # Seek to saved position self.pipeline.seek_simple( Gst.Format.TIME, @@ -69,20 +74,24 @@ class VideoPlayer: # Start playing self.pipeline.set_state(Gst.State.PLAYING) - self.is_playing = True + self.set_property("is-playing", True) + self.set_property("is-paused", False) def stop(self) -> None: """Stop playback and release resources""" self.pipeline.set_state(Gst.State.NULL) - self.is_playing = False + self.set_property("is-paused", True) + self.set_property("is-playing", False) def toggle_play_pause(self) -> None: """Toggle between play and pause states""" _, state, _ = self.pipeline.get_state(0) if state == Gst.State.PLAYING: self.pipeline.set_state(Gst.State.PAUSED) + self.set_property("is-paused", True) else: self.pipeline.set_state(Gst.State.PLAYING) + self.set_property("is-paused", False) def seek_relative(self, offset: float) -> None: """Seek relative to current position by offset seconds""" @@ -128,7 +137,7 @@ class VideoPlayer: success, duration = self.pipeline.query_duration(Gst.Format.TIME) return duration if success else None - def cycle_subtitles(self) -> str: + def cycle_subtitles(self) -> tuple[bool, int, str]: """Cycle through available subtitle tracks, including off state""" flags = self.playbin.get_property("flags") @@ -136,25 +145,24 @@ class VideoPlayer: n_text = self.playbin.get_property("n-text") if n_text == 0: - return "No subtitles available" + return False, 0, "" if not (flags & 0x00000004): # TEXT flag flags |= 0x00000004 self.playbin.set_property("flags", flags) self.playbin.set_property("current-text", 0) - return f"Subtitle track: {self._get_subtitle_info(0)}" + return True, 1, self._get_subtitle_lang(0) if current >= n_text - 1: flags &= ~0x00000004 # TEXT flag self.playbin.set_property("flags", flags) - return "Subtitles: Off" + return True, 0, "" next_track = current + 1 self.playbin.set_property("current-text", next_track) - return f"Subtitle track: {self._get_subtitle_info(next_track)}" + return True, next_track + 1, self._get_subtitle_lang(next_track) - def _get_subtitle_info(self, track_index: int) -> str: - """Get subtitle track info including language if available""" + def _get_subtitle_lang(self, track_index: int) -> str: caps: Gst.TagList | None = self.playbin.emit("get-text-tags", track_index) if not caps: return str(track_index)