Refactor core/ into logical sub-packages and split filter files

Reorganize the flat core/ directory (17 files) into three sub-packages:
- core/devices/ — LED device communication (led_client, wled/adalight clients, providers, DDP)
- core/processing/ — target processing pipeline (processor_manager, target processors, live streams, settings)
- core/capture/ — screen capture & calibration (screen_capture, calibration, pixel_processor, overlay)

Also split the monolithic filters/builtin.py (460 lines, 8 filters) into
individual files: brightness, saturation, gamma, downscaler, pixelate,
auto_crop, flip, color_correction.

Includes the ProcessorManager refactor from target-centric architecture:
ProcessorManager slimmed from ~1600 to ~490 lines with unified
_processors dict replacing duplicate _targets/_kc_targets dicts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-18 12:03:29 +03:00
parent 77dd342c4c
commit fc779eef39
50 changed files with 2740 additions and 2267 deletions

View File

@@ -4,7 +4,7 @@ import httpx
from fastapi import APIRouter, HTTPException, Depends
from wled_controller.api.auth import AuthRequired
from wled_controller.core.led_client import (
from wled_controller.core.devices.led_client import (
get_all_providers,
get_device_capabilities,
get_provider,
@@ -26,11 +26,11 @@ from wled_controller.api.schemas.devices import (
DiscoveredDeviceResponse,
DiscoverDevicesResponse,
)
from wled_controller.core.calibration import (
from wled_controller.core.capture.calibration import (
calibration_from_dict,
calibration_to_dict,
)
from wled_controller.core.processor_manager import ProcessorManager
from wled_controller.core.processing.processor_manager import ProcessorManager
from wled_controller.storage import DeviceStore
from wled_controller.storage.picture_target_store import PictureTargetStore
from wled_controller.utils import get_logger
@@ -50,6 +50,7 @@ def _device_to_response(device) -> DeviceResponse:
led_count=device.led_count,
enabled=device.enabled,
baud_rate=device.baud_rate,
auto_shutdown=device.auto_shutdown,
capabilities=sorted(get_device_capabilities(device.device_type)),
calibration=CalibrationSchema(**calibration_to_dict(device.calibration)),
created_at=device.created_at,
@@ -110,6 +111,11 @@ async def create_device(
detail=f"Failed to connect to {device_type} device at {device_url}: {e}"
)
# Resolve auto_shutdown default: True for adalight, False otherwise
auto_shutdown = device_data.auto_shutdown
if auto_shutdown is None:
auto_shutdown = device_type == "adalight"
# Create device in storage
device = store.create_device(
name=device_data.name,
@@ -117,6 +123,7 @@ async def create_device(
led_count=led_count,
device_type=device_type,
baud_rate=device_data.baud_rate,
auto_shutdown=auto_shutdown,
)
# Register in processor manager for health monitoring
@@ -127,6 +134,7 @@ async def create_device(
calibration=device.calibration,
device_type=device.device_type,
baud_rate=device.baud_rate,
auto_shutdown=device.auto_shutdown,
)
return _device_to_response(device)
@@ -233,6 +241,7 @@ async def update_device(
enabled=update_data.enabled,
led_count=update_data.led_count,
baud_rate=update_data.baud_rate,
auto_shutdown=update_data.auto_shutdown,
)
# Sync connection info in processor manager
@@ -246,6 +255,10 @@ async def update_device(
except ValueError:
pass
# Sync auto_shutdown in runtime state
if update_data.auto_shutdown is not None and device_id in manager._devices:
manager._devices[device_id].auto_shutdown = update_data.auto_shutdown
return _device_to_response(device)
except ValueError as e:
@@ -409,7 +422,6 @@ async def set_device_power(
body: dict,
_auth: AuthRequired,
store: DeviceStore = Depends(get_device_store),
manager = Depends(get_processor_manager),
):
"""Turn device on or off."""
device = store.get_device(device_id)
@@ -423,13 +435,11 @@ async def set_device_power(
raise HTTPException(status_code=400, detail="'on' must be a boolean")
try:
if device.device_type == "adalight":
if not on:
await manager.send_black_frame(device_id)
# "on" is a no-op for Adalight — next processing frame lights them up
else:
provider = get_provider(device.device_type)
await provider.set_power(device.url, on)
provider = get_provider(device.device_type)
await provider.set_power(
device.url, on,
led_count=device.led_count, baud_rate=device.baud_rate,
)
return {"on": on}
except Exception as e:
logger.error(f"Failed to set power for {device_id}: {e}")