149 lines
4.4 KiB
Python
149 lines
4.4 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
from enum import Enum, auto
|
|
from pathlib import Path
|
|
from typing import Optional, overload
|
|
|
|
from gi.repository import Gio, GObject
|
|
|
|
|
|
class FileType(Enum):
|
|
DIRECTORY = auto()
|
|
VIDEO = auto()
|
|
|
|
|
|
class FileItem(GObject.Object):
|
|
file_type: FileType
|
|
full_path: Path
|
|
thumbnail: bytes
|
|
_has_thumbnail: bool
|
|
|
|
__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
|
|
self.thumbnail = b""
|
|
self._has_thumbnail = False
|
|
|
|
@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")
|
|
|
|
@GObject.Property(type=int)
|
|
def saved_audio_track(self):
|
|
return self._load_attribute("audio_track", 0)
|
|
|
|
@saved_audio_track.setter
|
|
def set_saved_audio_track(self, value: int):
|
|
self._save_attribute("audio_track", value if value > 0 else None)
|
|
self.notify("saved-audio-track")
|
|
|
|
@GObject.Property(type=bool, default=False)
|
|
def has_thumbnail(self):
|
|
return self._has_thumbnail
|
|
|
|
@has_thumbnail.setter
|
|
def set_has_thumbnail(self, value: bool):
|
|
self._has_thumbnail = value
|
|
self.notify("has-thumbnail")
|
|
|
|
@overload
|
|
def _load_attribute(self, name: str, dfl: str) -> str: ...
|
|
|
|
@overload
|
|
def _load_attribute(self, name: str, dfl: bytes) -> bytes: ...
|
|
|
|
@overload
|
|
def _load_attribute(self, name: str, dfl: int) -> int: ...
|
|
|
|
def _load_attribute(self, name: str, dfl: str | bytes | int) -> str | bytes | 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 | bytes | float | int | None) -> None:
|
|
try:
|
|
if value is None:
|
|
os.removexattr(self.full_path, f"user.lazy_player.{name}")
|
|
else:
|
|
if isinstance(value, bytes):
|
|
os.setxattr(self.full_path, f"user.lazy_player.{name}", value)
|
|
else:
|
|
os.setxattr(
|
|
self.full_path, f"user.lazy_player.{name}", str(value).encode("utf8")
|
|
)
|
|
except OSError as err:
|
|
print(err, file=sys.stderr)
|
|
|
|
|
|
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)
|