Skip to content

Commit 140969b

Browse files
authored
Create Eventsub-specific CustomReward model (#285)
* Create Eventsub-specific CustomReward model * Update object in docstrings * Add missing slots attributes * Add typehints (and missing docs) * Fix CustomReward doc types * Add CustomReward object to eventsub docs
1 parent 0d80d12 commit 140969b

File tree

2 files changed

+114
-5
lines changed

2 files changed

+114
-5
lines changed

docs/exts/eventsub.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,12 @@ API Reference
209209
:members:
210210
:inherited-members:
211211

212+
.. attributetable::: CustomReward
213+
214+
.. autoclass:: CustomReward
215+
:members:
216+
:inherited-members:
217+
212218
.. attributetable::: CustomRewardAddUpdateRemoveData
213219
214220
.. autoclass:: CustomRewardAddUpdateRemoveData

twitchio/ext/eventsub/models.py

Lines changed: 108 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from aiohttp import web
1111

12-
from twitchio import CustomReward, PartialUser, parse_timestamp as _parse_datetime
12+
from twitchio import PartialUser, parse_timestamp as _parse_datetime
1313

1414
if TYPE_CHECKING:
1515
from .server import EventSubClient
@@ -382,6 +382,109 @@ def __init__(self, client: EventSubClient, data: dict):
382382
self.broadcaster = _transform_user(client, data, "broadcaster_user")
383383

384384

385+
class CustomReward:
386+
"""
387+
A Custom Reward
388+
389+
Attributes
390+
-----------
391+
broadcaster: :class:`twitchio.PartialUser`
392+
The channel that has this reward
393+
id: :class:`str`
394+
The ID of the reward
395+
title: :class:`str`
396+
The title of the reward
397+
cost: :class:`int`
398+
The cost of the reward in Channel Points
399+
prompt: :class:`str`
400+
The prompt of the reward
401+
enabled: Optional[:class:`bool`]
402+
Whether or not the reward is enabled. Will be `None` for Redemption events.
403+
paused: Optional[:class:`bool`]
404+
Whether or not the reward is paused. Will be `None` for Redemption events.
405+
in_stock: Optional[:class:`bool`]
406+
Whether or not the reward is in stock. Will be `None` for Redemption events.
407+
cooldown_until: Optional[:class:`datetime.datetime`]
408+
How long until the reward is off cooldown and can be redeemed again. Will be `None` for Redemption events.
409+
input_required: Optional[:class:`bool`]
410+
Whether or not the reward requires an input. Will be `None` for Redemption events.
411+
redemptions_skip_queue: Optional[:class:`bool`]
412+
Whether or not redemptions for this reward skips the queue. Will be `None` for Redemption events.
413+
redemptions_current_stream: Optional[:class:`int`]
414+
How many redemptions of this reward have been redeemed for this stream. Will be `None` for Redemption events.
415+
max_per_stream: Tuple[:class:`bool`, :class:`int`]
416+
Whether or not a per-stream redemption limit is in place, and if so, the maximum number of redemptions allowed
417+
per stream. Will be `None` for Redemption events.
418+
max_per_user_per_stream: Tuple[:class:`bool`, :class:`int`]
419+
Whether or not a per-user-per-stream redemption limit is in place, and if so, the maximum number of redemptions
420+
allowed per user per stream. Will be `None` for Redemption events.
421+
cooldown: Tuple[:class:`bool`, :class:`int`]
422+
Whether or not a global cooldown is in place, and if so, the number of seconds until the reward can be redeemed
423+
again. Will be `None` for Redemption events.
424+
background_color: Optional[:class:`str`]
425+
Hexadecimal color code for the background of the reward.
426+
image: Optional[:class:`str`]
427+
Image URL for the reward.
428+
"""
429+
430+
__slots__ = (
431+
"broadcaster",
432+
"id",
433+
"title",
434+
"cost",
435+
"prompt",
436+
"enabled",
437+
"paused",
438+
"in_stock",
439+
"cooldown_until",
440+
"input_required",
441+
"redemptions_skip_queue",
442+
"redemptions_current_stream",
443+
"max_per_stream",
444+
"max_per_user_stream",
445+
"cooldown",
446+
"background_color",
447+
"image",
448+
)
449+
450+
def __init__(self, data, broadcaster):
451+
self.broadcaster: PartialUser = broadcaster
452+
453+
self.id: str = data["id"]
454+
455+
self.title: str = data["title"]
456+
self.cost: int = data["cost"]
457+
self.prompt: str = data["prompt"]
458+
459+
self.enabled: bool = data.get("is_enabled", None)
460+
self.paused: bool = data.get("is_paused", None)
461+
self.in_stock: bool = data.get("is_in_stock", None)
462+
463+
self.cooldown_until: datetime.datetime = (
464+
_parse_datetime(data["cooldown_expires_at"]) if data.get("cooldown_expires_at", None) else None
465+
)
466+
467+
self.input_required: bool = data.get("is_user_input_required", None)
468+
self.redemptions_skip_queue: bool = data.get("should_redemptions_skip_request_queue", None)
469+
self.redemptions_current_stream: bool = data.get("redemptions_redeemed_current_stream", None)
470+
471+
self.max_per_stream: tuple[bool, int] = (
472+
data.get("max_per_stream", {}).get("is_enabled"),
473+
data.get("max_per_stream", {}).get("value"),
474+
)
475+
self.max_per_user_stream: tuple[bool, int] = (
476+
data.get("max_per_user_per_stream", {}).get("is_enabled"),
477+
data.get("max_per_user_per_stream", {}).get("value"),
478+
)
479+
self.cooldown: tuple[bool, int] = (
480+
data.get("global_cooldown", {}).get("is_enabled"),
481+
data.get("global_cooldown", {}).get("seconds"),
482+
)
483+
484+
self.background_color: str = data.get("background_color", None)
485+
self.image: str = data.get("image", data.get("default_image", {})).get("url_1x", None)
486+
487+
385488
class CustomRewardAddUpdateRemoveData(EventData):
386489
"""
387490
A Custom Reward Add/Update/Remove event
@@ -392,7 +495,7 @@ class CustomRewardAddUpdateRemoveData(EventData):
392495
The ID of the custom reward
393496
broadcaster: :class:`twitchio.PartialUser`
394497
The channel the custom reward was modified in
395-
reward: :class:`twitchio.CustomReward`
498+
reward: :class:`CustomReward`
396499
The reward object
397500
"""
398501

@@ -401,7 +504,7 @@ class CustomRewardAddUpdateRemoveData(EventData):
401504
def __init__(self, client: EventSubClient, data: dict):
402505
self.id: str = data["id"]
403506
self.broadcaster = _transform_user(client, data, "broadcaster_user")
404-
self.reward = CustomReward(client.client._http, data, self.broadcaster)
507+
self.reward = CustomReward(data, self.broadcaster)
405508

406509

407510
class CustomRewardRedemptionAddUpdateData(EventData):
@@ -422,7 +525,7 @@ class CustomRewardRedemptionAddUpdateData(EventData):
422525
One of "unknown", "unfulfilled", "fulfilled", or "cancelled"
423526
redeemed_at: :class:`datetime.datetime`
424527
When the reward was redeemed at
425-
reward: :class:`twitchio.CustomReward`
528+
reward: :class:`CustomReward`
426529
The reward object
427530
"""
428531

@@ -435,7 +538,7 @@ def __init__(self, client: EventSubClient, data: dict):
435538
self.input: str = data["user_input"]
436539
self.status: Literal["unknown", "unfulfilled", "fulfilled", "cancelled"] = data["status"]
437540
self.redeemed_at = _parse_datetime(data["redeemed_at"])
438-
self.reward = CustomReward(client.client._http, data["reward"], self.broadcaster)
541+
self.reward = CustomReward(data["reward"], self.broadcaster)
439542

440543

441544
class HypeTrainContributor:

0 commit comments

Comments
 (0)