heystreamer/app/routers/overlay.py
Bashy 6ad661c220 Initial commit — BashyOverlay v1
Twitch stream event platform with OBS browser source overlay.

Features:
- Twitch OAuth login (streamer + mod access)
- EventSub WebSocket for subs, gift subs, bits, channel points, follows, raids
- Chat commands via tmi.js in the overlay
- Gap audio — tone plays on new chat message after silence, volume/pitch scale with gap length
- Self-hosted media library (upload sounds and videos)
- Action configuration — map any event to sound, video, or alert
- Per-action cooldowns, test button, enable/disable toggle
- Multiple actions per event (all matching actions fire)
- Activity log dashboard with EventSub connection status
- Layout editor — iframe-based WYSIWYG with drag handles, live style preview
- Custom CSS and custom JS injection into overlay
- Custom DOM events (bashyoverlay:sub, bashyoverlay:raid, etc.) for custom JS hooks
- deploy.sh — one-shot setup and launch script

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 23:48:35 +03:00

57 lines
1.8 KiB
Python

from fastapi import APIRouter, WebSocket, WebSocketDisconnect
from fastapi.requests import Request
from fastapi.responses import HTMLResponse
from app.database import get_layout, get_settings
from app.dispatch import dispatch_event
from app.templates import templates
from app.ws import manager
router = APIRouter()
@router.get("/overlay", response_class=HTMLResponse)
async def overlay_page(request: Request):
settings = get_settings()
layout = get_layout()
return templates.TemplateResponse("overlay.html", {
"request": request,
"channel": settings.twitch_channel,
"gap_silence": settings.gap_silence_threshold,
"gap_scale_end": settings.gap_scale_end,
"gap_pitch_end": settings.gap_pitch_scale_end,
"layout": layout,
"custom_css": settings.custom_css,
"custom_js": settings.custom_js,
})
@router.get("/overlay/preview", response_class=HTMLResponse)
async def overlay_preview(request: Request):
settings = get_settings()
layout = get_layout()
return templates.TemplateResponse("overlay_preview.html", {
"request": request,
"layout": layout,
"custom_css": settings.custom_css,
"custom_js": settings.custom_js,
"alert_duration_ms": layout.alert_duration * 1000,
})
@router.websocket("/ws/overlay")
async def overlay_ws(websocket: WebSocket):
await manager.connect(websocket)
try:
while True:
data = await websocket.receive_json()
if data.get("type") == "command":
await dispatch_event(
"command",
username=data.get("user"),
event_detail=data.get("name"),
)
except WebSocketDisconnect:
manager.disconnect(websocket)
except Exception:
manager.disconnect(websocket)