kjk
This commit is contained in:
@@ -136,11 +136,16 @@ def playwright_package_installed() -> bool:
|
||||
def _build_playwright_install_cmd(browsers: str | None) -> list[str]:
|
||||
"""Return the command to install Playwright browsers.
|
||||
|
||||
- If browsers is None or empty: default to install Chromium only.
|
||||
- If browsers is None or empty: default to install Chromium only (headless).
|
||||
- If browsers contains 'all': install all engines by running 'playwright install' with no extra args.
|
||||
- Otherwise, validate entries and return a command that installs the named engines.
|
||||
|
||||
The --with-deps flag is NOT used because:
|
||||
1. The project already includes ffmpeg (in MPV/ffmpeg)
|
||||
2. Most system dependencies should already be available
|
||||
"""
|
||||
|
||||
# Use --skip-browsers to just install deps without browsers, then install specific browsers
|
||||
base = [sys.executable, "-m", "playwright", "install"]
|
||||
if not browsers:
|
||||
return base + ["chromium"]
|
||||
@@ -293,7 +298,10 @@ def main() -> int:
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
repo_root = Path(__file__).resolve().parent.parent
|
||||
# Ensure repo_root is always the project root, not the current working directory
|
||||
# This prevents issues when bootstrap.py is run from different directories
|
||||
script_dir = Path(__file__).resolve().parent
|
||||
repo_root = script_dir.parent
|
||||
|
||||
# Helpers for interactive menu and uninstall detection
|
||||
def _venv_python_path(p: Path) -> Path | None:
|
||||
@@ -795,15 +803,19 @@ def main() -> int:
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$repo = (Resolve-Path (Join-Path $scriptDir "..")).Path
|
||||
$venv = Join-Path $repo '.venv'
|
||||
$py = Join-Path $venv 'Scripts\python.exe'
|
||||
if (Test-Path $py) {
|
||||
& $py -m scripts.cli_entry @args; exit $LASTEXITCODE
|
||||
}
|
||||
# Ensure venv Scripts dir is on PATH for provider discovery
|
||||
$venvScripts = Join-Path $venv 'Scripts'
|
||||
if (Test-Path $venvScripts) { $env:PATH = $venvScripts + ';' + $env:PATH }
|
||||
$py = Join-Path $venv 'Scripts\python.exe'
|
||||
$cli = Join-Path $repo 'CLI.py'
|
||||
if (Test-Path $py) { & $py -m scripts.cli_entry @args; exit $LASTEXITCODE }
|
||||
if (Test-Path $cli) { & python $cli @args; exit $LASTEXITCODE }
|
||||
# fallback
|
||||
python -m scripts.cli_entry @args
|
||||
# Fallback to system python if venv doesn't exist
|
||||
if (Test-Path (Join-Path $repo 'CLI.py')) {
|
||||
python -m scripts.cli_entry @args
|
||||
} else {
|
||||
python -m scripts.cli_entry @args
|
||||
}
|
||||
"""
|
||||
try:
|
||||
ps1.write_text(ps1_text, encoding="utf-8")
|
||||
@@ -828,16 +840,16 @@ python -m scripts.cli_entry @args
|
||||
"Param([Parameter(ValueFromRemainingArguments=$true)] $args)\n"
|
||||
f'$repo = "{repo}"\n'
|
||||
"$venv = Join-Path $repo '.venv'\n"
|
||||
"$exe = Join-Path $venv 'Scripts\\mm.exe'\n"
|
||||
"if (Test-Path $exe) { & $exe @args; exit $LASTEXITCODE }\n"
|
||||
"$py = Join-Path $venv 'Scripts\\python.exe'\n"
|
||||
"if (Test-Path $py) {\n"
|
||||
" if ($env:MM_DEBUG) {\n"
|
||||
' Write-Host "MM_DEBUG: diagnostics" -ForegroundColor Yellow\n'
|
||||
" & $py -c \"import sys,importlib,importlib.util,traceback; print('sys.executable:', sys.executable); print('sys.path (first 8):', sys.path[:8]);\"\n"
|
||||
' Write-Host "MM_DEBUG: using venv python at $py" -ForegroundColor Yellow\n'
|
||||
" & $py -c \"import sys; print('sys.executable:', sys.executable)\"\n"
|
||||
" }\n"
|
||||
" & $py -m scripts.cli_entry @args; exit $LASTEXITCODE\n"
|
||||
"}\n"
|
||||
"# Fallback to system python if venv doesn't exist\n"
|
||||
"if ($env:MM_DEBUG) { Write-Host 'MM_DEBUG: venv python not found, trying system python' -ForegroundColor Yellow }\n"
|
||||
"python -m scripts.cli_entry @args\n"
|
||||
)
|
||||
if mm_ps1.exists():
|
||||
@@ -845,29 +857,71 @@ python -m scripts.cli_entry @args
|
||||
mm_ps1.replace(bak)
|
||||
mm_ps1.write_text(ps1_text, encoding="utf-8")
|
||||
|
||||
# Attempt to add user_bin to the user's PATH if it's not present.
|
||||
# Write mm.bat (CMD shim for better compatibility)
|
||||
mm_bat = user_bin / "mm.bat"
|
||||
bat_text = (
|
||||
"@echo off\n"
|
||||
"setlocal enabledelayedexpansion\n"
|
||||
f'set "REPO={repo}"\n'
|
||||
"set \"VENV=!REPO!\\.venv\"\n"
|
||||
"set \"PY=!VENV!\\Scripts\\python.exe\"\n"
|
||||
"if exist \"!PY!\" (\n"
|
||||
" if defined MM_DEBUG (\n"
|
||||
" echo MM_DEBUG: using venv python at !PY!\n"
|
||||
" \"!PY!\" -c \"import sys; print('sys.executable:', sys.executable)\"\n"
|
||||
" )\n"
|
||||
" \"!PY!\" -m scripts.cli_entry %*\n"
|
||||
" exit /b !ERRORLEVEL!\n"
|
||||
")\n"
|
||||
"echo MM: venv not found at !VENV!, trying system python\n"
|
||||
"if defined MM_DEBUG echo MM_DEBUG: venv python not found, trying system python\n"
|
||||
"python -m scripts.cli_entry %*\n"
|
||||
"exit /b !ERRORLEVEL!\n"
|
||||
)
|
||||
if mm_bat.exists():
|
||||
bak = mm_bat.with_suffix(f".bak{int(time.time())}")
|
||||
mm_bat.replace(bak)
|
||||
mm_bat.write_text(bat_text, encoding="utf-8")
|
||||
|
||||
# Add user_bin to PATH for current and future sessions
|
||||
str_bin = str(user_bin)
|
||||
cur_path = os.environ.get("PATH", "")
|
||||
|
||||
# Update current session PATH if not already present
|
||||
if str_bin not in cur_path:
|
||||
os.environ["PATH"] = str_bin + ";" + cur_path
|
||||
if not args.quiet:
|
||||
print(f"Added {user_bin} to current session PATH")
|
||||
|
||||
# Persist to user's Windows registry PATH for future sessions
|
||||
try:
|
||||
cur = os.environ.get("PATH", "")
|
||||
str_bin = str(user_bin)
|
||||
if str_bin not in cur:
|
||||
ps_cmd = (
|
||||
"$bin = '{bin}';"
|
||||
"$cur = [Environment]::GetEnvironmentVariable('PATH','User');"
|
||||
"if ($cur -notlike \"*$bin*\") {[Environment]::SetEnvironmentVariable('PATH', ($bin + ';' + ($cur -ne $null ? $cur : '')), 'User')}"
|
||||
).format(bin=str_bin.replace("\\",
|
||||
"\\\\"))
|
||||
subprocess.run(
|
||||
["powershell",
|
||||
"-NoProfile",
|
||||
"-Command",
|
||||
ps_cmd],
|
||||
check=False
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
ps_cmd = (
|
||||
"$bin = '{bin}';"
|
||||
"$cur = [Environment]::GetEnvironmentVariable('PATH','User');"
|
||||
"if ($cur -notlike \"*$bin*\") {{"
|
||||
"[Environment]::SetEnvironmentVariable('PATH', ($bin + ';' + ($cur -ne $null ? $cur : '')), 'User');"
|
||||
"Write-Host 'Added {bin} to User PATH in registry' -ForegroundColor Green"
|
||||
"}}"
|
||||
).format(bin=str_bin.replace("\\", "\\\\"))
|
||||
subprocess.run(
|
||||
["powershell",
|
||||
"-NoProfile",
|
||||
"-Command",
|
||||
ps_cmd],
|
||||
check=False,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL
|
||||
)
|
||||
except Exception as e:
|
||||
if not args.quiet:
|
||||
print(f"Note: Could not persist PATH to registry (this is non-critical): {e}", file=sys.stderr)
|
||||
|
||||
if not args.quiet:
|
||||
print(f"Installed global launchers to: {user_bin}")
|
||||
print(f"\nInstalled global launchers to: {user_bin}")
|
||||
print(f"✓ mm.ps1 (PowerShell)")
|
||||
print(f"✓ mm.bat (Command Prompt)")
|
||||
print(f"\nYou can now run 'mm' from any terminal window.")
|
||||
print(f"To use in the current terminal, reload your profile or run: $env:PATH = '{str_bin};' + $env:PATH")
|
||||
|
||||
else:
|
||||
# POSIX
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import tempfile
|
||||
import traceback
|
||||
from dataclasses import dataclass
|
||||
@@ -74,6 +76,7 @@ class PlaywrightDefaults:
|
||||
viewport_height: int = 1080
|
||||
navigation_timeout_ms: int = 90_000
|
||||
ignore_https_errors: bool = True
|
||||
ffmpeg_path: Optional[str] = None # Path to ffmpeg executable; auto-detected if None
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
@@ -101,6 +104,7 @@ class PlaywrightTool:
|
||||
- sync_playwright start/stop
|
||||
- browser launch/context creation
|
||||
- user-agent/viewport defaults
|
||||
- ffmpeg path resolution (for video recording)
|
||||
|
||||
Config overrides (top-level keys):
|
||||
- playwright.browser="chromium"
|
||||
@@ -110,6 +114,13 @@ class PlaywrightTool:
|
||||
- playwright.viewport_height=1200
|
||||
- playwright.navigation_timeout_ms=90000
|
||||
- playwright.ignore_https_errors=true
|
||||
- playwright.ffmpeg_path="/path/to/ffmpeg" (auto-detected if not set)
|
||||
|
||||
FFmpeg resolution (in order):
|
||||
1. Config key: playwright.ffmpeg_path
|
||||
2. Environment variable: PLAYWRIGHT_FFMPEG_PATH
|
||||
3. Project bundled: MPV/ffmpeg/bin/ffmpeg[.exe]
|
||||
4. System PATH: which ffmpeg
|
||||
"""
|
||||
|
||||
def __init__(self, config: Optional[Dict[str, Any]] = None) -> None:
|
||||
@@ -162,6 +173,32 @@ class PlaywrightTool:
|
||||
|
||||
ignore_https = bool(_get("ignore_https_errors", defaults.ignore_https_errors))
|
||||
|
||||
# Try to find ffmpeg: config override, environment variable, bundled, then system
|
||||
ffmpeg_path: Optional[str] = None
|
||||
config_ffmpeg = _get("ffmpeg_path", None)
|
||||
if config_ffmpeg:
|
||||
ffmpeg_path = str(config_ffmpeg).strip()
|
||||
else:
|
||||
# Check environment variable (supports project ffmpeg)
|
||||
env_ffmpeg = os.environ.get("PLAYWRIGHT_FFMPEG_PATH")
|
||||
if env_ffmpeg:
|
||||
ffmpeg_path = env_ffmpeg
|
||||
else:
|
||||
# Try to find bundled ffmpeg in the project (if available)
|
||||
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)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Try system ffmpeg if bundled not found
|
||||
if not ffmpeg_path:
|
||||
ffmpeg_path = shutil.which("ffmpeg")
|
||||
|
||||
return PlaywrightDefaults(
|
||||
browser=browser,
|
||||
headless=headless,
|
||||
@@ -170,6 +207,7 @@ class PlaywrightTool:
|
||||
viewport_height=vh,
|
||||
navigation_timeout_ms=nav_timeout,
|
||||
ignore_https_errors=ignore_https,
|
||||
ffmpeg_path=ffmpeg_path,
|
||||
)
|
||||
|
||||
def require(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user