Skip to content

Commit d18c8ec

Browse files
committed
eventsub additions
1 parent e09c710 commit d18c8ec

File tree

4 files changed

+117
-10
lines changed

4 files changed

+117
-10
lines changed

docs/changelog.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,12 @@
3030
:meth:`Twitchio.ext.eventsub.EventSubWSClient.subscribe_automod_message_hold <EventSubClient.subscribe_automod_message_hold>`
3131
- Added :meth:`Twitchio.ext.eventsub.EventSubClient.subscribe_channel_moderate <EventSubClient.subscribe_channel_moderate>` /
3232
:meth:`Twitchio.ext.eventsub.EventSubWSClient.subscribe_channel_moderate <EventSubClient.subscribe_channel_moderate>`
33-
- Added :meth:`Twitchio.ext.eventsub.EventSubClient.channel_suspicious_user_update <EventSubClient.channel_suspicious_user_update>` /
34-
:meth:`Twitchio.ext.eventsub.EventSubWSClient.channel_suspicious_user_update <EventSubClient.channel_suspicious_user_update>`
33+
- Added :meth:`Twitchio.ext.eventsub.EventSubClient.subscribe_suspicious_user_update <EventSubClient.subscribe_suspicious_user_update>` /
34+
:meth:`Twitchio.ext.eventsub.EventSubWSClient.subscribe_suspicious_user_update <EventSubClient.subscribe_suspicious_user_update>`
35+
- Added :meth:`Twitchio.ext.eventsub.EventSubClient.subscribe_channel_vip_add <EventSubClient.subscribe_channel_vip_add>` /
36+
:meth:`Twitchio.ext.eventsub.EventSubWSClient.subscribe_channel_vip_add <EventSubClient.subscribe_channel_vip_add>`
37+
- Added :meth:`Twitchio.ext.eventsub.EventSubClient.subscribe_channel_vip_remove <EventSubClient.subscribe_channel_vip_remove>` /
38+
:meth:`Twitchio.ext.eventsub.EventSubWSClient.subscribe_channel_vip_remove <EventSubClient.subscribe_channel_vip_remove>`
3539
- Added all accompanying models for those endpoints.
3640
- ext.sounds
3741
- Additions

twitchio/ext/eventsub/models.py

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,10 @@ class BaseEvent:
145145
__slots__ = ("_client", "_raw_data", "subscription", "headers")
146146

147147
@overload
148-
def __init__(self, client: EventSubClient, _data: str, request: web.Request):
149-
...
148+
def __init__(self, client: EventSubClient, _data: str, request: web.Request): ...
150149

151150
@overload
152-
def __init__(self, client: EventSubWSClient, _data: dict, request: None):
153-
...
151+
def __init__(self, client: EventSubWSClient, _data: dict, request: None): ...
154152

