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.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +373 -46
  5. data/lib/twitch/client.rb +109 -20
  6. data/lib/twitch/collection.rb +54 -8
  7. data/lib/twitch/eventsub_webhook.rb +140 -0
  8. data/lib/twitch/oauth.rb +51 -14
  9. data/lib/twitch/object.rb +93 -14
  10. data/lib/twitch/objects/ad_schedule.rb +4 -0
  11. data/lib/twitch/objects/analytics_report.rb +4 -0
  12. data/lib/twitch/objects/bits_leaderboard_entry.rb +4 -0
  13. data/lib/twitch/objects/charity_donation.rb +4 -0
  14. data/lib/twitch/objects/chat_settings.rb +4 -0
  15. data/lib/twitch/objects/cheermote.rb +4 -0
  16. data/lib/twitch/objects/content_classification_label.rb +4 -0
  17. data/lib/twitch/objects/drops_entitlement.rb +4 -0
  18. data/lib/twitch/objects/drops_entitlement_update.rb +4 -0
  19. data/lib/twitch/objects/extension.rb +4 -0
  20. data/lib/twitch/objects/extension_bits_product.rb +4 -0
  21. data/lib/twitch/objects/extension_configuration_segment.rb +4 -0
  22. data/lib/twitch/objects/extension_live_channel.rb +4 -0
  23. data/lib/twitch/objects/extension_secret.rb +4 -0
  24. data/lib/twitch/objects/extension_transaction.rb +4 -0
  25. data/lib/twitch/objects/guest_star_invite.rb +4 -0
  26. data/lib/twitch/objects/guest_star_session.rb +4 -0
  27. data/lib/twitch/objects/guest_star_settings.rb +4 -0
  28. data/lib/twitch/objects/shield_mode_status.rb +4 -0
  29. data/lib/twitch/objects/{tag.rb → team.rb} +1 -1
  30. data/lib/twitch/objects/user_active_extensions.rb +4 -0
  31. data/lib/twitch/objects/user_extension.rb +4 -0
  32. data/lib/twitch/resource.rb +29 -0
  33. data/lib/twitch/resources/ads.rb +18 -0
  34. data/lib/twitch/resources/analytics.rb +19 -0
  35. data/lib/twitch/resources/announcements.rb +1 -1
  36. data/lib/twitch/resources/automod.rb +7 -7
  37. data/lib/twitch/resources/badges.rb +2 -2
  38. data/lib/twitch/resources/banned_users.rb +3 -3
  39. data/lib/twitch/resources/bits.rb +16 -0
  40. data/lib/twitch/resources/blocked_terms.rb +3 -3
  41. data/lib/twitch/resources/channels.rb +4 -4
  42. data/lib/twitch/resources/charity_campaigns.rb +8 -0
  43. data/lib/twitch/resources/chat_settings.rb +20 -0
  44. data/lib/twitch/resources/chatters.rb +1 -1
  45. data/lib/twitch/resources/clips.rb +3 -9
  46. data/lib/twitch/resources/content_classification_labels.rb +8 -0
  47. data/lib/twitch/resources/custom_power_ups.rb +1 -1
  48. data/lib/twitch/resources/custom_reward_redemptions.rb +3 -4
  49. data/lib/twitch/resources/custom_rewards.rb +5 -5
  50. data/lib/twitch/resources/drops_entitlements.rb +17 -0
  51. data/lib/twitch/resources/emotes.rb +3 -3
  52. data/lib/twitch/resources/eventsub_conduits.rb +14 -4
  53. data/lib/twitch/resources/eventsub_subscriptions.rb +1 -1
  54. data/lib/twitch/resources/extensions.rb +99 -0
  55. data/lib/twitch/resources/games.rb +3 -3
  56. data/lib/twitch/resources/goals.rb +1 -1
  57. data/lib/twitch/resources/guest_star.rb +102 -0
  58. data/lib/twitch/resources/moderators.rb +3 -3
  59. data/lib/twitch/resources/pinned_chat_messages.rb +4 -11
  60. data/lib/twitch/resources/polls.rb +1 -1
  61. data/lib/twitch/resources/predictions.rb +1 -1
  62. data/lib/twitch/resources/raids.rb +2 -3
  63. data/lib/twitch/resources/search.rb +2 -2
  64. data/lib/twitch/resources/shield_mode.rb +18 -0
  65. data/lib/twitch/resources/shoutouts.rb +1 -1
  66. data/lib/twitch/resources/stream_markers.rb +1 -1
  67. data/lib/twitch/resources/stream_schedule.rb +4 -5
  68. data/lib/twitch/resources/streams.rb +2 -2
  69. data/lib/twitch/resources/subscriptions.rb +13 -2
  70. data/lib/twitch/resources/suspicious_users.rb +1 -1
  71. data/lib/twitch/resources/teams.rb +20 -0
  72. data/lib/twitch/resources/unban_requests.rb +2 -2
  73. data/lib/twitch/resources/users.rb +30 -34
  74. data/lib/twitch/resources/videos.rb +2 -2
  75. data/lib/twitch/resources/vips.rb +2 -2
  76. data/lib/twitch/resources/warnings.rb +2 -2
  77. data/lib/twitch/resources/whispers.rb +1 -1
  78. data/lib/twitch/version.rb +1 -1
  79. data/lib/twitch.rb +33 -10
  80. metadata +42 -46
  81. data/.env.example +0 -3
  82. data/.github/FUNDING.yml +0 -5
  83. data/.github/dependabot.yml +0 -11
  84. data/.github/workflows/ci.yml +0 -39
  85. data/.gitignore +0 -9
  86. data/.rubocop.yml +0 -16
  87. data/Gemfile +0 -13
  88. data/Gemfile.lock +0 -144
  89. data/Rakefile +0 -10
  90. data/bin/console +0 -23
  91. data/bin/setup +0 -8
  92. data/bin/smoke +0 -118
  93. data/lib/twitch/objects/banned_event.rb +0 -4
  94. data/lib/twitch/objects/followed_user.rb +0 -4
  95. data/lib/twitch/objects/hype_train_event.rb +0 -4
  96. data/lib/twitch/objects/moderator_event.rb +0 -4
  97. data/lib/twitch/resources/banned_events.rb +0 -8
  98. data/lib/twitch/resources/hype_train_events.rb +0 -10
  99. data/lib/twitch/resources/moderator_events.rb +0 -9
  100. data/lib/twitch/resources/tags.rb +0 -18
  101. data/mise.toml +0 -2
  102. data/twitchrb.gemspec +0 -29
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TwitchRB
2
2
 
