Source code for babase._discord
# Released under the MIT License. See LICENSE for details.
"""Functionality related to discord sdk integration"""
from __future__ import annotations
from typing import TYPE_CHECKING, override
import _babase
from babase._appsubsystem import AppSubsystem
if TYPE_CHECKING:
from typing import Any
# Add a config key preferably for this
ENABLE_DISCORD = True # disable this for now
[docs]
class DiscordSubsystem(AppSubsystem):
"""Discord SDK integration class.
Access the single shared instance of this class via the
:attr:`~babase.App.discord` attr on the :class:`~babase.App` class."""
# pylint: disable=too-many-positional-arguments
def __init__(self) -> None:
self.details: str | None = None
self.state: str | None = None
self.large_image_key: str | None = None
self.small_image_key: str | None = None
self.large_image_text: str | None = None
self.small_image_text: str | None = None
self.start_timestamp: float | None = None
self.end_timestamp: float | None = None
if not ENABLE_DISCORD:
return
if not self.is_available():
return
_babase.discord_start()
[docs]
@override
def on_app_shutdown(self) -> None:
"""Called when the app is shutting down."""
_babase.discord_shutdown()
[docs]
@staticmethod
def is_available() -> bool:
"""Check if the Discord SDK is available.
_babase.discord_is_ready() returns None if not available."""
return _babase.discord_is_ready() is not None
@property
def is_ready(self) -> bool:
"""Check if the Discord SDK is ready."""
return _babase.discord_is_ready()
[docs]
def set_presence(
self,
state: str | None = None,
details: str | None = None,
start_timestamp: float | None = None,
end_timestamp: float | None = None,
large_image_key: str | None = None,
small_image_key: str | None = None,
large_image_text: str | None = None,
small_image_text: str | None = None,
party_id: str | None = None,
party_size: tuple[int, int] | None = None,
) -> None:
"""Set Discord rich presence state.
Args:
state: Current game state (e.g. "In Match", "Main Menu")
details: Additional details about current activity
start_timestamp: Activity start time (epoch timestamp)
end_timestamp: Activity end time (epoch timestamp)
large_image_key: Key/Url for large image asset
large_image_text: Hover text for large image
small_image_key: Key/Url for small image asset
small_image_text: Hover text for small image
party_id: Current party ID for join/spectate
party_size: Tuple of (current_size, max_size)
"""
if not self.is_available():
return
# Build presence dict with only non-None values
presence: dict[str, Any] = {}
if state is not None:
self.state = state
presence['state'] = state
if details is not None:
self.details = details
presence['details'] = details
if start_timestamp is not None:
self.start_timestamp = start_timestamp
presence['start_timestamp'] = start_timestamp
if end_timestamp is not None:
self.end_timestamp = end_timestamp
presence['end_timestamp'] = end_timestamp
if large_image_key is not None:
self.large_image_key = large_image_key
presence['large_image_key'] = large_image_key
if small_image_key is not None:
self.small_image_key = small_image_key
presence['small_image_key'] = small_image_key
if large_image_text is not None:
self.large_image_text = large_image_text
presence['large_image_text'] = large_image_text
if small_image_text is not None:
self.small_image_text = small_image_text
presence['small_image_text'] = small_image_text
# Set party info if provided
if party_id is not None:
_babase.discord_set_party(party_id=party_id)
if party_size is not None:
_babase.discord_set_party(
current_party_size=party_size[0], max_party_size=party_size[1]
)
# Update rich presence
if presence:
_babase.discord_richpresence(**presence)
# Docs-generation hack; import some stuff that we likely only forward-declared
# in our actual source code so that docs tools can find it.
from typing import (Coroutine, Any, Literal, Callable,
Generator, Awaitable, Sequence, Self)
import asyncio
from concurrent.futures import Future
from pathlib import Path
from enum import Enum