heystreamer/app/main.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

60 lines
1.6 KiB
Python

import asyncio
import os
from contextlib import asynccontextmanager
from typing import Optional
from dotenv import load_dotenv
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from starlette.middleware.sessions import SessionMiddleware
from app.database import create_db, get_admin_user
from app.routers import actions, auth, dashboard, layout, media, overlay, settings
load_dotenv()
_eventsub_task: Optional[asyncio.Task] = None
def get_eventsub_task() -> Optional[asyncio.Task]:
return _eventsub_task
async def start_eventsub() -> None:
global _eventsub_task
from app.eventsub import run_eventsub
admin = get_admin_user()
if not admin:
return
if _eventsub_task and not _eventsub_task.done():
_eventsub_task.cancel()
try:
await _eventsub_task
except asyncio.CancelledError:
pass
_eventsub_task = asyncio.create_task(run_eventsub(admin.broadcaster_id, admin.access_token))
@asynccontextmanager
async def lifespan(app: FastAPI):
create_db()
await start_eventsub()
yield
if _eventsub_task and not _eventsub_task.done():
_eventsub_task.cancel()
app = FastAPI(title="BashyOverlay", lifespan=lifespan)
app.add_middleware(SessionMiddleware, secret_key=os.getenv("SECRET_KEY", "dev-secret-change-me"))
app.mount("/static", StaticFiles(directory="static"), name="static")
app.include_router(auth.router)
app.include_router(dashboard.router)
app.include_router(overlay.router)
app.include_router(actions.router)
app.include_router(media.router)
app.include_router(layout.router)
app.include_router(settings.router)