feat(video, settings, docs): add muted playback, nested Settings tabs, merge holidays tab; bump 2025.1.0-alpha.11
API/DB: add Event.muted with full CRUD wiring (Alembic migration), persist/return with autoplay/loop/volume
Dashboard: per‑event video options (autoplay/loop/volume/muted) with system defaults; Settings → Events → Videos defaults
Settings UX: nested tabs with controlled selection; Academic Calendar: merge “Schulferien Import”+“Liste” into “📥 Import & Liste”
Docs: update README and copilot-instructions (video payload, streaming 206, defaults keys); update program-info.json changelog; bump version to 2025.1.0‑alpha.11
This commit is contained in:
30
server/alembic/versions/21226a449037_add_muted_to_events.py
Normal file
30
server/alembic/versions/21226a449037_add_muted_to_events.py
Normal file
@@ -0,0 +1,30 @@
|
||||
"""add_muted_to_events
|
||||
|
||||
Revision ID: 21226a449037
|
||||
Revises: 910951fd300a
|
||||
Create Date: 2025-11-05 17:24:29.168692
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '21226a449037'
|
||||
down_revision: Union[str, None] = '910951fd300a'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# Add muted column to events table for video mute control
|
||||
op.add_column('events', sa.Column('muted', sa.Boolean(), nullable=True))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# Remove muted column
|
||||
op.drop_column('events', 'muted')
|
||||
@@ -50,6 +50,9 @@ with engine.connect() as conn:
|
||||
('presentation_interval', '10', 'Standard Intervall für Präsentationen (Sekunden)'),
|
||||
('presentation_page_progress', 'true', 'Seitenfortschrift anzeigen (Page-Progress) für Präsentationen'),
|
||||
('presentation_auto_progress', 'true', 'Automatischer Fortschritt (Auto-Progress) für Präsentationen'),
|
||||
('video_autoplay', 'true', 'Autoplay (automatisches Abspielen) für Videos'),
|
||||
('video_loop', 'true', 'Loop (Wiederholung) für Videos'),
|
||||
('video_volume', '0.8', 'Standard Lautstärke für Videos (0.0 - 1.0)'),
|
||||
]
|
||||
|
||||
for key, value, description in default_settings:
|
||||
|
||||
@@ -138,7 +138,14 @@ def get_event(event_id):
|
||||
"IsAllDay": False, # Assuming events are not all-day by default
|
||||
"MediaId": str(event.event_media_id) if event.event_media_id else None,
|
||||
"SlideshowInterval": event.slideshow_interval,
|
||||
"PageProgress": event.page_progress,
|
||||
"AutoProgress": event.auto_progress,
|
||||
"WebsiteUrl": event.event_media.url if event.event_media and hasattr(event.event_media, 'url') else None,
|
||||
# Video-specific fields
|
||||
"Autoplay": event.autoplay,
|
||||
"Loop": event.loop,
|
||||
"Volume": event.volume,
|
||||
"Muted": event.muted,
|
||||
"RecurrenceRule": event.recurrence_rule,
|
||||
"RecurrenceEnd": event.recurrence_end.isoformat() if event.recurrence_end else None,
|
||||
"SkipHolidays": event.skip_holidays,
|
||||
@@ -398,6 +405,7 @@ def create_event():
|
||||
autoplay = None
|
||||
loop = None
|
||||
volume = None
|
||||
muted = None
|
||||
if event_type == "video":
|
||||
event_media_id = data.get("event_media_id")
|
||||
if not event_media_id:
|
||||
@@ -406,6 +414,7 @@ def create_event():
|
||||
autoplay = data.get("autoplay", True)
|
||||
loop = data.get("loop", False)
|
||||
volume = data.get("volume", 0.8)
|
||||
muted = data.get("muted", False)
|
||||
|
||||
# created_by aus den Daten holen, Default: None
|
||||
created_by = data.get("created_by")
|
||||
@@ -435,6 +444,7 @@ def create_event():
|
||||
autoplay=autoplay,
|
||||
loop=loop,
|
||||
volume=volume,
|
||||
muted=muted,
|
||||
created_by=created_by,
|
||||
# Recurrence
|
||||
recurrence_rule=data.get("recurrence_rule"),
|
||||
@@ -514,6 +524,8 @@ def update_event(event_id):
|
||||
event.loop = data.get("loop")
|
||||
if "volume" in data:
|
||||
event.volume = data.get("volume")
|
||||
if "muted" in data:
|
||||
event.muted = data.get("muted")
|
||||
event.created_by = data.get("created_by", event.created_by)
|
||||
# Track previous values to decide on exception regeneration
|
||||
prev_rule = event.recurrence_rule
|
||||
|
||||
Reference in New Issue
Block a user