155153
def __init__(
156154
self, client: Union[EventSubClient, EventSubWSClient], _data: Union[str, dict], request: Optional[web.Request]
@@ -2164,9 +2162,7 @@ def __init__(self, client: EventSubClient, data: dict) -> None:
21642162
self.raid = self.RaidStatus(client, data["raid"]) if data.get("raid") is not None else None
21652163
self.unraid = self.RaidStatus(client, data["unraid"]) if data.get("unraid") is not None else None
21662164
self.delete = self.Delete(client, data["delete"]) if data.get("delete") is not None else None
2167-
self.automod_terms = (
2168-
self.AutoModTerms(client, data["automod_terms"]) if data.get("automod_terms") is not None else None
2169-
)
2165+
self.automod_terms = self.AutoModTerms(data["automod_terms"]) if data.get("automod_terms") is not None else None
21702166
self.unban_request = (
21712167
self.UnBanRequest(client, data["unban_request"]) if data.get("unban_request") is not None else None
21722168
)
@@ -2197,6 +2193,86 @@ def __init__(self, client: EventSubClient, data: dict) -> None:
21972193
self.trust_status: Literal["active_monitoring", "restricted", "none"] = data["low_trust_status"]
21982194

21992195

2196+
class AutoCustomReward:
2197+
"""
2198+
A reward object for an Auto Reward Redeem.
2199+
2200+
Attributes
2201+
-----------
2202+
type: :class:`str`
2203+
The type of the reward. One of ``single_message_bypass_sub_mode``, ``send_highlighted_message``, ``random_sub_emote_unlock``,
2204+
``chosen_sub_emote_unlock``, ``chosen_modified_sub_emote_unlock``, ``message_effect``, ``gigantify_an_emote``, ``celebration``.
2205+
cost: :class:`int`
2206+
How much the reward costs.
2207+
unlocked_emote_id: Optional[:class:`str`]
2208+
The unlocked emote, if applicable.
2209+
unlocked_emote_name: Optional[:class:`str`]
2210+
The unlocked emote, if applicable.
2211+
"""
2212+
2213+
def __init__(self, data: dict):
2214+
self.type: str = data["type"]
2215+
self.cost: int = data["cost"]
2216+
self.unlocked_emote_id: Optional[str] = data["unlocked_emote"] and data["unlocked_emote"]["id"]
2217+
self.unlocked_emote_name: Optional[str] = data["unlocked_emote"] and data["unlocked_emote"]["name"]
2218+
2219+
2220+
class AutoRewardRedeem(EventData):
2221+
"""
2222+
Represents an automatic reward redemption.
2223+
2224+
Attributes
2225+
-----------
2226+
broadcaster: :class:`~twitchio.PartialUser`
2227+
The channel where the reward was redeemed.
2228+
user: :class:`~twitchio.PartialUser`
2229+
The user that redeemed the reward.
2230+
id: :class:`str`
2231+
The ID of the redemption.
2232+
reward: :class:`AutoCustomReward`
2233+
The reward that was redeemed.
2234+
message: :class:`str`
2235+
The message the user sent.
2236+
message_emotes: :class:`dict`
2237+
The emote data for the message.
2238+
user_input: Optional[:class:`str`]
2239+
The input to the reward, if it requires any.
2240+
redeemed_at: :class:`datetime.datetime`
2241+
When the reward was redeemed.
2242+
"""
2243+
2244+
__slots__ = ("broadcaster", "user", "id", "reward", "message", "message_emotes", "user_input", "redeemed_at")
2245+
2246+
def __init__(self, client: EventSubClient, data: dict) -> None:
2247+
self.broadcaster: PartialUser = _transform_user(client, data, "broadcaster")
2248+
self.user: PartialUser = _transform_user(client, data, "user")
2249+
self.id: str = data["id"]
2250+
self.reward = AutoCustomReward(data["reward"])
2251+
self.message: str = data["message"]
2252+
self.message_emotes: dict = data["message_emotes"]
2253+
self.user_input: Optional[str] = data["user_input"]
2254+
self.redeemed_at: datetime.datetime = _parse_datetime(data["redeemed_at"])
2255+
2256+
2257+
class ChannelVIPAddRemove(EventData):
2258+
"""
2259+
Represents a VIP being added/removed from a channel.
2260+
2261+
Attributes
2262+
-----------
2263+
broadcaster: :class:`~twitchio.PartialUser`
2264+
The channel that the VIP was added/removed from.
2265+
user: :class:`~twitchio.PartialUser`
2266+
The user that was added/removed as a VIP.
2267+
"""
2268+
2269+
__slots__ = ("broadcaster", "user")
2270+
2271+
def __init__(self, client: EventSubClient, data: dict) -> None:
2272+
self.broadcaster: PartialUser = _transform_user(client, data, "broadcaster")
2273+
self.user: PartialUser = _transform_user(client, data, "user")
2274+
2275+
22002276
_DataType = Union[
22012277
ChannelBanData,
22022278
ChannelUnbanData,
@@ -2238,6 +2314,8 @@ def __init__(self, client: EventSubClient, data: dict) -> None:
22382314
AutomodTermsUpdateData,
22392315
SuspiciousUserUpdateData,
22402316
ChannelModerateData,
2317+
AutoRewardRedeem,
2318+
ChannelVIPAddRemove,
22412319
]
22422320

22432321

@@ -2285,6 +2363,8 @@ class _SubscriptionTypes(metaclass=_SubTypesMeta):
22852363
CustomRewardRedemptionAddUpdateData,
22862364
)
22872365

2366+
auto_reward_redeem = "channel.channel_points_automatic_reward_redemption.add", 1, AutoRewardRedeem
2367+
22882368
channel_goal_begin = "channel.goal.begin", 1, ChannelGoalBeginProgressData
22892369
channel_goal_progress = "channel.goal.progress", 1, ChannelGoalBeginProgressData
22902370
channel_goal_end = "channel.goal.end", 1, ChannelGoalEndData
@@ -2318,6 +2398,9 @@ class _SubscriptionTypes(metaclass=_SubTypesMeta):
23182398
unban_request_create = "channel.unban_request.create", 1, ChannelUnbanRequestCreateData
23192399
unban_request_resolve = "channel.unban_request.resolve", 1, ChannelUnbanRequestResolveData
23202400

