From bd0e2c1154c823503e97a91500e9ec17180f4278 Mon Sep 17 00:00:00 2001
From: Christian Heller <c.heller@plomlompom.de>
Date: Thu, 28 Nov 2024 19:53:29 +0100
Subject: [PATCH] Enforce proper mpv window closing even on direct keystroke
 input.

---
 src/ytplom/misc.py | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/src/ytplom/misc.py b/src/ytplom/misc.py
index 4d544ba..a85e6bc 100644
--- a/src/ytplom/misc.py
+++ b/src/ytplom/misc.py
@@ -17,6 +17,7 @@ from urllib.parse import urlparse, parse_qs
 from urllib.request import urlretrieve
 from urllib.error import HTTPError
 from threading import Thread
+from queue import Queue
 # non-included libs
 from jinja2 import (  # type: ignore
         Environment as JinjaEnv, FileSystemLoader as JinjaFSLoader)
@@ -473,6 +474,28 @@ class Player:
         self.last_update = PlayerUpdateId('')
         self._load_filenames()
         self._mpv: Optional[MPV] = None
+        self._kill_queue: Queue = Queue()
+        self._monitoring_kill = False
+
+    def _monitor_kill(self) -> None:
+        """Properly enforce mpv shutdown from direct interaction with mpv
+        client, as may happen with the "q" keystroke.  If not for the handling
+        below, this may keep the 'shutdown' window open/undead, as proper
+        destruction only seems ensured when commanded from within the main
+        Python thread …?
+        """
+        if self._monitoring_kill:
+            return
+        self._monitoring_kill = True
+
+        def kill_on_queue_get() -> None:
+            self._kill_queue.get()
+            if self._mpv:
+                self._mpv.wait_for_shutdown()
+            self._kill_mpv()
+            self._monitoring_kill = False
+
+        Thread(target=kill_on_queue_get, daemon=True).start()
 
     def _load_filenames(self) -> None:
         conn = DbConnection()
@@ -493,6 +516,7 @@ class Player:
         self._mpv = MPV(input_default_bindings=True,
                         input_vo_keyboard=True,
                         config=True)
+        self._monitor_kill()
         self._mpv.observe_property('pause', lambda a, b: self._signal_update())
         for path in [f.full_path for f in self._files]:
             self._mpv.command('loadfile', path, 'append')
@@ -506,8 +530,10 @@ class Player:
 
         @self._mpv.event_callback('shutdown')
         def on_shutdown(_) -> None:
-            self._mpv = None
-            self._signal_update()
+            """To properly enforce shutdown even on direct client interaction,
+            see self._monitor_kill for more thorough explanation.
+            """
+            self._kill_queue.put(True)
 
         self._mpv.command('playlist-play-index', self._idx)
 
@@ -515,6 +541,7 @@ class Player:
         if self._mpv:
             self._mpv.terminate()
             self._mpv = None
+        self._signal_update()
 
     @property
     def current_file(self) -> Optional[VideoFile]:
-- 
2.30.2