Add OBS widgets for streamers

- Add widget token authentication system
- Create leaderboard, current assignment, and progress widgets
- Support dark, light, and neon themes
- Add widget settings modal for URL generation
- Fix avatar loading through backend API proxy

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-01-09 19:16:50 +03:00
parent cd78a99ce7
commit 146ed5e489
18 changed files with 2286 additions and 2 deletions

View File

@@ -18,6 +18,7 @@ from app.models.inventory import UserInventory
from app.models.coin_transaction import CoinTransaction, CoinTransactionType
from app.models.consumable_usage import ConsumableUsage
from app.models.promo_code import PromoCode, PromoCodeRedemption
from app.models.widget_token import WidgetToken
__all__ = [
"User",
@@ -65,4 +66,5 @@ __all__ = [
"ConsumableUsage",
"PromoCode",
"PromoCodeRedemption",
"WidgetToken",
]

View File

@@ -0,0 +1,22 @@
from datetime import datetime
from sqlalchemy import DateTime, ForeignKey, String, Boolean
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.core.database import Base
class WidgetToken(Base):
"""Токен для авторизации OBS виджетов"""
__tablename__ = "widget_tokens"
id: Mapped[int] = mapped_column(primary_key=True)
token: Mapped[str] = mapped_column(String(64), unique=True, index=True)
participant_id: Mapped[int] = mapped_column(ForeignKey("participants.id", ondelete="CASCADE"))
marathon_id: Mapped[int] = mapped_column(ForeignKey("marathons.id", ondelete="CASCADE"))
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
expires_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
# Relationships
participant: Mapped["Participant"] = relationship("Participant")
marathon: Mapped["Marathon"] = relationship("Marathon")