twitch-api 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +130 -26
  3. data/lib/twitch/api_error.rb +5 -4
  4. data/lib/twitch/automod_message_status.rb +17 -0
  5. data/lib/twitch/bits_leader.rb +3 -1
  6. data/lib/twitch/category.rb +27 -0
  7. data/lib/twitch/channel.rb +46 -0
  8. data/lib/twitch/cheermote.rb +53 -0
  9. data/lib/twitch/cheermote_tier.rb +55 -0
  10. data/lib/twitch/cheermote_tier_image.rb +18 -0
  11. data/lib/twitch/cheermote_tier_images.rb +21 -0
  12. data/lib/twitch/client/custom_rewards.rb +35 -0
  13. data/lib/twitch/client/extensions.rb +20 -0
  14. data/lib/twitch/client/games.rb +20 -0
  15. data/lib/twitch/client/moderation.rb +28 -0
  16. data/lib/twitch/client/streams.rb +29 -0
  17. data/lib/twitch/client/subscriptions.rb +12 -0
  18. data/lib/twitch/client/users.rb +20 -0
  19. data/lib/twitch/client.rb +127 -100
  20. data/lib/twitch/clip.rb +5 -11
  21. data/lib/twitch/custom_reward.rb +91 -0
  22. data/lib/twitch/editor.rb +21 -0
  23. data/lib/twitch/entitlement_grant_url.rb +3 -2
  24. data/lib/twitch/extension.rb +37 -0
  25. data/lib/twitch/extensions_by_types.rb +32 -0
  26. data/lib/twitch/game.rb +4 -2
  27. data/lib/twitch/game_analytic.rb +4 -2
  28. data/lib/twitch/moderation_event.rb +33 -0
  29. data/lib/twitch/moderator.rb +20 -0
  30. data/lib/twitch/redemption.rb +35 -0
  31. data/lib/twitch/response.rb +42 -19
  32. data/lib/twitch/stream.rb +9 -11
  33. data/lib/twitch/stream_marker.rb +7 -8
  34. data/lib/twitch/stream_metadata.rb +27 -16
  35. data/lib/twitch/subscription.rb +28 -0
  36. data/lib/twitch/user.rb +8 -3
  37. data/lib/twitch/user_ban.rb +26 -0
  38. data/lib/twitch/user_follow.rb +4 -2
  39. data/lib/twitch/version.rb +3 -1
  40. data/lib/twitch/video.rb +7 -13
  41. data/lib/twitch-api.rb +3 -4
  42. metadata +57 -75
  43. data/.gitignore +0 -17
  44. data/.rspec +0 -3
  45. data/.travis.yml +0 -9
  46. data/Gemfile +0 -6
  47. data/Rakefile +0 -6
  48. data/bin/console +0 -14
  49. data/bin/setup +0 -8
  50. data/twitch-api.gemspec +0 -32
data/lib/twitch/client.rb CHANGED
@@ -1,149 +1,176 @@
1
- require "faraday"
2
- require "faraday_middleware"
3
-
4
- require "twitch/response"
5
- require "twitch/api_error"
6
- require "twitch/bits_leader"
7
- require "twitch/clip"
8
- require "twitch/entitlement_grant_url"
9
- require "twitch/game"
10
- require "twitch/game_analytic"
11
- require "twitch/stream"
12
- require "twitch/stream_marker"
13
- require "twitch/stream_metadata"
14
- require "twitch/user"
15
- require "twitch/user_follow"
16
- require "twitch/video"
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'faraday/parse_dates'
5
+ require 'faraday/retry'
6
+ require 'twitch_oauth2'
7
+
8
+ require_relative 'response'
9
+
10
+ require_relative 'api_error'
11
+ require_relative 'bits_leader'
12
+ require_relative 'category'
13
+ require_relative 'channel'
14
+ require_relative 'cheermote'
15
+ require_relative 'clip'
16
+ require_relative 'custom_reward'
17
+ require_relative 'editor'
18
+ require_relative 'entitlement_grant_url'
19
+ require_relative 'extension'
20
+ require_relative 'extensions_by_types'
21
+ require_relative 'game'
22
+ require_relative 'game_analytic'
23
+ require_relative 'moderation_event'
24
+ require_relative 'moderator'
25
+ require_relative 'stream'
26
+ require_relative 'stream_marker'
27
+ require_relative 'stream_metadata'
28
+ require_relative 'subscription'
29
+ require_relative 'user'
30
+ require_relative 'user_ban'
31
+ require_relative 'user_follow'
32
+ require_relative 'redemption'
33
+ require_relative 'video'
17
34
 
