Add capture template system with in-memory defaults and split device settings UI
Some checks failed
Validate / validate (push) Failing after 8s
Some checks failed
Validate / validate (push) Failing after 8s
- Generate default templates (MSS, DXcam, WGC) in memory from EngineRegistry at startup - Only persist user-created templates to JSON, skip defaults on load/save - Add capture_template_id to Device model and DeviceCreate schema - Remember last used template in localStorage, use it for new devices with fallback - Split Device Settings dialog into General Settings and Capture Settings - Add capture settings button (🎬) to device card - Separate default and custom templates with visual separator in Templates tab - Add capture engine integration to ProcessorManager - Add CLAUDE.md with git commit/push policy and server restart instructions - Add en/ru localization for all new UI elements Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,8 +13,9 @@ from wled_controller.core.calibration import (
|
||||
PixelMapper,
|
||||
create_default_calibration,
|
||||
)
|
||||
from wled_controller.core.capture_engines import CaptureEngine, EngineRegistry
|
||||
from wled_controller.core.pixel_processor import apply_color_correction, smooth_colors
|
||||
from wled_controller.core.screen_capture import capture_display, extract_border_pixels
|
||||
from wled_controller.core.screen_capture import extract_border_pixels
|
||||
from wled_controller.core.wled_client import WLEDClient
|
||||
from wled_controller.utils import get_logger
|
||||
|
||||
@@ -87,8 +88,10 @@ class ProcessorState:
|
||||
led_count: int
|
||||
settings: ProcessingSettings
|
||||
calibration: CalibrationConfig
|
||||
capture_template_id: str = "tpl_mss_default" # NEW: template ID for capture engine
|
||||
wled_client: Optional[WLEDClient] = None
|
||||
pixel_mapper: Optional[PixelMapper] = None
|
||||
capture_engine: Optional[CaptureEngine] = None # NEW: initialized capture engine
|
||||
is_running: bool = False
|
||||
task: Optional[asyncio.Task] = None
|
||||
metrics: ProcessingMetrics = field(default_factory=ProcessingMetrics)
|
||||
@@ -122,6 +125,7 @@ class ProcessorManager:
|
||||
led_count: int,
|
||||
settings: Optional[ProcessingSettings] = None,
|
||||
calibration: Optional[CalibrationConfig] = None,
|
||||
capture_template_id: str = "tpl_mss_default",
|
||||
):
|
||||
"""Add a device for processing.
|
||||
|
||||
@@ -131,6 +135,7 @@ class ProcessorManager:
|
||||
led_count: Number of LEDs
|
||||
settings: Processing settings (uses defaults if None)
|
||||
calibration: Calibration config (creates default if None)
|
||||
capture_template_id: Template ID for screen capture engine
|
||||
"""
|
||||
if device_id in self._processors:
|
||||
raise ValueError(f"Device {device_id} already exists")
|
||||
@@ -147,6 +152,7 @@ class ProcessorManager:
|
||||
led_count=led_count,
|
||||
settings=settings,
|
||||
calibration=calibration,
|
||||
capture_template_id=capture_template_id,
|
||||
)
|
||||
|
||||
self._processors[device_id] = state
|
||||
@@ -270,6 +276,21 @@ class ProcessorManager:
|
||||
logger.error(f"Failed to connect to WLED device {device_id}: {e}")
|
||||
raise RuntimeError(f"Failed to connect to WLED device: {e}")
|
||||
|
||||
# Initialize capture engine
|
||||
# Phase 2: Use MSS engine for all devices (template integration in Phase 5)
|
||||
try:
|
||||
# For now, always use MSS engine (Phase 5 will load from template)
|
||||
engine = EngineRegistry.create_engine("mss", {})
|
||||
engine.initialize()
|
||||
state.capture_engine = engine
|
||||
logger.debug(f"Initialized capture engine for device {device_id}: mss")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize capture engine for device {device_id}: {e}")
|
||||
# Cleanup WLED client before raising
|
||||
if state.wled_client:
|
||||
await state.wled_client.disconnect()
|
||||
raise RuntimeError(f"Failed to initialize capture engine: {e}")
|
||||
|
||||
# Initialize pixel mapper
|
||||
state.pixel_mapper = PixelMapper(
|
||||
state.calibration,
|
||||
@@ -321,6 +342,11 @@ class ProcessorManager:
|
||||
await state.wled_client.close()
|
||||
state.wled_client = None
|
||||
|
||||
# Cleanup capture engine
|
||||
if state.capture_engine:
|
||||
state.capture_engine.cleanup()
|
||||
state.capture_engine = None
|
||||
|
||||
logger.info(f"Stopped processing for device {device_id}")
|
||||
|
||||
async def _processing_loop(self, device_id: str):
|
||||
@@ -351,8 +377,11 @@ class ProcessorManager:
|
||||
|
||||
try:
|
||||
# Run blocking operations in thread pool to avoid blocking event loop
|
||||
# Capture screen (blocking I/O)
|
||||
capture = await asyncio.to_thread(capture_display, settings.display_index)
|
||||
# Capture screen using engine (blocking I/O)
|
||||
capture = await asyncio.to_thread(
|
||||
state.capture_engine.capture_display,
|
||||
settings.display_index
|
||||
)
|
||||
|
||||
# Extract border pixels (CPU-intensive)
|
||||
border_pixels = await asyncio.to_thread(extract_border_pixels, capture, settings.border_width)
|
||||
@@ -725,3 +754,31 @@ class ProcessorManager:
|
||||
"wled_led_type": h.wled_led_type,
|
||||
"error": h.error,
|
||||
}
|
||||
|
||||
def is_display_locked(self, display_index: int) -> bool:
|
||||
"""Check if a display is currently being captured by any device.
|
||||
|
||||
Args:
|
||||
display_index: Display index to check
|
||||
|
||||
Returns:
|
||||
True if the display is actively being captured
|
||||
"""
|
||||
for state in self._processors.values():
|
||||
if state.is_running and state.settings.display_index == display_index:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_display_lock_info(self, display_index: int) -> Optional[str]:
|
||||
"""Get the device ID that is currently capturing from a display.
|
||||
|
||||
Args:
|
||||
display_index: Display index to check
|
||||
|
||||
Returns:
|
||||
Device ID if locked, None otherwise
|
||||
"""
|
||||
for device_id, state in self._processors.items():
|
||||
if state.is_running and state.settings.display_index == display_index:
|
||||
return device_id
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user