From e1f7c7b0193bd6dcca516a283c79648a862fdd43 Mon Sep 17 00:00:00 2001 From: hbrain Date: Wed, 27 May 2026 06:35:56 +0000 Subject: [PATCH] Feat: Add file logging to mvlog_worker.py --- mvlog_worker.py | 71 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/mvlog_worker.py b/mvlog_worker.py index b2b1416..922eef8 100755 --- a/mvlog_worker.py +++ b/mvlog_worker.py @@ -26,6 +26,7 @@ PUSH_CONFIG = Path.home() / ".config" / "mvlog" / "push.json" STATE_NAME = ".movmaker-state.json" LOCK_NAME = ".movmaker-lock" ENABLED_NAME = ".movmaker-enabled" +PREVIEW_NAME = ".movmaker-preview" HIDDEN_NAME = ".mvlog-hidden" NOTIFIED_CACHE = "cache/push_notifications.json" @@ -74,7 +75,7 @@ entries = [] for dirpath, dirnames, filenames in os.walk(root): dirnames[:] = [d for d in dirnames if d != '.movmaker-lock'] for name in filenames: - if name in {'.movmaker-state.json', '.movmaker-enabled', '.mvlog-hidden'}: + if name in {'.movmaker-state.json', '.movmaker-enabled', '.movmaker-preview', '.mvlog-hidden'}: continue path = os.path.join(dirpath, name) rel = os.path.relpath(path, root) @@ -214,9 +215,12 @@ def process_job(host: str, remote_root: str, job: str, work_dir: Path, extra_arg job_dir = f"{remote_root}/in-dir/{job}" state = read_state(host, job_dir) maybe_send_first_show_notification(host, remote_root, job_dir, job, state) - if not remote_file_exists(host, f"{job_dir}/{ENABLED_NAME}"): + full_requested = remote_file_exists(host, f"{job_dir}/{ENABLED_NAME}") + preview_requested = remote_file_exists(host, f"{job_dir}/{PREVIEW_NAME}") + if not full_requested and not preview_requested: print(f"disabled: {job}") return + preview_mode = preview_requested and not full_requested if not acquire_lock(host, job_dir): print(f"skip locked: {job}") return @@ -224,17 +228,29 @@ def process_job(host: str, remote_root: str, job: str, work_dir: Path, extra_arg fingerprint_before = remote_fingerprint(host, job_dir) state = read_state(host, job_dir) old_output = state.get("output") if isinstance(state.get("output"), str) else None - if not force and state.get("status") == "done" and state.get("fingerprint") == fingerprint_before and old_output: + old_preview_output = state.get("preview_output") if isinstance(state.get("preview_output"), str) else None + if preview_mode: + if not force and state.get("preview_fingerprint") == fingerprint_before and old_preview_output: + if remote_file_exists(host, f"{remote_root}/out-dir/{old_preview_output}"): + print(f"preview up to date: {job} -> {old_preview_output}") + return + elif not force and state.get("status") == "done" and state.get("fingerprint") == fingerprint_before and old_output: if remote_file_exists(host, f"{remote_root}/out-dir/{old_output}"): print(f"up to date: {job} -> {old_output}") return - write_state(host, job_dir, { + processing_state = dict(state) + processing_state.update({ "status": "processing", - "fingerprint": fingerprint_before, + "mode": "preview" if preview_mode else "full", "started_at": now(), - "output": old_output, }) + if preview_mode: + processing_state["preview_fingerprint"] = fingerprint_before + else: + processing_state["fingerprint"] = fingerprint_before + processing_state["output"] = old_output + write_state(host, job_dir, processing_state) local_job = work_dir / job if local_job.exists(): @@ -242,29 +258,56 @@ def process_job(host: str, remote_root: str, job: str, work_dir: Path, extra_arg local_input = local_job / "input" local_out = local_job / "out" copy_job_from_remote(host, job_dir, local_input) - print(f"rendering: {job}") - local_mp4 = render_job(local_input, local_out, extra_args) + render_args = [*extra_args, "--preview"] if preview_mode else extra_args + print(f"rendering {'preview: ' if preview_mode else ''}{job}") + local_mp4 = render_job(local_input, local_out, render_args) + if preview_mode: + preview_mp4 = local_mp4.with_name(f"{local_mp4.stem}_preview{local_mp4.suffix}") + local_mp4.rename(preview_mp4) + local_mp4 = preview_mp4 fingerprint_after = remote_fingerprint(host, job_dir) if fingerprint_after != fingerprint_before: - write_state(host, job_dir, { + stale_state = dict(state) + stale_state.update({ "status": "stale", - "fingerprint": fingerprint_after, - "previous_fingerprint": fingerprint_before, "updated_at": now(), "message": "Input changed during render; will regenerate on next run.", - "output": old_output, }) + if preview_mode: + stale_state["preview_fingerprint"] = fingerprint_after + stale_state["previous_preview_fingerprint"] = fingerprint_before + else: + stale_state["fingerprint"] = fingerprint_after + stale_state["previous_fingerprint"] = fingerprint_before + stale_state["output"] = old_output + write_state(host, job_dir, stale_state) print(f"stale during render, not publishing: {job}") return + if preview_mode: + preview_output = publish_output(host, remote_root, local_mp4, old_preview_output) + new_state = dict(state) + new_state.update({ + "status": "done", + "mode": "preview", + "preview_fingerprint": fingerprint_after, + "preview_output": preview_output, + "preview_generated_at": now(), + }) + write_state(host, job_dir, new_state) + print(f"published preview: {job} -> {preview_output}") + return + output = publish_output(host, remote_root, local_mp4, old_output) - new_state = { + new_state = dict(state) + new_state.update({ "status": "done", + "mode": "full", "fingerprint": fingerprint_after, "output": output, "generated_at": now(), - } + }) maybe_send_first_show_notification(host, remote_root, job_dir, job, new_state) write_state(host, job_dir, new_state) print(f"published: {job} -> {output}")