18
35
  module Twitch
36
+ # Core class for requests
19
37
  class Client
20
- # Helix API endpoint.
21
- API_ENDPOINT = "https://api.twitch.tv/helix".freeze
38
+ # Base connection to Helix API.
39
+ CONNECTION = Faraday.new(
40
+ 'https://api.twitch.tv/helix', {
41
+ headers: { 'User-Agent': "twitch-api ruby client #{Twitch::VERSION}" }
42
+ }
43
+ ) do |faraday|
44
+ faraday.request :retry,
45
+ exceptions: [*Faraday::Retry::Middleware::DEFAULT_EXCEPTIONS, Faraday::ConnectionFailed]
46
+
47
+ faraday.response :parse_dates
48
+
49
+ faraday.request :json
50
+ faraday.response :json
51
+ end
52
+
53
+ attr_reader :tokens
22
54
 
23
55
  # Initializes a Twitch client.
24
- #
25
- # - client_id [String] The client ID.
26
- # Used as the Client-ID header in a request.
27
- # - access_token [String] An access token.
28
- # Used as the Authorization header in a request.
29
- # Any "Bearer " prefix will be stripped.
30
- # - with_raw [Boolean] Whether to include raw HTTP response
31
- # Intended for testing/checking API results
32
- def initialize(client_id: nil, access_token: nil, with_raw: false)
33
- if client_id.nil? && access_token.nil?
34
- raise "An identifier token (client ID or bearer token) is required"
35
- elsif !!client_id && !!access_token
36
- warn(%{WARNING:
37
- It is recommended that only one identifier token is specified.
38
- Unpredictable behavior may follow.})
39
- end
56
+ #
57
+ # - tokens [TwitchOAuth2::Tokens] Tokens object with their refreshing logic inside.
58
+ # All client and authentication information (`client_id`, `:scopes`, etc.) stores there.
59
+ def initialize(tokens:)
60
+ @tokens = tokens
40
61
 
41
- headers = {
42
- "User-Agent": "twitch-api ruby client #{Twitch::VERSION}"
43
- }
44
- unless client_id.nil?
45
- headers["Client-ID"] = client_id
46
- end
47
- unless access_token.nil?
48
- access_token = access_token.gsub(/^Bearer /, "")
49
- headers["Authorization"] = "Bearer #{access_token}"
50
- end
51
-
52
- @conn = Faraday.new(API_ENDPOINT, { headers: headers }) do |faraday|
53
- faraday.request :json
54
- faraday.response :json
55
- faraday.adapter Faraday.default_adapter
56
- end
62
+ CONNECTION.headers['Client-ID'] = self.tokens.client.client_id
57
63
 
58
- @with_raw = with_raw
64
+ renew_authorization_header
59
65
  end
60
66
 
61
67
  def create_clip(options = {})
62
- Response.new(Clip, post('clips', options))
68
+ initialize_response Clip, post('clips', options)
63
69
  end
64
70
 
65
71
  def create_entitlement_grant_url(options = {})
66
- Response.new(EntitlementGrantUrl, post('entitlements/upload', options))
67
- end
68
-
69
- def create_stream_marker(options = {})
70
- Response.new(StreamMarker, post('streams/markers', options))
72
+ initialize_response EntitlementGrantUrl, post('entitlements/upload', options)
71
73
  end
72
74
 
73
75
  def get_clips(options = {})
74
- Response.new(Clip, get('clips', options))
76
+ initialize_response Clip, get('clips', options)
75
77
  end
76
78
 
77
79
  def get_bits_leaderboard(options = {})
78
- Response.new(BitsLeader, get('bits/leaderboard', options))
80
+ initialize_response BitsLeader, get('bits/leaderboard', options)
79
81
  end
80
82
 