3
- [![CI](https://github.com/deanpcmad/twitchrb/actions/workflows/ci.yml/badge.svg)](https://github.com/deanpcmad/twitchrb/actions/workflows/ci.yml)
3
+ [![CI](https://github.com/d34ndev/twitchrb/actions/workflows/ci.yml/badge.svg)](https://github.com/d34ndev/twitchrb/actions/workflows/ci.yml)
4
4
  [![Gem Version](https://badge.fury.io/rb/twitchrb.svg)](https://badge.fury.io/rb/twitchrb)
5
5
  [![Downloads](https://img.shields.io/gem/dt/twitchrb.svg)](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 (sending chat, managing channels, etc.).
67
+ and required for anything that acts on behalf of a user (managing channels, polls, rewards, etc.).
35
68
 
36
- Some endpoints require an **app access token** instead — issued to your application, not a user. These
37
- are the EventSub APIs (subscriptions over webhooks, conduits, and shards), plus a few others noted in
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. They're built using OpenStruct so you can easily access data in a Ruby-ish way.
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 a Token
178
- # grant_type can be either "authorization_code" or "client_credentials"
179
- # scope is a space-delimited list of scopes. This is optional depending on the grant_type
180
- @oauth.create(grant_type: "", scope: "")
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
- ### Banned Events
491
-
492
- ```ruby
493
- # Retrieves all ban and un-ban events for a channel
494
- # Available parameters: user_id
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
- ### Tags
1155
+ ### Hype Train Status
973
1156
 
974
1157
  ```ruby
975
- # Get all stream tags
976
- @client.tags.list
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
- # Replace stream tags for a broadcaster
982
- # Required scope: channel:manage:broadcast
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
- tag_ids = ["tag-id-1", "tag-id-2"]
985
- @client.tags.replace(broadcaster_id: 123, tag_ids: tag_ids)
1176
+ @client.ads.snooze(broadcaster_id: 123)
986
1177
  ```
987
1178
 
988
- ### Hype Train Status
1179
+ ### Analytics
989
1180
 
990
1181
  ```ruby
991
- # Get hype train status for a broadcaster
992
- # Required scope: channel:read:hype_train
993
- # broadcaster_id must match the currently authenticated user
994
- @client.hype_train_status.retrieve(broadcaster_id: 123)
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
- ### Moderator Events
1193
+ ### Bits
998
1194
 
999
1195
  ```ruby
1000
- # Get moderator events for a broadcaster
1001
- # Required scope: moderation:read
1002
- # broadcaster_id must match the currently authenticated user
1003
- @client.moderator_events.list(broadcaster_id: 123)
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/deanpcmad/twitchrb.
1336
+ Bug reports and pull requests are welcome on GitHub at https://github.com/d34ndev/twitchrb.
1010
1337
 
1011
1338
  ## License
1012
1339