From 47cf3af672fd17209275fb693e1b41dde498e42b Mon Sep 17 00:00:00 2001 From: prez <47797982+prez@users.noreply.github.com> Date: Thu, 2 Jul 2026 13:36:35 +0200 Subject: [PATCH] macos: fix yt-dlp closes #585 syncplay spawns mpv as a subprocess, inheriting its env. mpv in turn spawns yt-dlp, and this inherits PYTHONHOME / PYTHONPATH pointing at syncplay's bundled python, making any python change where it looks for its stdlib, causing it to crash with `ModuleNotFoundError: No module named 'encodings'`. I do not fully understand why the old code did things the way it did, but it appears as if it attempted to work around this by hardcoding PATH (questionable) to "common" (and incomplete) locations, then doing a peculiar and fragile dance to extract its PYTHONPATH... my hypothesis is that the only thing breaking yt-dlp is the inherited PYTHONHOME/PYTHONPATH, so just drop that and rely on python locating its stdlib. --- syncplay/players/mpv.py | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/syncplay/players/mpv.py b/syncplay/players/mpv.py index f1187c9e4..0a88e8110 100755 --- a/syncplay/players/mpv.py +++ b/syncplay/players/mpv.py @@ -2,17 +2,15 @@ import os import random import re -import sys import time import subprocess import threading -import ast from syncplay import constants from syncplay.messages import getMessage from syncplay.players.basePlayer import BasePlayer from syncplay.utils import getRuntimeDir, isURL, findResourcePath -from syncplay.utils import isMacOS, isWindows, isASCII +from syncplay.utils import isMacOS, isWindows from syncplay.utils import playerPathExists from syncplay.vendor.python_mpv_jsonipc.python_mpv_jsonipc import MPV @@ -601,30 +599,14 @@ def __init__(self, playerController, playerIPCHandler, playerPath, filePath, arg env = os.environ.copy() if 'TERM' in env: del env['TERM'] - # On macOS, youtube-dl requires system python to run. Set the environment - # to allow that version of python to be executed in the mpv subprocess. + # On macOS, the .app bundle sets PYTHONHOME and PYTHONPATH + # to the bundled Python. If inherited by mpv subprocesses + # (e.g. yt-dlp), this overrides where Python looks for its + # standard library, causing "No module named 'encodings'". + # Clear these so yt-dlp uses its own Python correctly if isMacOS(): - try: - env['PATH'] = '/opt/homebrew/bin:/usr/local/bin:/usr/bin' - ytdl_path = subprocess.check_output(['which', 'youtube-dl'], text=True, env=env).rstrip('\n') - with open(ytdl_path, 'rb') as f: - ytdl_shebang = f.readline() - ytdl_python = ytdl_shebang.decode('utf-8').lstrip('!#').rstrip('\n') - if '/usr/bin/env' in ytdl_python: - python_name = ytdl_python.split(' ')[1] - python_executable = subprocess.check_output(['which', python_name], text=True, env=env).rstrip('\n') - else: - python_executable = ytdl_python - pythonLibs = subprocess.check_output([python_executable, '-E', '-c', - 'import sys; print(sys.path)'], - text=True, env=dict()) - pythonLibs = ast.literal_eval(pythonLibs) - pythonPath = ':'.join(pythonLibs[1:]) - except Exception as e: - pythonPath = None - if pythonPath is not None: - env['PATH'] = python_executable + ':' + env['PATH'] - env['PYTHONPATH'] = pythonPath + env.pop('PYTHONHOME', None) + env.pop('PYTHONPATH', None) try: self.mpvpipe = self.playerIPCHandler( loglevel="info",