81
- def get_games(options = {})
82
- Response.new(Game, get('games', options))
83
+ def get_cheermotes(options = {})
84
+ initialize_response Cheermote, get('bits/cheermotes', options)
83
85
  end
84
86
 
85
- def get_top_games(options = {})
86
- Response.new(Game, get('games/top', options))
87
- end
87
+ require_relative 'client/extensions'
88
+ include Extensions
88
89
 
89
- def get_game_analytics(options = {})
90
- Response.new(GameAnalytic, get('analytics/games', options))
91
- end
90
+ require_relative 'client/games'
91
+ include Games
92
+
93
+ require_relative 'client/moderation'
94
+ include Moderation
95
+
96
+ require_relative 'client/streams'
97
+ include Streams
92
98
 
93
- def get_stream_markers(options = {})
94
- Response.new(StreamMarkerResponse, get('streams/markers', options))
99
+ require_relative 'client/subscriptions'
100
+ include Subscriptions
101
+
102
+ def get_videos(options = {})
103
+ initialize_response Video, get('videos', options)
95
104
  end
96
105
 
97
- def get_streams(options = {})
98
- Response.new(Stream, get('streams', options))
106
+ require_relative 'client/users'
107
+ include Users
108
+
109
+ require_relative 'client/custom_rewards'
110
+ include CustomRewards
111
+
112
+ ## https://dev.twitch.tv/docs/api/reference#get-channel-information
113
+ def get_channels(options = {})
114
+ initialize_response Channel, get('channels', options)
99
115
  end
100
116
 
101
- def get_streams_metadata(options = {})
102
- Response.new(StreamMetadata, get('streams/metadata', options))
117
+ ## https://dev.twitch.tv/docs/api/reference/#search-channels
118
+ def search_channels(options = {})
119
+ initialize_response Channel, get('search/channels', options)
103
120
  end
104
121
 
105
- def get_users_follows(options = {})
106
- Response.new(UserFollow, get('users/follows', options))
122
+ ## https://dev.twitch.tv/docs/api/reference#modify-channel-information
123
+ def modify_channel(options = {})
124
+ response = patch('channels', options)
125
+
126
+ return true if response.body.empty?
127
+
128
+ response.body
107
129
  end
108
130
 
109
- def get_users(options = {})
110
- Response.new(User, get('users', options))
131
+ ## https://dev.twitch.tv/docs/api/reference/#start-commercial
132
+ def start_commercial(options = {})
133
+ initialize_response nil, post('channels/commercial', options)
111
134
  end
112
135
 
113
- def update_user(options = {})
114
- Response.new(User, put('users', options))
136
+ ## https://dev.twitch.tv/docs/api/reference/#get-channel-editors
137
+ def get_channel_editors(options = {})
138
+ initialize_response Editor, get('channels/editors', options)
115
139
  end
116
140
 
117
- def get_videos(options = {})
118
- Response.new(Video, get('videos', options))
141
+ ## https://dev.twitch.tv/docs/api/reference/#search-categories
142
+ def search_categories(options = {})
143
+ initialize_response Category, get('search/categories', options)
119
144
  end
120
145
 
121
146
  private
122
147
 
123
- def get(resource, params)
124
- http_res = @conn.get(resource, params)
125
- finish(http_res)
126
- end
148
+ def initialize_response(data_class, http_response)
149
+ Response.new(data_class, http_response: http_response)
150
+ end
127
151
 
128
- def post(resource, params)
129
- http_res = @conn.post(resource, params)
130
- finish(http_res)
152
+ %w[get post put patch].each do |http_method|
153
+ define_method http_method do |resource, params|
154
+ request http_method, resource, params
131
155
  end
156
+ end
132
157
 
133
- def put(resource, params)
134
- http_res = @conn.put(resource, params)
135
- finish(http_res)
136
- end
158
+ def renew_authorization_header
159
+ CONNECTION.headers['Authorization'] = "Bearer #{tokens.access_token}"
160
+ end
137
161
 
138
- def finish(http_res)
139
- unless http_res.success?
140
- raise ApiError.new(http_res.status, http_res.body)
141
- end
162
+ def request(http_method, resource, params)
163
+ http_response = CONNECTION.public_send http_method, resource, params
142
164
 
