Skip to content

Fix Windows compatibility in helpers - #117

Open
yamarames wants to merge 1 commit into
browser-use:mainfrom
yamarames:windows-compat
Open

Fix Windows compatibility in helpers#117
yamarames wants to merge 1 commit into
browser-use:mainfrom
yamarames:windows-compat

Conversation

@yamarames

@yamarames yamarames commented Aug 4, 2026

Copy link
Copy Markdown

What

Four defects that make the helpers unusable on Windows. Each was found by running the tool against real footage during a fresh install, not by inspection.

1. grade.py — auto-grade crashes on every clip

metadata=print:file=<path> is a filter argument, where : separates options and \ escapes. An absolute Windows path is destroyed by the filter parser:

[AVFilterGraph] No option name near 'UsersUserAppDataLocalTempt1.txt'
subprocess.CalledProcessError: Command '[... 'metadata=print:file=C:\Users\...']' returned non-zero exit status 4294967274

Fixed by passing a bare filename with cwd set, which requires no filter-arg escaping on any platform.

This is the widest-reaching of the four: auto is the default grade mode, and render.py calls auto_grade_for_clip for every segment whenever the EDL says "grade": "auto".

2. render.py — subtitle burn-in fails

Same root cause. The existing escaping handled : but left \ for the filter parser to consume, so libass received a path with no separators:

[AVFilterGraph] Error initializing filters
Error : No such file or directory

Fixed by converting to forward slashes (accepted by ffmpeg on Windows, no-op on POSIX) before escaping the drive colon. Subtitles-applied-last is Hard Rule 1 in SKILL.md, so this hits on the first real subtitled render.

3. Five helpers — UnicodeEncodeError on cp1252 consoles

Windows consoles default to cp1252, which cannot encode the ± × characters used in progress output:

UnicodeEncodeError: 'charmap' codec can't encode character '\u2192' in position 4

render.py alone has 14 such prints, so a long render dies partway with the encode work already spent. Each entry point now reconfigures stdout/stderr to UTF-8.

4. timeline_view.py — unreadable labels

FONT_CANDIDATES listed only macOS and Linux paths, so PIL fell back to a fixed-size bitmap font that ignores the requested size. Word labels and the time ruler were illegible, which defeats the purpose of the drill-down tool at cut-decision time. Added Consolas, Courier New, Segoe UI and Arial after the existing entries, so macOS and Linux resolution order is unchanged.

Verification

Windows 10, ffmpeg 8.1, Python 3.11. A two-segment EDL rendered end to end: per-segment auto-grade → lossless concat → burned subtitles → two-pass loudnorm. A timeline_view of the output confirms both caption cues are visible and the cut lands where the EDL says. Duration matched expectation (4.10s vs 4.0s, encoder rounding).

Escaping alternatives were tested rather than assumed — for the metadata path, forward-slash-plus-single-escape and double-escape both still fail, while quad-escape and bare-filename-plus-cwd both work; the latter was chosen as the one that needs no platform branching.

Risk

No behavior change on macOS or Linux. The cwd change is platform-neutral, .replace("\\", "/") is a no-op on POSIX paths, reconfigure() is guarded by hasattr, and the font additions are appended below the existing candidates.

🤖 Generated with Claude Code


Summary by cubic

Fixes four Windows-only bugs in the helper scripts so auto-grade, subtitle burn-in, and timeline labels work end to end on Windows. No behavior change on macOS or Linux.

  • Bug Fixes
    • Auto-grade: pass a bare filename and set cwd for metadata=print:file=... to avoid Windows filter-arg escaping crashes.
    • Subtitles: convert paths to forward slashes and escape the drive colon before applying the subtitles filter.
    • Console output: reconfigure stdout/stderr to UTF-8 in all entry points to prevent UnicodeEncodeError on cp1252 consoles.
    • Timeline fonts: add Windows fallbacks (Consolas, Courier New, Segoe UI, Arial) so labels render at the correct size.

Written for commit a1b09af. Summary will update on new commits.

Review in cubic

Four defects that made the helpers unusable on Windows. Each was found by
running the tool against real footage, not by inspection.

