summaryrefslogtreecommitdiff
path: root/modui/mpvwidget.py
diff options
context:
space:
mode:
authorMia Herkt <mia@0x0.st>2022-12-20 15:45:55 +0100
committerMia Herkt <mia@0x0.st>2022-12-20 16:19:49 +0100
commiteebd5d8c6d8a756384b6cf1b2cc76b8a83cdf929 (patch)
tree764a7c28cbdc165d0cf843f8cc0f6bc53ab224b6 /modui/mpvwidget.py
parentdcea8bffe19b8ba308f9361d6c8ef08281ddff1b (diff)
Add moderation TUI
This ended up way fancier than I imagined.
Diffstat (limited to 'modui/mpvwidget.py')
-rw-r--r--modui/mpvwidget.py88
1 files changed, 88 insertions, 0 deletions
diff --git a/modui/mpvwidget.py b/modui/mpvwidget.py
new file mode 100644
index 0000000..50e5859
--- /dev/null
+++ b/modui/mpvwidget.py
@@ -0,0 +1,88 @@
+import time
+import fcntl, struct, termios
+from sys import stdout
+
+from textual import events, log
+from textual.widgets import Static
+
+from fhost import app as fhost_app
+
+class MpvWidget(Static):
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
+
+ self.mpv = None
+ self.vo = fhost_app.config.get("MOD_PREVIEW_PROTO")
+
+ if not self.vo in ["sixel", "kitty"]:
+ self.update("⚠ Previews not enabled. \n\nSet MOD_PREVIEW_PROTO to 'sixel' or 'kitty' in config.py,\nwhichever is supported by your terminal.")
+ else:
+ try:
+ import mpv
+ self.mpv = mpv.MPV()
+ self.mpv.profile = "sw-fast"
+ self.mpv["vo"] = self.vo
+ self.mpv[f"vo-{self.vo}-config-clear"] = False
+ self.mpv[f"vo-{self.vo}-alt-screen"] = False
+ self.mpv[f"vo-sixel-buffered"] = True
+ self.mpv["audio"] = False
+ self.mpv["loop-file"] = "inf"
+ self.mpv["image-display-duration"] = 0.5 if self.vo == "sixel" else "inf"
+ except Exception as e:
+ self.mpv = None
+ self.update(f"⚠ Previews require python-mpv with libmpv 0.36.0 or later \n\nError was:\n{type(e).__name__}: {e}")
+
+ def start_mpv(self, f: str|None = None, pos: float|str|None = None) -> None:
+ self.display = True
+ self.screen._refresh_layout()
+
+ if self.mpv:
+ if self.content_region.x:
+ r, c, w, h = struct.unpack('hhhh', fcntl.ioctl(0, termios.TIOCGWINSZ, '12345678'))
+ width = int((w / c) * self.content_region.width)
+ height = int((h / r) * (self.content_region.height + (1 if self.vo == "sixel" else 0)))
+ self.mpv[f"vo-{self.vo}-left"] = self.content_region.x + 1
+ self.mpv[f"vo-{self.vo}-top"] = self.content_region.y + 1
+ self.mpv[f"vo-{self.vo}-rows"] = self.content_region.height + (1 if self.vo == "sixel" else 0)
+ self.mpv[f"vo-{self.vo}-cols"] = self.content_region.width
+ self.mpv[f"vo-{self.vo}-width"] = width
+ self.mpv[f"vo-{self.vo}-height"] = height
+
+ if pos != None:
+ self.mpv["start"] = pos
+
+ if f:
+ self.mpv.loadfile(f)
+ else:
+ self.mpv.playlist_play_index(0)
+
+ def stop_mpv(self, wait: bool = False) -> None:
+ if self.mpv:
+ if not self.mpv.idle_active:
+ self.mpv.stop(True)
+ if wait:
+ time.sleep(0.1)
+ self.clear_mpv()
+ self.display = False
+
+ def on_resize(self, size) -> None:
+ if self.mpv:
+ if not self.mpv.idle_active:
+ t = self.mpv.time_pos
+ self.stop_mpv()
+ if t:
+ self.mpv["start"] = t
+ self.start_mpv()
+
+ def clear_mpv(self) -> None:
+ if self.vo == "kitty":
+ stdout.write("\033_Ga=d;\033\\")
+ stdout.flush()
+
+ def shutdown(self) -> None:
+ if self.mpv:
+ self.mpv.stop()
+ del self.mpv
+ if self.vo == "kitty":
+ stdout.write("\033_Ga=d;\033\\\033[?25l")
+ stdout.flush()