feat: load optional XDG TOML configuration with session overrides

This commit is contained in:
2026-10-11 14:41:11 +02:00
parent 0dce073287
commit 722a225da5
16 changed files with 461 additions and 89 deletions
+44 -11
View File
@@ -21,10 +21,14 @@ def check_cli_instances(root, app, fixtures):
runtime = shutil.which("deno") or shutil.which("node")
canonical = "https://www.youtube.com/watch?v=aqz-KE-bpKQ"
def invoke(arguments):
result = subprocess.run([str(cli), *arguments], capture_output=True, text=True, timeout=20)
if result.returncode:
raise RuntimeError(f"CLI {arguments} failed: {result.returncode}; {result.stdout}{result.stderr}")
config = root / "xdg/terebi/config.toml"
environment = dict(os.environ, XDG_CONFIG_HOME=str(config.parent.parent))
def invoke(arguments, expected_code=0):
result = subprocess.run([str(cli), *arguments], capture_output=True, text=True, timeout=20,
env=environment)
if result.returncode != expected_code:
raise RuntimeError(f"CLI {arguments} returned {result.returncode}, expected {expected_code}; {result.stdout}{result.stderr}")
return result
def wait_states(count, ready, message):
@@ -41,6 +45,8 @@ def check_cli_instances(root, app, fixtures):
return states
time.sleep(0.02) # Infrastructure deadline; assertions use native events/PTS, not wall dates.
raise RuntimeError(f"{message}: native state deadline: {states}")
def settings(state):
return (state["showBufferInfo"], state["automaticQuality"], state["snapToEdges"])
with StreamingServer(fixtures) as server:
if extractor and runtime:
@@ -58,8 +64,8 @@ def check_cli_instances(root, app, fixtures):
+ " --load-info-json " + shlex.quote(str(metadata))
+ ' "${args[@]:0:${#args[@]}-2}"\n')
wrapper.chmod(0o755)
settings = {"directory": str(root), "path": str(root) + os.pathsep + os.environ.get("PATH", "")}
(app / "Contents/Resources/cli-check.json").write_text(json.dumps(settings))
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))
movie = fixtures / "cache.mp4"
audio = root / "audio with spaces.wav"
shutil.copy2(fixtures / "audio.wav", audio)
@@ -69,15 +75,23 @@ def check_cli_instances(root, app, fixtures):
and state["position"] > 0 and state["hasVideo"] for state in states.values()),
"cold default CLI opens one actual player window")
first_pid = next(iter(first))
if settings(first[first_pid]) != (False, False, True) or config.parent.exists():
raise RuntimeError(f"missing config must use defaults without creating a file: {first}")
invoke([])
wait_states(1, lambda states: states[first_pid]["media"] == movie.name,
"warm default CLI reuses the existing process without replacing media")
config.parent.mkdir(parents=True)
config_text = '"show_buffer_info" = true # optional display\n automatic_quality = true\nsnap_to_edges = false\n'
config.write_text(config_text)
invoke(["--new-instance"])
second = wait_states(2, lambda states: any(state["media"] == "" and state["status"] == 0
and settings(state) == (True, True, False)
for pid, state in states.items() if pid != first_pid),
"empty independent CLI creates exactly one extra player")
empty_pid = next(pid for pid in second if pid != first_pid)
if settings(second[first_pid]) != (False, False, True) or config.read_text() != config_text:
raise RuntimeError(f"config loading changed an existing session or wrote the file: {second}")
invoke(["--new-instance", str(audio)])
third = wait_states(3, lambda states: any(state["media"] == audio.name and state["status"] == 3
and state["hasAudio"] and not state["hasVideo"]
@@ -85,17 +99,34 @@ def check_cli_instances(root, app, fixtures):
"independent local media reaches only the freshly launched process")
if third[first_pid]["media"] != movie.name or third[first_pid]["status"] != 3 or third[empty_pid]["media"]:
raise RuntimeError(f"independent launch disturbed an existing player: {third}")
count = 3
config.write_text("show_buffer_info = [\n")
failure = invoke(["--new-instance"], expected_code=78)
if str(config) not in failure.stderr:
raise RuntimeError(f"configuration failure omitted its path: {failure.stderr}")
invoke(["--no-config"])
unchanged = wait_states(3, lambda _: True, "bypass reuses an existing process without resetting its settings")
if any(settings(unchanged[pid]) != settings(third[pid]) for pid in third):
raise RuntimeError(f"warm bypass changed an existing session: {third}; {unchanged}")
invoke(["--no-config", "--new-instance", str(movie)])
bypass = wait_states(4, lambda states: any(state["media"] == movie.name and state["status"] == 3
and settings(state) == (False, False, True)
for pid, state in states.items() if pid not in third),
"fresh bypass skips invalid config and plays with built-in settings")
invoke(["--no-config", "--new-instance", "--help"])
wait_states(4, lambda _: True, "help skips invalid config without starting another process")
config.write_text(config_text)
count = 4
if extractor and runtime:
invoke(["--new-instance", "--url", canonical])
fourth = wait_states(4, lambda states: any(
fourth = wait_states(5, lambda states: any(
state["media"] == "Independent YouTube fixture" and state["status"] == 3
and state["position"] > 0 and state["hasAudio"] and state["hasVideo"]
for pid, state in states.items() if pid not in third),
and settings(state) == (True, True, False)
for pid, state in states.items() if pid not in bypass),
"independent YouTube playback reaches only one new registered process")
if fourth[first_pid]["media"] != movie.name or fourth[first_pid]["status"] != 3 or fourth[empty_pid]["media"]:
raise RuntimeError(f"independent YouTube launch disturbed existing playback: {fourth}")
count = 4
count = 5
else:
print("SKIP independent YouTube playback: yt-dlp and a supported JS runtime are required")
@@ -111,7 +142,9 @@ def check_cli_instances(root, app, fixtures):
changed = [pid for pid in before if before[pid]["media"] != after[pid]["media"]]
if len(changed) != 1:
raise RuntimeError(f"default media open changed multiple players: {before}; {after}")
print("PASS actual CLI instances: cold/default reuse, independent empty/local/YouTube, one window per PID, targeted media, original playback retained, help, warm replacement")
if config.read_text() != config_text:
raise RuntimeError("native app startup modified config.toml")
print("PASS actual CLI instances: native startup config/defaults/invalid-file error/bypass/read-only settings, cold/default reuse, independent empty/local/YouTube, one window per PID, targeted media, original playback retained, help, warm replacement")