Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions helpers/timeline_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import argparse
import json
import os
import subprocess
import sys
import tempfile
Expand All @@ -31,6 +32,17 @@
from PIL import Image, ImageDraw, ImageFont


# Windows consoles default to cp1252, which raises UnicodeEncodeError when the
# status prints below include a non-ASCII path (accents, emoji, CJK). Force
# UTF-8 on stdout/stderr so this helper behaves identically on Windows, macOS,
# and Linux. No-op where the stream is already UTF-8 or can't be reconfigured.
for _stream in (sys.stdout, sys.stderr):
try:
_stream.reconfigure(encoding="utf-8")
except (AttributeError, ValueError):
pass


# -------- Frame extraction ---------------------------------------------------


Expand Down Expand Up @@ -151,12 +163,21 @@ def find_silences(words: list[dict], start: float, end: float, threshold: float
# -------- Font loading -------------------------------------------------------


# Windows has no fixed font directory on C:, so derive it from %WINDIR%
# (falls back to the default install path). Consolas mirrors the monospace
# intent of Menlo/DejaVuSansMono; Arial is the sans fallback. Without these,
# every candidate below misses on Windows and load_font drops to PIL's tiny
# default bitmap font, rendering the filmstrip labels nearly illegibly.
_WIN_FONTS = Path(os.environ.get("WINDIR", r"C:\Windows")) / "Fonts"

FONT_CANDIDATES = [
"/System/Library/Fonts/Menlo.ttc",
"/System/Library/Fonts/Helvetica.ttc",
"/System/Library/Fonts/SFNSMono.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf",
"/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf",
str(_WIN_FONTS / "consola.ttf"), # Consolas — Windows monospace
str(_WIN_FONTS / "arial.ttf"), # Arial — Windows sans fallback
]


Expand Down
11 changes: 11 additions & 0 deletions helpers/transcribe.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@
import requests


# Windows consoles default to cp1252, which raises UnicodeEncodeError when the
# status prints below include a non-ASCII video filename (accents, emoji, CJK).
# Force UTF-8 on stdout/stderr so this helper behaves identically on Windows,
# macOS, and Linux. No-op where the stream is already UTF-8 or can't reconfigure.
for _stream in (sys.stdout, sys.stderr):
try:
_stream.reconfigure(encoding="utf-8")
except (AttributeError, ValueError):
pass


SCRIBE_URL = "https://api.elevenlabs.io/v1/speech-to-text"


Expand Down
49 changes: 49 additions & 0 deletions tests/test_timeline_fonts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
r"""Regression test for cross-platform font selection in timeline_view.py.

Bug: FONT_CANDIDATES listed only macOS and Linux font paths. On Windows every
candidate failed Path.exists(), so load_font fell through to PIL's default
bitmap font (which ignores the requested size), rendering the filmstrip labels
nearly illegibly. Fix: add Windows candidates derived from %WINDIR%\Fonts
(Consolas + Arial). These tests pin the candidate list and the env-derived
font dir, and confirm load_font always returns a usable font — on any host.
"""
import os
import sys
import unittest
from pathlib import Path

HELPERS_DIR = Path(__file__).resolve().parent.parent / "helpers"
sys.path.insert(0, str(HELPERS_DIR))
import timeline_view # noqa: E402


class FontCandidatesTest(unittest.TestCase):
def test_windows_fonts_present(self):
# Both Windows fallbacks must be in the candidate list, under a Fonts dir.
names = [Path(c).name.lower() for c in timeline_view.FONT_CANDIDATES]
self.assertIn("consola.ttf", names)
self.assertIn("arial.ttf", names)
for c in timeline_view.FONT_CANDIDATES:
if Path(c).name.lower() in ("consola.ttf", "arial.ttf"):
self.assertEqual(Path(c).parent.name, "Fonts")

def test_macos_and_linux_fonts_still_present(self):
# The fix must not drop the original POSIX candidates.
joined = " ".join(timeline_view.FONT_CANDIDATES)
self.assertIn("/System/Library/Fonts/Menlo.ttc", joined)
self.assertIn("DejaVuSansMono.ttf", joined)

def test_win_fonts_dir_respects_windir(self):
# The Windows font dir is derived from %WINDIR%, not hardcoded to C:.
windir = os.environ.get("WINDIR", r"C:\Windows")
self.assertEqual(timeline_view._WIN_FONTS, Path(windir) / "Fonts")

def test_load_font_never_raises(self):
# load_font must return a usable font object on any host, falling back
# to PIL's default only when no candidate file exists.
font = timeline_view.load_font(14)
self.assertIsNotNone(font)


if __name__ == "__main__":
unittest.main()