Remove led_count from static, gradient, color_cycle, and effect CSS sources
These types always auto-size from the connected device — the explicit led_count override was unused clutter. Streams now use getattr fallback. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -573,8 +573,9 @@ class StaticColorStripStream(ColorStripStream):
|
||||
def _update_from_source(self, source) -> None:
|
||||
color = source.color if isinstance(source.color, list) and len(source.color) == 3 else [255, 255, 255]
|
||||
self._source_color = color # stored separately so configure() can rebuild
|
||||
self._auto_size = not source.led_count # True when led_count == 0
|
||||
led_count = source.led_count if source.led_count and source.led_count > 0 else 1
|
||||
_lc = getattr(source, "led_count", 0)
|
||||
self._auto_size = not _lc
|
||||
led_count = _lc if _lc and _lc > 0 else 1
|
||||
self._led_count = led_count
|
||||
self._animation = source.animation # dict or None; read atomically by _animate_loop
|
||||
self._rebuild_colors()
|
||||
@@ -798,8 +799,9 @@ class ColorCycleColorStripStream(ColorStripStream):
|
||||
self._color_list = [
|
||||
c for c in raw if isinstance(c, list) and len(c) == 3
|
||||
] or default
|
||||
self._auto_size = not source.led_count
|
||||
self._led_count = source.led_count if source.led_count > 0 else 1
|
||||
_lc = getattr(source, "led_count", 0)
|
||||
self._auto_size = not _lc
|
||||
self._led_count = _lc if _lc > 0 else 1
|
||||
self._rebuild_colors()
|
||||
|
||||
def _rebuild_colors(self) -> None:
|
||||
@@ -950,8 +952,9 @@ class GradientColorStripStream(ColorStripStream):
|
||||
|
||||
def _update_from_source(self, source) -> None:
|
||||
self._stops = list(source.stops) if source.stops else []
|
||||
self._auto_size = not source.led_count
|
||||
led_count = source.led_count if source.led_count and source.led_count > 0 else 1
|
||||
_lc = getattr(source, "led_count", 0)
|
||||
self._auto_size = not _lc
|
||||
led_count = _lc if _lc and _lc > 0 else 1
|
||||
self._led_count = led_count
|
||||
self._animation = source.animation # dict or None; read atomically by _animate_loop
|
||||
self._rebuild_colors()
|
||||
|
||||
@@ -203,8 +203,9 @@ class EffectColorStripStream(ColorStripStream):
|
||||
|
||||
def _update_from_source(self, source) -> None:
|
||||
self._effect_type = getattr(source, "effect_type", "fire")
|
||||
self._auto_size = not source.led_count
|
||||
self._led_count = source.led_count if source.led_count and source.led_count > 0 else 1
|
||||
_lc = getattr(source, "led_count", 0)
|
||||
self._auto_size = not _lc
|
||||
self._led_count = _lc if _lc and _lc > 0 else 1
|
||||
self._palette_name = getattr(source, "palette", None) or _EFFECT_DEFAULT_PALETTE.get(self._effect_type, "fire")
|
||||
self._palette_lut = _build_palette_lut(self._palette_name)
|
||||
color = getattr(source, "color", None)
|
||||
|
||||
@@ -116,9 +116,10 @@ export function onCSSTypeChange() {
|
||||
}
|
||||
_syncAnimationSpeedState();
|
||||
|
||||
// LED count — not needed for composite/mapped/audio/api_input (uses device count)
|
||||
// LED count — only shown for picture, api_input, notification
|
||||
const hasLedCount = ['picture', 'api_input', 'notification'];
|
||||
document.getElementById('css-editor-led-count-group').style.display =
|
||||
(type === 'composite' || type === 'mapped' || type === 'audio' || type === 'api_input') ? 'none' : '';
|
||||
hasLedCount.includes(type) ? '' : 'none';
|
||||
|
||||
// Sync clock — shown for animated types (static, gradient, color_cycle, effect)
|
||||
const clockTypes = ['static', 'gradient', 'color_cycle', 'effect'];
|
||||
@@ -716,7 +717,6 @@ export function createColorStripCard(source, pictureSourceMap, audioSourceMap) {
|
||||
<span class="stream-card-prop" title="${t('color_strip.static_color')}">
|
||||
<span style="display:inline-block;width:14px;height:14px;background:${hexColor};border:1px solid #888;border-radius:2px;vertical-align:middle;margin-right:4px"></span>${hexColor.toUpperCase()}
|
||||
</span>
|
||||
${source.led_count ? `<span class="stream-card-prop" title="${t('color_strip.leds')}">${ICON_LED} ${source.led_count}</span>` : ''}
|
||||
${animBadge}
|
||||
${clockBadge}
|
||||
`;
|
||||
@@ -727,7 +727,6 @@ export function createColorStripCard(source, pictureSourceMap, audioSourceMap) {
|
||||
).join('');
|
||||
propsHtml = `
|
||||
<span class="stream-card-prop">${swatches}</span>
|
||||
${source.led_count ? `<span class="stream-card-prop" title="${t('color_strip.leds')}">${ICON_LED} ${source.led_count}</span>` : ''}
|
||||
${clockBadge}
|
||||
`;
|
||||
} else if (isGradient) {
|
||||
@@ -749,7 +748,6 @@ export function createColorStripCard(source, pictureSourceMap, audioSourceMap) {
|
||||
propsHtml = `
|
||||
${cssGradient ? `<span style="flex:1 1 100%;height:12px;background:${cssGradient};border-radius:3px;border:1px solid rgba(128,128,128,0.3)"></span>` : ''}
|
||||
<span class="stream-card-prop">${ICON_PALETTE} ${stops.length} ${t('color_strip.gradient.stops_count')}</span>
|
||||
${source.led_count ? `<span class="stream-card-prop" title="${t('color_strip.leds')}">${ICON_LED} ${source.led_count}</span>` : ''}
|
||||
${animBadge}
|
||||
${clockBadge}
|
||||
`;
|
||||
@@ -759,7 +757,6 @@ export function createColorStripCard(source, pictureSourceMap, audioSourceMap) {
|
||||
propsHtml = `
|
||||
<span class="stream-card-prop">${ICON_FPS} ${escapeHtml(effectLabel)}</span>
|
||||
${paletteLabel ? `<span class="stream-card-prop" title="${t('color_strip.effect.palette')}">${ICON_PALETTE} ${escapeHtml(paletteLabel)}</span>` : ''}
|
||||
${source.led_count ? `<span class="stream-card-prop" title="${t('color_strip.leds')}">${ICON_LED} ${source.led_count}</span>` : ''}
|
||||
${clockBadge}
|
||||
`;
|
||||
} else if (isComposite) {
|
||||
@@ -1103,7 +1100,6 @@ export async function saveCSSEditor() {
|
||||
intensity: parseFloat(document.getElementById('css-editor-effect-intensity').value),
|
||||
scale: parseFloat(document.getElementById('css-editor-effect-scale').value),
|
||||
mirror: document.getElementById('css-editor-effect-mirror').checked,
|
||||
led_count: parseInt(document.getElementById('css-editor-led-count').value) || 0,
|
||||
};
|
||||
// Meteor uses a color picker
|
||||
if (payload.effect_type === 'meteor') {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* - Navigation: network-first with offline fallback
|
||||
*/
|
||||
|
||||
const CACHE_NAME = 'ledgrab-v11';
|
||||
const CACHE_NAME = 'ledgrab-v12';
|
||||
|
||||
// Only pre-cache static assets (no auth required).
|
||||
// Do NOT pre-cache '/' — it requires API key auth and would cache an error page.
|
||||
|
||||
@@ -134,7 +134,6 @@ class ColorStripSource:
|
||||
id=sid, name=name, source_type="static",
|
||||
created_at=created_at, updated_at=updated_at, description=description,
|
||||
clock_id=clock_id, color=color,
|
||||
led_count=data.get("led_count") or 0,
|
||||
animation=data.get("animation"),
|
||||
)
|
||||
|
||||
@@ -145,7 +144,6 @@ class ColorStripSource:
|
||||
id=sid, name=name, source_type="gradient",
|
||||
created_at=created_at, updated_at=updated_at, description=description,
|
||||
clock_id=clock_id, stops=stops,
|
||||
led_count=data.get("led_count") or 0,
|
||||
animation=data.get("animation"),
|
||||
)
|
||||
|
||||
@@ -156,7 +154,6 @@ class ColorStripSource:
|
||||
id=sid, name=name, source_type="color_cycle",
|
||||
created_at=created_at, updated_at=updated_at, description=description,
|
||||
clock_id=clock_id, colors=colors,
|
||||
led_count=data.get("led_count") or 0,
|
||||
)
|
||||
|
||||
if source_type == "composite":
|
||||
@@ -204,7 +201,6 @@ class ColorStripSource:
|
||||
id=sid, name=name, source_type="effect",
|
||||
created_at=created_at, updated_at=updated_at, description=description,
|
||||
clock_id=clock_id, effect_type=data.get("effect_type") or "fire",
|
||||
led_count=data.get("led_count") or 0,
|
||||
palette=data.get("palette") or "fire",
|
||||
color=color,
|
||||
intensity=float(data.get("intensity") or 1.0),
|
||||
@@ -313,13 +309,11 @@ class StaticColorStripSource(ColorStripSource):
|
||||
"""
|
||||
|
||||
color: list = field(default_factory=lambda: [255, 255, 255]) # [R, G, B]
|
||||
led_count: int = 0 # 0 = use device LED count
|
||||
animation: Optional[dict] = None # {"enabled": bool, "type": str, "speed": float} or None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
d = super().to_dict()
|
||||
d["color"] = list(self.color)
|
||||
d["led_count"] = self.led_count
|
||||
d["animation"] = self.animation
|
||||
return d
|
||||
|
||||
@@ -332,7 +326,7 @@ class GradientColorStripSource(ColorStripSource):
|
||||
Each stop has a primary color; optionally a second "right" color to create
|
||||
a hard discontinuity (bidirectional stop) at that position.
|
||||
|
||||
LED count auto-sizes from the connected device when led_count == 0.
|
||||
LED count auto-sizes from the connected device.
|
||||
"""
|
||||
|
||||
# Each stop: {"position": float, "color": [R,G,B], "color_right": [R,G,B] | null}
|
||||
@@ -340,13 +334,11 @@ class GradientColorStripSource(ColorStripSource):
|
||||
{"position": 0.0, "color": [255, 0, 0]},
|
||||
{"position": 1.0, "color": [0, 0, 255]},
|
||||
])
|
||||
led_count: int = 0 # 0 = use device LED count
|
||||
animation: Optional[dict] = None # {"enabled": bool, "type": str, "speed": float} or None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
d = super().to_dict()
|
||||
d["stops"] = [dict(s) for s in self.stops]
|
||||
d["led_count"] = self.led_count
|
||||
d["animation"] = self.animation
|
||||
return d
|
||||
|
||||
@@ -357,19 +349,17 @@ class ColorCycleColorStripSource(ColorStripSource):
|
||||
|
||||
All LEDs receive the same solid color at any point in time, smoothly
|
||||
interpolating between the configured color stops in a continuous loop.
|
||||
LED count auto-sizes from the connected device when led_count == 0.
|
||||
LED count auto-sizes from the connected device.
|
||||
"""
|
||||
|
||||
colors: list = field(default_factory=lambda: [
|
||||
[255, 0, 0], [255, 255, 0], [0, 255, 0],
|
||||
[0, 255, 255], [0, 0, 255], [255, 0, 255],
|
||||
])
|
||||
led_count: int = 0 # 0 = use device LED count
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
d = super().to_dict()
|
||||
d["colors"] = [list(c) for c in self.colors]
|
||||
d["led_count"] = self.led_count
|
||||
return d
|
||||
|
||||
|
||||
@@ -379,11 +369,10 @@ class EffectColorStripSource(ColorStripSource):
|
||||
|
||||
The effect_type field selects which algorithm to use:
|
||||
fire, meteor, plasma, noise, aurora.
|
||||
LED count auto-sizes from the connected device when led_count == 0.
|
||||
LED count auto-sizes from the connected device.
|
||||
"""
|
||||
|
||||
effect_type: str = "fire" # fire | meteor | plasma | noise | aurora
|
||||
led_count: int = 0 # 0 = use device LED count
|
||||
palette: str = "fire" # named color palette
|
||||
color: list = field(default_factory=lambda: [255, 80, 0]) # [R,G,B] for meteor head
|
||||
intensity: float = 1.0 # effect-specific intensity (0.1–2.0)
|
||||
@@ -393,7 +382,6 @@ class EffectColorStripSource(ColorStripSource):
|
||||
def to_dict(self) -> dict:
|
||||
d = super().to_dict()
|
||||
d["effect_type"] = self.effect_type
|
||||
d["led_count"] = self.led_count
|
||||
d["palette"] = self.palette
|
||||
d["color"] = list(self.color)
|
||||
d["intensity"] = self.intensity
|
||||
|
||||
@@ -155,7 +155,6 @@ class ColorStripStore:
|
||||
description=description,
|
||||
clock_id=clock_id,
|
||||
color=rgb,
|
||||
led_count=led_count,
|
||||
animation=animation,
|
||||
)
|
||||
elif source_type == "gradient":
|
||||
@@ -171,7 +170,6 @@ class ColorStripStore:
|
||||
{"position": 0.0, "color": [255, 0, 0]},
|
||||
{"position": 1.0, "color": [0, 0, 255]},
|
||||
],
|
||||
led_count=led_count,
|
||||
animation=animation,
|
||||
)
|
||||
elif source_type == "color_cycle":
|
||||
@@ -188,7 +186,6 @@ class ColorStripStore:
|
||||
description=description,
|
||||
clock_id=clock_id,
|
||||
colors=colors if isinstance(colors, list) and len(colors) >= 2 else default_colors,
|
||||
led_count=led_count,
|
||||
)
|
||||
elif source_type == "effect":
|
||||
rgb = color if isinstance(color, list) and len(color) == 3 else [255, 80, 0]
|
||||
@@ -201,7 +198,6 @@ class ColorStripStore:
|
||||
description=description,
|
||||
clock_id=clock_id,
|
||||
effect_type=effect_type or "fire",
|
||||
led_count=led_count,
|
||||
palette=palette or "fire",
|
||||
color=rgb,
|
||||
intensity=float(intensity) if intensity else 1.0,
|
||||
@@ -402,27 +398,19 @@ class ColorStripStore:
|
||||
if color is not None:
|
||||
if isinstance(color, list) and len(color) == 3:
|
||||
source.color = color
|
||||
if led_count is not None:
|
||||
source.led_count = led_count
|
||||
if animation is not None:
|
||||
source.animation = animation
|
||||
elif isinstance(source, GradientColorStripSource):
|
||||
if stops is not None and isinstance(stops, list):
|
||||
source.stops = stops
|
||||
if led_count is not None:
|
||||
source.led_count = led_count
|
||||
if animation is not None:
|
||||
source.animation = animation
|
||||
elif isinstance(source, ColorCycleColorStripSource):
|
||||
if colors is not None and isinstance(colors, list) and len(colors) >= 2:
|
||||
source.colors = colors
|
||||
if led_count is not None:
|
||||
source.led_count = led_count
|
||||
elif isinstance(source, EffectColorStripSource):
|
||||
if effect_type is not None:
|
||||
source.effect_type = effect_type
|
||||
if led_count is not None:
|
||||
source.led_count = led_count
|
||||
if palette is not None:
|
||||
source.palette = palette
|
||||
if color is not None and isinstance(color, list) and len(color) == 3:
|
||||
|
||||
Reference in New Issue
Block a user