143
- {
144
- http_res: http_res,
145
- with_raw: @with_raw
146
- }
165
+ if http_response.status == 401
166
+ renew_authorization_header
167
+
168
+ http_response = CONNECTION.public_send http_method, resource, params
147
169
  end
170
+
171
+ return http_response if http_response.success?
172
+
173
+ raise APIError.new(http_response.status, http_response.body)
174
+ end
148
175
  end
149
176
  end
data/lib/twitch/clip.rb CHANGED
@@ -1,9 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Twitch
2
4
  # A small segment of a broadcast captured by another user.
3
5
  class Clip
4
- # Fields to be converted from ISO 8601 string to a typed date.
5
- DATE_ATTRIBUTES = [:created_at]
6
-
7
6
  # ID of the clip.
8
7
  attr_reader :id
9
8
  # Title of the clip.
@@ -34,14 +33,9 @@ module Twitch
34
33
  attr_reader :video_id
35
34
 
36
35
  def initialize(attributes = {})
37
- attributes.each do |k, v|
38
- if DATE_ATTRIBUTES.include?(k.to_sym)
39
- instance_variable_set("@#{k}", Time.parse(v))
40
- else
41
- instance_variable_set("@#{k}", v)
42
- end
36
+ attributes.each do |key, value|
37
+ instance_variable_set "@#{key}", value
43
38
  end
44
39
  end
45
-
46
40
  end
47
- end
41
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ ## Data object for Twitch custom rewards
5
+ class CustomReward
6
+ ## Data object for images of Twitch custom rewards
7
+ class CustomRewardImage
8
+ # The URL to a small version of the image.
9
+ attr_reader :url_1x
10
+ # The URL to a medium version of the image.
11
+ attr_reader :url_2x
12
+ # The URL to a large version of the image.
13
+ attr_reader :url_4x
14
+
15
+ def initialize(attributes = {})
16
+ attributes.each do |key, value|
17
+ instance_variable_set "@#{key}", value
18
+ end
19
+ end
20
+ end
21
+
22
+ # The ID that uniquely identifies the broadcaster.
23
+ attr_reader :broadcaster_id
24
+ # The broadcaster’s login name.
25
+ attr_reader :broadcaster_login
26
+ # The broadcaster’s display name.
27
+ attr_reader :broadcaster_name
28
+ # The ID that uniquely identifies this custom reward.
29
+ attr_reader :id
30
+ # The title of the reward.
31
+ attr_reader :title
32
+ # The prompt shown to the viewer when they redeem the reward if user input is required
33
+ # (see the `is_user_input_required` field).
34
+ attr_reader :prompt
35
+ # The cost of the reward in Channel Points.
36
+ attr_reader :cost
37
+ # A set of custom images for the reward.
38
+ # This field is `nil` if the broadcaster didn’t upload images.
39
+ attr_reader :image
40
+ # A set of default images for the reward.
41
+ attr_reader :default_image
42
+ # The background color to use for the reward.
43
+ # The color is in Hex format (for example, `#00E5CB`).
44
+ attr_reader :background_color
45
+ # A Boolean value that determines whether the reward is enabled.
46
+ # Is `true` if enabled; otherwise, `false`. Disabled rewards aren’t shown to the user.
47
+ attr_reader :is_enabled
48
+ # A Boolean value that determines whether the user must enter information
49
+ # when redeeming the reward. Is `true` if the user is prompted.
50
+ attr_reader :is_user_input_required
51
+ # The settings used to determine whether to apply a maximum to the number of redemptions
52
+ # allowed per live stream.
53
+ attr_reader :max_per_stream_setting
54
+ # The settings used to determine whether to apply a maximum to the number of redemptions
55
+ # allowed per user per live stream.
56
+ attr_reader :max_per_user_per_stream_setting
57
+ # The settings used to determine whether to apply a cooldown period between redemptions
58
+ # and the length of the cooldown.
59
+ attr_reader :global_cooldown_setting
60
+ # A Boolean value that determines whether the reward is currently paused.
61
+ # Is `true` if the reward is paused. Viewers can’t redeem paused rewards.
62
+ attr_reader :is_paused
63
+ # A Boolean value that determines whether the reward is currently in stock.
64
+ # Is `true` if the reward is in stock. Viewers can’t redeem out of stock rewards.
65
+ attr_reader :is_in_stock
66
+ # A Boolean value that determines whether redemptions should be set to FULFILLED status
67
+ # immediately when a reward is redeemed. If `false`, status is set to UNFULFILLED
68
+ # and follows the normal request queue process.
69
+ attr_reader :should_redemptions_skip_request_queue
70
+ # The number of redemptions redeemed during the current live stream.
71
+ # The number counts against the `max_per_stream_setting` limit.
72
+ # This field is `nil` if the broadcaster’s stream isn’t live
73
+ # or `max_per_stream_setting` isn’t enabled.
74
+ attr_reader :redemptions_redeemed_current_stream
75
+ # The timestamp of when the cooldown period expires.
76
+ # Is `nil` if the reward isn’t in a cooldown state.
77
+ # See the `global_cooldown_setting` field.
78
+ attr_reader :cooldown_expires_at
79
+
80
+ IMAGE_ATTRS = %w[image default_image].freeze
81
+ private_constant :IMAGE_ATTRS
82
+
83
+ def initialize(attributes = {})
84
+ attributes.each do |key, value|
85
+ value = CustomRewardImage.new(value) if IMAGE_ATTRS.include?(key) && !value.nil?
86
+
87
+ instance_variable_set "@#{key}", value
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ ## A user who can edit broadcast content, settings, etc.
5
+ class Editor
6
+ ## An ID that uniquely identifies a user with editor permissions.
7
+ attr_reader :user_id
8
+
9
+ ## The user’s display name.
10
+ attr_reader :user_name
11
+
12
+ ## The date and time when the user became one of the broadcaster’s editors.
13
+ attr_reader :created_at
14
+
15
+ def initialize(attributes = {})
16
+ attributes.each do |key, value|
17
+ instance_variable_set "@#{key}", value
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Twitch
2
4
  # A URL that can be used to notify users of an entitlement.
