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

64 lines
2.1 KiB
Python

import os
from typing import Optional
import httpx
from fastapi import Depends, HTTPException, Request
from fastapi.responses import RedirectResponse
from sqlmodel import Session, select
from app.database import get_session
from app.models import User
TWITCH_CLIENT_ID = os.getenv("TWITCH_CLIENT_ID", "")
TWITCH_CLIENT_SECRET = os.getenv("TWITCH_CLIENT_SECRET", "")
TWITCH_REDIRECT_URI = os.getenv("TWITCH_REDIRECT_URI", "http://localhost:8000/auth/callback")
SCOPES = "channel:read:subscriptions bits:read channel:read:redemptions moderator:read:followers"
TWITCH_AUTH_URL = (
"https://id.twitch.tv/oauth2/authorize"
f"?client_id={TWITCH_CLIENT_ID}"
f"&redirect_uri={TWITCH_REDIRECT_URI}"
"&response_type=code"
f"&scope={SCOPES.replace(' ', '+')}"
)
async def exchange_code(code: str) -> dict:
async with httpx.AsyncClient() as client:
r = await client.post("https://id.twitch.tv/oauth2/token", data={
"client_id": TWITCH_CLIENT_ID,
"client_secret": TWITCH_CLIENT_SECRET,
"code": code,
"grant_type": "authorization_code",
"redirect_uri": TWITCH_REDIRECT_URI,
})
r.raise_for_status()
return r.json()
async def get_twitch_user(access_token: str) -> dict:
async with httpx.AsyncClient() as client:
r = await client.get(
"https://api.twitch.tv/helix/users",
headers={"Authorization": f"Bearer {access_token}", "Client-Id": TWITCH_CLIENT_ID},
)
r.raise_for_status()
return r.json()["data"][0]
def get_current_user(request: Request, session: Session = Depends(get_session)) -> Optional[User]:
user_id = request.session.get("user_id")
if not user_id:
return None
return session.get(User, user_id)
def require_user(request: Request, session: Session = Depends(get_session)) -> User:
user_id = request.session.get("user_id")
if not user_id:
raise HTTPException(status_code=307, headers={"Location": "/auth/login"})
user = session.get(User, user_id)
if not user:
raise HTTPException(status_code=307, headers={"Location": "/auth/login"})
return user