Skip to content

Commit 11eafca

Browse files
abrichrclaude
andauthored
fix(ci): use v9 branch config for python-semantic-release (#13)
* feat: disable window capture by default, add recording profiling with auto-wormhole - Make window reader/writer conditional on RECORD_WINDOW_DATA (defaults to False), eliminating unnecessary thread + process + expensive platform API calls - Add throttle to read_window_events (0.1s) and memory_writer (1s) loops - Add profiling summary at end of record() with duration, event counts/rates, config flags, main thread check, and thread count - Auto-send profiling.json via Magic Wormhole after recording stops Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: skip window requirement when RECORD_WINDOW_DATA=False, set log level to WARNING - When window capture is disabled, skip the window timestamp requirement in process_events instead of discarding all action events - Set loguru log level to WARNING by default (was DEBUG) to reduce noise during recording Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: set log level to INFO not WARNING Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: handle missing video frames on early Ctrl+C video_post_callback crashes with KeyError 'last_frame' when recording stops before any action triggers a video frame write. Guard against missing state keys and close the container gracefully. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: guard window event save when capture disabled, fix PyAV pict_type compat - Second reference to prev_window_event in process_events was unguarded, causing AttributeError when RECORD_WINDOW_DATA=False - PyAV pict_type="I" raises TypeError on newer versions; fall back to integer constant Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: use PictureType.I enum for PyAV pict_type, add video tests - Use av.video.frame.PictureType.I instead of string "I" which is unsupported in current PyAV versions - Add test_video.py with tests for frame writing, key frames, and PictureType enum compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: use Agg backend for matplotlib, improve wormhole-not-found message - Set matplotlib to non-interactive Agg backend so plotting works from background threads (fixes RuntimeError when Recorder runs record() in a non-main thread) - Improve wormhole-not-found message with install instructions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: reset stop sequence index after match to prevent IndexError When the stop sequence was fully matched, the index wasn't reset. Extra keypresses after the match would index past the end of the sequence list, causing IndexError. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add per-screenshot timing to profiling, fix stop sequence IndexError - Track screenshot duration (avg/max/min ms) and total iteration duration per screen reader loop iteration in profiling.json - Reset stop sequence index after match to prevent IndexError on extra keypresses Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: make send_profile opt-in CLI flag, add magic-wormhole as regular dep Profiling data is no longer auto-sent via wormhole after every recording. Use --send_profile flag to opt in. Also promotes magic-wormhole from optional [share] extra to a regular dependency since sharing is core functionality. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add pixel_ratio and audio_start_time to CaptureSession HTML visualizer referenced these attributes which didn't exist on CaptureSession. Added properties with safe fallbacks and updated html.py to use getattr with defaults. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(ci): use v9 branch config for python-semantic-release The `branch = "main"` key is from v7/v8 and is silently ignored by v9, causing "No release will be made, 0.3.0 has already been released!" on every push. Use the v9 `[branches.main]` table. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d7134a8 commit 11eafca

File tree

8 files changed

+282
-52
lines changed

8 files changed

+282
-52
lines changed

openadapt_capture/capture.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,34 @@ def audio_path(self) -> Path | None:
314314
audio_path = self.capture_dir / "audio.flac"
315315
return audio_path if audio_path.exists() else None
316316

317+
@property
318+
def pixel_ratio(self) -> float:
319+
"""Display pixel ratio (physical/logical), e.g. 2.0 for Retina.
320+
321+
Defaults to 1.0 if not stored in the recording.
322+
"""
323+
# Check if the Recording model has a pixel_ratio column
324+
ratio = getattr(self._recording, "pixel_ratio", None)
325+
if ratio is not None:
326+
return float(ratio)
327+
# Check the config JSON for pixel_ratio
328+
config = getattr(self._recording, "config", None)
329+
if isinstance(config, dict) and "pixel_ratio" in config:
330+
return float(config["pixel_ratio"])
331+
return 1.0
332+
333+
@property
334+
def audio_start_time(self) -> float | None:
335+
"""Start timestamp of the audio recording, or None if unavailable."""
336+
# Check the AudioInfo relationship for the timestamp
337+
audio_infos = getattr(self._recording, "audio_info", None)
338+
if audio_infos:
339+
first = audio_infos[0] if isinstance(audio_infos, list) else audio_infos
340+
ts = getattr(first, "timestamp", None)
341+
if ts is not None:
342+
return float(ts)
343+
return None
344+
317345
def raw_events(self) -> list[PydanticActionEvent]:
318346
"""Get all raw action events (unprocessed).
319347

openadapt_capture/cli.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def record(
1717
video: bool = True,
1818
audio: bool = False,
1919
images: bool = False,
20+
send_profile: bool = False,
2021
) -> None:
2122
"""Record GUI interactions.
2223
@@ -26,6 +27,7 @@ def record(
2627
video: Capture video (default: True).
2728
audio: Capture audio (default: False).
2829
images: Save screenshots as PNGs (default: False).
30+
send_profile: Send profiling data via wormhole after recording (default: False).
2931
"""
3032
import time
3133

@@ -43,6 +45,7 @@ def record(
4345
capture_video=video,
4446
capture_audio=audio,
4547
capture_images=images,
48+
send_profile=send_profile,
4649
) as recorder:
4750
recorder.wait_for_ready()
4851
try:

openadapt_capture/plotting.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99
from collections import defaultdict
1010
from itertools import cycle
1111

12-
import matplotlib.pyplot as plt
12+
import matplotlib
13+
14+
matplotlib.use("Agg") # non-interactive backend; works from any thread
15+
16+
import matplotlib.pyplot as plt # noqa: E402
1317
from loguru import logger
1418

1519
from openadapt_capture.db import models

0 commit comments

Comments
 (0)