feat: add capture strategy interface and manual button strategy

This commit is contained in:
pyr0ball 2026-07-13 10:28:10 -07:00
parent f93d51d500
commit b707aef137
3 changed files with 62 additions and 0 deletions

View file

@ -0,0 +1,15 @@
from abc import ABC, abstractmethod
import numpy as np
class CaptureStrategy(ABC):
"""Watches a stream of frames and decides when to fire a capture."""
@abstractmethod
def reset(self) -> None:
"""Clear any internal state, e.g. after a capture fires."""
@abstractmethod
def observe(self, frame: np.ndarray) -> bool:
"""Feed the latest frame. Returns True exactly once per capture."""

View file

@ -0,0 +1,22 @@
import numpy as np
from .base import CaptureStrategy
class ManualButtonStrategy(CaptureStrategy):
"""Fires only when trigger() has been called since the last observe()."""
def __init__(self) -> None:
self._armed = False
def trigger(self) -> None:
self._armed = True
def reset(self) -> None:
self._armed = False
def observe(self, frame: np.ndarray) -> bool:
if self._armed:
self._armed = False
return True
return False

View file

@ -0,0 +1,25 @@
import numpy as np
from bookmark.capture_strategies.manual_button import ManualButtonStrategy
def test_does_not_fire_without_trigger():
strategy = ManualButtonStrategy()
frame = np.zeros((10, 10, 3), dtype=np.uint8)
assert strategy.observe(frame) is False
def test_fires_once_after_trigger():
strategy = ManualButtonStrategy()
frame = np.zeros((10, 10, 3), dtype=np.uint8)
strategy.trigger()
assert strategy.observe(frame) is True
assert strategy.observe(frame) is False
def test_reset_clears_armed_state():
strategy = ManualButtonStrategy()
frame = np.zeros((10, 10, 3), dtype=np.uint8)
strategy.trigger()
strategy.reset()
assert strategy.observe(frame) is False