Fix filter_template expansion in test routes and select defaults

filter_template references were silently ignored in PP template test,
picture source test, and KC target test routes — they created a no-op
FilterTemplateFilter instead of expanding into the referenced template's
filters. Centralized expansion logic into PostprocessingTemplateStore.
resolve_filter_instances() and use it in all test routes + live stream
manager.

Also fixed empty template_id when adding filter_template filters: the
select dropdown showed the first template visually but onchange never
fired, saving "" instead. Now initializes with first choice's value and
auto-corrects stale/empty values at render time.

Other fixes: ScreenCapture dimensions now use actual image shape after
filter processing; brightness source label emoji updates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-25 01:27:46 +03:00
parent 68ce394ccc
commit 359f33fdbb
10 changed files with 82 additions and 60 deletions

View File

@@ -256,8 +256,8 @@ class ProcessedLiveStream(LiveStream):
if idle_image is not _idle_src_buf:
processed = ScreenCapture(
image=idle_image,
width=cached_source_frame.width,
height=cached_source_frame.height,
width=idle_image.shape[1],
height=idle_image.shape[0],
display_index=cached_source_frame.display_index,
)
with self._frame_lock:
@@ -293,8 +293,8 @@ class ProcessedLiveStream(LiveStream):
processed = ScreenCapture(
image=image,
width=source_frame.width,
height=source_frame.height,
width=image.shape[1],
height=image.shape[0],
display_index=source_frame.display_index,
)
with self._frame_lock:

View File

@@ -239,44 +239,24 @@ class LiveStreamManager:
return ProcessedLiveStream(source_live, filters), source_stream_id
def _resolve_filters(self, filter_instances, _visited=None):
"""Recursively resolve filter instances, expanding filter_template refs.
def _resolve_filters(self, filter_instances):
"""Resolve filter instances into instantiated PostprocessingFilter objects.
Args:
filter_instances: List of FilterInstance configs.
_visited: Set of template IDs already in the expansion stack
(prevents circular references).
Returns:
List of instantiated PostprocessingFilter objects.
Expands filter_template references via the store, then creates instances.
"""
if _visited is None:
_visited = set()
if self._pp_template_store:
flat = self._pp_template_store.resolve_filter_instances(filter_instances)
else:
flat = [fi for fi in filter_instances if fi.filter_id != "filter_template"]
resolved = []
for fi in filter_instances:
if fi.filter_id == "filter_template":
template_id = fi.options.get("template_id", "")
if not template_id or not self._pp_template_store:
continue
if template_id in _visited:
logger.warning(
f"Circular filter template reference detected: {template_id}, skipping"
)
continue
try:
pp = self._pp_template_store.get_template(template_id)
_visited.add(template_id)
resolved.extend(self._resolve_filters(pp.filters, _visited))
_visited.discard(template_id)
except ValueError:
logger.warning(f"Referenced filter template '{template_id}' not found, skipping")
else:
try:
resolved.append(
FilterRegistry.create_instance(fi.filter_id, fi.options)
)
except ValueError as e:
logger.warning(f"Skipping unknown filter '{fi.filter_id}': {e}")
for fi in flat:
try:
resolved.append(
FilterRegistry.create_instance(fi.filter_id, fi.options)
)
except ValueError as e:
logger.warning(f"Skipping unknown filter '{fi.filter_id}': {e}")
return resolved
def _create_static_image_live_stream(self, config) -> StaticImageLiveStream: