From 7301870d7cca4dd9b83ec0f89e3b01c50c682ad7 Mon Sep 17 00:00:00 2001 From: Alberto Sottile Date: Thu, 18 Mar 2021 19:55:49 +0100 Subject: [PATCH] Update python_mpv_jsonipc to 1.1.13 keeping our changes --- .../python_mpv_jsonipc/python_mpv_jsonipc.py | 86 +++++++++++-------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/syncplay/vendor/python_mpv_jsonipc/python_mpv_jsonipc.py b/syncplay/vendor/python_mpv_jsonipc/python_mpv_jsonipc.py index 7a0d287..3329b2d 100644 --- a/syncplay/vendor/python_mpv_jsonipc/python_mpv_jsonipc.py +++ b/syncplay/vendor/python_mpv_jsonipc/python_mpv_jsonipc.py @@ -38,7 +38,7 @@ class MPVError(Exception): class WindowsSocket(threading.Thread): """ Wraps a Windows named pipe in a high-level interface. (Internal) - + Data is automatically encoded and decoded as JSON. The callback function will be called for each inbound message. """ @@ -52,7 +52,7 @@ class WindowsSocket(threading.Thread): ipc_socket = "\\\\.\\pipe\\" + ipc_socket self.callback = callback self.quit_callback = quit_callback - + access = _winapi.GENERIC_READ | _winapi.GENERIC_WRITE limit = 5 # Connection may fail at first. Try 5 times. for _ in range(limit): @@ -120,7 +120,7 @@ class WindowsSocket(threading.Thread): class UnixSocket(threading.Thread): """ Wraps a Unix/Linux socket in a high-level interface. (Internal) - + Data is automatically encoded and decoded as JSON. The callback function will be called for each inbound message. """ @@ -189,7 +189,7 @@ class MPVProcess: """ Manages an MPV process, ensuring the socket or pipe is available. (Internal) """ - def __init__(self, ipc_socket, mpv_location=None, **kwargs): + def __init__(self, ipc_socket, mpv_location=None, env=None, **kwargs): """ Create and start the MPV process. Will block until socket/pipe is available. @@ -203,9 +203,8 @@ class MPVProcess: mpv_location = "mpv.exe" else: mpv_location = "mpv" - + log.debug("Staring MPV from {0}.".format(mpv_location)) - ipc_socket_name = ipc_socket if os.name == 'nt': ipc_socket = "\\\\.\\pipe\\" + ipc_socket @@ -214,14 +213,12 @@ class MPVProcess: log.debug("Using IPC socket {0} for MPV.".format(ipc_socket)) self.ipc_socket = ipc_socket - args = [mpv_location] - self._set_default(kwargs, "idle", True) - self._set_default(kwargs, "input_ipc_server", ipc_socket_name) - self._set_default(kwargs, "input_terminal", False) - self._set_default(kwargs, "terminal", False) - args.extend("--{0}={1}".format(v[0].replace("_", "-"), self._mpv_fmt(v[1])) - for v in kwargs.items()) - self.process = subprocess.Popen(args) + args = self._get_arglist(mpv_location, **kwargs) + + self._start_process(ipc_socket, args, env=env) + + def _start_process(self, ipc_socket, args, env): + self.process = subprocess.Popen(args, env=env) ipc_exists = False for _ in range(100): # Give MPV 10 seconds to start. time.sleep(0.1) @@ -236,7 +233,7 @@ class MPVProcess: else: self.process.terminate() raise MPVError("MPV start timed out.") - + if not ipc_exists or self.process.returncode is not None: self.process.terminate() raise MPVError("MPV not started.") @@ -245,6 +242,16 @@ class MPVProcess: if key not in prop_dict: prop_dict[key] = value + def _get_arglist(self, exec_location, **kwargs): + args = [exec_location] + self._set_default(kwargs, "idle", True) + self._set_default(kwargs, "input_ipc_server", self.ipc_socket) + self._set_default(kwargs, "input_terminal", False) + self._set_default(kwargs, "terminal", False) + args.extend("--{0}={1}".format(v[0].replace("_", "-"), self._mpv_fmt(v[1])) + for v in kwargs.items()) + return args + def _mpv_fmt(self, data): if data == True: return "yes" @@ -278,7 +285,7 @@ class MPVInter: self.quit_callback = quit_callback if self.callback is None: self.callback = lambda event, data: None - + self.socket = Socket(ipc_socket, self.event_callback, self.quit_callback) self.socket.start() self.command_id = 1 @@ -286,7 +293,7 @@ class MPVInter: self.socket_lock = threading.Lock() self.cid_result = {} self.cid_wait = {} - + def stop(self, join=True): """Terminate the underlying connection.""" self.socket.stop(join) @@ -298,11 +305,11 @@ class MPVInter: self.cid_wait[data["request_id"]].set() elif "event" in data: self.callback(data["event"], data) - + def command(self, command, *args): """ Issue a command to MPV. Will block until completed or timeout is reached. - + *command* is the name of the MPV command All further arguments are forwarded to the MPV command. @@ -344,13 +351,13 @@ class EventHandler(threading.Thread): """Create an instance of the thread.""" self.queue = queue.Queue() threading.Thread.__init__(self) - + def put_task(self, func, *args): """ Put a new task to the thread. - + *func* is the function to call - + All further arguments are forwarded to *func*. """ self.queue.put((func, args)) @@ -374,10 +381,10 @@ class EventHandler(threading.Thread): class MPV: """ The main MPV interface class. Use this to control MPV. - + This will expose all mpv commands as callable methods and all properties. You can set properties and call the commands directly. - + Please note that if you are using a really old MPV version, a fallback command list is used. Not all commands may actually work when this fallback is used. """ @@ -412,16 +419,7 @@ class MPV: ipc_socket = "/tmp/{0}".format(rand_file) if start_mpv: - # Attempt to start MPV 3 times. - for i in range(3): - try: - self.mpv_process = MPVProcess(ipc_socket, mpv_location, **kwargs) - break - except MPVError: - log.warning("MPV start failed.", exc_info=1) - continue - else: - raise MPVError("MPV process retry limit reached.") + self._start_mpv(ipc_socket, mpv_location, **kwargs) self.mpv_inter = MPVInter(ipc_socket, self._callback, self._quit_callback) self.properties = set(x.replace("-", "_") for x in self.command("get_property", "property-list")) @@ -440,7 +438,7 @@ class MPV: self.observer_lock = threading.Lock() self.keybind_id = 1 self.keybind_lock = threading.Lock() - + if log_handler is not None and loglevel is not None: self.command("request_log_messages", loglevel) @self.on_event("log-message") @@ -458,6 +456,18 @@ class MPV: if len(args) == 2 and args[0] == "custom-bind": self.event_handler.put_task(self.key_bindings[args[1]]) + def _start_mpv(self, ipc_socket, mpv_location, **kwargs): + # Attempt to start MPV 3 times. + for i in range(3): + try: + self.mpv_process = MPVProcess(ipc_socket, mpv_location, **kwargs) + break + except MPVError: + log.warning("MPV start failed.", exc_info=1) + continue + else: + raise MPVError("MPV process retry limit reached.") + def _quit_callback(self): """ Internal handler for quit events. @@ -567,7 +577,7 @@ class MPV: self.bind_property_observer(name, func) return func return wrapper - + def wait_for_property(self, name): """ Waits for the value of a property to change. @@ -615,11 +625,11 @@ class MPV: """ Send a command to MPV. All commands are bound to the class by default, except JSON IPC specific commands. This may also be useful to retain - compatibility with python-mpv, as it does not bind all of the commands. + compatibility with python-mpv, as it does not bind all of the commands. *command* is the command name. - All further arguments are forwarded to the MPV command. + All further arguments are forwarded to the MPV command. """ return self.mpv_inter.command(command, *args)