Add Avisynth video encoding workflow
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AvisynthRunnerSet:
|
||||
default: Path
|
||||
runner64: Path | None = None
|
||||
runner32: Path | None = None
|
||||
|
||||
def for_script(self, script: Path) -> Path:
|
||||
if sys.platform != "win32":
|
||||
return self.default
|
||||
if script_requests_32bit(script):
|
||||
if self.runner32 is None:
|
||||
raise RuntimeError(
|
||||
f"{script} requests 32-bit AviSynth with a trailing #32bit "
|
||||
"marker, but no 32-bit runner was found. Set "
|
||||
"MBT_AVS_RUNNER32 or provide tools/avisynth_runner/"
|
||||
"mbt_avs_runner32.exe."
|
||||
)
|
||||
return self.runner32
|
||||
return self.default
|
||||
|
||||
|
||||
def bundled_runner_path(name: str | None = None) -> Path | None:
|
||||
if name is None:
|
||||
name = "mbt_avs_runner.exe" if sys.platform == "win32" else "mbt_avs_runner"
|
||||
runner = _runner_dir() / name
|
||||
return runner if runner.is_file() else None
|
||||
|
||||
|
||||
def runner_path_from_env_or_bundled() -> Path | None:
|
||||
runners = runner_set_from_env_or_bundled()
|
||||
return runners.default if runners is not None else None
|
||||
|
||||
|
||||
def runner_set_from_env_or_bundled() -> AvisynthRunnerSet | None:
|
||||
if sys.platform == "win32":
|
||||
return _windows_runner_set_from_env_or_bundled()
|
||||
|
||||
env_path = os.environ.get("MBT_AVS_RUNNER", "").strip()
|
||||
if env_path:
|
||||
runner = validate_runner_path(env_path)
|
||||
return AvisynthRunnerSet(default=runner, runner64=runner)
|
||||
bundled = bundled_runner_path()
|
||||
if bundled is not None:
|
||||
return AvisynthRunnerSet(default=bundled, runner64=bundled)
|
||||
return None
|
||||
|
||||
|
||||
def _windows_runner_set_from_env_or_bundled() -> AvisynthRunnerSet | None:
|
||||
runner64 = _optional_runner_from_env("MBT_AVS_RUNNER64")
|
||||
if runner64 is None:
|
||||
runner64 = _optional_runner_from_env("MBT_AVS_RUNNER")
|
||||
if runner64 is None:
|
||||
runner64 = bundled_runner_path("mbt_avs_runner.exe")
|
||||
|
||||
runner32 = _optional_runner_from_env("MBT_AVS_RUNNER32")
|
||||
if runner32 is None:
|
||||
runner32 = bundled_runner_path("mbt_avs_runner32.exe")
|
||||
|
||||
default = runner64 or runner32
|
||||
if default is None:
|
||||
return None
|
||||
return AvisynthRunnerSet(default=default, runner64=runner64, runner32=runner32)
|
||||
|
||||
|
||||
def _optional_runner_from_env(name: str) -> Path | None:
|
||||
raw = os.environ.get(name, "").strip()
|
||||
if not raw:
|
||||
return None
|
||||
return validate_runner_path(raw)
|
||||
|
||||
|
||||
def validate_runner_path(raw_path: str) -> Path:
|
||||
runner_path = Path(raw_path.strip().strip('"')).expanduser()
|
||||
for candidate in _runner_candidates(runner_path):
|
||||
if candidate.is_file():
|
||||
return candidate.resolve()
|
||||
raise RuntimeError(
|
||||
f"Avisynth runner file not found: {runner_path}. "
|
||||
"Use the full path, set MBT_AVS_RUNNER, or leave blank to use the "
|
||||
"bundled runner when present."
|
||||
)
|
||||
|
||||
|
||||
def _runner_candidates(path: Path) -> list[Path]:
|
||||
candidates = [path]
|
||||
if len(path.parts) == 1:
|
||||
candidates.append(_runner_dir() / path.name)
|
||||
return candidates
|
||||
|
||||
|
||||
def _runner_dir() -> Path:
|
||||
return Path(__file__).resolve().parent / "avisynth_runner"
|
||||
|
||||
|
||||
def script_requests_32bit(script: Path) -> bool:
|
||||
lines = script.read_text(encoding="utf-8").splitlines()
|
||||
while lines and not lines[-1].strip():
|
||||
lines.pop()
|
||||
if not lines:
|
||||
return False
|
||||
normalized = "".join(lines[-1].split()).lower()
|
||||
return normalized in {"#32bit", "#32-bit"}
|
||||
Reference in New Issue
Block a user