twitch-api 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb54134c100870a945316675e056f7c32c0cd67ea354d19bfba277d7a1660fb1
4
- data.tar.gz: 4fa7aff219b7993eb679d7444e7ebd35d309923d3ffcc52daa5d3130ec2ce6b7
3
+ metadata.gz: 496abaceb2ef84dbd33eee192a05daf8270d9c77c373ba6beadaf915bb1cf426
4
+ data.tar.gz: 66a591c5e4c176fab22c198b907020a31dffd2499c7d95cada41e0cd53feb7f1
5
5
  SHA512:
6
- metadata.gz: 8a8429635b999c142b06996ed11ff36d35b10dac4ed68d255bd6eefd9341e3360f13e3d8c1b8ce8ac303efccde1ff48fdba9f613396971ffeef7129b28af8680
7
- data.tar.gz: 51b75f09e9df2d67045e0c9b8e32f707425156641066789b6544e8384cc2b20cc532a274c698a30b5e2ae5e49f2269f5b920b67e58676642fdbf6705db9a2488
6
+ metadata.gz: c9a8bc3775456383bfa0162aff51fc62d35374dcd8fe355b46ec3fb0fe5733fe0164319a3fc1fd0487df2043aae49a8d5e9976f01bddc59572ea6a3e24028c9f
7
+ data.tar.gz: b5498b3112dfb9d61a64f04780a46d3aa895ba827b38074739f1b7c4dbdc31d9f4b1687c1c277e3b131a556f9848df65ff47193d7582f08af13fcf0f8e25b34b
data/README.md CHANGED
@@ -1,14 +1,31 @@
1
- # Ruby Twitch API (work in progress)
1
+ # Ruby Twitch API
2
2
 
