twitchrb 1.11.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +97 -0
- data/LICENSE.txt +1 -1
- data/README.md +373 -46
- data/lib/twitch/client.rb +109 -20
- data/lib/twitch/collection.rb +54 -8
- data/lib/twitch/eventsub_webhook.rb +140 -0
- data/lib/twitch/oauth.rb +51 -14
- data/lib/twitch/object.rb +93 -14
- data/lib/twitch/objects/ad_schedule.rb +4 -0
- data/lib/twitch/objects/analytics_report.rb +4 -0
- data/lib/twitch/objects/bits_leaderboard_entry.rb +4 -0
- data/lib/twitch/objects/charity_donation.rb +4 -0
- data/lib/twitch/objects/chat_settings.rb +4 -0
- data/lib/twitch/objects/cheermote.rb +4 -0
- data/lib/twitch/objects/content_classification_label.rb +4 -0
- data/lib/twitch/objects/drops_entitlement.rb +4 -0
- data/lib/twitch/objects/drops_entitlement_update.rb +4 -0
- data/lib/twitch/objects/extension.rb +4 -0
- data/lib/twitch/objects/extension_bits_product.rb +4 -0
- data/lib/twitch/objects/extension_configuration_segment.rb +4 -0
- data/lib/twitch/objects/extension_live_channel.rb +4 -0
- data/lib/twitch/objects/extension_secret.rb +4 -0
- data/lib/twitch/objects/extension_transaction.rb +4 -0
- data/lib/twitch/objects/guest_star_invite.rb +4 -0
- data/lib/twitch/objects/guest_star_session.rb +4 -0
- data/lib/twitch/objects/guest_star_settings.rb +4 -0
- data/lib/twitch/objects/shield_mode_status.rb +4 -0
- data/lib/twitch/objects/{tag.rb → team.rb} +1 -1
- data/lib/twitch/objects/user_active_extensions.rb +4 -0
- data/lib/twitch/objects/user_extension.rb +4 -0
- data/lib/twitch/resource.rb +29 -0
- data/lib/twitch/resources/ads.rb +18 -0
- data/lib/twitch/resources/analytics.rb +19 -0
- data/lib/twitch/resources/announcements.rb +1 -1
- data/lib/twitch/resources/automod.rb +7 -7
- data/lib/twitch/resources/badges.rb +2 -2
- data/lib/twitch/resources/banned_users.rb +3 -3
- data/lib/twitch/resources/bits.rb +16 -0
- data/lib/twitch/resources/blocked_terms.rb +3 -3
- data/lib/twitch/resources/channels.rb +4 -4
- data/lib/twitch/resources/charity_campaigns.rb +8 -0
- data/lib/twitch/resources/chat_settings.rb +20 -0
- data/lib/twitch/resources/chatters.rb +1 -1
- data/lib/twitch/resources/clips.rb +3 -9
- data/lib/twitch/resources/content_classification_labels.rb +8 -0
- data/lib/twitch/resources/custom_power_ups.rb +1 -1
- data/lib/twitch/resources/custom_reward_redemptions.rb +3 -4
- data/lib/twitch/resources/custom_rewards.rb +5 -5
- data/lib/twitch/resources/drops_entitlements.rb +17 -0
- data/lib/twitch/resources/emotes.rb +3 -3
- data/lib/twitch/resources/eventsub_conduits.rb +14 -4
- data/lib/twitch/resources/eventsub_subscriptions.rb +1 -1
- data/lib/twitch/resources/extensions.rb +99 -0
- data/lib/twitch/resources/games.rb +3 -3
- data/lib/twitch/resources/goals.rb +1 -1
- data/lib/twitch/resources/guest_star.rb +102 -0
- data/lib/twitch/resources/moderators.rb +3 -3
- data/lib/twitch/resources/pinned_chat_messages.rb +4 -11
- data/lib/twitch/resources/polls.rb +1 -1
- data/lib/twitch/resources/predictions.rb +1 -1
- data/lib/twitch/resources/raids.rb +2 -3
- data/lib/twitch/resources/search.rb +2 -2
- data/lib/twitch/resources/shield_mode.rb +18 -0
- data/lib/twitch/resources/shoutouts.rb +1 -1
- data/lib/twitch/resources/stream_markers.rb +1 -1
- data/lib/twitch/resources/stream_schedule.rb +4 -5
- data/lib/twitch/resources/streams.rb +2 -2
- data/lib/twitch/resources/subscriptions.rb +13 -2
- data/lib/twitch/resources/suspicious_users.rb +1 -1
- data/lib/twitch/resources/teams.rb +20 -0
- data/lib/twitch/resources/unban_requests.rb +2 -2
- data/lib/twitch/resources/users.rb +30 -34
- data/lib/twitch/resources/videos.rb +2 -2
- data/lib/twitch/resources/vips.rb +2 -2
- data/lib/twitch/resources/warnings.rb +2 -2
- data/lib/twitch/resources/whispers.rb +1 -1
- data/lib/twitch/version.rb +1 -1
- data/lib/twitch.rb +33 -10
- metadata +42 -46
- data/.env.example +0 -3
- data/.github/FUNDING.yml +0 -5
- data/.github/dependabot.yml +0 -11
- data/.github/workflows/ci.yml +0 -39
- data/.gitignore +0 -9
- data/.rubocop.yml +0 -16
- data/Gemfile +0 -13
- data/Gemfile.lock +0 -144
- data/Rakefile +0 -10
- data/bin/console +0 -23
- data/bin/setup +0 -8
- data/bin/smoke +0 -118
- data/lib/twitch/objects/banned_event.rb +0 -4
- data/lib/twitch/objects/followed_user.rb +0 -4
- data/lib/twitch/objects/hype_train_event.rb +0 -4
- data/lib/twitch/objects/moderator_event.rb +0 -4
- data/lib/twitch/resources/banned_events.rb +0 -8
- data/lib/twitch/resources/hype_train_events.rb +0 -10
- data/lib/twitch/resources/moderator_events.rb +0 -9
- data/lib/twitch/resources/tags.rb +0 -18
- data/mise.toml +0 -2
- data/twitchrb.gemspec +0 -29
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# TwitchRB
|
|
2
2
|
|
|
3
|
-
[](https://github.com/d34ndev/twitchrb/actions/workflows/ci.yml)
|
|
4
4
|
[](https://badge.fury.io/rb/twitchrb)
|
|
5
5
|
[](https://rubygems.org/gems/twitchrb)
|
|
6
6
|
|
|
@@ -14,6 +14,8 @@ Add this line to your application's Gemfile:
|
|
|
14
14
|
gem "twitchrb"
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
Upgrading from 1.x? Version 2.0 has breaking changes. See [Upgrading from 1.x](CHANGELOG.md#upgrading-from-1x) in the changelog.
|
|
18
|
+
|
|
17
19
|
## Usage
|
|
18
20
|
|
|
19
21
|
### Set Client Details
|
|
@@ -26,17 +28,46 @@ An access token is required because the Helix API requires authentication.
|
|
|
26
28
|
@client = Twitch::Client.new(client_id: "abc123", access_token: "xyz123")
|
|
27
29
|
```
|
|
28
30
|
|
|
31
|
+
Requests time out after 30 seconds (10 seconds to open the connection) by default, raising
|
|
32
|
+
`Faraday::TimeoutError` or `Faraday::ConnectionFailed`. Both can be changed on `Twitch::Client` and `Twitch::OAuth`:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
@client = Twitch::Client.new(client_id: "abc123", access_token: "xyz123", timeout: 10, open_timeout: 5)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
#### Refreshing User Access Tokens
|
|
39
|
+
|
|
40
|
+
User access tokens expire after a few hours. Pass the `refresh_token` and your `client_secret` and the client
|
|
41
|
+
will refresh an expired token automatically, then retry the request. Twitch may issue a new refresh token each
|
|
42
|
+
time, so use `on_token_refresh` to store the new tokens:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
@client = Twitch::Client.new(
|
|
46
|
+
client_id: "abc123",
|
|
47
|
+
client_secret: "your-client-secret", # omit for public clients
|
|
48
|
+
access_token: user.twitch_access_token,
|
|
49
|
+
refresh_token: user.twitch_refresh_token,
|
|
50
|
+
on_token_refresh: ->(token) {
|
|
51
|
+
user.update!(twitch_access_token: token.access_token, twitch_refresh_token: token.refresh_token)
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Or refresh manually
|
|
56
|
+
@client.refresh_access_token!
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The client refreshes once per expired token, even across threads. If the refresh token itself is invalid (e.g.
|
|
60
|
+
the user disconnected your app), the error from Twitch is raised, e.g. `Twitch::Errors::BadRequestError`.
|
|
61
|
+
|
|
29
62
|
#### User vs. App Access Tokens
|
|
30
63
|
|
|
31
64
|
Most endpoints accept a **user access token** — issued for a specific Twitch user via the
|
|
32
65
|
[authorization code](https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#authorization-code-grant-flow)
|
|
33
66
|
or [device code](https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#device-code-grant-flow) flows,
|
|
34
|
-
and required for anything that acts on behalf of a user (
|
|
67
|
+
and required for anything that acts on behalf of a user (managing channels, polls, rewards, etc.).
|
|
35
68
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
each section below. App tokens are obtained with the `client_credentials` grant and need only your
|
|
39
|
-
Client ID and Client Secret:
|
|
69
|
+
An **app access token** is issued to your application, not a user. App tokens are obtained with the
|
|
70
|
+
`client_credentials` grant and need only your Client ID and Client Secret:
|
|
40
71
|
|
|
41
72
|
```ruby
|
|
42
73
|
oauth = Twitch::OAuth.new(client_id: "abc123", client_secret: "your-client-secret")
|
|
@@ -48,12 +79,43 @@ token = oauth.create(grant_type: "client_credentials")
|
|
|
48
79
|
App tokens expire (typically after ~60 days). Use `oauth.validate(token: ...)` to check the remaining
|
|
49
80
|
lifetime, and `oauth.create(grant_type: "client_credentials")` to mint a fresh one when needed.
|
|
50
81
|
|
|
82
|
+
**These require an app access token:**
|
|
83
|
+
|
|
84
|
+
- EventSub over webhooks or conduits: `eventsub_subscriptions` and `eventsub_conduits` (including shards).
|
|
85
|
+
EventSub over WebSockets requires a user access token instead.
|
|
86
|
+
- `users.authorization`
|
|
87
|
+
- `extensions.transactions`, and `extensions.bits_products`/`update_bits_product` (the token's Client ID must be the extension's)
|
|
88
|
+
|
|
89
|
+
**These also accept an app access token**, as long as the user in the request (e.g. `sender_id` or
|
|
90
|
+
`moderator_id`) has previously authorized your app with the required scope through one of the user token flows.
|
|
91
|
+
This is how chatbots can act without storing each user's token. Chat endpoints need the bot account to have
|
|
92
|
+
granted `user:bot`, and the broadcaster to have granted `channel:bot` or made the bot a moderator — see
|
|
93
|
+
[Chatbots](https://dev.twitch.tv/docs/chat/authenticating/) for details.
|
|
94
|
+
|
|
95
|
+
- Chat: `chat_messages.create`, `chat_messages.delete`, `announcements.create`, `shoutouts.create`,
|
|
96
|
+
`pinned_chat_messages` (all methods), `chatters.list`, `chat_settings.update`
|
|
97
|
+
- Moderation: `automod` (all methods), `banned_users` (all methods), `blocked_terms` (all methods),
|
|
98
|
+
`moderators.channels`, `shield_mode` (all methods), `warnings.create`, `suspicious_users` (all methods)
|
|
99
|
+
- Ads: `channels.commercial`, `ads.schedule`, `ads.snooze`
|
|
100
|
+
|
|
51
101
|
### Resources
|
|
52
102
|
|
|
53
103
|
The gem maps as closely as we can to the Twitch API so you can easily convert API examples to gem code.
|
|
54
104
|
|
|
55
105
|
Responses are created as objects like `Twitch::Channel`. Having types like `Twitch::User` is handy for understanding what
|
|
56
|
-
type of object you're working with.
|
|
106
|
+
type of object you're working with. Attributes can be read with dot notation or like a hash, and nested data is wrapped too:
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
user = @client.users.retrieve(username: "twitchdev")
|
|
110
|
+
|
|
111
|
+
user.display_name #=> "TwitchDev"
|
|
112
|
+
user[:display_name] #=> "TwitchDev"
|
|
113
|
+
user.missing_attribute #=> nil
|
|
114
|
+
|
|
115
|
+
# Convert back to a hash or JSON, including nested data
|
|
116
|
+
user.to_h
|
|
117
|
+
user.to_json
|
|
118
|
+
```
|
|
57
119
|
|
|
58
120
|
### Pagination
|
|
59
121
|
|
|
@@ -85,11 +147,38 @@ results.last
|
|
|
85
147
|
results.cursor
|
|
86
148
|
#=> "abc123"
|
|
87
149
|
|
|
88
|
-
# Retrieve the next page
|
|
150
|
+
# Retrieve the next page manually
|
|
89
151
|
@client.clips.list(broadcaster_id: 123, after: results.cursor)
|
|
90
152
|
#=> Twitch::Collection
|
|
91
153
|
```
|
|
92
154
|
|
|
155
|
+
#### Automatic Pagination
|
|
156
|
+
|
|
157
|
+
Collections from paginated endpoints can fetch their following pages for you. Each extra page is a separate
|
|
158
|
+
API request (and counts towards your rate limit), so use `first:` to request up to 100 items per page.
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
followers = @client.channels.followers(broadcaster_id: 123, first: 100)
|
|
162
|
+
|
|
163
|
+
# Fetch the next page, or nil on the last page
|
|
164
|
+
followers.next_page? #=> true
|
|
165
|
+
followers.next_page #=> Twitch::Collection
|
|
166
|
+
|
|
167
|
+
# Iterate over every item across all pages. Pages are fetched lazily, only as needed.
|
|
168
|
+
followers.auto_paginate.each { |follower| puts follower.user_name }
|
|
169
|
+
|
|
170
|
+
# Stop after 250 items, without fetching any more pages than needed
|
|
171
|
+
followers.auto_paginate.first(250)
|
|
172
|
+
|
|
173
|
+
# Get every item as an array
|
|
174
|
+
followers.auto_paginate.to_a
|
|
175
|
+
|
|
176
|
+
# Iterate page by page
|
|
177
|
+
followers.each_page do |page|
|
|
178
|
+
puts "#{page.data.size} followers on this page"
|
|
179
|
+
end
|
|
180
|
+
```
|
|
181
|
+
|
|
93
182
|
### Rate Limiting
|
|
94
183
|
|
|
95
184
|
The Twitch API has rate limits to ensure fair usage. TwitchRB automatically tracks rate limit information from API responses and can warn you when approaching limits.
|
|
@@ -168,33 +257,59 @@ The `rate_limiter` object has several useful methods:
|
|
|
168
257
|
|
|
169
258
|
### OAuth
|
|
170
259
|
|
|
171
|
-
This library includes the ability to create, refresh and revoke OAuth tokens.
|
|
260
|
+
This library includes the ability to create, refresh, validate and revoke OAuth tokens.
|
|
261
|
+
|
|
262
|
+
Failed token requests raise the same errors as API requests (e.g. `Twitch::Errors::BadRequestError`),
|
|
263
|
+
with Twitch's message available as `error.twitch_error_message`.
|
|
172
264
|
|
|
173
265
|
```ruby
|
|
174
266
|
# Firstly, set the client details
|
|
267
|
+
# client_secret can be omitted for public clients using the device code flow
|
|
175
268
|
@oauth = Twitch::OAuth.new(client_id: "", client_secret: "")
|
|
176
269
|
|
|
177
|
-
# Create
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
270
|
+
# Create an app access token (client credentials grant flow)
|
|
271
|
+
@oauth.create(grant_type: "client_credentials")
|
|
272
|
+
|
|
273
|
+
# Exchange the code from the authorization code grant flow for a user access token
|
|
274
|
+
# https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#authorization-code-grant-flow
|
|
275
|
+
token = @oauth.exchange_code(code: params[:code], redirect_uri: "http://localhost:3000/callback")
|
|
276
|
+
token.access_token
|
|
277
|
+
token.refresh_token
|
|
181
278
|
|
|
182
279
|
# Refresh a Token
|
|
183
280
|
@oauth.refresh(refresh_token: "")
|
|
184
281
|
|
|
185
|
-
# Device Code Grant Flow
|
|
186
|
-
# scopes is required and is a space-delimited list of scopes
|
|
187
|
-
# https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#device-code-grant-flow
|
|
188
|
-
@oauth.device(scopes: "bits:read channel:read:subscriptions")
|
|
189
|
-
|
|
190
282
|
# Validate an Access Token
|
|
191
283
|
# Returns false if the token is invalid
|
|
192
284
|
@oauth.validate(token: "")
|
|
193
285
|
|
|
194
286
|
# Revoke a Token
|
|
287
|
+
# Returns false if the token couldn't be revoked
|
|
195
288
|
@oauth.revoke(token: "")
|
|
196
289
|
```
|
|
197
290
|
|
|
291
|
+
#### Device Code Grant Flow
|
|
292
|
+
|
|
293
|
+
For apps with limited input, such as CLIs, set-top boxes or games.
|
|
294
|
+
See [the Twitch docs](https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#device-code-grant-flow).
|
|
295
|
+
|
|
296
|
+
```ruby
|
|
297
|
+
# scopes can be an array or a space-delimited string
|
|
298
|
+
scopes = ["user:read:email", "chat:read"]
|
|
299
|
+
device = @oauth.device(scopes: scopes)
|
|
300
|
+
|
|
301
|
+
puts "Go to #{device.verification_uri} and enter #{device.user_code}"
|
|
302
|
+
|
|
303
|
+
# Poll until the user has authorized the app
|
|
304
|
+
token = begin
|
|
305
|
+
sleep device.interval
|
|
306
|
+
@oauth.device_token(device_code: device.device_code, scopes: scopes)
|
|
307
|
+
rescue Twitch::Errors::BadRequestError => e
|
|
308
|
+
retry if e.twitch_error_message == "authorization_pending"
|
|
309
|
+
raise
|
|
310
|
+
end
|
|
311
|
+
```
|
|
312
|
+
|
|
198
313
|
### Users
|
|
199
314
|
|
|
200
315
|
```ruby
|
|
@@ -254,6 +369,19 @@ This library includes the ability to create, refresh and revoke OAuth tokens.
|
|
|
254
369
|
# #<Twitch::UserAuthorization user_id="72938118", user_name="deanpcmad", user_login="deanpcmad", scopes=["user:read:email"], has_authorized=true>
|
|
255
370
|
@client.users.authorization(id: 123)
|
|
256
371
|
@client.users.authorization(ids: [123, 321])
|
|
372
|
+
|
|
373
|
+
# Gets all extensions the authenticated user has installed, active or not
|
|
374
|
+
# Required scope: user:read:broadcast or user:edit:broadcast (needed to include inactive extensions)
|
|
375
|
+
@client.users.extensions
|
|
376
|
+
|
|
377
|
+
# Gets the active extensions for a user, or the authenticated user if user_id is omitted
|
|
378
|
+
@client.users.active_extensions(user_id: 123)
|
|
379
|
+
|
|
380
|
+
# Updates the authenticated user's active extensions
|
|
381
|
+
# Required scope: user:edit:broadcast
|
|
382
|
+
@client.users.update_extensions(data: {
|
|
383
|
+
panel: { "1" => { active: true, id: "abc123", version: "1.0.0" } }
|
|
384
|
+
})
|
|
257
385
|
```
|
|
258
386
|
|
|
259
387
|
### Channels
|
|
@@ -437,6 +565,54 @@ end
|
|
|
437
565
|
@client.eventsub_subscriptions.delete(id: "abc12-abc12-abc12")
|
|
438
566
|
```
|
|
439
567
|
|
|
568
|
+
### EventSub Webhooks
|
|
569
|
+
|
|
570
|
+
When Twitch sends EventSub notifications to your webhook callback, you must verify each request came from Twitch
|
|
571
|
+
before trusting it. `Twitch::EventsubWebhook` checks the HMAC signature using the `secret` you passed when creating
|
|
572
|
+
the subscription, and rejects messages older than 10 minutes to guard against replay attacks.
|
|
573
|
+
|
|
574
|
+
Pass the **raw** request body, as the signature covers the exact bytes Twitch sent. `headers` can be a Hash,
|
|
575
|
+
a Rack env, or Rails' `request.headers`.
|
|
576
|
+
|
|
577
|
+
```ruby
|
|
578
|
+
# Rails example
|
|
579
|
+
class TwitchWebhooksController < ApplicationController
|
|
580
|
+
skip_forgery_protection
|
|
581
|
+
|
|
582
|
+
def create
|
|
583
|
+
webhook = Twitch::EventsubWebhook.new(
|
|
584
|
+
secret: ENV["TWITCH_EVENTSUB_SECRET"],
|
|
585
|
+
headers: request.headers,
|
|
586
|
+
body: request.raw_post
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
return head :forbidden unless webhook.valid?
|
|
590
|
+
|
|
591
|
+
if webhook.verification?
|
|
592
|
+
# Twitch confirms you own the callback when you create a subscription
|
|
593
|
+
render plain: webhook.challenge
|
|
594
|
+
elsif webhook.notification?
|
|
595
|
+
# Twitch may send a message more than once, so skip message IDs you've already processed
|
|
596
|
+
# webhook.subscription_type #=> "channel.follow"
|
|
597
|
+
# webhook.event #=> #<Twitch::Object user_id="1234", user_login="cool_user", ...>
|
|
598
|
+
head :no_content
|
|
599
|
+
elsif webhook.revocation?
|
|
600
|
+
# webhook.subscription.status #=> "authorization_revoked"
|
|
601
|
+
head :no_content
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
# Or just check the signature and timestamp
|
|
607
|
+
Twitch::EventsubWebhook.verify(secret: "...", headers: request.headers, body: request.raw_post)
|
|
608
|
+
|
|
609
|
+
# Allow a different maximum message age, in seconds (default 600)
|
|
610
|
+
Twitch::EventsubWebhook.new(secret: "...", headers: request.headers, body: request.raw_post, max_age: 300)
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
Other readers: `message_id`, `message_type`, `timestamp`, `retry?`, `subscription_version`, `payload` (the parsed body),
|
|
614
|
+
`signature_valid?`, and `expired?`.
|
|
615
|
+
|
|
440
616
|
### Custom Power-ups
|
|
441
617
|
|
|
442
618
|
```ruby
|
|
@@ -484,15 +660,13 @@ shards = [
|
|
|
484
660
|
}
|
|
485
661
|
}
|
|
486
662
|
]
|
|
487
|
-
@client.eventsub_conduits.update_shards(id: "abc123-def456", shards: shards)
|
|
488
|
-
```
|
|
663
|
+
result = @client.eventsub_conduits.update_shards(id: "abc123-def456", shards: shards)
|
|
489
664
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
@client.banned_events.list(broadcaster_id: 123)
|
|
665
|
+
# Twitch accepts up to 100 shards per request, so larger lists are sent in batches automatically.
|
|
666
|
+
# Twitch applies the valid shards even if others fail, so check errors for any that didn't update:
|
|
667
|
+
result.errors.each do |error|
|
|
668
|
+
puts "Shard #{error.id} failed: #{error.message} (#{error.code})"
|
|
669
|
+
end
|
|
496
670
|
```
|
|
497
671
|
|
|
498
672
|
### Banned Users
|
|
@@ -735,6 +909,11 @@ messages = [{msg_id: "abc1", msg_text: "is this allowed?"}, {msg_id: "abc2", msg
|
|
|
735
909
|
# Required scope: channel:read:charity
|
|
736
910
|
# broadcaster_id must match the currently authenticated user
|
|
737
911
|
@client.charity_campaigns.list broadcaster_id: 123
|
|
912
|
+
|
|
913
|
+
# Gets the donations made to the broadcaster's active charity campaign
|
|
914
|
+
# Required scope: channel:read:charity
|
|
915
|
+
# broadcaster_id must match the currently authenticated user
|
|
916
|
+
@client.charity_campaigns.donations(broadcaster_id: 123)
|
|
738
917
|
```
|
|
739
918
|
|
|
740
919
|
### Chatters
|
|
@@ -900,8 +1079,12 @@ outcomes = [
|
|
|
900
1079
|
# Check if a user is subscribed to a broadcaster
|
|
901
1080
|
# Required scope: user:read:subscriptions
|
|
902
1081
|
# user_id must match the currently authenticated user
|
|
1082
|
+
# Returns a collection with the subscription, or raises Twitch::Errors::EntityNotFoundError if not subscribed
|
|
903
1083
|
@client.subscriptions.is_subscribed(broadcaster_id: 123, user_id: 456)
|
|
904
1084
|
|
|
1085
|
+
# Or get true/false
|
|
1086
|
+
@client.subscriptions.subscribed?(broadcaster_id: 123, user_id: 456)
|
|
1087
|
+
|
|
905
1088
|
# Get subscription counts and points for a broadcaster
|
|
906
1089
|
# Required scope: channel:read:subscriptions
|
|
907
1090
|
# broadcaster_id must match the currently authenticated user
|
|
@@ -969,44 +1152,188 @@ outcomes = [
|
|
|
969
1152
|
@client.stream_markers.list(video_id: "video-id")
|
|
970
1153
|
```
|
|
971
1154
|
|
|
972
|
-
###
|
|
1155
|
+
### Hype Train Status
|
|
973
1156
|
|
|
974
1157
|
```ruby
|
|
975
|
-
# Get
|
|
976
|
-
|
|
1158
|
+
# Get hype train status for a broadcaster
|
|
1159
|
+
# Required scope: channel:read:hype_train
|
|
1160
|
+
# broadcaster_id must match the currently authenticated user
|
|
1161
|
+
@client.hype_train_status.retrieve(broadcaster_id: 123)
|
|
1162
|
+
```
|
|
977
1163
|
|
|
978
|
-
# Get stream tags for a specific broadcaster
|
|
979
|
-
@client.tags.stream(broadcaster_id: 123)
|
|
980
1164
|
|
|
981
|
-
|
|
982
|
-
|
|
1165
|
+
### Ads
|
|
1166
|
+
|
|
1167
|
+
```ruby
|
|
1168
|
+
# Gets the broadcaster's ad schedule and snooze details
|
|
1169
|
+
# Required scope: channel:read:ads
|
|
1170
|
+
# broadcaster_id must match the currently authenticated user
|
|
1171
|
+
@client.ads.schedule(broadcaster_id: 123)
|
|
1172
|
+
|
|
1173
|
+
# Pushes back the next scheduled ad by 5 minutes
|
|
1174
|
+
# Required scope: channel:manage:ads
|
|
983
1175
|
# broadcaster_id must match the currently authenticated user
|
|
984
|
-
|
|
985
|
-
@client.tags.replace(broadcaster_id: 123, tag_ids: tag_ids)
|
|
1176
|
+
@client.ads.snooze(broadcaster_id: 123)
|
|
986
1177
|
```
|
|
987
1178
|
|
|
988
|
-
###
|
|
1179
|
+
### Analytics
|
|
989
1180
|
|
|
990
1181
|
```ruby
|
|
991
|
-
#
|
|
992
|
-
# Required scope:
|
|
993
|
-
#
|
|
994
|
-
@client.
|
|
1182
|
+
# Gets URLs for downloadable CSV reports about the authenticated user's extensions
|
|
1183
|
+
# Required scope: analytics:read:extensions
|
|
1184
|
+
# Available parameters: extension_id, type, started_at, ended_at, first, after
|
|
1185
|
+
@client.analytics.extensions(extension_id: "abc123")
|
|
1186
|
+
|
|
1187
|
+
# Gets URLs for downloadable CSV reports about the authenticated user's games
|
|
1188
|
+
# Required scope: analytics:read:games
|
|
1189
|
+
# Available parameters: game_id, type, started_at, ended_at, first, after
|
|
1190
|
+
@client.analytics.games(game_id: 123)
|
|
995
1191
|
```
|
|
996
1192
|
|
|
997
|
-
###
|
|
1193
|
+
### Bits
|
|
998
1194
|
|
|
999
1195
|
```ruby
|
|
1000
|
-
#
|
|
1001
|
-
# Required scope:
|
|
1002
|
-
#
|
|
1003
|
-
@client.
|
|
1196
|
+
# Gets the Bits leaderboard for the authenticated broadcaster
|
|
1197
|
+
# Required scope: bits:read
|
|
1198
|
+
# Available parameters: count, period, started_at, user_id
|
|
1199
|
+
@client.bits.leaderboard(count: 10, period: "week")
|
|
1200
|
+
|
|
1201
|
+
# Gets the global Cheermotes, plus a broadcaster's custom Cheermotes if broadcaster_id is given
|
|
1202
|
+
@client.bits.cheermotes
|
|
1203
|
+
@client.bits.cheermotes(broadcaster_id: 123)
|
|
1204
|
+
```
|
|
1205
|
+
|
|
1206
|
+
### Chat Settings
|
|
1207
|
+
|
|
1208
|
+
```ruby
|
|
1209
|
+
# Gets a broadcaster's chat settings
|
|
1210
|
+
# Pass moderator_id (matching the authenticated user) to include non_moderator_chat_delay settings
|
|
1211
|
+
@client.chat_settings.retrieve(broadcaster_id: 123)
|
|
1212
|
+
@client.chat_settings.retrieve(broadcaster_id: 123, moderator_id: 321)
|
|
1213
|
+
|
|
1214
|
+
# Updates a broadcaster's chat settings
|
|
1215
|
+
# Required scope: moderator:manage:chat_settings
|
|
1216
|
+
# moderator_id must match the currently authenticated user
|
|
1217
|
+
# Available attributes: emote_mode, follower_mode, follower_mode_duration, non_moderator_chat_delay,
|
|
1218
|
+
# non_moderator_chat_delay_duration, slow_mode, slow_mode_wait_time, subscriber_mode, unique_chat_mode
|
|
1219
|
+
@client.chat_settings.update(broadcaster_id: 123, moderator_id: 321, slow_mode: true, slow_mode_wait_time: 10)
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1222
|
+
### Shield Mode
|
|
1223
|
+
|
|
1224
|
+
```ruby
|
|
1225
|
+
# Gets a broadcaster's Shield Mode status
|
|
1226
|
+
# Required scope: moderator:read:shield_mode or moderator:manage:shield_mode
|
|
1227
|
+
# moderator_id must match the currently authenticated user
|
|
1228
|
+
@client.shield_mode.retrieve(broadcaster_id: 123, moderator_id: 321)
|
|
1229
|
+
|
|
1230
|
+
# Turns Shield Mode on or off
|
|
1231
|
+
# Required scope: moderator:manage:shield_mode
|
|
1232
|
+
# moderator_id must match the currently authenticated user
|
|
1233
|
+
@client.shield_mode.update(broadcaster_id: 123, moderator_id: 321, is_active: true)
|
|
1234
|
+
```
|
|
1235
|
+
|
|
1236
|
+
### Content Classification Labels
|
|
1237
|
+
|
|
1238
|
+
```ruby
|
|
1239
|
+
# Gets the content classification labels that can be applied to a channel with channels.update
|
|
1240
|
+
@client.content_classification_labels.list
|
|
1241
|
+
@client.content_classification_labels.list(locale: "en-US")
|
|
1242
|
+
```
|
|
1243
|
+
|
|
1244
|
+
### Teams
|
|
1245
|
+
|
|
1246
|
+
```ruby
|
|
1247
|
+
# Gets a team by ID or name
|
|
1248
|
+
@client.teams.retrieve(id: 123)
|
|
1249
|
+
@client.teams.retrieve(name: "staff")
|
|
1250
|
+
|
|
1251
|
+
# Gets the teams a broadcaster is a member of
|
|
1252
|
+
@client.teams.channel(broadcaster_id: 123)
|
|
1253
|
+
```
|
|
1254
|
+
|
|
1255
|
+
### Drops Entitlements
|
|
1256
|
+
|
|
1257
|
+
```ruby
|
|
1258
|
+
# Gets Drops entitlements
|
|
1259
|
+
# The Client ID must be owned by a member of the organization that owns the game
|
|
1260
|
+
# Available parameters: id, user_id, game_id, fulfillment_status, first, after
|
|
1261
|
+
@client.drops_entitlements.list(user_id: 123)
|
|
1262
|
+
|
|
1263
|
+
# Updates the fulfillment status of Drops entitlements (CLAIMED or FULFILLED)
|
|
1264
|
+
@client.drops_entitlements.update(entitlement_ids: ["abc", "def"], fulfillment_status: "FULFILLED")
|
|
1265
|
+
```
|
|
1266
|
+
|
|
1267
|
+
### Extensions
|
|
1268
|
+
|
|
1269
|
+
Most Extensions endpoints require a signed JWT created by your Extension Backend Service rather than an
|
|
1270
|
+
OAuth token. Pass the JWT as the client's `access_token`. See
|
|
1271
|
+
[Signing the JWT](https://dev.twitch.tv/docs/extensions/building/#signing-the-jwt).
|
|
1272
|
+
|
|
1273
|
+
```ruby
|
|
1274
|
+
@ext_client = Twitch::Client.new(client_id: "extension-client-id", access_token: signed_jwt)
|
|
1275
|
+
|
|
1276
|
+
# Gets an extension (requires a JWT), or a released extension (app or user token)
|
|
1277
|
+
@ext_client.extensions.retrieve(extension_id: "abc123")
|
|
1278
|
+
@client.extensions.released(extension_id: "abc123", extension_version: "1.0.0")
|
|
1279
|
+
|
|
1280
|
+
# Gets live channels that have the extension installed or activated
|
|
1281
|
+
@client.extensions.live_channels(extension_id: "abc123")
|
|
1282
|
+
|
|
1283
|
+
# Gets and sets configuration segments (requires a JWT)
|
|
1284
|
+
# segment: broadcaster, developer or global. Pass an array to get more than one.
|
|
1285
|
+
@ext_client.extensions.configuration(extension_id: "abc123", segment: "broadcaster", broadcaster_id: 123)
|
|
1286
|
+
@ext_client.extensions.set_configuration(extension_id: "abc123", segment: "broadcaster", broadcaster_id: 123, content: "{}", version: "1")
|
|
1287
|
+
@ext_client.extensions.set_required_configuration(broadcaster_id: 123, extension_id: "abc123", extension_version: "1.0.0", required_configuration: "RCS")
|
|
1288
|
+
|
|
1289
|
+
# Sends a PubSub message or chat message (requires a JWT)
|
|
1290
|
+
@ext_client.extensions.send_pubsub_message(broadcaster_id: 123, target: ["broadcast"], message: "hello")
|
|
1291
|
+
@ext_client.extensions.send_chat_message(broadcaster_id: 123, text: "hello", extension_id: "abc123", extension_version: "1.0.0")
|
|
1292
|
+
|
|
1293
|
+
# Gets or creates the extension's JWT secrets (requires a JWT)
|
|
1294
|
+
@ext_client.extensions.secrets(extension_id: "abc123")
|
|
1295
|
+
@ext_client.extensions.create_secret(extension_id: "abc123", delay: 300)
|
|
1296
|
+
|
|
1297
|
+
# Gets and updates Bits products
|
|
1298
|
+
# Requires an app access token whose Client ID matches the extension's
|
|
1299
|
+
@app_client.extensions.bits_products(should_include_all: true)
|
|
1300
|
+
@app_client.extensions.update_bits_product(sku: "sku-1", cost: { amount: 100, type: "bits" }, display_name: "Thing")
|
|
1301
|
+
|
|
1302
|
+
# Gets Bits transactions for the extension
|
|
1303
|
+
# Requires an app access token
|
|
1304
|
+
@app_client.extensions.transactions(extension_id: "abc123")
|
|
1305
|
+
```
|
|
1306
|
+
|
|
1307
|
+
### Guest Star (Beta)
|
|
1308
|
+
|
|
1309
|
+
```ruby
|
|
1310
|
+
# Gets and updates a channel's Guest Star settings
|
|
1311
|
+
@client.guest_star.settings(broadcaster_id: 123, moderator_id: 321)
|
|
1312
|
+
@client.guest_star.update_settings(broadcaster_id: 123, slot_count: 4)
|
|
1313
|
+
|
|
1314
|
+
# Gets, creates and ends a Guest Star session
|
|
1315
|
+
@client.guest_star.session(broadcaster_id: 123, moderator_id: 321)
|
|
1316
|
+
@client.guest_star.create_session(broadcaster_id: 123)
|
|
1317
|
+
@client.guest_star.end_session(broadcaster_id: 123, session_id: "abc")
|
|
1318
|
+
|
|
1319
|
+
# Gets, sends and deletes invites
|
|
1320
|
+
@client.guest_star.invites(broadcaster_id: 123, moderator_id: 321, session_id: "abc")
|
|
1321
|
+
@client.guest_star.send_invite(broadcaster_id: 123, moderator_id: 321, session_id: "abc", guest_id: 456)
|
|
1322
|
+
@client.guest_star.delete_invite(broadcaster_id: 123, moderator_id: 321, session_id: "abc", guest_id: 456)
|
|
1323
|
+
|
|
1324
|
+
# Assigns, moves and removes guests in slots
|
|
1325
|
+
@client.guest_star.assign_slot(broadcaster_id: 123, moderator_id: 321, session_id: "abc", guest_id: 456, slot_id: "1")
|
|
1326
|
+
@client.guest_star.update_slot(broadcaster_id: 123, moderator_id: 321, session_id: "abc", source_slot_id: "1", destination_slot_id: "2")
|
|
1327
|
+
@client.guest_star.delete_slot(broadcaster_id: 123, moderator_id: 321, session_id: "abc", guest_id: 456, slot_id: "1")
|
|
1328
|
+
|
|
1329
|
+
# Updates a slot's audio, video, live and volume settings
|
|
1330
|
+
@client.guest_star.update_slot_settings(broadcaster_id: 123, moderator_id: 321, session_id: "abc", slot_id: "1", volume: 50)
|
|
1004
1331
|
```
|
|
1005
1332
|
|
|
1006
1333
|
|
|
1007
1334
|
## Contributing
|
|
1008
1335
|
|
|
1009
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
|
1336
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/d34ndev/twitchrb.
|
|
1010
1337
|
|
|
1011
1338
|
## License
|
|
1012
1339
|
|