Skip to content

Commit f30b2ff

Browse files
committed
Add Bits Use model and docs
1 parent cb073b6 commit f30b2ff

File tree

5 files changed

+130
-2
lines changed

5 files changed

+130
-2
lines changed

docs/references/events.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ Events Reference
4444
- :meth:`~eventsub.AdBreakBeginSubscription`
4545
- :func:`~twitchio.event_ad_break()`
4646
- :class:`~models.eventsub_.ChannelAdBreakBegin`
47+
* - Channel Bits Use
48+
- :meth:`~eventsub.ChannelBitsUseSubscription`
49+
- :func:`~twitchio.event_bits_use()`
50+
- :class:`~models.eventsub_.ChannelBitsUse`
4751
* - Channel Chat Clear
4852
- :meth:`~eventsub.ChatClearSubscription`
4953
- :func:`~twitchio.event_chat_clear()`
@@ -785,6 +789,18 @@ Chat / Messages
785789

786790
:param twitchio.Whisper payload: The EventSub payload for this event.
787791

792+
.. py:function:: event_bits_use(payload: twitchio.ChannelBitsUse) -> None
793+
:async:
794+
795+
Event dispatched whenever Bits are used on a channel.
796+
797+
Corresponds to the Twitch EventSub subscription :es-docs:`Channel Bits Use <channelbitsuse>`.
798+
799+
You must subscribe to EventSub with :class:`~twitchio.eventsub.ChannelBitsUseSubscription` for each required user
800+
to receive this event.
801+
802+
:param twitchio.ChannelBitsUse payload: The EventSub payload for this event.
803+
788804
Goals
789805
-----
790806

docs/references/eventsub_models.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ Eventsub
4848
.. autoclass:: twitchio.ChannelAdBreakBegin()
4949
:members:
5050

51+
.. attributetable:: twitchio.ChannelBitsUse
52+
53+
.. autoclass:: twitchio.ChannelBitsUse()
54+
:members:
55+
5156
.. attributetable:: twitchio.ChannelChatClear
5257

5358
.. autoclass:: twitchio.ChannelChatClear()
@@ -476,6 +481,16 @@ Eventsub
476481
.. autoclass:: twitchio.HypeTrainEnd()
477482
:members:
478483

484+
.. attributetable:: twitchio.PowerUp
485+
486+
.. autoclass:: twitchio.PowerUp()
487+
:members:
488+
489+
.. attributetable:: twitchio.PowerUpEmote
490+
491+
.. autoclass:: twitchio.PowerUpEmote()
492+
:members:
493+
479494
.. attributetable:: twitchio.ShieldModeBegin
480495

481496
.. autoclass:: twitchio.ShieldModeBegin()

twitchio/events.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ async def event_chat_clear_user(payload: twitchio.ChannelChatClearUserMessages)
6565
async def event_chat_settings_update(payload: twitchio.ChatSettingsUpdate) -> None: ...
6666
async def event_chat_user_message_hold(payload: twitchio.ChatUserMessageHold) -> None: ...
6767
async def event_chat_user_message_update(payload: twitchio.ChatUserMessageUpdate) -> None: ...
68+
async def event_bits_use(payload: twitchio.ChannelBitsUse) -> None: ...
6869

6970
# Shared Chat
7071
async def event_shared_chat_begin(payload: twitchio.SharedChatSessionBegin) -> None: ...

twitchio/models/eventsub_.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
"Boundary",
7575
"ChannelAdBreakBegin",
7676
"ChannelBan",
77+
"ChannelBitsUse",
7778
"ChannelChatClear",
7879
"ChannelChatClearUserMessages",
7980
"ChannelCheer",
@@ -156,6 +157,8 @@
156157
"ModerateUnbanRequest",
157158
"ModerateWarn",
158159
"PollVoting",
160+
"PowerUp",
161+
"PowerUpEmote",
159162
"SharedChatSessionBegin",
160163
"SharedChatSessionEnd",
161164
"SharedChatSessionUpdate",
@@ -719,6 +722,97 @@ def __repr__(self) -> str:
719722
return f"<AutomodTermsUpdate broadcaster={self.broadcaster} moderator={self.moderator} action={self.action} automod={self.automod}>"
720723

721724