3
3
  This library is a Ruby implementation of the [Twitch Helix API](https://dev.twitch.tv/docs/api).
4
4
 
5
+ The goal is to provide access for the newest supported APIs provided by Twitch, while keeping extensiblity for their future expansion. These are still in development, as is this library which should remain in pace with changes made.
6
+
7
+ Guaranteed supported APIs include:
8
+ * Helix REST (full rolling support)
9
+ * Helix Webhooks (coming soon)
10
+
11
+ The future may bring:
12
+ * PubSub
13
+ * TMI/chat
14
+
15
+ These will not be considered:
16
+ * Twitch kraken API
17
+ * [Twitch GraphQL API](https://github.com/mauricew/twitch-graphql-api)
18
+
5
19
  ## Installation
6
- Ruby 2.1 or later is required.
20
+ Ruby 2.1 or later compatibility is guaranteed, however the target is 2.0 and above.
7
21
 
8
- Add this line to your application's Gemfile:
22
+ Add to your application's Gemfile:
9
23
 
10
24
  ```ruby
25
+ # If you want a full release
11
26
  gem 'twitch-api'
27
+ # If you want to live on the edge
28
+ gem 'twitch-api', :git => 'https://github.com/mauricew/ruby-twitch-api'
12
29
  ```
13
30
 
14
31
  And then execute:
@@ -20,14 +37,16 @@ Or install it yourself as:
20
37
  $ gem install twitch-api
21
38
 
22
39
  ## Usage
23
- A client must be initialized with your client ID, and optionally an OAuth access token.
40
+ A client must be initialized with your client ID or bearer access token.
24
41
  ```
25
42
  client = Twitch::Client.new client_id: "YOUR_CLIENT_ID"
43
+ # or
44
+ client = Twitch::Client.new access_token: "YOUR_ACCESS_TOKEN"
26
45
  ```
27
- The retrieval methods take in a hash equal to the GET parameters of the API endpoint, and return a response object containing the data and other associated request information:
28
- * **data** is the data you would get back
29
- * **rate_limit** contains the number of API requests that can be made in total within a 60-second window. See **rate_limit_remaining** and **rate_limit_resets_at** to determine the current allowed rate.
30
- * **pagination** (optional) is an hash that usually contains one member (*cursor*) which lets you pagniate through certain requests.
46
+ The retrieval methods take in a hash equal to the parameters of the API endpoint, and return a response object containing the data and other associated request information:
47
+ * **data** is the data you would get back. Even if it's an array of one object, it remains the same as what comes from the API.
48
+ * **rate_limit** and associated fields contain API request limit information. Clip creation counts for a second limit (duration currently unknown).
49
+ * **pagination** is an hash that appears when data can be traversed, and contains one member (*cursor*) which lets you pagniate through certain requests.
31
50
  ```
32
51
  # Get top live streams
33
52
  client.get_streams.data
@@ -38,9 +57,15 @@ client.get_users({login: "disguisedtoasths"}).data.first
38
57
  client.get_games({name: ["Heroes of the Storm", "Super Mario Odyssey"]}).data
39
58
  ```
40
59
 
60
+ ### Error handling
61
+ An *ApiError* is raised whenever an HTTP error response is returned.
62
+ Rescue it to access the body of the response, which should include an error message.
63
+
41
64
  ## Development
42
65
 
43
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
66
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. (Tests require a Twitch Client ID; since cassettes exist you can use any value.)
67
+
68
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
44
69
 
45
70
  To install this gem onto your local machine, run `bundle exec rake install`.
46
71
 
@@ -1,6 +1,10 @@
1
1
  module Twitch
2
+ # An error returned by the API.
2
3
  class ApiError < StandardError
3
- attr_reader :status_code, :body
4
+ # HTTP status code of the response.
5
+ attr_reader :status_code
6
+ # Body content of the response.
7
+ attr_reader :body
4
8
 
5
9
  def initialize(status_code, body)
6
10
  @status_code = status_code
@@ -3,34 +3,74 @@ require "faraday_middleware"
3
3
 
4
4
  require "twitch/response"
5
5
  require "twitch/api_error"
6
+ require "twitch/clip"
7
+ require "twitch/entitlement_grant_url"
8
+ require "twitch/game"
6
9
  require "twitch/stream"
7
10
  require "twitch/stream_metadata"
8
11
  require "twitch/user"
9
12
  require "twitch/user_follow"
10
- require "twitch/game"
11
13
  require "twitch/video"
12
14
 
13
15
  module Twitch
14
16
  class Client
17
+ # Helix API endpoint.
15
18
  API_ENDPOINT = "https://api.twitch.tv/helix".freeze
16
19
 
20
+ # Initializes a Twitch client.
21
+ #
22
+ # - client_id [String] The client ID.
23
+ # Used as the Client-ID header in a request.
24
+ # - access_token [String] An access token.
25
+ # Used as the Authorization header in a request.
26
+ # Any "Bearer " prefix will be stripped.
17
27
  def initialize(client_id: nil, access_token: nil)
18
- raise "Client ID is required" if client_id.nil?
19
-
28
+ if client_id.nil? && access_token.nil?
29
+ raise "An identifier token (client ID or bearer token) is required"
30
+ elsif !!client_id && !!access_token
31
+ warn(%{WARNING:
32
+ It is recommended that only one identifier token is specified.
33
+ Unpredictable behavior may follow.})
34
+ end
35
+
20
36
  headers = {
21
- "Client-ID": client_id,
22
37
  "User-Agent": "twitch-api ruby client #{Twitch::VERSION}"
23
38
  }
39
+ unless client_id.nil?
40
+ headers["Client-ID"] = client_id
41
+ end
24
42
  unless access_token.nil?
43
+ access_token = access_token.gsub(/^Bearer /, "")
25
44
  headers["Authorization"] = "Bearer #{access_token}"
26
45
  end
27
46
 
28
47
  @conn = Faraday.new(API_ENDPOINT, { headers: headers }) do |faraday|
48
+ faraday.request :json
29
49
  faraday.response :json
30
50
  faraday.adapter Faraday.default_adapter
31
51
  end
32
52
  end
33
53
 
54
+ def create_clip(options = {})
55
+ res = post('clips', options)
56
+
57
+ clip = res[:data].map { |c| Clip.new(c) }
58
+ Response.new(clip, res[:rate_limit_headers])
59
+ end
60
+
61
+ def create_entitlement_grant_url(options = {})
62
+ res = post('entitlements/upload', options)
63
+
64
+ entitlement_grant = res[:data].map { |e| EntitlementGrantUrl.new(e) }
65
+ Response.new(entitlement_grant, res[:rate_limit_headers])
66
+ end
67
+
68
+ def get_clips(options = {})
69
+ res = get('clips', options)
70
+
71
+ clips = res[:data].map { |c| Clip.new(c) }
72
+ Response.new(clips, res[:rate_limit_headers])
73
+ end
34
74
 
35
75
  def get_games(options = {})
36
76
  res = get('games', options)
@@ -39,6 +79,13 @@ module Twitch
39
79
  Response.new(games, res[:rate_limit_headers])
40
80
  end
41
81
 
82
+ def get_top_games(options = {})
83
+ res = get('games/top', options)
84
+
85
+ games = res[:data].map { |g| Game.new(g) }
86
+ Response.new(games, res[:rate_limit_headers], res[:pagination])
87
+ end
88
+
42
89
  def get_streams(options = {})
43
90
  res = get('streams', options)
44
91
 
@@ -67,6 +114,13 @@ module Twitch
67
114
  Response.new(users, res[:rate_limit_headers])
68
115
  end
69
116
 
117
+ def update_user(options = {})
118
+ res = put('users', options)
119
+
120
+ user = res[:data].map { |u| User.new(u) }
121
+ Response.new(user, res[:rate_limit_headers])
122
+ end
123
+
70
124
  def get_videos(options = {})
71
125
  res = get('videos', options)
72
126
 
@@ -78,16 +132,31 @@ module Twitch
78
132
 
79
133
  def get(resource, params)
80
134
  http_res = @conn.get(resource, params)
135
+ finish(http_res)
136
+ end
137
+
138
+ def post(resource, params)
139
+ http_res = @conn.post(resource, params)
140
+ finish(http_res)
141
+ end
81
142
 
143
+ def put(resource, params)
144
+ http_res = @conn.put(resource, params)
145
+ finish(http_res)
146
+ end
147
+
148
+ def finish(http_res)
82
149
  unless http_res.success?
83
150
  raise ApiError.new(http_res.status, http_res.body)
84
151
  end
85
152
 
86
- rate_limit_headers = Hash[http_res.headers.select { |k,v|
153
+ rate_limit_headers = Hash[http_res.headers.select do |k,v|
87
154
  k.to_s.downcase.match(/^ratelimit/)
88
- }.map { |k,v| [k.gsub('ratelimit-', '').to_sym, v] }]
155
+ end.map { |k,v| [k.gsub('ratelimit-', '').to_sym, v] }]
89
156
 
90
- pagination = http_res.body['pagination'] if http_res.body.key?('pagination')
157
+ if http_res.body.key?('pagination')
158
+ pagination = http_res.body['pagination']
159
+ end
91
160
 
92
161
  {
93
162
  data: http_res.body['data'],
@@ -0,0 +1,43 @@
1
+ module Twitch
2
+ # A small segment of a broadcast captured by another user.
3
+ class Clip
4
+ # Fields to be converted from ISO 8601 string to a typed date.
5
+ DATE_ATTRIBUTES = [:created_at]
6
+
7
+ # ID of the clip.
8
+ attr_reader :id
9
+ # Title of the clip.
10
+ attr_reader :title
11
+ # Date the clip was created.
12
+ attr_reader :created_at
13
+ # URL of the clip.
14
+ attr_reader :url
15
+ # URL of the thumbnail image.
16
+ attr_reader :thumbnail_url
17
+ # URL for embedding the clip.
18
+ attr_reader :embed_url
19
+ # Number of views.
20
+ attr_reader :view_count
21
+ # Language of the originating broadcast.
22
+ attr_reader :language
23
+ # (User) ID of the clip's source broadcast.
24
+ attr_reader :broadcaster_id
25
+ # (User) ID of the clip's creator.
26
+ attr_reader :creator_id
27
+ # ID of the game being played.
28
+ attr_reader :game_id
29
+ # ID of the archived broadcast (may not be available).
30
+ attr_reader :video_id
31
+
32
+ def initialize(attributes = {})
33
+ attributes.each do |k, v|
34
+ if DATE_ATTRIBUTES.include?(k.to_sym)
35
+ instance_variable_set("@#{k}", Time.parse(v))
36
+ else
37
+ instance_variable_set("@#{k}", v)
38
+ end
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,13 @@
1
+ module Twitch
2
+ # A URL that can be used to notify users of an entitlement.
3
+ class EntitlementGrantUrl
4
+ # The URL to upload an entitlement manifest.
5
+ # See the Twitch API documentation on how to use this.
6
+ attr_reader :url
7
+
8
+ def initialize(attributes = {})
9
+ @url = attributes['url']
10
+ end
11
+
12
+ end
13
+ end
@@ -1,11 +1,21 @@
1
1
  module Twitch
2
+ # A filterable category for a stream.
3
+ # (not necessarily limited to games, e.g. 'IRL')
2
4
  class Game
3
- attr_reader :id, :name, :box_art_url
5
+ # ID of the game.
6
+ attr_reader :id
7
+ # Name of the game
8
+ attr_reader :name
9
+ # Box art URL template.
10
+ #
11
+ # Substitute the {width} and {height} string tokens
12
+ # with your desired numeric values.
13
+ attr_reader :box_art_url
4
14
 
5
15
  def initialize(attributes = {})
6
16
  @id = attributes['id']
7
17
  @name = attributes['name']
8
- @box_art_url = attributes['name']
18
+ @box_art_url = attributes['box_art_url']
9
19
  end
10
20
  end
11
21
  end
@@ -1,6 +1,25 @@
1
1
  module Twitch
2
+ # A compiled response from the API.
2
3
  class Response
3
- attr_reader :data, :pagination, :rate_limit, :rate_limit_remaining, :rate_limit_resets_at
4
+ # The requested data.
5
+ attr_reader :data
6
+ # A hash containing a pagination token.
7
+ # Access it with
8
+ # pagination['cursor']
9
+ attr_reader :pagination
10
+ # The total amount of calls that can be used in
11
+ # the rate limit period (one minute by default).
12
+ attr_reader :rate_limit
13
+ # The remaining amount of calls for the rate limit period.
14
+ attr_reader :rate_limit_remaining
15
+ # The date at which the rate limit is reset.
16
+ attr_reader :rate_limit_resets_at
17
+ # The total amount of clips that can be created in
18
+ # the clip rate limit period (currently unknown).
19
+ attr_reader :clip_rate_limit
20
+ # The remaining amount of clips that can be created in
21
+ # the clip rate limit period.
22
+ attr_reader :clip_rate_limit_remaining
4
23
 
5
24
  def initialize(data, rate_limit_headers, pagination = nil)
6
25
  @data = data
@@ -9,6 +28,11 @@ module Twitch
9
28
  @rate_limit_remaining = rate_limit_headers[:remaining].to_i
10
29
  @rate_limit_resets_at = Time.at(rate_limit_headers[:reset].to_i)
11
30
 
31
+ if rate_limit_headers.keys.any? { |k| k.to_s.start_with?('helixclipscreation') }
32
+ @clip_rate_limit = rate_limit_headers[:'helixclipscreation-limit']
33
+ @clip_rate_limit_remaining = rate_limit_headers[:'helixclipscreation-remaining']
34
+ end
35
+
12
36
  @pagination = pagination
13
37
  end
14
38
  end
@@ -1,9 +1,33 @@
1
1
  require "time"
2
2
 
3
3
  module Twitch
4
+ # A user's broadcasting session.
4
5
  class Stream
5
- attr_reader :id, :user_id, :game_id, :community_ids, :type, :title, :viewer_count, :started_at, :language, :thumbnail_url
6
+ # Fields to be converted from ISO 8601 string to a typed date.
6
7
  DATE_ATTRIBUTES = [:started_at]
8
+
9
+ # ID of the stream.
10
+ attr_reader :id
11
+ # ID of the user broadcasting.
12
+ attr_reader :user_id
13
+ # ID of the game being broadcast.
14
+ attr_reader :game_id
15
+ # Associated community IDs for the broadcaster.
16
+ attr_reader :community_ids
17
+ # The type of broadcast
18
+ # which may include 'live', 'playlist', or 'watch_party'.
19
+ attr_reader :type
20
+ # Title of the stream session.
21
+ attr_reader :title
22
+ # Concurrent viewer count of the broadcast.
23
+ attr_reader :viewer_count
24
+ # Date at which the broadcast started.
25
+ attr_reader :started_at
26
+ # Language of the broadcast.
27
+ attr_reader :language
28
+ # URL of the latest thumbnail image for the broadcast.
29
+ attr_reader :thumbnail_url
30
+
7
31
 
8
32
  def initialize(attributes = {})
9
33
  attributes.each do |k, v|
@@ -1,13 +1,23 @@
1
1
  module Twitch
2
+ # A set of metadata to provide additional information about a
3
+ # game being streamed.
4
+ # Additional getters are assigned at initialization time, e.g.
5
+ # self.hearthstone
6
+ # has data when Hearthstone is being streamed.
7
+ # Other games may be included, but will be set to nil
8
+ # if they aren't the game currently being streamed.
2
9
  class StreamMetadata
3
- attr_reader :user_id, :game_id
10
+ # ID of the streaming user.
11
+ attr_reader :user_id
12
+ # ID of the game being playead.
13
+ attr_reader :game_id
4
14
 
5
15
  def initialize(attributes = {})
6
16
  @user_id = attributes['user_id']
7
17
  @game_id = attributes['game_id']
8
18
 
9
- # Since more games can be supported in the future, this will ensure
10
- # they will all be available.
19
+ # Since more games can be supported in the future,
20
+ # this will ensure they will all be available.
11
21
  attributes.each do |k, v|
12
22
  unless instance_variables.include?("@#{k}".to_sym)
13
23
  self.class.send(:attr_reader, k.to_sym)
@@ -1,7 +1,26 @@
1
1
  module Twitch
2
2
  class User
3
- # All fields are read-only until update support is implemented
4
- attr_reader :id, :login, :display_name, :type, :broadcaster_type, :description, :profile_image_url, :offline_image_url, :view_count
3
+ # ID of the user.
4
+ attr_reader :id
5
+ # Unformatted (lowercase) username of the user.
6
+ attr_reader :login
7
+ # Formatted username of the user.
8
+ attr_reader :display_name
9
+ # Represents a special role of a user.
10
+ # (global mod, admin, staff)
11
+ attr_reader :type
12
+ # Represents a special broadcaster role of a user.
13
+ # (partner, affilaite)
14
+ attr_reader :broadcaster_type
15
+ # Description/biographical info of a user.
16
+ attr_reader :description
17
+ # URL to the user's profile image.
18
+ attr_reader :profile_image_url
19
+ # URL to the image displayed in the video box
20
+ # when the stream is offline.
21
+ attr_reader :offline_image_url
22
+ # Total number of visits to the user's stream page.
23
+ attr_reader :view_count
5
24
 
6
25
  def initialize(attributes = {})
7
26
  attributes.each do |k, v|
@@ -1,6 +1,12 @@
1
1
  module Twitch
2
+ # Represents a relationship of one user following another.
2
3
  class UserFollow
3
- attr_reader :from_id, :to_id, :followed_at
4
+ # User ID of the *following* user.
5
+ attr_reader :from_id
6
+ # User ID of the *followed* user.
7
+ attr_reader :to_id
8
+ # Date at which the follow action was performed.
9
+ attr_reader :followed_at
4
10
 
5
11
  def initialize(attributes = {})
6
12
  @from_id = attributes['from_id']
@@ -1,3 +1,4 @@
1
1
  module Twitch
2
- VERSION = "0.1.0"
2
+ # Library version.
3
+ VERSION = "0.2.0"
3
4
  end
@@ -1,11 +1,37 @@
1
1
  require "time"
2
2
 
3
3
  module Twitch
4
+ # A captured broadcast or portion of a broadcast.
4
5
  class Video
5
6
  DATE_ATTRIBUTES = [:created_at, :published_at]
6
7
 
7
- attr_reader :id, :title, :description, :language, :view_count, :created_at,
8
- :published_at, :thumbnail_url, :type, :url, :user_id, :viewable, :duration
8
+ # ID of the video.
9
+ attr_reader :id
10
+ # Title of the video.
11
+ attr_reader :title
12
+ # Description of the video.
13
+ attr_reader :description
14
+ # Language of the video.
15
+ attr_reader :language
16
+ # Number of views
17
+ attr_reader :view_count
18
+ # Date the video was created.
19
+ attr_reader :created_at
20
+ # Date the video was published.
21
+ attr_reader :published_at
22
+ # URL to the thumbnail image of the video.
23
+ attr_reader :thumbnail_url
24
+ # Type of the video (archive, highlight or upload).
25
+ attr_reader :type
26
+ # URL of the video.
27
+ attr_reader :url
28
+ # ID of the user who uploaded/broadcasted the video.
29
+ attr_reader :user_id
30
+ # Viewability of the video (public or private)
31
+ attr_reader :viewable
32
+ # Duration of the video, in the format
33
+ # 0h0m0s
34
+ attr_reader :duration
9
35
 
10
36
  def initialize(attributes = {})
11
37
  attributes.each do |k, v|
@@ -16,5 +42,6 @@ module Twitch
16
42
  end
17
43
  end
18
44
  end
45
+
19
46
  end
20
47
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twitch-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maurice Wahba
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-11-21 00:00:00.000000000 Z
11
+ date: 2018-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -127,6 +127,8 @@ files:
127
127
  - lib/twitch-api.rb
128
128
  - lib/twitch/api_error.rb
129
129
  - lib/twitch/client.rb
130
+ - lib/twitch/clip.rb
131
+ - lib/twitch/entitlement_grant_url.rb
130
132
  - lib/twitch/game.rb
131
133
  - lib/twitch/response.rb
132
134
  - lib/twitch/stream.rb