Refactor FileItem

This commit is contained in:
Jan Hamal Dvořák 2025-03-09 09:57:24 +01:00
parent 1f32d17d19
commit f89623a201
2 changed files with 44 additions and 52 deletions

View file

@ -3,7 +3,7 @@ from __future__ import annotations
import os import os
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Any, cast, overload from typing import Any, cast
import gi import gi
@ -152,13 +152,13 @@ class MainWindow(Gtk.ApplicationWindow):
self._populate_file_list() self._populate_file_list()
return return
position = self._load_attribute("position", 0) position = file_item.load_attribute("position", 0)
# Start playing the video # Start playing the video
full_path = os.path.abspath(file_item.full_path) full_path = os.path.abspath(file_item.full_path)
self.playbin.set_property("uri", f"file://{full_path}") self.playbin.set_property("uri", f"file://{full_path}")
track = self._load_attribute("subtitle_track", -2) track = file_item.load_attribute("subtitle_track", -2)
if track >= 0: if track >= 0:
flags = self.playbin.get_property("flags") flags = self.playbin.get_property("flags")
@ -207,18 +207,10 @@ class MainWindow(Gtk.ApplicationWindow):
self.set_child(self.stack) self.set_child(self.stack)
@property @property
def currently_playing(self): def selection(self) -> FileItem:
selected_item = self.selection_model.get_selected_item() selected_item = self.selection_model.get_selected_item()
assert selected_item
if not selected_item: return cast(FileItem, selected_item)
return None
file_item = cast(FileItem, selected_item)
if file_item.file_type == FileType.DIRECTORY:
return None
return file_item.full_path
def _setup_list_item(self, factory: Gtk.SignalListItemFactory, list_item: Gtk.ListItem): def _setup_list_item(self, factory: Gtk.SignalListItemFactory, list_item: Gtk.ListItem):
# Create horizontal box to hold icon and label # Create horizontal box to hold icon and label
@ -367,46 +359,15 @@ class MainWindow(Gtk.ApplicationWindow):
def _save_position(self) -> None: def _save_position(self) -> None:
"""Save current playback position as xattr""" """Save current playback position as xattr"""
file_item = self.selection
assert file_item.file_type != FileType.DIRECTORY
success, position = self.pipeline.query_position(Gst.Format.TIME) success, position = self.pipeline.query_position(Gst.Format.TIME)
success2, duration = self.pipeline.query_duration(Gst.Format.TIME) success2, duration = self.pipeline.query_duration(Gst.Format.TIME)
if success and success2: if success and success2:
self._save_attribute("position", position) file_item.save_attribute("position", position)
self._save_attribute("duration", duration) file_item.save_attribute("duration", duration)
def _save_attribute(self, name: str, value: str | float | int | None):
path = self.currently_playing
if path is None:
return
try:
if value is None:
os.removexattr(path, f"user.lazy_player.{name}")
else:
os.setxattr(path, f"user.lazy_player.{name}", str(value).encode("utf8"))
except OSError as err:
print(err, file=sys.stderr)
@overload
def _load_attribute(self, name: str, dfl: str) -> str: ...
@overload
def _load_attribute(self, name: str, dfl: int) -> int: ...
def _load_attribute(self, name: str, dfl: str | int) -> str | int:
path = self.currently_playing
if path is None:
return dfl
try:
strval = os.getxattr(path, f"user.lazy_player.{name}")
return type(dfl)(strval)
except OSError as err:
print(err, file=sys.stderr)
return dfl
def _cycle_subtitles(self) -> None: def _cycle_subtitles(self) -> None:
"""Cycle through available subtitle tracks, including off state""" """Cycle through available subtitle tracks, including off state"""
@ -427,7 +388,9 @@ class MainWindow(Gtk.ApplicationWindow):
self.playbin.set_property("current-text", 0) self.playbin.set_property("current-text", 0)
track_info = self._get_subtitle_info(0) track_info = self._get_subtitle_info(0)
self.show_overlay_text(f"Subtitle track: {track_info}") self.show_overlay_text(f"Subtitle track: {track_info}")
self._save_attribute("subtitle_track", 0) file_item = self.selection
assert file_item.file_type != FileType.DIRECTORY
file_item.save_attribute("subtitle_track", 0)
return return
# If we're on the last track, disable subtitles # If we're on the last track, disable subtitles
@ -435,7 +398,9 @@ class MainWindow(Gtk.ApplicationWindow):
flags &= ~0x00000004 # TEXT flag flags &= ~0x00000004 # TEXT flag
self.playbin.set_property("flags", flags) self.playbin.set_property("flags", flags)
self.show_overlay_text("Subtitles: Off") self.show_overlay_text("Subtitles: Off")
self._save_attribute("subtitle_track", -1) file_item = self.selection
assert file_item.file_type != FileType.DIRECTORY
file_item.save_attribute("subtitle_track", -1)
return return
# Otherwise cycle to next track # Otherwise cycle to next track
@ -443,7 +408,9 @@ class MainWindow(Gtk.ApplicationWindow):
self.playbin.set_property("current-text", next_track) self.playbin.set_property("current-text", next_track)
track_info = self._get_subtitle_info(next_track) track_info = self._get_subtitle_info(next_track)
self.show_overlay_text(f"Subtitle track: {track_info}") self.show_overlay_text(f"Subtitle track: {track_info}")
self._save_attribute("subtitle_track", next_track) file_item = self.selection
assert file_item.file_type != FileType.DIRECTORY
file_item.save_attribute("subtitle_track", next_track)
def show_overlay_text(self, text: str, timeout_seconds: float = 1.0) -> None: def show_overlay_text(self, text: str, timeout_seconds: float = 1.0) -> None:
"""Show text in a centered overlay that disappears after timeout""" """Show text in a centered overlay that disappears after timeout"""

View file

@ -1,7 +1,9 @@
from __future__ import annotations from __future__ import annotations
import os import os
import sys
from enum import Enum, auto from enum import Enum, auto
from typing import overload
import gi import gi
@ -39,3 +41,26 @@ class FileItem(GObject.Object):
return FileItem(name, FileType.VIDEO, path) return FileItem(name, FileType.VIDEO, path)
raise ValueError(f"Unsupported file type: {path}") raise ValueError(f"Unsupported file type: {path}")
@overload
def load_attribute(self, name: str, dfl: str) -> str: ...
@overload
def load_attribute(self, name: str, dfl: int) -> int: ...
def load_attribute(self, name: str, dfl: str | int) -> str | int:
try:
strval = os.getxattr(self.full_path, f"user.lazy_player.{name}")
return type(dfl)(strval)
except OSError as err:
print(err, file=sys.stderr)
return dfl
def save_attribute(self, name: str, value: str | float | int | None) -> None:
try:
if value is None:
os.removexattr(self.full_path, f"user.lazy_player.{name}")
else:
os.setxattr(self.full_path, f"user.lazy_player.{name}", str(value).encode("utf8"))
except OSError as err:
print(err, file=sys.stderr)