Backend optimizations, frontend optimizations, and UI design improvements
Backend optimizations: - GZip middleware for compressed responses - Concurrent WebSocket broadcast - Skip status polling when no clients connected - Deduplicated token validation with caching - Fire-and-forget HA state callbacks - Single stat() per browser item - Metadata caching (LRU) - M3U playlist optimization - Autostart setup (Task Scheduler + hidden VBS launcher) Frontend code optimizations: - Fix thumbnail blob URL memory leak - Fix WebSocket ping interval leak on reconnect - Skip artwork re-fetch when same track playing - Deduplicate volume slider logic - Extract magic numbers into named constants - Standardize error handling with toast notifications - Cache play/pause SVG constants - Loading state management for async buttons - Request deduplication for rapid clicks - Cache 30+ DOM element references - Deduplicate volume updates over WebSocket Frontend design improvements: - Progress bar seek thumb and hover expansion - Custom themed scrollbars - Toast notification accent border strips - Keyboard focus-visible states - Album art ambient glow effect - Animated sliding tab indicator - Mini-player top progress line - Empty state SVG illustrations - Responsive tablet breakpoint (601-900px) - Horizontal player layout on wide screens (>900px) - Glassmorphism mini-player with backdrop blur - Vinyl spin animation (toggleable) - Table horizontal scroll on narrow screens Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,31 +18,37 @@ logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/api/media", tags=["media"])
|
||||
|
||||
|
||||
async def _run_callback(callback_name: str) -> None:
|
||||
"""Run a callback if configured. Failures are logged but don't raise."""
|
||||
def _run_callback(callback_name: str) -> None:
|
||||
"""Fire-and-forget a callback if configured. Failures are logged but don't block."""
|
||||
if not settings.callbacks or callback_name not in settings.callbacks:
|
||||
return
|
||||
|
||||
from .scripts import _run_script
|
||||
async def _execute():
|
||||
from .scripts import _run_script
|
||||
|
||||
callback = settings.callbacks[callback_name]
|
||||
loop = asyncio.get_event_loop()
|
||||
result = await loop.run_in_executor(
|
||||
None,
|
||||
lambda: _run_script(
|
||||
command=callback.command,
|
||||
timeout=callback.timeout,
|
||||
shell=callback.shell,
|
||||
working_dir=callback.working_dir,
|
||||
),
|
||||
)
|
||||
if result["exit_code"] != 0:
|
||||
logger.warning(
|
||||
"Callback %s failed with exit code %s: %s",
|
||||
callback_name,
|
||||
result["exit_code"],
|
||||
result["stderr"],
|
||||
)
|
||||
try:
|
||||
callback = settings.callbacks[callback_name]
|
||||
loop = asyncio.get_event_loop()
|
||||
result = await loop.run_in_executor(
|
||||
None,
|
||||
lambda: _run_script(
|
||||
command=callback.command,
|
||||
timeout=callback.timeout,
|
||||
shell=callback.shell,
|
||||
working_dir=callback.working_dir,
|
||||
),
|
||||
)
|
||||
if result["exit_code"] != 0:
|
||||
logger.warning(
|
||||
"Callback %s failed with exit code %s: %s",
|
||||
callback_name,
|
||||
result["exit_code"],
|
||||
result["stderr"],
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Callback %s error: %s", callback_name, e)
|
||||
|
||||
asyncio.create_task(_execute())
|
||||
|
||||
|
||||
@router.get("/status", response_model=MediaStatus)
|
||||
@@ -70,7 +76,7 @@ async def play(_: str = Depends(verify_token)) -> dict:
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="Failed to start playback - no active media session",
|
||||
)
|
||||
await _run_callback("on_play")
|
||||
_run_callback("on_play")
|
||||
return {"success": True}
|
||||
|
||||
|
||||
@@ -88,7 +94,7 @@ async def pause(_: str = Depends(verify_token)) -> dict:
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="Failed to pause - no active media session",
|
||||
)
|
||||
await _run_callback("on_pause")
|
||||
_run_callback("on_pause")
|
||||
return {"success": True}
|
||||
|
||||
|
||||
@@ -106,7 +112,7 @@ async def stop(_: str = Depends(verify_token)) -> dict:
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="Failed to stop - no active media session",
|
||||
)
|
||||
await _run_callback("on_stop")
|
||||
_run_callback("on_stop")
|
||||
return {"success": True}
|
||||
|
||||
|
||||
@@ -124,7 +130,7 @@ async def next_track(_: str = Depends(verify_token)) -> dict:
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="Failed to skip - no active media session",
|
||||
)
|
||||
await _run_callback("on_next")
|
||||
_run_callback("on_next")
|
||||
return {"success": True}
|
||||
|
||||
|
||||
@@ -142,7 +148,7 @@ async def previous_track(_: str = Depends(verify_token)) -> dict:
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="Failed to go back - no active media session",
|
||||
)
|
||||
await _run_callback("on_previous")
|
||||
_run_callback("on_previous")
|
||||
return {"success": True}
|
||||
|
||||
|
||||
@@ -165,7 +171,7 @@ async def set_volume(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="Failed to set volume",
|
||||
)
|
||||
await _run_callback("on_volume")
|
||||
_run_callback("on_volume")
|
||||
return {"success": True, "volume": request.volume}
|
||||
|
||||
|
||||
@@ -178,7 +184,7 @@ async def toggle_mute(_: str = Depends(verify_token)) -> dict:
|
||||
"""
|
||||
controller = get_media_controller()
|
||||
muted = await controller.toggle_mute()
|
||||
await _run_callback("on_mute")
|
||||
_run_callback("on_mute")
|
||||
return {"success": True, "muted": muted}
|
||||
|
||||
|
||||
@@ -199,7 +205,7 @@ async def seek(request: SeekRequest, _: str = Depends(verify_token)) -> dict:
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="Failed to seek - no active media session or seek not supported",
|
||||
)
|
||||
await _run_callback("on_seek")
|
||||
_run_callback("on_seek")
|
||||
return {"success": True, "position": request.position}
|
||||
|
||||
|
||||
@@ -210,7 +216,7 @@ async def turn_on(_: str = Depends(verify_token)) -> dict:
|
||||
Returns:
|
||||
Success status
|
||||
"""
|
||||
await _run_callback("on_turn_on")
|
||||
_run_callback("on_turn_on")
|
||||
return {"success": True}
|
||||
|
||||
|
||||
@@ -221,7 +227,7 @@ async def turn_off(_: str = Depends(verify_token)) -> dict:
|
||||
Returns:
|
||||
Success status
|
||||
"""
|
||||
await _run_callback("on_turn_off")
|
||||
_run_callback("on_turn_off")
|
||||
return {"success": True}
|
||||
|
||||
|
||||
@@ -232,7 +238,7 @@ async def toggle(_: str = Depends(verify_token)) -> dict:
|
||||
Returns:
|
||||
Success status
|
||||
"""
|
||||
await _run_callback("on_toggle")
|
||||
_run_callback("on_toggle")
|
||||
return {"success": True}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user