3
5
  class EntitlementGrantUrl
@@ -8,6 +10,5 @@ module Twitch
8
10
  def initialize(attributes = {})
9
11
  @url = attributes['url']
10
12
  end
11
-
12
13
  end
13
- end
14
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ # A feature used to augment dynamic information on a stream.
5
+ class Extension
6
+ # ID of the extension.
7
+ attr_reader :id
8
+ # Version number of the extension.
9
+ attr_reader :version
10
+ # Name of the extension.
11
+ attr_reader :name
12
+ # Whether the extension is configured such that it can be activated.
13
+ attr_reader :can_activate
14
+ # The extension types that you can activate for this extension. Possible values are:
15
+ # `component`, `mobile`, `overlay`, `panel`
16
+ attr_reader :type
17
+
18
+ # Optional attributes for extensions from `get` methods results
19
+
20
+ # A Boolean value that determines the extension’s activation state.
21
+ # If false, the user has not configured this component extension.
22
+ attr_reader :active
23
+
24
+ # Optional attributes for extensions with `component` type
25
+
26
+ # The x-coordinate where the extension is placed.
27
+ attr_reader :x
28
+ # The y-coordinate where the extension is placed.
29
+ attr_reader :y
30
+
31
+ def initialize(attributes = {})
32
+ attributes.each do |key, value|
33
+ instance_variable_set "@#{key}", value
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ # A dictionary (Hash) of Extensions by their types and placements
5
+ class ExtensionsByTypes
6
+ # A dictionary that contains the data for a panel extension.
7
+ # The dictionary’s key is a sequential number beginning with 1.
8
+ # The following fields contain the panel’s data for each key.
9
+ attr_reader :panel
10
+
11
+ # A dictionary that contains the data for a video-overlay extension.
12
+ # The dictionary’s key is a sequential number beginning with 1.
13
+ # The following fields contain the overlay’s data for each key.
14
+ attr_reader :overlay
15
+
16
+ # A dictionary that contains the data for a video-component extension.
17
+ # The dictionary’s key is a sequential number beginning with 1.
18
+ # The following fields contain the component’s data for each key.
19
+ attr_reader :component
20
+
21
+ def initialize(attributes = {})
22
+ %w[panel overlay component].each do |type|
23
+ instance_variable_set(
24
+ "@#{type}",
25
+ attributes[type].transform_values do |extension_data|
26
+ Extension.new(extension_data)
27
+ end
28
+ )
29
+ end
30
+ end
31
+ end
32
+ end
data/lib/twitch/game.rb CHANGED
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Twitch
2
- # A filterable category for a stream.
4
+ # A filterable category for a stream.
3
5
  # (not necessarily limited to games, e.g. 'IRL')
