lazy-player/lazy_player/file_model.py

121 lines
3.5 KiB
Python

from __future__ import annotations
import os
from enum import Enum, auto
from pathlib import Path
from typing import Optional, overload
import gi
gi.require_version("GObject", "2.0")
from gi.repository import Gio, GObject # NOQA: E402
class FileType(Enum):
DIRECTORY = auto()
VIDEO = auto()
class FileItem(GObject.Object):
file_type: FileType
full_path: Path
__gtype_name__ = "FileItem"
def __init__(self, name: str, file_type: FileType, full_path: Path):
super().__init__()
self.name = name
self.file_type = file_type
self.full_path = full_path
@GObject.Property(type=GObject.TYPE_UINT64)
def saved_position(self) -> int:
return self._load_attribute("position", 0)
@saved_position.setter
def set_saved_position(self, value: int):
self._save_attribute("position", value if value else None)
self.notify("saved-position")
@GObject.Property(type=GObject.TYPE_UINT64)
def saved_duration(self):
return self._load_attribute("duration", 1) or 1
@saved_duration.setter
def set_saved_duration(self, value: int):
self._save_attribute("duration", value if value > 0 else None)
self.notify("saved-duration")
@GObject.Property(type=int)
def saved_subtitle_track(self):
return self._load_attribute("subtitle_track", -2)
@saved_subtitle_track.setter
def set_saved_subtitle_track(self, value: int):
self._save_attribute("subtitle_track", value if value >= -1 else None)
self.notify("saved-subtitle-track")
@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:
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:
pass
class FileListModel(GObject.Object, Gio.ListModel):
"""A ListModel implementation for FileItems"""
__gtype_name__ = "FileListModel"
items: list[FileItem]
def __init__(self):
super().__init__()
self.items = []
def do_get_item_type(self) -> GObject.GType:
return GObject.type_from_name("FileItem")
def do_get_n_items(self) -> int:
return len(self.items)
def do_get_item(self, position: int) -> Optional[FileItem]:
if 0 <= position < len(self.items):
return self.items[position]
return None
def remove_all(self) -> None:
removed = len(self.items)
self.items = []
self.items_changed(0, removed, 0)
def set_items(self, items: list[FileItem]):
removed = len(self.items)
self.items = list(items)
self.items_changed(0, removed, len(self.items))
def append(self, item: FileItem) -> None:
pos = len(self.items)
self.items.append(item)
self.items_changed(pos, 0, 1)
def remove(self, position: int) -> None:
if 0 <= position < len(self.items):
self.items.pop(position)
self.items_changed(position, 1, 0)