119 lines
3.7 KiB
Python
119 lines
3.7 KiB
Python
|
|
from pydantic import BaseModel
|
||
|
|
|
||
|
|
from yuxi.channel.extensions.twitch.types import TwitchRole
|
||
|
|
|
||
|
|
|
||
|
|
class TwitchAccountConfig(BaseModel):
|
||
|
|
username: str = ""
|
||
|
|
access_token: str = ""
|
||
|
|
client_id: str | None = None
|
||
|
|
channel: str = ""
|
||
|
|
enabled: bool = True
|
||
|
|
allow_from: list[str] = []
|
||
|
|
allowed_roles: list[TwitchRole] = []
|
||
|
|
require_mention: bool = True
|
||
|
|
response_prefix: str | None = None
|
||
|
|
client_secret: str | None = None
|
||
|
|
refresh_token: str | None = None
|
||
|
|
expires_in: int | None = None
|
||
|
|
obtainment_timestamp: float | None = None
|
||
|
|
|
||
|
|
|
||
|
|
class TwitchConfig(BaseModel):
|
||
|
|
enabled: bool = True
|
||
|
|
name: str | None = None
|
||
|
|
default_account: str = "default"
|
||
|
|
username: str | None = None
|
||
|
|
access_token: str | None = None
|
||
|
|
client_id: str | None = None
|
||
|
|
channel: str | None = None
|
||
|
|
require_mention: bool = True
|
||
|
|
allow_from: list[str] = []
|
||
|
|
allowed_roles: list[TwitchRole] = []
|
||
|
|
response_prefix: str | None = None
|
||
|
|
client_secret: str | None = None
|
||
|
|
refresh_token: str | None = None
|
||
|
|
accounts: dict[str, TwitchAccountConfig] = {}
|
||
|
|
block_streaming: bool = True
|
||
|
|
block_streaming_coalesce_max_delay_ms: int = 500
|
||
|
|
block_streaming_coalesce_min_chars: int = 100
|
||
|
|
send_chunk_interval_ms: int = 1500
|
||
|
|
eventsub_enabled: bool = True
|
||
|
|
|
||
|
|
|
||
|
|
_MERGE_FIELDS = (
|
||
|
|
"username",
|
||
|
|
"access_token",
|
||
|
|
"client_id",
|
||
|
|
"channel",
|
||
|
|
"require_mention",
|
||
|
|
"allow_from",
|
||
|
|
"allowed_roles",
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def normalize_twitch_channel(channel: str) -> str:
|
||
|
|
return channel.strip().removeprefix("#").lower()
|
||
|
|
|
||
|
|
|
||
|
|
def is_account_configured(account: TwitchAccountConfig) -> bool:
|
||
|
|
return bool(account.username and account.access_token and account.channel)
|
||
|
|
|
||
|
|
|
||
|
|
def get_account_config(config: TwitchConfig, account_id: str = "default") -> TwitchAccountConfig:
|
||
|
|
account = config.accounts.get(account_id)
|
||
|
|
if account is None:
|
||
|
|
if account_id == "default":
|
||
|
|
return TwitchAccountConfig(
|
||
|
|
username=config.username or "",
|
||
|
|
access_token=config.access_token or "",
|
||
|
|
client_id=config.client_id,
|
||
|
|
channel=config.channel or "",
|
||
|
|
require_mention=config.require_mention,
|
||
|
|
allow_from=list(config.allow_from),
|
||
|
|
allowed_roles=list(config.allowed_roles),
|
||
|
|
response_prefix=config.response_prefix,
|
||
|
|
)
|
||
|
|
return TwitchAccountConfig()
|
||
|
|
|
||
|
|
if account_id == "default":
|
||
|
|
merged = account.model_copy()
|
||
|
|
for field_name in _MERGE_FIELDS:
|
||
|
|
base_val = getattr(config, field_name, None)
|
||
|
|
is_empty = False
|
||
|
|
if isinstance(base_val, str) and not base_val:
|
||
|
|
is_empty = True
|
||
|
|
elif isinstance(base_val, list) and not base_val:
|
||
|
|
is_empty = True
|
||
|
|
if base_val is None or is_empty:
|
||
|
|
continue
|
||
|
|
setattr(merged, field_name, base_val)
|
||
|
|
return merged
|
||
|
|
|
||
|
|
return account
|
||
|
|
|
||
|
|
|
||
|
|
def list_account_ids(config: TwitchConfig) -> list[str]:
|
||
|
|
if config.accounts:
|
||
|
|
return list(config.accounts.keys())
|
||
|
|
return ["default"]
|
||
|
|
|
||
|
|
|
||
|
|
def has_configured_state(config: TwitchConfig) -> bool:
|
||
|
|
if config.accounts:
|
||
|
|
return any(is_account_configured(acct) for acct in config.accounts.values())
|
||
|
|
default = TwitchAccountConfig(
|
||
|
|
username=config.username or "",
|
||
|
|
access_token=config.access_token or "",
|
||
|
|
channel=config.channel or "",
|
||
|
|
)
|
||
|
|
return is_account_configured(default)
|
||
|
|
|
||
|
|
|
||
|
|
def resolve_default_to(config: TwitchConfig, account_id: str | None = None) -> str | None:
|
||
|
|
aid = account_id or config.default_account
|
||
|
|
account = get_account_config(config, aid)
|
||
|
|
if is_account_configured(account):
|
||
|
|
return normalize_twitch_channel(account.channel)
|
||
|
|
return None
|