2401+
channel_vip_add = "channel.vip.add", 1, ChannelVIPAddRemove
2402+
channel_vip_remove = "channel.vip.remove", 1, ChannelVIPAddRemove
2403+
23212404
user_authorization_grant = "user.authorization.grant", 1, UserAuthorizationGrantedData
23222405
user_authorization_revoke = "user.authorization.revoke", 1, UserAuthorizationRevokedData
23232406

twitchio/ext/eventsub/server.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ def subscribe_channel_prediction_lock(self, broadcaster: Union[PartialUser, str,
248248
def subscribe_channel_prediction_end(self, broadcaster: Union[PartialUser, str, int]):
249249
return self._subscribe_with_broadcaster(models.SubscriptionTypes.prediction_end, broadcaster)
250250

251+
def subscribe_channel_auto_reward_redeem(self, broadcaster: Union[PartialUser, str, int]):
252+
return self._subscribe_with_broadcaster(models.SubscriptionTypes.auto_reward_redeem, broadcaster)
253+
251254
def subscribe_channel_shield_mode_begin(
252255
self, broadcaster: Union[PartialUser, str, int], moderator: Union[PartialUser, str, int]
253256
):
@@ -335,6 +338,12 @@ def subscribe_channel_moderate(
335338
models.SubscriptionTypes.channel_moderate, broadcaster, moderator
336339
)
337340

341+
def subscribe_channel_vip_add(self, broadcaster: Union[PartialUser, str, int]):
342+
return self._subscribe_with_broadcaster(models.SubscriptionTypes.channel_vip_add, broadcaster)
343+
344+
def subscribe_channel_vip_remove(self, broadcaster: Union[PartialUser, str, int]):
345+
return self._subscribe_with_broadcaster(models.SubscriptionTypes.channel_vip_remove, broadcaster)
346+
338347
async def subscribe_user_authorization_granted(self):
339348
return await self._http.create_webhook_subscription(
340349
models.SubscriptionTypes.user_authorization_grant, {"client_id": self.client._http.client_id}

twitchio/ext/eventsub/websocket.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ def __init__(self, client: Client, http: http.EventSubHTTP):
9797
self._pump_task: Optional[asyncio.Task] = None
9898
self._timeout: Optional[int] = None
9999
self._session_id: Optional[str] = None
100-
self._target_user_id: int | None = None # each websocket can only have one authenticated user on it for some bizzare reason, but this isnt documented anywhere
100+
self._target_user_id: int | None = (
101+
None # each websocket can only have one authenticated user on it for some bizzare reason, but this isnt documented anywhere
102+
)
101103
self.remaining_slots: int = 300 # default to 300
102104

103105
def __hash__(self) -> int:
@@ -483,6 +485,9 @@ async def subscribe_channel_prediction_lock(self, broadcaster: Union[PartialUser
483485
async def subscribe_channel_prediction_end(self, broadcaster: Union[PartialUser, str, int], token: str):
484486
await self._subscribe_with_broadcaster(models.SubscriptionTypes.prediction_end, broadcaster, token)
485487

488+
async def subscribe_channel_auto_reward_redeem(self, broadcaster: Union[PartialUser, str, int], token: str):
489+
await self._subscribe_with_broadcaster(models.SubscriptionTypes.auto_reward_redeem, broadcaster, token)
490+
486491
async def subscribe_channel_shield_mode_begin(
487492
self, broadcaster: Union[PartialUser, str, int], moderator: Union[PartialUser, str, int], token: str
488493
):
@@ -569,3 +574,9 @@ async def subscribe_channel_moderate(
569574
await self._subscribe_with_broadcaster_moderator(
570575
models.SubscriptionTypes.channel_moderate, broadcaster, moderator, token
571576
)
577+
578+
async def subscribe_channel_vip_add(self, broadcaster: Union[PartialUser, str, int], token: str):
579+
await self._subscribe_with_broadcaster(models.SubscriptionTypes.channel_vip_add, broadcaster, token)
580+
581+
async def subscribe_channel_vip_remove(self, broadcaster: Union[PartialUser, str, int], token: str):
582+
await self._subscribe_with_broadcaster(models.SubscriptionTypes.channel_vip_remove, broadcaster, token)

0 commit comments

Comments
 (0)