twitch_api/helix/mod.rs
1//! Helix endpoints or the [New Twitch API](https://dev.twitch.tv/docs/api)
2//!
3//! [`HelixClient`] provides convenience function for sending requests as described on [the crate documentation](crate).
4//!
5//! ### Manual Usage
6//!
7//! Aside from using [`HelixClient`], you can decide to use this library without any specific client implementation.
8//!
9//! ```rust
10//! use twitch_api::{helix::{self, Request, RequestGet, users::{GetUsersRequest, User}}, types};
11//!
12//! # #[tokio::main]
13//! # async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
14//!
15//! let logins: &[&types::UserNameRef] = &["justintv123".into()];
16//! let request = GetUsersRequest::logins(logins);
17//!
18//! // Send it however you want
19//! // Create a [`http::Response<hyper::body::Bytes>`] with RequestGet::create_request, which takes an access token and a client_id
20//! let response = send_http_request(request.create_request("accesstoken", "client_id")?)?;
21//!
22//! // then parse the response
23//! let uri = request.get_uri()?;
24//! let user: helix::Response<_, Vec<User>> = GetUsersRequest::parse_response(Some(request), &uri, response)?;
25//! println!("{:#?}", user);
26//! # Ok(())
27//! # }
28//! # fn send_http_request(_: http::Request<hyper::body::Bytes>) -> Result<http::Response<hyper::body::Bytes>,&'static str> {
29//! # Ok(http::Response::builder().body(r#"{"data":[{"id":"141981764","login":"twitchdev","display_name":"TwitchDev","type":"","broadcaster_type":"partner","description":"Supportingthird-partydevelopersbuildingTwitchintegrationsfromchatbotstogameintegrations.","profile_image_url":"https://static-cdn.jtvnw.net/jtv_user_pictures/8a6381c7-d0c0-4576-b179-38bd5ce1d6af-profile_image-300x300.png","offline_image_url":"https://static-cdn.jtvnw.net/jtv_user_pictures/3f13ab61-ec78-4fe6-8481-8682cb3b0ac2-channel_offline_image-1920x1080.png","view_count":5980557,"email":"not-real@email.com","created_at":"2016-12-14T20:32:28.894263Z"}]}"#.as_bytes().to_owned().into()).unwrap())
30//! # }
31//! ```
32//!
33//! ## Implemented Endpoints
34//!
35//! <!-- generate with "cargo xtask overview" (with a nightly toolchain) -->
36//! <!-- BEGIN-OVERVIEW -->
37//! <details><summary style="cursor: pointer">Ads 🟢 3/3</summary>
38//!
39//! | Endpoint | Helper | Module |
40//! |---|---|---|
41//! | [Start Commercial](https://dev.twitch.tv/docs/api/reference#start-commercial) | - | [`channels::start_commercial`] |
42//! | [Get Ad Schedule](https://dev.twitch.tv/docs/api/reference#get-ad-schedule) | - | [`channels::get_ad_schedule`] |
43//! | [Snooze Next Ad](https://dev.twitch.tv/docs/api/reference#snooze-next-ad) | - | [`channels::snooze_next_ad`] |
44//!
45//! </details>
46//!
47//! <details><summary style="cursor: pointer">Analytics 🔴 0/2</summary>
48//!
49//! | Endpoint | Helper | Module |
50//! |---|---|---|
51//! | [Get Extension Analytics](https://dev.twitch.tv/docs/api/reference#get-extension-analytics) | - | - |
52//! | [Get Game Analytics](https://dev.twitch.tv/docs/api/reference#get-game-analytics) | - | - |
53//!
54//! </details>
55//!
56//! <details><summary style="cursor: pointer">Bits 🟡 2/4</summary>
57//!
58//! | Endpoint | Helper | Module |
59//! |---|---|---|
60//! | [Get Bits Leaderboard](https://dev.twitch.tv/docs/api/reference#get-bits-leaderboard) | - | [`bits::get_bits_leaderboard`] |
61//! | [Get Cheermotes](https://dev.twitch.tv/docs/api/reference#get-cheermotes) | - | [`bits::get_cheermotes`] |
62//! | [Get Custom Power-up](https://dev.twitch.tv/docs/api/reference#get-custom-power-up) | - | - |
63//! | [Get Extension Transactions](https://dev.twitch.tv/docs/api/reference#get-extension-transactions) | - | - |
64//!
65//! </details>
66//!
67//! <details><summary style="cursor: pointer">CCLs 🟢 1/1</summary>
68//!
69//! | Endpoint | Helper | Module |
70//! |---|---|---|
71//! | [Get Content Classification Labels](https://dev.twitch.tv/docs/api/reference#get-content-classification-labels) | [`HelixClient::get_content_classification_labels`], [`HelixClient::get_content_classification_labels_for_locale`] | [`ccls::get_content_classification_labels`] |
72//!
73//! </details>
74//!
75//! <details><summary style="cursor: pointer">Channel Points 🟢 6/6</summary>
76//!
77//! | Endpoint | Helper | Module |
78//! |---|---|---|
79//! | [Create Custom Rewards](https://dev.twitch.tv/docs/api/reference#create-custom-rewards) | - | [`points::create_custom_rewards`] |
80//! | [Delete Custom Reward](https://dev.twitch.tv/docs/api/reference#delete-custom-reward) | - | [`points::delete_custom_reward`] |
81//! | [Get Custom Reward](https://dev.twitch.tv/docs/api/reference#get-custom-reward) | [`HelixClient::get_custom_rewards`] | [`points::get_custom_reward`] |
82//! | [Get Custom Reward Redemption](https://dev.twitch.tv/docs/api/reference#get-custom-reward-redemption) | - | [`points::get_custom_reward_redemption`] |
83//! | [Update Custom Reward](https://dev.twitch.tv/docs/api/reference#update-custom-reward) | - | [`points::update_custom_reward`] |
84//! | [Update Redemption Status](https://dev.twitch.tv/docs/api/reference#update-redemption-status) | - | [`points::update_redemption_status`] |
85//!
86//! </details>
87//!
88//! <details><summary style="cursor: pointer">Channels 🟢 5/5</summary>
89//!
90//! | Endpoint | Helper | Module |
91//! |---|---|---|
92//! | [Get Channel Information](https://dev.twitch.tv/docs/api/reference#get-channel-information) | - | [`channels::get_channel_information`] |
93//! | [Modify Channel Information](https://dev.twitch.tv/docs/api/reference#modify-channel-information) | - | [`channels::modify_channel_information`] |
94//! | [Get Channel Editors](https://dev.twitch.tv/docs/api/reference#get-channel-editors) | - | [`channels::get_channel_editors`] |
95//! | [Get Followed Channels](https://dev.twitch.tv/docs/api/reference#get-followed-channels) | [`HelixClient::get_followed_channels`] | [`channels::get_followed_channels`] |
96//! | [Get Channel Followers](https://dev.twitch.tv/docs/api/reference#get-channel-followers) | - | [`channels::get_channel_followers`] |
97//!
98//! </details>
99//!
100//! <details><summary style="cursor: pointer">Charity 🟢 2/2</summary>
101//!
102//! | Endpoint | Helper | Module |
103//! |---|---|---|
104//! | [Get Charity Campaign](https://dev.twitch.tv/docs/api/reference#get-charity-campaign) | - | [`charity::get_charity_campaign`] |
105//! | [Get Charity Campaign Donations](https://dev.twitch.tv/docs/api/reference#get-charity-campaign-donations) | - | [`charity::get_charity_campaign_donations`] |
106//!
107//! </details>
108//!
109//! <details><summary style="cursor: pointer">Chat 🟢 19/19</summary>
110//!
111//! | Endpoint | Helper | Module |
112//! |---|---|---|
113//! | [Get Chatters](https://dev.twitch.tv/docs/api/reference#get-chatters) | [`HelixClient::get_chatters`] | [`chat::get_chatters`] |
114//! | [Get Channel Emotes](https://dev.twitch.tv/docs/api/reference#get-channel-emotes) | [`HelixClient::get_channel_emotes_from_id`], [`HelixClient::get_channel_emotes_from_login`] | [`chat::get_channel_emotes`] |
115//! | [Get Global Emotes](https://dev.twitch.tv/docs/api/reference#get-global-emotes) | [`HelixClient::get_global_emotes`] | [`chat::get_global_emotes`] |
116//! | [Get Emote Sets](https://dev.twitch.tv/docs/api/reference#get-emote-sets) | [`HelixClient::get_emote_sets`] | [`chat::get_emote_sets`] |
117//! | [Get Channel Chat Badges](https://dev.twitch.tv/docs/api/reference#get-channel-chat-badges) | - | [`chat::get_channel_chat_badges`] |
118//! | [Get Global Chat Badges](https://dev.twitch.tv/docs/api/reference#get-global-chat-badges) | - | [`chat::get_global_chat_badges`] |
119//! | [Get Chat Settings](https://dev.twitch.tv/docs/api/reference#get-chat-settings) | [`HelixClient::get_chat_settings`] | [`chat::get_chat_settings`] |
120//! | [Get Shared Chat Session](https://dev.twitch.tv/docs/api/reference#get-shared-chat-session) | [`HelixClient::get_shared_chat_session`] | [`chat::get_shared_chat_session`] |
121//! | [Get User Emotes](https://dev.twitch.tv/docs/api/reference#get-user-emotes) | [`HelixClient::get_user_emotes`], [`HelixClient::get_user_emotes_in_channel`] | [`chat::get_user_emotes`] |
122//! | [Update Chat Settings](https://dev.twitch.tv/docs/api/reference#update-chat-settings) | - | [`chat::update_chat_settings`] |
123//! | [Send Chat Announcement](https://dev.twitch.tv/docs/api/reference#send-chat-announcement) | [`HelixClient::send_chat_announcement`] | [`chat::send_chat_announcement`] |
124//! | [Send a Shoutout](https://dev.twitch.tv/docs/api/reference#send-a-shoutout) | - | [`chat::send_a_shoutout`] |
125//! | [Send Chat Message](https://dev.twitch.tv/docs/api/reference#send-chat-message) | [`HelixClient::send_chat_message`], [`HelixClient::send_chat_message_reply`] | [`chat::send_chat_message`] |
126//! | [Get Pinned Chat Message](https://dev.twitch.tv/docs/api/reference#get-pinned-chat-message) | [`HelixClient::get_pinned_chat_message`] | [`chat::get_pinned_chat_message`] |
127//! | [Pin Chat Message](https://dev.twitch.tv/docs/api/reference#pin-chat-message) | [`HelixClient::pin_chat_message`] | [`chat::pin_chat_message`] |
128//! | [Update Pinned Chat Message](https://dev.twitch.tv/docs/api/reference#update-pinned-chat-message) | [`HelixClient::update_pinned_chat_message`] | [`chat::update_pinned_chat_message`] |
129//! | [Unpin Chat Message](https://dev.twitch.tv/docs/api/reference#unpin-chat-message) | [`HelixClient::unpin_chat_message`] | [`chat::unpin_chat_message`] |
130//! | [Get User Chat Color](https://dev.twitch.tv/docs/api/reference#get-user-chat-color) | [`HelixClient::get_user_chat_color`], [`HelixClient::get_users_chat_colors`] | [`chat::get_user_chat_color`] |
131//! | [Update User Chat Color](https://dev.twitch.tv/docs/api/reference#update-user-chat-color) | [`HelixClient::update_user_chat_color`] | [`chat::update_user_chat_color`] |
132//!
133//! </details>
134//!
135//! <details><summary style="cursor: pointer">Clips 🟢 4/4</summary>
136//!
137//! | Endpoint | Helper | Module |
138//! |---|---|---|
139//! | [Create Clip](https://dev.twitch.tv/docs/api/reference#create-clip) | - | [`clips::create_clip`] |
140//! | [Create Clip From VOD](https://dev.twitch.tv/docs/api/reference#create-clip-from-vod) | [`HelixClient::create_clip_from_vod`] | [`clips::create_clip_from_vod`] |
141//! | [Get Clips](https://dev.twitch.tv/docs/api/reference#get-clips) | - | [`clips::get_clips`] |
142//! | [Get Clips Download](https://dev.twitch.tv/docs/api/reference#get-clips-download) | [`HelixClient::get_clips_download`] | [`clips::get_clips_download`] |
143//!
144//! </details>
145//!
146//! <details><summary style="cursor: pointer">Conduits 🟢 6/6</summary>
147//!
148//! | Endpoint | Helper | Module |
149//! |---|---|---|
150//! | [Get Conduits](https://dev.twitch.tv/docs/api/reference#get-conduits) | [`HelixClient::get_conduits`] | [`eventsub::get_conduits`] |
151//! | [Create Conduits](https://dev.twitch.tv/docs/api/reference#create-conduits) | [`HelixClient::create_conduit`] | [`eventsub::create_conduit`] |
152//! | [Update Conduits](https://dev.twitch.tv/docs/api/reference#update-conduits) | [`HelixClient::update_conduit`] | [`eventsub::update_conduit`] |
153//! | [Delete Conduit](https://dev.twitch.tv/docs/api/reference#delete-conduit) | [`HelixClient::delete_conduit`] | [`eventsub::delete_conduit`] |
154//! | [Get Conduit Shards](https://dev.twitch.tv/docs/api/reference#get-conduit-shards) | [`HelixClient::get_conduit_shards`] | [`eventsub::get_conduit_shards`] |
155//! | [Update Conduit Shards](https://dev.twitch.tv/docs/api/reference#update-conduit-shards) | [`HelixClient::update_conduit_shards`] | [`eventsub::update_conduit_shards`] |
156//!
157//! </details>
158//!
159//! <details><summary style="cursor: pointer">Entitlements 🔴 0/2</summary>
160//!
161//! | Endpoint | Helper | Module |
162//! |---|---|---|
163//! | [Get Drops Entitlements](https://dev.twitch.tv/docs/api/reference#get-drops-entitlements) | - | - |
164//! | [Update Drops Entitlements](https://dev.twitch.tv/docs/api/reference#update-drops-entitlements) | - | - |
165//!
166//! </details>
167//!
168//! <details><summary style="cursor: pointer">EventSub 🟢 3/3</summary>
169//!
170//! | Endpoint | Helper | Module |
171//! |---|---|---|
172//! | [Create EventSub Subscription](https://dev.twitch.tv/docs/api/reference#create-eventsub-subscription) | [`HelixClient::create_eventsub_subscription`] | [`eventsub::create_eventsub_subscription`] |
173//! | [Delete EventSub Subscription](https://dev.twitch.tv/docs/api/reference#delete-eventsub-subscription) | [`HelixClient::delete_eventsub_subscription`] | [`eventsub::delete_eventsub_subscription`] |
174//! | [Get EventSub Subscriptions](https://dev.twitch.tv/docs/api/reference#get-eventsub-subscriptions) | [`HelixClient::get_eventsub_subscriptions`] | [`eventsub::get_eventsub_subscriptions`] |
175//!
176//! </details>
177//!
178//! <details><summary style="cursor: pointer">Extensions 🔴 0/12</summary>
179//!
180//! | Endpoint | Helper | Module |
181//! |---|---|---|
182//! | [Get Extension Configuration Segment](https://dev.twitch.tv/docs/api/reference#get-extension-configuration-segment) | - | - |
183//! | [Set Extension Configuration Segment](https://dev.twitch.tv/docs/api/reference#set-extension-configuration-segment) | - | - |
184//! | [Set Extension Required Configuration](https://dev.twitch.tv/docs/api/reference#set-extension-required-configuration) | - | - |
185//! | [Send Extension PubSub Message](https://dev.twitch.tv/docs/api/reference#send-extension-pubsub-message) | - | - |
186//! | [Get Extension Live Channels](https://dev.twitch.tv/docs/api/reference#get-extension-live-channels) | - | - |
187//! | [Get Extension Secrets](https://dev.twitch.tv/docs/api/reference#get-extension-secrets) | - | - |
188//! | [Create Extension Secret](https://dev.twitch.tv/docs/api/reference#create-extension-secret) | - | - |
189//! | [Send Extension Chat Message](https://dev.twitch.tv/docs/api/reference#send-extension-chat-message) | - | - |
190//! | [Get Extensions](https://dev.twitch.tv/docs/api/reference#get-extensions) | - | - |
191//! | [Get Released Extensions](https://dev.twitch.tv/docs/api/reference#get-released-extensions) | - | - |
192//! | [Get Extension Bits Products](https://dev.twitch.tv/docs/api/reference#get-extension-bits-products) | - | - |
193//! | [Update Extension Bits Product](https://dev.twitch.tv/docs/api/reference#update-extension-bits-product) | - | - |
194//!
195//! </details>
196//!
197//! <details><summary style="cursor: pointer">Games 🟢 2/2</summary>
198//!
199//! | Endpoint | Helper | Module |
200//! |---|---|---|
201//! | [Get Top Games](https://dev.twitch.tv/docs/api/reference#get-top-games) | - | [`games::get_top_games`] |
202//! | [Get Games](https://dev.twitch.tv/docs/api/reference#get-games) | [`HelixClient::get_games_by_id`] | [`games::get_games`] |
203//!
204//! </details>
205//!
206//! <details><summary style="cursor: pointer">Goals 🟢 1/1</summary>
207//!
208//! | Endpoint | Helper | Module |
209//! |---|---|---|
210//! | [Get Creator Goals](https://dev.twitch.tv/docs/api/reference#get-creator-goals) | - | [`goals::get_creator_goals`] |
211//!
212//! </details>
213//!
214//! <details><summary style="cursor: pointer">Guest Star 🔴 0/12</summary>
215//!
216//! | Endpoint | Helper | Module |
217//! |---|---|---|
218//! | [Get Channel Guest Star Settings](https://dev.twitch.tv/docs/api/reference#get-channel-guest-star-settings) | - | - |
219//! | [Update Channel Guest Star Settings](https://dev.twitch.tv/docs/api/reference#update-channel-guest-star-settings) | - | - |
220//! | [Get Guest Star Session](https://dev.twitch.tv/docs/api/reference#get-guest-star-session) | - | - |
221//! | [Create Guest Star Session](https://dev.twitch.tv/docs/api/reference#create-guest-star-session) | - | - |
222//! | [End Guest Star Session](https://dev.twitch.tv/docs/api/reference#end-guest-star-session) | - | - |
223//! | [Get Guest Star Invites](https://dev.twitch.tv/docs/api/reference#get-guest-star-invites) | - | - |
224//! | [Send Guest Star Invite](https://dev.twitch.tv/docs/api/reference#send-guest-star-invite) | - | - |
225//! | [Delete Guest Star Invite](https://dev.twitch.tv/docs/api/reference#delete-guest-star-invite) | - | - |
226//! | [Assign Guest Star Slot](https://dev.twitch.tv/docs/api/reference#assign-guest-star-slot) | - | - |
227//! | [Update Guest Star Slot](https://dev.twitch.tv/docs/api/reference#update-guest-star-slot) | - | - |
228//! | [Delete Guest Star Slot](https://dev.twitch.tv/docs/api/reference#delete-guest-star-slot) | - | - |
229//! | [Update Guest Star Slot Settings](https://dev.twitch.tv/docs/api/reference#update-guest-star-slot-settings) | - | - |
230//!
231//! </details>
232//!
233//! <details><summary style="cursor: pointer">Hype Train 🟢 1/1</summary>
234//!
235//! | Endpoint | Helper | Module |
236//! |---|---|---|
237//! | [Get Hype Train Status](https://dev.twitch.tv/docs/api/reference#get-hype-train-status) | [`HelixClient::get_hype_train_status`] | [`hypetrain::get_hype_train_status`] |
238//!
239//! </details>
240//!
241//! <details><summary style="cursor: pointer">Moderation 🟢 25/25</summary>
242//!
243//! | Endpoint | Helper | Module |
244//! |---|---|---|
245//! | [Check AutoMod Status](https://dev.twitch.tv/docs/api/reference#check-automod-status) | - | [`moderation::check_automod_status`] |
246//! | [Manage Held AutoMod Messages](https://dev.twitch.tv/docs/api/reference#manage-held-automod-messages) | - | [`moderation::manage_held_automod_messages`] |
247//! | [Get AutoMod Settings](https://dev.twitch.tv/docs/api/reference#get-automod-settings) | - | [`moderation::get_automod_settings`] |
248//! | [Update AutoMod Settings](https://dev.twitch.tv/docs/api/reference#update-automod-settings) | - | [`moderation::update_automod_settings`] |
249//! | [Get Banned Users](https://dev.twitch.tv/docs/api/reference#get-banned-users) | [`HelixClient::get_banned_users_in_channel_from_id`] | [`moderation::get_banned_users`] |
250//! | [Ban User](https://dev.twitch.tv/docs/api/reference#ban-user) | [`HelixClient::ban_user`] | [`moderation::ban_user`] |
251//! | [Unban User](https://dev.twitch.tv/docs/api/reference#unban-user) | [`HelixClient::unban_user`] | [`moderation::unban_user`] |
252//! | [Get Unban Requests](https://dev.twitch.tv/docs/api/reference#get-unban-requests) | [`HelixClient::get_unban_requests`] | [`moderation::get_unban_requests`] |
253//! | [Resolve Unban Requests](https://dev.twitch.tv/docs/api/reference#resolve-unban-requests) | - | [`moderation::resolve_unban_request`] |
254//! | [Get Blocked Terms](https://dev.twitch.tv/docs/api/reference#get-blocked-terms) | - | [`moderation::get_blocked_terms`] |
255//! | [Add Blocked Term](https://dev.twitch.tv/docs/api/reference#add-blocked-term) | - | [`moderation::add_blocked_term`] |
256//! | [Remove Blocked Term](https://dev.twitch.tv/docs/api/reference#remove-blocked-term) | - | [`moderation::remove_blocked_term`] |
257//! | [Delete Chat Messages](https://dev.twitch.tv/docs/api/reference#delete-chat-messages) | [`HelixClient::delete_chat_message`] | [`moderation::delete_chat_messages`] |
258//! | [Get Moderated Channels](https://dev.twitch.tv/docs/api/reference#get-moderated-channels) | [`HelixClient::get_moderated_channels`] | [`moderation::get_moderated_channels`] |
259//! | [Get Moderators](https://dev.twitch.tv/docs/api/reference#get-moderators) | [`HelixClient::get_moderators_in_channel_from_id`] | [`moderation::get_moderators`] |
260//! | [Add Channel Moderator](https://dev.twitch.tv/docs/api/reference#add-channel-moderator) | [`HelixClient::add_channel_moderator`] | [`moderation::add_channel_moderator`] |
261//! | [Remove Channel Moderator](https://dev.twitch.tv/docs/api/reference#remove-channel-moderator) | [`HelixClient::remove_channel_moderator`] | [`moderation::remove_channel_moderator`] |
262//! | [Get VIPs](https://dev.twitch.tv/docs/api/reference#get-vips) | [`HelixClient::get_vips_in_channel`] | [`channels::get_vips`] |
263//! | [Add Channel VIP](https://dev.twitch.tv/docs/api/reference#add-channel-vip) | [`HelixClient::add_channel_vip`] | [`channels::add_channel_vip`] |
264//! | [Remove Channel VIP](https://dev.twitch.tv/docs/api/reference#remove-channel-vip) | [`HelixClient::remove_channel_vip`] | [`channels::remove_channel_vip`] |
265//! | [Update Shield Mode Status](https://dev.twitch.tv/docs/api/reference#update-shield-mode-status) | - | [`moderation::update_shield_mode_status`] |
266//! | [Get Shield Mode Status](https://dev.twitch.tv/docs/api/reference#get-shield-mode-status) | - | [`moderation::get_shield_mode_status`] |
267//! | [Warn Chat User](https://dev.twitch.tv/docs/api/reference#warn-chat-user) | [`HelixClient::warn_chat_user`] | [`moderation::warn_chat_user`] |
268//! | [Add Suspicious Status to Chat User](https://dev.twitch.tv/docs/api/reference#add-suspicious-status-to-chat-user) | [`HelixClient::add_suspicious_status_to_chat_user`] | [`moderation::add_suspicious_status_to_chat_user`] |
269//! | [Remove Suspicious Status From Chat User](https://dev.twitch.tv/docs/api/reference#remove-suspicious-status-from-chat-user) | [`HelixClient::remove_suspicious_status_from_chat_user`] | [`moderation::remove_suspicious_status_from_chat_user`] |
270//!
271//! </details>
272//!
273//! <details><summary style="cursor: pointer">Polls 🟢 3/3</summary>
274//!
275//! | Endpoint | Helper | Module |
276//! |---|---|---|
277//! | [Get Polls](https://dev.twitch.tv/docs/api/reference#get-polls) | - | [`polls::get_polls`] |
278//! | [Create Poll](https://dev.twitch.tv/docs/api/reference#create-poll) | - | [`polls::create_poll`] |
279//! | [End Poll](https://dev.twitch.tv/docs/api/reference#end-poll) | - | [`polls::end_poll`] |
280//!
281//! </details>
282//!
283//! <details><summary style="cursor: pointer">Predictions 🟢 3/3</summary>
284//!
285//! | Endpoint | Helper | Module |
286//! |---|---|---|
287//! | [Get Predictions](https://dev.twitch.tv/docs/api/reference#get-predictions) | - | [`predictions::get_predictions`] |
288//! | [Create Prediction](https://dev.twitch.tv/docs/api/reference#create-prediction) | - | [`predictions::create_prediction`] |
289//! | [End Prediction](https://dev.twitch.tv/docs/api/reference#end-prediction) | - | [`predictions::end_prediction`] |
290//!
291//! </details>
292//!
293//! <details><summary style="cursor: pointer">Raids 🟢 2/2</summary>
294//!
295//! | Endpoint | Helper | Module |
296//! |---|---|---|
297//! | [Start a raid](https://dev.twitch.tv/docs/api/reference#start-a-raid) | [`HelixClient::start_a_raid`] | [`raids::start_a_raid`] |
298//! | [Cancel a raid](https://dev.twitch.tv/docs/api/reference#cancel-a-raid) | [`HelixClient::cancel_a_raid`] | [`raids::cancel_a_raid`] |
299//!
300//! </details>
301//!
302//! <details><summary style="cursor: pointer">Schedule 🟡 5/6</summary>
303//!
304//! | Endpoint | Helper | Module |
305//! |---|---|---|
306//! | [Get Channel Stream Schedule](https://dev.twitch.tv/docs/api/reference#get-channel-stream-schedule) | - | [`schedule::get_channel_stream_schedule`] |
307//! | [Get Channel iCalendar](https://dev.twitch.tv/docs/api/reference#get-channel-icalendar) | - | - |
308//! | [Update Channel Stream Schedule](https://dev.twitch.tv/docs/api/reference#update-channel-stream-schedule) | - | [`schedule::update_channel_stream_schedule`] |
309//! | [Create Channel Stream Schedule Segment](https://dev.twitch.tv/docs/api/reference#create-channel-stream-schedule-segment) | - | [`schedule::create_channel_stream_schedule_segment`] |
310//! | [Update Channel Stream Schedule Segment](https://dev.twitch.tv/docs/api/reference#update-channel-stream-schedule-segment) | - | [`schedule::update_channel_stream_schedule_segment`] |
311//! | [Delete Channel Stream Schedule Segment](https://dev.twitch.tv/docs/api/reference#delete-channel-stream-schedule-segment) | - | [`schedule::delete_channel_stream_schedule_segment`] |
312//!
313//! </details>
314//!
315//! <details><summary style="cursor: pointer">Search 🟢 2/2</summary>
316//!
317//! | Endpoint | Helper | Module |
318//! |---|---|---|
319//! | [Search Categories](https://dev.twitch.tv/docs/api/reference#search-categories) | [`HelixClient::search_categories`] | [`search::search_categories`] |
320//! | [Search Channels](https://dev.twitch.tv/docs/api/reference#search-channels) | [`HelixClient::search_channels`] | [`search::search_channels`] |
321//!
322//! </details>
323//!
324//! <details><summary style="cursor: pointer">Streams 🟢 5/5</summary>
325//!
326//! | Endpoint | Helper | Module |
327//! |---|---|---|
328//! | [Get Stream Key](https://dev.twitch.tv/docs/api/reference#get-stream-key) | [`HelixClient::get_stream_key`] | [`streams::get_stream_key`] |
329//! | [Get Streams](https://dev.twitch.tv/docs/api/reference#get-streams) | [`HelixClient::get_streams_from_ids`], [`HelixClient::get_streams_from_logins`] | [`streams::get_streams`] |
330//! | [Get Followed Streams](https://dev.twitch.tv/docs/api/reference#get-followed-streams) | [`HelixClient::get_followed_streams`] | [`streams::get_followed_streams`] |
331//! | [Create Stream Marker](https://dev.twitch.tv/docs/api/reference#create-stream-marker) | [`HelixClient::create_stream_marker`] | [`streams::create_stream_marker`] |
332//! | [Get Stream Markers](https://dev.twitch.tv/docs/api/reference#get-stream-markers) | - | [`streams::get_stream_markers`] |
333//!
334//! </details>
335//!
336//! <details><summary style="cursor: pointer">Subscriptions 🟢 2/2</summary>
337//!
338//! | Endpoint | Helper | Module |
339//! |---|---|---|
340//! | [Get Broadcaster Subscriptions](https://dev.twitch.tv/docs/api/reference#get-broadcaster-subscriptions) | [`HelixClient::get_broadcaster_subscriptions`] | [`subscriptions::get_broadcaster_subscriptions`] |
341//! | [Check User Subscription](https://dev.twitch.tv/docs/api/reference#check-user-subscription) | - | [`subscriptions::check_user_subscription`] |
342//!
343//! </details>
344//!
345//! <details><summary style="cursor: pointer">Tags 🟢 2/2</summary>
346//!
347//! | Endpoint | Helper | Module |
348//! |---|---|---|
349//! | [Get All Stream Tags](https://dev.twitch.tv/docs/api/reference#get-all-stream-tags) | - | [`tags::get_all_stream_tags`] |
350//! | [Get Stream Tags](https://dev.twitch.tv/docs/api/reference#get-stream-tags) | - | [`streams::get_stream_tags`] |
351//!
352//! </details>
353//!
354//! <details><summary style="cursor: pointer">Teams 🟢 2/2</summary>
355//!
356//! | Endpoint | Helper | Module |
357//! |---|---|---|
358//! | [Get Channel Teams](https://dev.twitch.tv/docs/api/reference#get-channel-teams) | - | [`teams::get_channel_teams`] |
359//! | [Get Teams](https://dev.twitch.tv/docs/api/reference#get-teams) | - | [`teams::get_teams`] |
360//!
361//! </details>
362//!
363//! <details><summary style="cursor: pointer">Users 🟢 9/9</summary>
364//!
365//! | Endpoint | Helper | Module |
366//! |---|---|---|
367//! | [Get Users](https://dev.twitch.tv/docs/api/reference#get-users) | [`HelixClient::get_user_from_id`], [`HelixClient::get_user_from_login`], [`HelixClient::get_users_from_ids`], [`HelixClient::get_users_from_logins`] | [`users::get_users`] |
368//! | [Update User](https://dev.twitch.tv/docs/api/reference#update-user) | [`HelixClient::update_user_description`] | [`users::update_user`] |
369//! | [Get Authorization By User](https://dev.twitch.tv/docs/api/reference#get-authorization-by-user) | [`HelixClient::get_authorization_by_user`] | [`users::get_authorization_by_user`] |
370//! | [Get User Block List](https://dev.twitch.tv/docs/api/reference#get-user-block-list) | - | [`users::get_user_block_list`] |
371//! | [Block User](https://dev.twitch.tv/docs/api/reference#block-user) | [`HelixClient::block_user`] | [`users::block_user`] |
372//! | [Unblock User](https://dev.twitch.tv/docs/api/reference#unblock-user) | [`HelixClient::unblock_user`] | [`users::unblock_user`] |
373//! | [Get User Extensions](https://dev.twitch.tv/docs/api/reference#get-user-extensions) | [`HelixClient::get_user_extensions`] | [`users::get_user_extensions`] |
374//! | [Get User Active Extensions](https://dev.twitch.tv/docs/api/reference#get-user-active-extensions) | [`HelixClient::get_user_active_extensions`] | [`users::get_user_active_extensions`] |
375//! | [Update User Extensions](https://dev.twitch.tv/docs/api/reference#update-user-extensions) | - | [`users::update_user_extensions`] |
376//!
377//! </details>
378//!
379//! <details><summary style="cursor: pointer">Videos 🟢 2/2</summary>
380//!
381//! | Endpoint | Helper | Module |
382//! |---|---|---|
383//! | [Get Videos](https://dev.twitch.tv/docs/api/reference#get-videos) | - | [`videos::get_videos`] |
384//! | [Delete Videos](https://dev.twitch.tv/docs/api/reference#delete-videos) | - | [`videos::delete_videos`] |
385//!
386//! </details>
387//!
388//! <details><summary style="cursor: pointer">Whispers 🟢 1/1</summary>
389//!
390//! | Endpoint | Helper | Module |
391//! |---|---|---|
392//! | [Send Whisper](https://dev.twitch.tv/docs/api/reference#send-whisper) | [`HelixClient::send_whisper`] | [`whispers::send_whisper`] |
393//!
394//! </details>
395//!
396//! <!-- END-OVERVIEW -->
397
398use serde_derive::Deserialize;
399#[doc(no_inline)]
400#[cfg(feature = "twitch_oauth2")]
401pub use twitch_oauth2::Scope;
402#[cfg(feature = "twitch_oauth2")]
403use twitch_oauth2::TwitchToken;
404
405#[cfg(feature = "client")]
406pub mod client;
407mod endpoints;
408pub mod pagination;
409pub mod request;
410pub mod response;
411
412#[cfg(feature = "client")]
413#[doc(inline)]
414pub use client::{client_ext::make_stream, *};
415pub use endpoints::*;
416#[cfg(feature = "client")]
417#[doc(inline)]
418pub use request::errors::ClientRequestError;
419#[doc(inline)]
420pub use request::errors::{
421 CreateRequestError, HelixRequestDeleteError, HelixRequestGetError, HelixRequestPatchError,
422 HelixRequestPostError, HelixRequestPutError, InvalidUri, SerializeError,
423};
424#[doc(inline)]
425pub use request::{Request, RequestDelete, RequestGet, RequestPatch, RequestPost, RequestPut};
426#[doc(inline)]
427pub use response::Response;
428
429#[doc(inline)]
430pub use pagination::PaginationState;
431
432pub(crate) mod ser;
433pub(crate) use crate::deserialize_default_from_null;
434use crate::parse_json;
435pub(crate) use request::parse_single_return;
436
437#[derive(PartialEq, Deserialize, Debug)]
438struct InnerResponse<D> {
439 data: D,
440 /// A cursor value, to be used in a subsequent request to specify the starting point of the next set of results.
441 #[serde(default)]
442 pagination: Pagination,
443 #[serde(default)]
444 total: Option<i64>,
445 #[serde(default, flatten)]
446 other: Option<serde_json::Map<String, serde_json::Value>>,
447}
448
449#[derive(Deserialize, Debug)]
450#[cfg(feature = "unsupported")]
451#[cfg_attr(nightly, doc(cfg(feature = "unsupported")))]
452struct CustomInnerResponse<'a> {
453 #[serde(borrow)]
454 data: &'a serde_json::value::RawValue,
455 #[serde(default)]
456 pagination: Pagination,
457 #[serde(default)]
458 total: Option<i64>,
459 // FIXME: There is an issue with RawValue on flatten maps. https://github.com/serde-rs/json/issues/599
460 #[serde(flatten, default)]
461 other: serde_json::Map<String, serde_json::Value>,
462}
463
464#[derive(Deserialize, Clone, Debug)]
465struct HelixRequestError {
466 error: String,
467 status: u16,
468 message: String,
469}
470
471/// Deserialize 0, "0" or "" as None
472fn deserialize_none_from_empty_or_zero_string<'de, D, S>(
473 deserializer: D,
474) -> Result<Option<S>, D::Error>
475where
476 D: serde::Deserializer<'de>,
477 S: serde::Deserialize<'de>, {
478 use serde::de::IntoDeserializer;
479 struct Inner<S>(std::marker::PhantomData<S>);
480 impl<'de, S> serde::de::Visitor<'de> for Inner<S>
481 where S: serde::Deserialize<'de>
482 {
483 type Value = Option<S>;
484
485 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
486 formatter.write_str("any string or integer")
487 }
488
489 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
490 where E: serde::de::Error {
491 match value {
492 "" => Ok(None),
493 "0" => Ok(None),
494 v => S::deserialize(v.into_deserializer()).map(Some),
495 }
496 }
497
498 fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
499 where E: serde::de::Error {
500 match &*value {
501 "" => Ok(None),
502 "0" => Ok(None),
503 v => S::deserialize(v.into_deserializer()).map(Some),
504 }
505 }
506
507 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
508 where E: serde::de::Error {
509 if v == 0 {
510 Ok(None)
511 } else {
512 S::deserialize(v.into_deserializer()).map(Some)
513 }
514 }
515
516 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
517 where E: serde::de::Error {
518 if v == 0 {
519 Ok(None)
520 } else {
521 S::deserialize(v.into_deserializer()).map(Some)
522 }
523 }
524
525 fn visit_unit<E>(self) -> Result<Self::Value, E>
526 where E: serde::de::Error {
527 Ok(None)
528 }
529 }
530
531 deserializer.deserialize_any(Inner(std::marker::PhantomData))
532}
533
534/// A request that can be paginated.
535pub trait Paginated: Request<PaginationData = PaginationState<Self>>
536where Self: Sized {
537 /// Should returns the current pagination cursor.
538 ///
539 /// # Notes
540 ///
541 /// Pass [`Option::None`] if no cursor is found.
542 fn set_pagination(&mut self, cursor: Option<Cursor>);
543}
544
545/// A cursor for pagination. This is needed because of how pagination is represented in the [New Twitch API](https://dev.twitch.tv/docs/api)
546#[derive(PartialEq, Deserialize, Debug, Clone, Default)]
547struct Pagination {
548 #[serde(default)]
549 cursor: Option<Cursor>,
550}
551
552/// A cursor is a pointer to the current "page" in the twitch api pagination
553#[aliri_braid::braid(serde)]
554pub struct Cursor;
555
556impl CursorRef {
557 /// Get a borrowed [`Cow<'_, CursorRef>`](std::borrow::Cow::Borrowed)
558 pub fn as_cow(&self) -> ::std::borrow::Cow<'_, Self> { self.into() }
559}
560
561impl Cursor {
562 /// Get a owned [`Cow<'_, CursorRef>`](std::borrow::Cow::Owned)
563 const fn into_cow<'a>(self) -> std::borrow::Cow<'a, CursorRef> { std::borrow::Cow::Owned(self) }
564}
565
566/// Errors that can happen when creating a body
567#[derive(thiserror::Error, Debug, displaydoc::Display)]
568#[non_exhaustive]
569pub enum BodyError {
570 /// could not serialize as json
571 JsonError(#[from] serde_json::Error),
572 /// could not serialize to query
573 QuerySerializeError(#[from] ser::Error),
574 /// uri is invalid
575 InvalidUri(#[from] InvalidUri),
576}
577
578/// Create a body. Used for specializing request bodies
579pub trait HelixRequestBody {
580 /// Create the body
581 fn try_to_body(&self) -> Result<hyper::body::Bytes, BodyError>;
582}
583
584/// An empty body.
585///
586/// Implements [`HelixRequestBody::try_to_body`], returning an empty vector
587#[derive(Default, Clone, Copy)]
588pub struct EmptyBody;
589
590impl HelixRequestBody for EmptyBody {
591 fn try_to_body(&self) -> Result<hyper::body::Bytes, BodyError> { Ok(<_>::default()) }
592}
593
594// TODO: I would want specialization for this. For now, to override this behavior for a body, we specify a sealed trait
595impl<T> HelixRequestBody for T
596where T: serde::Serialize + private::SealedSerialize
597{
598 fn try_to_body(&self) -> Result<hyper::body::Bytes, BodyError> {
599 serde_json::to_vec(&self)
600 .map_err(Into::into)
601 .map(Into::into)
602 }
603}
604
605pub(crate) mod private {
606 pub trait SealedSerialize {}
607}