4
6
  class Game
5
7
  # ID of the game.
@@ -8,7 +10,7 @@ module Twitch
8
10
  attr_reader :name
9
11
  # Box art URL template.
10
12
  #
11
- # Substitute the {width} and {height} string tokens
13
+ # Substitute the {width} and {height} string tokens
12
14
  # with your desired numeric values.
13
15
  attr_reader :box_art_url
14
16
 
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Twitch
2
- # A
4
+ # Data object for `/analytics/games` requests
3
5
  class GameAnalytic
4
6
  # ID of the game requested.
5
7
  attr_reader :game_id
@@ -11,4 +13,4 @@ module Twitch
11
13
  @url = attributes['URL']
12
14
  end
13
15
  end
14
- end
16
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ # Information about a moderation action.
5
+ # The action is determined based on the `event_type` field.
6
+ class ModerationEvent
7
+ # Fields to be converted from ISO 8601 string to a typed date.
8
+ DATE_ATTRIBUTES = %i[event_timestamp].freeze
9
+
10
+ # ID of the moderation event.
11
+ attr_reader :id
12
+ # Event type.
13
+ # The `moderation.user` prefix is for user bans and unbans in a channel.
14
+ # The `moderation.moderator` prefix is for addition and removal of moderators in a channel.
15
+ attr_reader :event_type
16
+ # Time at which the event happened.
17
+ attr_reader :event_timestamp
18
+ # Version of the endpoint the data was retrieved from.
19
+ attr_reader :version
20
+ # A hash containing information about the moderation action.
21
+ attr_reader :event_data
22
+
23
+ def initialize(attributes = {})
24
+ attributes.each do |key, value|
25
+ if DATE_ATTRIBUTES.include?(key.to_sym)
26
+ instance_variable_set "@#{key}", Time.parse(value)
27
+ else
28
+ instance_variable_set "@#{key}", value
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ # A user who wields some form of power in a broadcaster's Twitch chat.
5
+ # This is simply a user ID/name pair.
6
+ class Moderator
7
+ # User ID of the moderator.
8
+ attr_reader :user_id
9
+ # The user’s login name.
10
+ attr_reader :user_login
11
+ # The user’s display name.
12
+ attr_reader :user_name
13
+
14
+ def initialize(attributes = {})
15
+ attributes.each do |key, value|
16
+ instance_variable_set "@#{key}", value
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ # Data object for Twitch users
5
+ class Redemption
6
+ # ID of the broadcaster.
7
+ attr_reader :broadcaster_id
8
+ # Unformatted (lowercase) username of thebroadcaster.
9
+ attr_reader :broadcaster_login
10
+ # Formatted username of the broadcaster.
11
+ attr_reader :broadcaster_display_name
12
+ # ID of the redemption.
13
+ attr_reader :id
14
+ # ID of the user.
15
+ attr_reader :user_id
16
+ # Unformatted (lowercase) username of the user.
17
+ attr_reader :user_login
18
+ # Formatted username of the user.
19
+ attr_reader :user_name
20
+ # The associated reward being redeemed
21
+ attr_reader :reward
22
+ # The user input (e.g. text) if allowed by the reward
23
+ attr_reader :user_input
24
+ # The status of the redemption's fulfillment
25
+ attr_reader :status
26
+ # The timestamp of the redemption
27
+ attr_reader :redeemed_at
28
+
29
+ def initialize(attributes = {})
30
+ attributes.each do |key, value|
31
+ instance_variable_set "@#{key}", value
32
+ end
33
+ end
34
+ end
35
+ end