build: bundle playback and YouTube dependencies
Build pinned LGPL playback libraries and package standalone YouTube helpers inside the signed native app. Keep the CLI inside the app and relocate private library links for installation without runtime Homebrew dependencies. Record adaptive fixture completion in its EXIT trap: cancellation can exit with status 143 before the TERM trap writes its marker, while native pause and quality preservation remain correct.
This commit is contained in:
+24
-13
@@ -5,7 +5,6 @@ from pathlib import Path
|
||||
import plistlib
|
||||
import selectors
|
||||
import shutil
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -17,9 +16,10 @@ from streaming import StreamingServer
|
||||
|
||||
def check_cli_instances(root, app, fixtures):
|
||||
cli = root / "terebi"
|
||||
shutil.copy2(app_source.parent / "terebi", cli)
|
||||
extractor = shutil.which("yt-dlp")
|
||||
runtime = shutil.which("deno") or shutil.which("node")
|
||||
cli.symlink_to(app / "Contents/MacOS/terebi-cli")
|
||||
extractor = app / "Contents/MacOS/yt-dlp-offline"
|
||||
(app / "Contents/MacOS/yt-dlp").rename(extractor)
|
||||
runtime = app / "Contents/MacOS/deno"
|
||||
canonical = "https://www.youtube.com/watch?v=aqz-KE-bpKQ"
|
||||
reported_urls = [f"https://www.youtube.com/watch?v=progress00{index}" for index in range(1, 5)]
|
||||
|
||||
@@ -152,16 +152,25 @@ def check_cli_instances(root, app, fixtures):
|
||||
"url": server.base_url + "/media/cache.mp4", "protocol": "http", "ext": "mp4",
|
||||
"vcodec": "mpeg4", "acodec": "aac", "dynamic_range": "SDR",
|
||||
"http_headers": {"X-Terebi-Fixture": "combined"}} for height in (180, 360)]}))
|
||||
choices.append(f" {shlex.quote(url)}) info={shlex.quote(str(metadata))} ;;")
|
||||
wrapper = root / "yt-dlp"
|
||||
wrapper.write_text("#!/bin/bash\nset -eu\nargs=(\"$@\")\n"
|
||||
'case "${args[${#args[@]}-1]}" in\n' + "\n".join(choices)
|
||||
+ '\n *) echo "Fixture extraction deliberately failed" >&2; exit 1 ;;\nesac\nexec '
|
||||
+ shlex.quote(extractor) + ' --load-info-json "$info"'
|
||||
+ ' "${args[@]:0:${#args[@]}-2}"\n')
|
||||
wrapper.chmod(0o755)
|
||||
choices.append(f" if (!strcmp(url, {json.dumps(url)})) info = {json.dumps(str(metadata))};")
|
||||
wrapper = app / "Contents/MacOS/yt-dlp"
|
||||
source = root / "offline-extractor.c"
|
||||
source.write_text(
|
||||
'#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n'
|
||||
'int main(int argc, char **argv) {\n'
|
||||
' if (argc < 3) return 1;\n'
|
||||
' const char *url = argv[argc - 1];\n char *info = NULL;\n'
|
||||
+ "\n".join(choices)
|
||||
+ '\n if (!info) { fputs("Fixture extraction deliberately failed\\n", stderr); return 1; }\n'
|
||||
+ f' char *args[argc + 2]; args[0] = {json.dumps(str(extractor))};\n'
|
||||
+ ' args[1] = "--load-info-json"; args[2] = info;\n'
|
||||
+ ' for (int i = 1; i < argc - 2; ++i) args[i + 2] = argv[i];\n'
|
||||
+ ' args[argc] = NULL;\n execv(args[0], args); perror("execv"); return 1;\n}\n')
|
||||
subprocess.run(["xcrun", "clang", "-O2", str(source), "-o", str(wrapper)], check=True)
|
||||
subprocess.run(["codesign", "--force", "--sign", "-", str(wrapper)], check=True)
|
||||
runtime_settings = {"directory": str(root), "path": str(root) + os.pathsep + os.environ.get("PATH", "")}
|
||||
(app / "Contents/Resources/cli-check.json").write_text(json.dumps(runtime_settings))
|
||||
subprocess.run(["codesign", "--force", "--sign", "-", str(app)], check=True)
|
||||
movie = fixtures / "cache.mp4"
|
||||
audio = root / "audio with spaces.wav"
|
||||
shutil.copy2(fixtures / "audio.wav", audio)
|
||||
@@ -457,7 +466,7 @@ def check_cli_instances(root, app, fixtures):
|
||||
|
||||
|
||||
|
||||
app_source, library, fixtures = map(lambda path: Path(path).resolve(), sys.argv[1:])
|
||||
app_source, library, fixtures, dependencies_root = map(lambda path: Path(path).resolve(), sys.argv[1:])
|
||||
with tempfile.TemporaryDirectory(prefix="terebi-startup-") as directory:
|
||||
root = Path(directory)
|
||||
app = root / "terebi.app"
|
||||
@@ -468,6 +477,8 @@ with tempfile.TemporaryDirectory(prefix="terebi-startup-") as directory:
|
||||
info["CFBundleIdentifier"] = identifier
|
||||
info_path.write_bytes(plistlib.dumps(info))
|
||||
shutil.copy2(library, app / "Contents/Frameworks/libterebi-player.dylib")
|
||||
subprocess.run([sys.executable, str(Path(__file__).resolve().parent.parent / "Scripts/bundle.py"),
|
||||
"--app", str(app), "--dependencies", str(dependencies_root)], check=True)
|
||||
pipe = root / "result.fifo"
|
||||
os.mkfifo(pipe)
|
||||
descriptor = os.open(pipe, os.O_RDONLY | os.O_NONBLOCK)
|
||||
|
||||
Reference in New Issue
Block a user