1. grade.py — auto-grade crashed with CalledProcessError on every clip.
   `metadata=print:file=<path>` is a FILTER argument, where ':' separates
   options and '\' escapes, so an absolute Windows path arrived as
   "No option name near 'UsersUserAppDataLocalTempt1.txt'". Now passes a
   bare filename with cwd set, which needs no filter-arg escaping on any
   platform. Auto is the default grade mode and render.py uses it whenever
   the EDL says "auto", so this blocked the main pipeline.

2. render.py — subtitle burn-in failed with "No such file or directory"
   from libass, for the same reason: the existing escaping handled ':' but
   left '\' intact for the filter parser to eat. Now converts to forward
   slashes (accepted by ffmpeg on Windows, no-op on POSIX) before escaping
   the drive colon. This is Hard Rule 1 in SKILL.md, so it would have hit
   on the first real subtitled render.

3. All five helpers that print status — UnicodeEncodeError on Windows
   consoles, which default to cp1252 and cannot encode the '→', '≥', '±',
   '×', '…' characters in the progress output. render.py alone has 14 such
   prints, so a long render would die partway with the work already done.
   Each entry point now reconfigures stdout/stderr to UTF-8.

4. timeline_view.py — FONT_CANDIDATES listed only macOS and Linux paths,
   so PIL fell back to a fixed-size bitmap font that ignores the requested
   size. Word labels and time rulers were unreadable, which defeats the
   point of the drill-down tool at cut-decision time. Added Consolas,
   Courier New, Segoe UI, and Arial as fallbacks after the existing entries.

Verified end to end on Windows 10 with ffmpeg 8.1: two-segment EDL with
per-segment auto-grade, lossless concat, burned subtitles and two-pass
loudnorm renders correctly, and a timeline_view of the output confirms
both caption cues are visible and the cut lands where the EDL says.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="helpers/grade.py">

<violation number="1" location="helpers/grade.py:127">
P2: The new `cwd=str(meta_file.parent)` on the sampling subprocess changes the directory the ffmpeg `-i` input is resolved against. `video` is passed straight through from the caller (grade.py standalone passes the raw, possibly-relative `args.input`/`args.analyze` with no `.resolve()`), so a relative input like `python helpers/grade.py input.mp4 -o out.mp4` — a documented usage — will now fail with CalledProcessError because ffmpeg looks for `input.mp4` inside the OS temp dir. This also violates the stated "no behavior change on macOS/Linux" goal since it breaks previously-working relative paths on all platforms. Recommend resolving the input to an absolute path before building the command (e.g. `"-i", str(video.resolve())`) so the cwd change only affects where the bare-name metadata file is written.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread helpers/grade.py
]
subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
subprocess.run(
cmd, check=True, cwd=str(meta_file.parent),

@cubic-dev-ai cubic-dev-ai Bot Aug 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new cwd=str(meta_file.parent) on the sampling subprocess changes the directory the ffmpeg -i input is resolved against. video is passed straight through from the caller (grade.py standalone passes the raw, possibly-relative args.input/args.analyze with no .resolve()), so a relative input like python helpers/grade.py input.mp4 -o out.mp4 — a documented usage — will now fail with CalledProcessError because ffmpeg looks for input.mp4 inside the OS temp dir. This also violates the stated "no behavior change on macOS/Linux" goal since it breaks previously-working relative paths on all platforms. Recommend resolving the input to an absolute path before building the command (e.g. "-i", str(video.resolve())) so the cwd change only affects where the bare-name metadata file is written.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At helpers/grade.py, line 127:

<comment>The new `cwd=str(meta_file.parent)` on the sampling subprocess changes the directory the ffmpeg `-i` input is resolved against. `video` is passed straight through from the caller (grade.py standalone passes the raw, possibly-relative `args.input`/`args.analyze` with no `.resolve()`), so a relative input like `python helpers/grade.py input.mp4 -o out.mp4` — a documented usage — will now fail with CalledProcessError because ffmpeg looks for `input.mp4` inside the OS temp dir. This also violates the stated "no behavior change on macOS/Linux" goal since it breaks previously-working relative paths on all platforms. Recommend resolving the input to an absolute path before building the command (e.g. `"-i", str(video.resolve())`) so the cwd change only affects where the bare-name metadata file is written.</comment>

<file context>
@@ -101,15 +109,24 @@ def _sample_frame_stats(
         ]
-        subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+        subprocess.run(
+            cmd, check=True, cwd=str(meta_file.parent),
+            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
+        )
</file context>
Fix with cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants