|
30 | 30 | import sys |
31 | 31 | from typing import Union, Callable, List, Optional, Tuple, Any |
32 | 32 |
|
| 33 | +from twitchio.errors import HTTPException |
33 | 34 | from . import models |
34 | 35 | from .websocket import WSConnection |
35 | 36 | from .http import TwitchHTTP |
@@ -83,7 +84,11 @@ def __init__( |
83 | 84 |
|
84 | 85 | self._http = TwitchHTTP(self, api_token=token, client_secret=client_secret) |
85 | 86 | self._connection = WSConnection( |
86 | | - client=self, token=token, loop=self.loop, initial_channels=initial_channels, heartbeat=heartbeat |
| 87 | + client=self, |
| 88 | + token=token, |
| 89 | + loop=self.loop, |
| 90 | + initial_channels=initial_channels, |
| 91 | + heartbeat=heartbeat, |
87 | 92 | ) |
88 | 93 |
|
89 | 94 | self._events = {} |
@@ -127,7 +132,10 @@ def from_client_credentials( |
127 | 132 | self._http = TwitchHTTP(self, client_id=client_id, client_secret=client_secret) |
128 | 133 | self._heartbeat = heartbeat |
129 | 134 | self._connection = WSConnection( |
130 | | - client=self, loop=self.loop, initial_channels=None, heartbeat=self._heartbeat |
| 135 | + client=self, |
| 136 | + loop=self.loop, |
| 137 | + initial_channels=None, |
| 138 | + heartbeat=self._heartbeat, |
131 | 139 | ) # The only reason we're even creating this is to avoid attribute errors |
132 | 140 | self._events = {} |
133 | 141 | self._waiting = [] |
@@ -192,7 +200,10 @@ async def wrapped(func): |
192 | 200 | if inspect.iscoroutinefunction(inner_cb): |
193 | 201 | self.loop.create_task(wrapped(inner_cb)) |
194 | 202 | else: |
195 | | - warnings.warn(f"event '{name}' callback is not a coroutine", category=RuntimeWarning) |
| 203 | + warnings.warn( |
| 204 | + f"event '{name}' callback is not a coroutine", |
| 205 | + category=RuntimeWarning, |
| 206 | + ) |
196 | 207 |
|
197 | 208 | if name in self._events: |
198 | 209 | for event in self._events[name]: |
@@ -239,7 +250,11 @@ def decorator(func: Callable) -> Callable: |
239 | 250 | return decorator |
240 | 251 |
|
241 | 252 | async def wait_for( |
242 | | - self, event: str, predicate: Callable[[], bool] = lambda *a: True, *, timeout=60.0 |
| 253 | + self, |
| 254 | + event: str, |
| 255 | + predicate: Callable[[], bool] = lambda *a: True, |
| 256 | + *, |
| 257 | + timeout=60.0, |
243 | 258 | ) -> Tuple[Any]: |
244 | 259 | """|coro| |
245 | 260 |
|
@@ -285,8 +300,26 @@ def get_channel(self, name: str) -> Optional[Channel]: |
285 | 300 | # With the associated users as a set. |
286 | 301 | # We create a Channel here and return it only if the cache has that channel key. |
287 | 302 |
|
288 | | - channel = Channel(name=name, websocket=self._connection) |
289 | | - return channel |
| 303 | + return Channel(name=name, websocket=self._connection) |
| 304 | + |
| 305 | + async def fetch_channel(self, broadcaster: str) -> list: |
| 306 | + """Retrieve a channel from the API. |
| 307 | +
|
| 308 | + Parameters |
| 309 | + ----------- |
| 310 | + name: str |
| 311 | + The channel name or ID to request from API. Returns empty list if no channel was found. |
| 312 | +
|
| 313 | + Returns |
| 314 | + -------- |
| 315 | + :class:`list` |
| 316 | + """ |
| 317 | + |
| 318 | + if not broadcaster.isdigit(): |
| 319 | + get_id = await self.fetch_users(names=[broadcaster.lower()]) |
| 320 | + broadcaster = get_id[0].id |
| 321 | + |
| 322 | + return await self._http.get_channels(broadcaster) |
290 | 323 |
|
291 | 324 | async def join_channels(self, channels: Union[List[str], Tuple[str]]): |
292 | 325 | """|coro| |
@@ -334,7 +367,11 @@ def create_user(self, user_id: int, user_name: str) -> PartialUser: |
334 | 367 |
|
335 | 368 | @user_cache() |
336 | 369 | async def fetch_users( |
337 | | - self, names: List[str] = None, ids: List[int] = None, token: str = None, force=False |
| 370 | + self, |
| 371 | + names: List[str] = None, |
| 372 | + ids: List[int] = None, |
| 373 | + token: str = None, |
| 374 | + force=False, |
338 | 375 | ) -> List[User]: |
339 | 376 | """|coro| |
340 | 377 | Fetches users from the helix API |
@@ -378,6 +415,34 @@ async def fetch_clips(self, ids: List[str]): |
378 | 415 | data = await self._http.get_clips(ids=ids) |
379 | 416 | return [models.Clip(self._http, d) for d in data] |
380 | 417 |
|
| 418 | + async def fetch_channel(self, broadcaster: str): |
| 419 | + """Retrieve a channel from the API. |
| 420 | +
|
| 421 | + Parameters |
| 422 | + ----------- |
| 423 | + name: str |
| 424 | + The channel name or ID to request from API. Returns empty dict if no channel was found. |
| 425 | +
|
| 426 | + Returns |
| 427 | + -------- |
| 428 | + :class:`twitchio.ChannelInfo` |
| 429 | + """ |
| 430 | + |
| 431 | + if not broadcaster.isdigit(): |
| 432 | + get_id = await self.fetch_users(names=[broadcaster.lower()]) |
| 433 | + if not get_id: |
| 434 | + raise IndexError("Invalid channel name.") |
| 435 | + broadcaster = get_id[0].id |
| 436 | + try: |
| 437 | + data = await self._http.get_channels(broadcaster) |
| 438 | + |
| 439 | + from .models import ChannelInfo |
| 440 | + |
| 441 | + return ChannelInfo(self._http, data=data[0]) |
| 442 | + |
| 443 | + except HTTPException: |
| 444 | + raise HTTPException("Incorrect channel ID.") |
| 445 | + |
381 | 446 | async def fetch_videos( |
382 | 447 | self, |
383 | 448 | ids: List[int] = None, |
@@ -419,7 +484,13 @@ async def fetch_videos( |
419 | 484 | from .models import Video |
420 | 485 |
|
421 | 486 | data = await self._http.get_videos( |
422 | | - ids, user_id=user_id, game_id=game_id, period=period, sort=sort, type=type, language=language |
| 487 | + ids, |
| 488 | + user_id=user_id, |
| 489 | + game_id=game_id, |
| 490 | + period=period, |
| 491 | + sort=sort, |
| 492 | + type=type, |
| 493 | + language=language, |
423 | 494 | ) |
424 | 495 | return [Video(self._http, x) for x in data] |
425 | 496 |
|
|
0 commit comments