This commit is contained in:
2026-01-09 16:02:49 -08:00
parent a70482fdf1
commit 6c13604664
2 changed files with 65 additions and 21 deletions

View File

@@ -8,6 +8,10 @@ downloads Playwright browser binaries by running `python -m playwright install`.
By default this script installs **Chromium** only to conserve space; pass By default this script installs **Chromium** only to conserve space; pass
`--browsers all` to install all supported engines (chromium, firefox, webkit). `--browsers all` to install all supported engines (chromium, firefox, webkit).
FFmpeg: The project includes ffmpeg binaries for Windows (in MPV/ffmpeg). On Linux/macOS,
install ffmpeg using your system package manager (apt install ffmpeg, brew install ffmpeg, etc.).
ffmpeg-python is installed as a dependency, but requires ffmpeg itself to be on your PATH.
Note: This Python script is the canonical installer for the project — prefer Note: This Python script is the canonical installer for the project — prefer
running `python ./scripts/bootstrap.py` locally. The platform scripts running `python ./scripts/bootstrap.py` locally. The platform scripts
(`scripts/bootstrap.ps1` and `scripts/bootstrap.sh`) are now thin wrappers (`scripts/bootstrap.ps1` and `scripts/bootstrap.sh`) are now thin wrappers
@@ -641,7 +645,7 @@ def main() -> int:
if not playwright_package_installed(): if not playwright_package_installed():
if not args.quiet: if not args.quiet:
print("'playwright' package not found; installing it via pip...") print("'playwright' package not found; installing it via pip...")
run([sys.executable, "-m", "pip", "install", "playwright"]) run([sys.executable, "-m", "pip", "install", "--no-cache-dir", "playwright"])
if not args.quiet: if not args.quiet:
print( print(
@@ -668,6 +672,7 @@ def main() -> int:
"pip", "pip",
"install", "install",
"--upgrade", "--upgrade",
"--no-cache-dir",
"pip", "pip",
"setuptools", "setuptools",
"wheel", "wheel",
@@ -686,13 +691,13 @@ def main() -> int:
print( print(
f"Installing Python dependencies into local venv from {req_file}..." f"Installing Python dependencies into local venv from {req_file}..."
) )
run([str(venv_python), "-m", "pip", "install", "-r", str(req_file)]) run([str(venv_python), "-m", "pip", "install", "--no-cache-dir", "-r", str(req_file)])
if not args.no_playwright: if not args.no_playwright:
if not playwright_package_installed(): if not playwright_package_installed():
if not args.quiet: if not args.quiet:
print("'playwright' package not installed in venv; installing it...") print("'playwright' package not installed in venv; installing it...")
run([str(venv_python), "-m", "pip", "install", "playwright"]) run([str(venv_python), "-m", "pip", "install", "--no-cache-dir", "playwright"])
if not args.quiet: if not args.quiet:
print( print(
@@ -711,7 +716,7 @@ def main() -> int:
# Install the project into the local venv (editable mode is the default, opinionated) # Install the project into the local venv (editable mode is the default, opinionated)
if not args.quiet: if not args.quiet:
print("Installing project into local venv (editable mode)") print("Installing project into local venv (editable mode)")
run([str(venv_python), "-m", "pip", "install", "-e", str(repo_root / "scripts")]) run([str(venv_python), "-m", "pip", "install", "--no-cache-dir", "-e", str(repo_root / "scripts")])
# Verify top-level 'CLI' import and, if missing, attempt to make it available # Verify top-level 'CLI' import and, if missing, attempt to make it available
if not args.quiet: if not args.quiet:

View File

@@ -174,30 +174,49 @@ class PlaywrightTool:
ignore_https = bool(_get("ignore_https_errors", defaults.ignore_https_errors)) ignore_https = bool(_get("ignore_https_errors", defaults.ignore_https_errors))
# Try to find ffmpeg: config override, environment variable, bundled, then system # Try to find ffmpeg: config override, environment variable, bundled, then system
# This checks if ffmpeg is actually available (not just the path to it)
ffmpeg_path: Optional[str] = None ffmpeg_path: Optional[str] = None
config_ffmpeg = _get("ffmpeg_path", None) config_ffmpeg = _get("ffmpeg_path", None)
if config_ffmpeg: if config_ffmpeg:
ffmpeg_path = str(config_ffmpeg).strip() # User explicitly configured ffmpeg path
else: candidate = str(config_ffmpeg).strip()
if Path(candidate).exists():
ffmpeg_path = candidate
else:
debug(f"Configured ffmpeg path does not exist: {candidate}")
if not ffmpeg_path:
# Check environment variable (supports project ffmpeg) # Check environment variable (supports project ffmpeg)
env_ffmpeg = os.environ.get("PLAYWRIGHT_FFMPEG_PATH") env_ffmpeg = os.environ.get("PLAYWRIGHT_FFMPEG_PATH")
if env_ffmpeg: if env_ffmpeg and Path(env_ffmpeg).exists():
ffmpeg_path = env_ffmpeg ffmpeg_path = env_ffmpeg
elif env_ffmpeg:
debug(f"PLAYWRIGHT_FFMPEG_PATH set but path does not exist: {env_ffmpeg}")
if not ffmpeg_path:
# Try to find bundled ffmpeg in the project (Windows-only, in MPV/ffmpeg/bin)
try:
repo_root = Path(__file__).resolve().parent.parent
bundled_ffmpeg = repo_root / "MPV" / "ffmpeg" / "bin"
if bundled_ffmpeg.exists():
ffmpeg_exe = bundled_ffmpeg / ("ffmpeg.exe" if os.name == "nt" else "ffmpeg")
if ffmpeg_exe.exists():
ffmpeg_path = str(ffmpeg_exe)
debug(f"Found bundled ffmpeg at: {ffmpeg_path}")
except Exception as e:
debug(f"Error checking for bundled ffmpeg: {e}")
if not ffmpeg_path:
# Try system ffmpeg if bundled not found
system_ffmpeg = shutil.which("ffmpeg")
if system_ffmpeg:
ffmpeg_path = system_ffmpeg
debug(f"Found system ffmpeg at: {ffmpeg_path}")
else: else:
# Try to find bundled ffmpeg in the project (if available) # ffmpeg not found - log a debug message but don't fail
try: # ffmpeg-python may still work with system installation, or user might not need it
repo_root = Path(__file__).resolve().parent.parent debug("ffmpeg not found on PATH. For best compatibility, install ffmpeg: Windows (use bundled or choco install ffmpeg), macOS (brew install ffmpeg), Linux (apt install ffmpeg or equivalent)")
bundled_ffmpeg = repo_root / "MPV" / "ffmpeg" / "bin"
if bundled_ffmpeg.exists():
ffmpeg_exe = bundled_ffmpeg / ("ffmpeg.exe" if os.name == "nt" else "ffmpeg")
if ffmpeg_exe.exists():
ffmpeg_path = str(ffmpeg_exe)
except Exception:
pass
# Try system ffmpeg if bundled not found
if not ffmpeg_path:
ffmpeg_path = shutil.which("ffmpeg")
return PlaywrightDefaults( return PlaywrightDefaults(
browser=browser, browser=browser,
@@ -219,6 +238,26 @@ class PlaywrightTool:
"playwright is required; install with: pip install playwright; then: playwright install" "playwright is required; install with: pip install playwright; then: playwright install"
) )
def ffmpeg_available(self) -> bool:
"""Check if ffmpeg is available on the system."""
return bool(self.defaults.ffmpeg_path)
def require_ffmpeg(self) -> None:
"""Require ffmpeg to be available; raise a helpful error if not.
This should be called before operations that need ffmpeg (e.g., video recording).
"""
if not self.ffmpeg_available():
raise RuntimeError(
"ffmpeg is required but not found on your system.\n"
"Install it using:\n"
" Windows: choco install ffmpeg (if using Chocolatey) or use the bundled version in MPV/ffmpeg\n"
" macOS: brew install ffmpeg\n"
" Linux: apt install ffmpeg (Ubuntu/Debian) or equivalent for your distribution\n"
"\n"
"Or set the PLAYWRIGHT_FFMPEG_PATH environment variable to point to your ffmpeg executable."
)
@contextlib.contextmanager @contextlib.contextmanager
def open_page( def open_page(
self, self,