725+
class PowerUpEmote:
726+
"""
727+
Represents a PowerUp Emote on a channel bits use event.
728+
729+
Attributes
730+
----------
731+
id: str
732+
The ID that uniquely identifies this emote.
733+
name: str
734+
The human readable emote token.
735+
"""
736+
737+
__slots__ = ("id", "name")
738+
739+
def __init__(self, data: PowerUpEmoteDataData) -> None:
740+
self.id: str = data["id"]
741+
self.name: str = data["name"]
742+
743+
744+
class PowerUp:
745+
"""
746+
Represents a PowerUp on a channel bits use event.
747+
748+
Attributes
749+
----------
750+
emote: PowerUpEmote | None
751+
Emote associated with the reward. Is `None` if no emote was used.
752+
type: typing.Literal["message_effect", "celebration", "gigantify_an_emote"]
753+
The type of Power-up redeemed.
754+
755+
- message_effect
756+
- celebration
757+
- gigantify_an_emote
758+
759+
message_effect_id: str | None
760+
The ID of the message effect. Is `None` if no message effect was used.
761+
"""
762+
763+
__slots__ = ("emote", "message_effect_id", "type")
764+
765+
def __init__(self, data: PowerUpData) -> None:
766+
emote = data.get("emote")
767+
self.emote: PowerUpEmote | None = PowerUpEmote(emote) if emote is not None else None
768+
self.type: Literal["message_effect", "celebration", "gigantify_an_emote"] = data["type"]
769+
self.message_effect_id: str | None = data.get("message_effect_id")
770+
771+
772+
class ChannelBitsUse(BaseEvent):
773+
"""
774+
Represents a channel bits use event.
775+
776+
Attributes
777+
----------
778+
broadcaster: PartialUser
779+
The broadcastter / channel where the Bits were redeemed.
780+
user: PartialUser
781+
The redeeming user.
782+
bits: int
783+
The number of Bits used.
784+
type: typing.Literal["cheer", "power_up"]
785+
What the Bits were used for.
786+
text: str | None
787+
The chat message in plain text. Is `None` if no chat message was used.
788+
fragments: list[ChatMessageFragment]
789+
The ordered list of chat message fragments. Is `None` if no chat message was used.
790+
power_up: PowerUp | None
791+
Data about Power-up. Is `None` if a Power-up is not used.
792+
"""
793+
794+
subscription_type = "channel.bits.use"
795+
796+
__slots__ = ("bits", "broadcaster", "fragments", "power_up", "text", "type", "user")
797+
798+
def __init__(self, payload: ChannelBitsUseEvent, *, http: HTTPClient) -> None:
799+
self.broadcaster = PartialUser(
800+
payload["broadcaster_user_id"], payload["broadcaster_user_login"], payload["broadcaster_user_name"], http=http
801+
)
802+
self.user = PartialUser(payload["user_id"], payload["user_login"], payload["user_name"], http=http)
803+
self.bits: int = int(payload["bits"])
804+
self.type: Literal["cheer", "power_up"] = payload["type"]
805+
self.text: str | None = payload.get("message").get("text")
806+
power_up = payload.get("power_up")
807+
self.power_up: PowerUp | None = PowerUp(power_up) if power_up is not None else None
808+
self.fragments: list[ChatMessageFragment] = [
809+
ChatMessageFragment(fragment, http=http) for fragment in payload["message"]["fragments"]
810+
]
811+
812+
def __repr__(self) -> str:
813+
return f"<ChannelBitsUse broadcaster={self.broadcaster} user={self.user} bits={self.bits} type={self.type}>"
814+
815+
722816
class ChannelUpdate(BaseEvent):
723817
"""
724818
Represents a channel update event.

twitchio/types_/eventsub.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@
131131
"ModerateUnbanRequestData",
132132
"ModerateWarnData",
133133
"PollChoiceData",
134+
"PowerUpData",
135+
"PowerUpEmoteDataData",
134136
"ReedemedRewardData",
135137
"ShieldModeBeginEvent",
136138
"ShieldModeEndEvent",
@@ -356,14 +358,14 @@ class ChannelAdBreakBeginEvent(BaseBroadcasterEvent):
356358
is_automatic: str
357359

358360

359-
class PowerUpEmote(TypedDict):
361+
class PowerUpEmoteDataData(TypedDict):
360362
id: str
361363
name: str
362364

363365

364366
class PowerUpData(TypedDict):
365367
type: Literal["message_effect", "celebration", "gigantify_an_emote"]
366-
emote: PowerUpEmote | None
368+
emote: PowerUpEmoteDataData | None
367369
message_effect_id: str | None
368370

369371

0 commit comments

Comments
 (0)