Fix MPV socket getting created in CWD (#675) (fixes #674)

* Disable creation of secondary MPV socket by default

* Fix secondary and primary MPV sockets getting conflated

* Store MPV socket in $XDG_RUNTIME_DIR
This commit is contained in:
peelz 2024-04-29 13:55:10 -04:00 committed by GitHub
parent 0a9700058e
commit 887131ef9f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 9 deletions

View File

@ -1,5 +1,6 @@
# coding:utf8 # coding:utf8
import os import os
import random
import re import re
import sys import sys
import time import time
@ -10,7 +11,7 @@ import ast
from syncplay import constants from syncplay import constants
from syncplay.messages import getMessage from syncplay.messages import getMessage
from syncplay.players.basePlayer import BasePlayer from syncplay.players.basePlayer import BasePlayer
from syncplay.utils import isURL, findResourcePath from syncplay.utils import getRuntimeDir, isURL, findResourcePath
from syncplay.utils import isMacOS, isWindows, isASCII from syncplay.utils import isMacOS, isWindows, isASCII
from syncplay.vendor.python_mpv_jsonipc.python_mpv_jsonipc import MPV from syncplay.vendor.python_mpv_jsonipc.python_mpv_jsonipc import MPV
@ -375,7 +376,7 @@ class MpvPlayer(BasePlayer):
self._listener.sendLine(['loadfile', filePath], notReadyAfterThis=True) self._listener.sendLine(['loadfile', filePath], notReadyAfterThis=True)
def setFeatures(self, featureList): def setFeatures(self, featureList):
self.sendMpvOptions() self._sendMpvOptions()
def setPosition(self, value): def setPosition(self, value):
if value < constants.DO_NOT_RESET_POSITION_THRESHOLD and self._recentlyReset(): if value < constants.DO_NOT_RESET_POSITION_THRESHOLD and self._recentlyReset():
@ -408,7 +409,7 @@ class MpvPlayer(BasePlayer):
self._storePosition(0) self._storePosition(0)
# TO TRY: self._listener.setReadyToSend(False) # TO TRY: self._listener.setReadyToSend(False)
def sendMpvOptions(self): def _sendMpvOptions(self):
options = [] options = []
for option in constants.MPV_SYNCPLAYINTF_OPTIONS_TO_SEND: for option in constants.MPV_SYNCPLAYINTF_OPTIONS_TO_SEND:
options.append("{}={}".format(option, self._client._config[option])) options.append("{}={}".format(option, self._client._config[option]))
@ -420,8 +421,9 @@ class MpvPlayer(BasePlayer):
options_string = ", ".join(options) options_string = ", ".join(options)
self._listener.sendLine(["script-message-to", "syncplayintf", "set_syncplayintf_options", options_string]) self._listener.sendLine(["script-message-to", "syncplayintf", "set_syncplayintf_options", options_string])
self._setOSDPosition() self._setOSDPosition()
publicIPCSocket = self._listener.mpv_arguments.get("input-ipc-server") if self._listener.mpv_arguments.get("input-ipc-server") else "mpvSyncplaySocket" socketPath = self._listener.mpv_arguments.get("input-ipc-server")
self._setProperty("input-ipc-server", publicIPCSocket) if socketPath is not None:
self._setProperty("input-ipc-server", socketPath)
def _handleUnknownLine(self, line): def _handleUnknownLine(self, line):
self.mpvErrorCheck(line) self.mpvErrorCheck(line)
@ -449,7 +451,7 @@ class MpvPlayer(BasePlayer):
#self._client.ui.showDebugMessage("{} = {} / {}".format(update_string, paused_update, position_update)) #self._client.ui.showDebugMessage("{} = {} / {}".format(update_string, paused_update, position_update))
if "<get_syncplayintf_options>" in line: if "<get_syncplayintf_options>" in line:
self.sendMpvOptions() self._sendMpvOptions()
if line == "<SyncplayUpdateFile>" or "Playing:" in line: if line == "<SyncplayUpdateFile>" or "Playing:" in line:
self._client.ui.showDebugMessage("Not ready to send due to <SyncplayUpdateFile>") self._client.ui.showDebugMessage("Not ready to send due to <SyncplayUpdateFile>")
@ -620,8 +622,15 @@ class MpvPlayer(BasePlayer):
env['PATH'] = python_executable + ':' + env['PATH'] env['PATH'] = python_executable + ':' + env['PATH']
env['PYTHONPATH'] = pythonPath env['PYTHONPATH'] = pythonPath
try: try:
socket = self.mpv_arguments.get('input-ipc-server') self.mpvpipe = self.playerIPCHandler(
self.mpvpipe = self.playerIPCHandler(mpv_location=self.playerPath, ipc_socket=socket, loglevel="info", log_handler=self.__playerController.mpv_log_handler, quit_callback=self.stop_client, env=env, **self.mpv_arguments) loglevel="info",
ipc_socket=self._get_ipc_socket(),
mpv_location=self.playerPath,
log_handler=self.__playerController.mpv_log_handler,
quit_callback=self.stop_client,
env=env,
**self.mpv_arguments
)
except Exception as e: except Exception as e:
self.quitReason = getMessage("media-player-error").format(str(e)) + " " + getMessage("mpv-failed-advice") self.quitReason = getMessage("media-player-error").format(str(e)) + " " + getMessage("mpv-failed-advice")
self.__playerController.reactor.callFromThread(self.__playerController._client.ui.showErrorMessage, self.quitReason, True) self.__playerController.reactor.callFromThread(self.__playerController._client.ui.showErrorMessage, self.quitReason, True)
@ -630,6 +639,12 @@ class MpvPlayer(BasePlayer):
#self.mpvpipe.show_text("HELLO WORLD!", 1000) #self.mpvpipe.show_text("HELLO WORLD!", 1000)
threading.Thread.__init__(self, name="MPV Listener") threading.Thread.__init__(self, name="MPV Listener")
def _get_ipc_socket(self):
if isWindows():
# On Windows, mpv expects a named pipe identifier (not a path)
return "syncplay-mpv-{0}".format(random.randint(0, 2**48))
return getRuntimeDir().joinpath("mpv-socket").as_posix()
def __getCwd(self, filePath, env): def __getCwd(self, filePath, env):
if not filePath: if not filePath:
return None return None

View File

@ -1,5 +1,5 @@
import ast import ast
import atexit
import datetime import datetime
import hashlib import hashlib
import itertools import itertools
@ -10,11 +10,13 @@ import re
import string import string
import subprocess import subprocess
import sys import sys
import tempfile
import time import time
import traceback import traceback
import urllib.error import urllib.error
import urllib.parse import urllib.parse
import urllib.request import urllib.request
from pathlib import Path
from syncplay import constants from syncplay import constants
from syncplay.messages import getMessage from syncplay.messages import getMessage
@ -37,9 +39,28 @@ def isMacOS():
def isBSD(): def isBSD():
return constants.OS_BSD in sys.platform or sys.platform.startswith(constants.OS_DRAGONFLY) return constants.OS_BSD in sys.platform or sys.platform.startswith(constants.OS_DRAGONFLY)
def isWindowsConsole(): def isWindowsConsole():
return os.path.basename(sys.executable) == "SyncplayConsole.exe" return os.path.basename(sys.executable) == "SyncplayConsole.exe"
def getRuntimeDir():
cachedPath = getattr(getRuntimeDir, "cachedPath", None)
if cachedPath is not None:
return cachedPath
baseDir = None
if not isWindows() and not isMacOS():
baseDir = os.getenv("XDG_RUNTIME_DIR", None)
tmp = tempfile.TemporaryDirectory(prefix="syncplay-", dir=baseDir)
atexit.register(tmp.cleanup)
o = Path(tmp.name)
setattr(getRuntimeDir, "cachedPath", o)
return o
def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None): def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
"""Retry calling the decorated function using an exponential backoff. """Retry calling the decorated function using an exponential backoff.