feat: asset-based image/video sources, notification sounds, UI improvements
Some checks failed
Lint & Test / test (push) Has been cancelled

- Replace URL-based image_source/url fields with image_asset_id/video_asset_id
  on StaticImagePictureSource and VideoCaptureSource (clean break, no migration)
- Resolve asset IDs to file paths at runtime via AssetStore.get_file_path()
- Add EntitySelect asset pickers for image/video in stream editor modal
- Add notification sound configuration (global sound + per-app overrides)
- Unify per-app color and sound overrides into single "Per-App Overrides" section
- Persist notification history between server restarts
- Add asset management system (upload, edit, delete, soft-delete)
- Replace emoji buttons with SVG icons throughout UI
- Various backend improvements: SQLite stores, auth, backup, MQTT, webhooks
This commit is contained in:
2026-03-26 20:40:25 +03:00
parent c0853ce184
commit e2e1107df7
100 changed files with 2935 additions and 992 deletions

View File

@@ -593,22 +593,19 @@
"streams.add.video": "Add Video Source",
"streams.edit.video": "Edit Video Source",
"picture_source.type.video": "Video",
"picture_source.type.video.desc": "Stream frames from video file, URL, or YouTube",
"picture_source.video.url": "Video URL:",
"picture_source.video.url.hint": "Local file path, HTTP URL, or YouTube URL",
"picture_source.video.url.placeholder": "https://example.com/video.mp4",
"picture_source.type.video.desc": "Stream frames from an uploaded video asset",
"picture_source.video.loop": "Loop:",
"picture_source.video.speed": "Playback Speed:",
"picture_source.video.start_time": "Start Time (s):",
"picture_source.video.end_time": "End Time (s):",
"picture_source.video.resolution_limit": "Max Width (px):",
"picture_source.video.resolution_limit.hint": "Downscale video at decode time for performance",
"streams.image_source": "Image Source:",
"streams.image_source.placeholder": "https://example.com/image.jpg or C:\\path\\to\\image.png",
"streams.image_source.hint": "Enter a URL (http/https) or local file path to an image",
"streams.validate_image.validating": "Validating...",
"streams.validate_image.valid": "Image accessible",
"streams.validate_image.invalid": "Image not accessible",
"streams.image_asset": "Image Asset:",
"streams.image_asset.select": "Select image asset…",
"streams.image_asset.search": "Search image assets…",
"streams.video_asset": "Video Asset:",
"streams.video_asset.select": "Select video asset…",
"streams.video_asset.search": "Search video assets…",
"targets.title": "Targets",
"targets.description": "Targets bridge color strip sources to output devices. Each target references a device and a color strip source.",
"targets.subtab.wled": "LED",
@@ -1105,6 +1102,22 @@
"color_strip.notification.app_colors.label": "Color Mappings:",
"color_strip.notification.app_colors.hint": "Per-app color overrides. Each row maps an app name to a specific notification color.",
"color_strip.notification.app_colors.add": "+ Add Mapping",
"color_strip.notification.app_overrides": "Per-App Overrides",
"color_strip.notification.app_overrides.label": "App Overrides:",
"color_strip.notification.app_overrides.hint": "Per-app overrides for color and sound. Each row can set a custom color, sound asset, and volume for a specific app.",
"color_strip.notification.app_overrides.add": "+ Add Override",
"color_strip.notification.app_overrides.app_placeholder": "App name",
"color_strip.notification.sound": "Sound",
"color_strip.notification.sound.asset": "Sound Asset:",
"color_strip.notification.sound.asset.hint": "Pick a sound asset to play when a notification fires. Leave empty for silent.",
"color_strip.notification.sound.none": "None (silent)",
"color_strip.notification.sound.search": "Search sounds…",
"color_strip.notification.sound.volume": "Volume:",
"color_strip.notification.sound.volume.hint": "Global volume for notification sounds (0100%).",
"color_strip.notification.sound.app_sounds": "Per-App Sounds:",
"color_strip.notification.sound.app_sounds.hint": "Override sound and volume for specific apps. Empty sound = mute that app.",
"color_strip.notification.sound.app_sounds.add": "+ Add Override",
"color_strip.notification.sound.app_name_placeholder": "App name",
"color_strip.notification.endpoint": "Webhook Endpoint:",
"color_strip.notification.endpoint.hint": "Use this URL to trigger notifications from external systems. POST with optional JSON body: {\"app\": \"AppName\", \"color\": \"#FF0000\"}.",
"color_strip.notification.save_first": "Save the source first to see the webhook endpoint URL.",
@@ -1963,9 +1976,35 @@
"update.install_type.docker": "Docker",
"update.install_type.dev": "Development",
"color_strip": {
"notification": {
"search_apps": "Search notification apps…"
}
}
"color_strip.notification.search_apps": "Search notification apps…",
"asset.group.title": "Assets",
"asset.upload": "Upload Asset",
"asset.edit": "Edit Asset",
"asset.name": "Name:",
"asset.name.hint": "Display name for this asset.",
"asset.description": "Description:",
"asset.description.hint": "Optional description for this asset.",
"asset.file": "File:",
"asset.file.hint": "Select a file to upload (sound, image, video, or other).",
"asset.drop_or_browse": "Drop file here or click to browse",
"asset.uploaded": "Asset uploaded",
"asset.updated": "Asset updated",
"asset.deleted": "Asset deleted",
"asset.confirm_delete": "Delete this asset?",
"asset.error.name_required": "Name is required",
"asset.error.no_file": "Please select a file to upload",
"asset.error.delete_failed": "Failed to delete asset",
"asset.play": "Play",
"asset.download": "Download",
"asset.prebuilt": "Prebuilt",
"asset.prebuilt_restored": "{count} prebuilt asset(s) restored",
"asset.prebuilt_none_to_restore": "All prebuilt assets are already available",
"asset.restore_prebuilt": "Restore Prebuilt Sounds",
"asset.type.sound": "Sound",
"asset.type.image": "Image",
"asset.type.video": "Video",
"asset.type.other": "Other",
"streams.group.assets": "Assets",
"section.empty.assets": "No assets yet. Click + to upload one."
}