|
32 | 32 | from typing import TYPE_CHECKING, Any, TypeAlias, Unpack |
33 | 33 |
|
34 | 34 | from twitchio.client import Client |
| 35 | +from twitchio.user import PartialUser |
35 | 36 |
|
36 | 37 | from ...utils import _is_submodule |
37 | 38 | from .context import Context |
|
43 | 44 | if TYPE_CHECKING: |
44 | 45 | from collections.abc import Callable, Coroutine, Iterable, Mapping |
45 | 46 |
|
| 47 | + from twitchio.authentication.payloads import ClientCredentialsPayload, ValidateTokenPayload |
46 | 48 | from twitchio.eventsub.subscriptions import SubscriptionPayload |
47 | 49 | from twitchio.models.eventsub_ import ChannelPointsRedemptionAdd, ChannelPointsRedemptionUpdate, ChatMessage |
48 | 50 | from twitchio.types_.eventsub import SubscriptionResponse |
49 | | - from twitchio.user import PartialUser |
| 51 | + from twitchio.user import User |
50 | 52 |
|
51 | 53 | from .components import Component |
52 | 54 | from .types_ import BotOptions |
@@ -176,6 +178,7 @@ def __init__( |
176 | 178 | self._components: dict[str, Component] = {} |
177 | 179 | self._base_converter: _BaseConverter = _BaseConverter(self) |
178 | 180 | self.__modules: dict[str, types.ModuleType] = {} |
| 181 | + self._owner: User | None = None |
179 | 182 |
|
180 | 183 | @property |
181 | 184 | def bot_id(self) -> str: |
@@ -204,6 +207,64 @@ def owner_id(self) -> str | None: |
204 | 207 | """ |
205 | 208 | return self._owner_id |
206 | 209 |
|
| 210 | + @property |
| 211 | + def owner(self) -> User | None: |
| 212 | + """Property which returns the :class:`~twitchio.User` associated with with the User who owns this bot. |
| 213 | +
|
| 214 | + Could be ``None`` if no ``owner_id`` was passed to the Bot constructor or the request failed. |
| 215 | + Passing a ``owner_id`` is highly recommended. |
| 216 | +
|
| 217 | + .. important:: |
| 218 | +
|
| 219 | + If ``owner_id`` has not been passed to the constructor of this :class:`.Bot` this will return ``None``. |
| 220 | + """ |
| 221 | + return self._owner |
| 222 | + |
| 223 | + async def login(self, *, token: str | None = None, load_tokens: bool = True, save_tokens: bool = True) -> None: |
| 224 | + if self._login_called: |
| 225 | + return |
| 226 | + |
| 227 | + self._login_called = True |
| 228 | + self._save_tokens = save_tokens |
| 229 | + |
| 230 | + if not self._http.client_id: |
| 231 | + raise RuntimeError('Expected a valid "client_id", instead received: %s', self._http.client_id) |
| 232 | + |
| 233 | + if not token and not self._http.client_secret: |
| 234 | + raise RuntimeError(f'Expected a valid "client_secret", instead received: {self._http.client_secret}') |
| 235 | + |
| 236 | + if not token: |
| 237 | + payload: ClientCredentialsPayload = await self._http.client_credentials_token() |
| 238 | + validated: ValidateTokenPayload = await self._http.validate_token(payload.access_token) |
| 239 | + token = payload.access_token |
| 240 | + |
| 241 | + logger.info("Generated App Token for Client-ID: %s", validated.client_id) |
| 242 | + |
| 243 | + self._http._app_token = token |
| 244 | + |
| 245 | + if load_tokens: |
| 246 | + async with self._http._token_lock: |
| 247 | + await self.load_tokens() |
| 248 | + |
| 249 | + if self._bot_id: |
| 250 | + logger.debug("Fetching Clients self user for %r", self.__class__.__name__) |
| 251 | + partial = PartialUser(id=self._bot_id, http=self._http) |
| 252 | + self._user = await partial.user() if self._fetch_self else partial |
| 253 | + |
| 254 | + if self._owner_id: |
| 255 | + logger.debug("Fetching owner User for %r", self.__class__.__name__) |
| 256 | + partial = PartialUser(id=self._owner_id, http=self._http) |
| 257 | + |
| 258 | + try: |
| 259 | + user = await partial.user() |
| 260 | + except Exception: |
| 261 | + logger.warning("Failed to retrieve the Owner User during startup. Owner will be None.") |
| 262 | + else: |
| 263 | + self._owner = user |
| 264 | + |
| 265 | + await self.setup_hook() |
| 266 | + self._setup_called = True |
| 267 | + |
207 | 268 | async def close(self, **options: Any) -> None: |
208 | 269 | for module in tuple(self.__modules): |
209 | 270 | try: |
|
0 commit comments