kappa 0.4.0 → 1.0.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.
data/README.md CHANGED
@@ -7,7 +7,6 @@ Kappa is the Ruby library for interfacing with the [Twitch.tv API](https://githu
7
7
  [![Dependency Status](https://gemnasium.com/schmich/kappa.png)](https://gemnasium.com/schmich/kappa)
8
8
  [![Coverage Status](https://coveralls.io/repos/schmich/kappa/badge.png?branch=master)](https://coveralls.io/r/schmich/kappa?branch=master)
9
9
  [![Code Climate](https://codeclimate.com/github/schmich/kappa.png)](https://codeclimate.com/github/schmich/kappa)
10
- [![Bitdeli](https://d2weczhvl823v0.cloudfront.net/schmich/kappa/trend.png)](https://bitdeli.com/free "Bitdeli")
11
10
 
12
11
  ## Getting Started
13
12
 
@@ -22,6 +21,10 @@ frag = Twitch.channels.get('lethalfrag')
22
21
  puts frag.streaming?
23
22
  ```
24
23
 
24
+ ```ruby
25
+ gem 'kappa', '~> 1.0'
26
+ ```
27
+
25
28
  ## Configuration
26
29
 
27
30
  When making requests to Twitch, you must specify a client ID for your application.
@@ -36,13 +39,79 @@ Twitch.configure do |config|
36
39
  end
37
40
  ```
38
41
 
39
- ## Overview
42
+ See the [`Twitch.configure`](http://rdoc.info/gems/kappa/Twitch#configure-class_method) documentation.
40
43
 
41
- ### <a id="channels"></a>Channels
44
+ ## Examples
45
+
46
+ Get the featured streams on the Twitch.tv homepage:
47
+
48
+ ```ruby
49
+ Twitch.streams.featured do |stream|
50
+ channel = stream.channel
51
+ puts "#{channel.display_name}: #{stream.viewer_count} viewers"
52
+ puts "#{channel.status}"
53
+ puts '-' * 80
54
+ end
55
+ ```
56
+
57
+ See if certain users are streaming:
58
+
59
+ ```ruby
60
+ users = ['destiny', 'followgrubby', 'incontroltv']
61
+ Twitch.streams.find(:channel => users) do |stream|
62
+ puts "#{stream.channel.name} is streaming #{stream.game_name}."
63
+ end
64
+ ```
65
+
66
+ Get the most popular games being streamed:
42
67
 
43
- Channels serve as the home location for a [user's](#users) content. Channels have a [stream](#streams), can run commercials, store [videos](#videos), display information and status, and have a customized page including banners and backgrounds.
68
+ ```ruby
69
+ Twitch.games.top(:limit => 3) do |game|
70
+ print "#{game.name}: "
71
+ print "#{game.viewer_count} viewers in "
72
+ puts "#{game.channel_count} channels"
73
+ end
74
+ ```
44
75
 
45
- See also [`Channel`](http://rdoc.info/gems/kappa/Kappa/V2/Channel) documentation.
76
+ Get streams for a particular game:
77
+
78
+ ```ruby
79
+ Twitch.streams.find(:game => 'League of Legends') do |stream|
80
+ next if stream.viewer_count < 1000
81
+ puts "#{stream.channel.display_name}: #{stream.viewer_count}"
82
+ end
83
+ ```
84
+
85
+ Get info for a single user:
86
+
87
+ ```ruby
88
+ user = Twitch.users.get('lethalfrag')
89
+ stream = user.stream
90
+
91
+ puts user.display_name
92
+ if stream
93
+ puts "Streaming #{stream.game_name} at #{stream.url}"
94
+ else
95
+ puts 'Not streaming.'
96
+ end
97
+ ```
98
+
99
+ Get the followers of a channel:
100
+
101
+ ```ruby
102
+ channel = Twitch.channels.get('day9tv')
103
+ channel.followers do |user|
104
+ puts user.display_name
105
+ end
106
+ ```
107
+
108
+ ## Resources
109
+
110
+ ### <a id="channels"></a>Channels
111
+
112
+ Channels serve as the home location for a [user's](#users) content. Channels have a [stream](#streams),
113
+ can run commercials, store [videos](#videos), display information and status, and have a customized page
114
+ including banners and backgrounds. See the [`Channel`](http://rdoc.info/gems/kappa/Twitch/V2/Channel) documentation.
46
115
 
47
116
  ```ruby
48
117
  c = Twitch.channels.get('destiny')
@@ -57,9 +126,9 @@ c.followers # => [#<Kappa::V2::User>, ...]
57
126
 
58
127
  ### <a id="streams"></a>Streams
59
128
 
60
- Streams are video broadcasts that are currently live. They belong to a [user](#users) and are part of a [channel](#channels).
61
-
62
- See also [`Stream`](http://rdoc.info/gems/kappa/Kappa/V2/Stream) and [`Streams`](http://rdoc.info/gems/kappa/Kappa/V2/Streams) documentation.
129
+ Streams are video broadcasts that are currently live. They belong to a [user](#users) and are part of a
130
+ [channel](#channels). See the [`Stream`](http://rdoc.info/gems/kappa/Twitch/V2/Stream) and
131
+ [`Streams`](http://rdoc.info/gems/kappa/Twitch/V2/Streams) documentation.
63
132
 
64
133
  ```ruby
65
134
  s = Twitch.streams.get('idrajit')
@@ -71,9 +140,9 @@ s.channel.url # => "http://www.twitch.tv/idrajit"
71
140
 
72
141
  ### <a id="users"></a>Users
73
142
 
74
- These are members of the Twitch community who have a Twitch account. If broadcasting, they can own a [stream](#streams) that they can broadcast on their [channel](#channels). If mainly viewing, they might follow or subscribe to channels.
75
-
76
- See also [`User`](http://rdoc.info/gems/kappa/Kappa/V2/User) documentation.
143
+ These are members of the Twitch community who have a Twitch account. If broadcasting, they can own a
144
+ [stream](#streams) that they can broadcast on their [channel](#channels). If mainly viewing, they might
145
+ follow or subscribe to channels. See the [`User`](http://rdoc.info/gems/kappa/Twitch/V2/User) documentation.
77
146
 
78
147
  ```ruby
79
148
  u = Twitch.users.get('snoopeh')
@@ -84,9 +153,10 @@ u.following.map(&:name) # => ["national_esl1", "dreamhacklol", "riotgames"]
84
153
 
85
154
  ### <a id="videos"></a>Videos
86
155
 
87
- Videos are broadcasts or highlights owned by a [channel](#channels). Broadcasts are unedited videos that are saved after a streaming session. Highlights are videos edited from broadcasts by the channel's owner.
88
-
89
- See also [`Video`](http://rdoc.info/gems/kappa/Kappa/V2/Video) and [`Videos`](http://rdoc.info/gems/kappa/Kappa/V2/Videos) documentation.
156
+ Videos are broadcasts or highlights owned by a [channel](#channels). Broadcasts are unedited videos that are saved
157
+ after a streaming session. Highlights are videos edited from broadcasts by the channel's owner. See the
158
+ [`Video`](http://rdoc.info/gems/kappa/Twitch/V2/Video) and [`Videos`](http://rdoc.info/gems/kappa/Twitch/V2/Videos)
159
+ documentation.
90
160
 
91
161
  ```ruby
92
162
  v = Twitch.videos.get('a395995729')
@@ -99,9 +169,8 @@ v.view_count # => 12506
99
169
 
100
170
  ### <a id="teams"></a>Teams
101
171
 
102
- Teams are an organization of [channels](#channels).
103
-
104
- See also [`Team`](http://rdoc.info/gems/kappa/Kappa/V2/Team) documentation.
172
+ Teams are an organization of [channels](#channels). See the [`Team`](http://rdoc.info/gems/kappa/Twitch/V2/Team)
173
+ documentation.
105
174
 
106
175
  ```ruby
107
176
  t = Twitch.teams.get('teamliquid')
@@ -113,13 +182,14 @@ t.updated_at # => 2013-05-24 00:17:10 UTC
113
182
 
114
183
  ### <a id="games"></a>Games
115
184
 
116
- Games are categories (e.g. League of Legends, Diablo 3) used by [streams](#streams) and [channels](#channels). Games can be searched for by query.
117
-
118
- See also [`Game`](http://rdoc.info/gems/kappa/Kappa/V2/Game), [`Games`](http://rdoc.info/gems/kappa/Kappa/V2/Games), and [`GameSuggestion`](http://rdoc.info/gems/kappa/Kappa/V2/GameSuggestion) documentation.
185
+ Games are categories (e.g. League of Legends, Diablo 3) used by [streams](#streams) and [channels](#channels).
186
+ Games can be searched for by query. See the [`Game`](http://rdoc.info/gems/kappa/Twitch/V2/Game),
187
+ [`Games`](http://rdoc.info/gems/kappa/Twitch/V2/Games), and
188
+ [`GameSuggestion`](http://rdoc.info/gems/kappa/Twitch/V2/GameSuggestion) documentation.
119
189
 
120
190
  ```ruby
121
- top = Twitch.games.top(:limit => 3)
122
- top.map(&:name) # => ["League of Legends", "Dota 2", "StarCraft II: Heart of the Swarm"]
191
+ top = Twitch.games.top(:limit => 2)
192
+ top.map(&:name) # => ["League of Legends", "StarCraft II: Heart of the Swarm"]
123
193
  ```
124
194
 
125
195
  ```ruby
@@ -127,16 +197,34 @@ g = Twitch.games.top(:limit => 1).first
127
197
  g.name # => "League of Legends"
128
198
  g.channel_count # => 906
129
199
  g.viewer_count # => 79223
130
- g.box_images.medium_url # =>"http://static-cdn.jtvnw.net/ttv-boxart/League%20of%20Legends-272x380.jpg"
200
+ g.box_images.medium_url # =>"http://static-cdn.jtvnw.net/ttv-boxart/31412.jpg"
131
201
  ```
132
202
 
133
203
  ```ruby
134
204
  s = Twitch.games.find(:name => 'diablo', :live => true)
135
- s.map(&:name) # => ["Diablo III", "Diablo II", "Diablo", "Diablo II: Lord of Destruction"]
136
- s.map(&:popularity) # => [120, 4, 1, 1]
205
+ s.map(&:name) # => ["Diablo III", "Diablo II", "Diablo"]
206
+ s.map(&:popularity) # => [120, 4, 1]
137
207
  ```
138
208
 
139
- ## Examples
209
+ ## Errors
210
+
211
+ All errors derive from `Twitch::Error`.
212
+
213
+ - `Twitch:Error` - Base class for all errors.
214
+ - `Twitch::Error::ResponseError` - Base class for all Twitch.tv API response errors.
215
+ - `Twitch::Error::FormatError` - The returned data was incorrectly formatted (e.g. invalid JSON).
216
+ - `Twitch::Error::ClientError` - The server returned a 4xx status code.
217
+ - `Twitch::Error::ServerError` - The server returned a 5xx status code.
218
+
219
+ All `ResponseError` errors have additional diagnostic information:
220
+
221
+ ```ruby
222
+ e.status # => 422
223
+ e.body # => '{"status":422,"message":"...","error":"..."}'
224
+ e.url # => "https://api.twitch.tv/streams/desrow"
225
+ ```
226
+
227
+ See the [`ResponseError`](http://rdoc.info/gems/kappa/Twitch/Error/ResponseError) documentation.
140
228
 
141
229
  ## Documentation
142
230
 
@@ -194,3 +282,4 @@ end
194
282
  Copyright &copy; 2013 Chris Schmich
195
283
  <br />
196
284
  MIT License, See [LICENSE](LICENSE) for details.
285
+ [![githalytics.com alpha](https://cruel-carlota.pagodabox.com/b885add21cf8f2b473d1394edc1cf5b4 "githalytics.com")](http://githalytics.com/schmich/kappa)
data/lib/kappa.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'kappa/id_equality'
2
2
  require 'kappa/proxy'
3
+ require 'kappa/status'
4
+ require 'kappa/errors'
3
5
  require 'kappa/connection'
4
6
  require 'kappa/configuration'
5
7
  require 'kappa/query'
data/lib/kappa/channel.rb CHANGED
@@ -68,57 +68,57 @@ module Twitch::V2
68
68
  # Get the users following this channel.
69
69
  # @note The number of followers is potentially very large, so it's recommended that you specify a `:limit`.
70
70
  # @example
71
- # f = c.followers(:limit => 20)
71
+ # channel.followers(:limit => 20)
72
+ # @example
73
+ # channel.followers do |follower|
74
+ # puts follower.display_name
75
+ # end
72
76
  # @param options [Hash] Filter criteria.
73
- # @option options [Fixnum] :limit (none) Limit on the number of results returned.
77
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
74
78
  # @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
79
+ # @yield Optional. If a block is given, each follower is yielded.
80
+ # @yieldparam [User] follower Current follower.
75
81
  # @see User
76
82
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/channels.md#get-channelschannelfollows GET /channels/:channel/follows
77
- # @return [Array<User>] List of users following this channel.
78
- def followers(options = {})
83
+ # @return [Array<User>] Users following this channel, if no block is given.
84
+ # @return [nil] If a block is given.
85
+ def followers(options = {}, &block)
86
+ name = CGI.escape(@name)
79
87
  return @query.connection.accumulate(
80
- :path => "channels/#{@name}/follows",
88
+ :path => "channels/#{name}/follows",
81
89
  :json => 'follows',
82
90
  :sub_json => 'user',
83
91
  :create => -> hash { User.new(hash, @query) },
84
92
  :limit => options[:limit],
85
- :offset => options[:offset]
93
+ :offset => options[:offset],
94
+ &block
86
95
  )
87
96
  end
88
97
 
89
98
  # Get the videos for a channel, most recently created first.
90
99
  # @note This incurs additional web requests.
100
+ # @note You can get videos directly from a channel name via {Videos#for_channel}.
101
+ # @example
102
+ # v = channel.videos(:type => :broadcasts)
91
103
  # @example
92
- # c = Twitch.channels.get('idrajit')
93
- # v = c.videos(:type => :broadcasts)
104
+ # channel.videos(:type => :highlights) do |video|
105
+ # next if video.view_count < 10000
106
+ # puts video.url
107
+ # end
94
108
  # @param options [Hash] Filter criteria.
95
109
  # @option options [Symbol] :type (:highlights) The type of videos to return. Valid values are `:broadcasts`, `:highlights`.
96
- # @option options [Fixnum] :limit (none) Limit on the number of results returned.
110
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
97
111
  # @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
112
+ # @yield Optional. If a block is given, each video is yielded.
113
+ # @yieldparam [Video] video Current video.
98
114
  # @see Video
115
+ # @see Videos#for_channel Videos#for_channel
99
116
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/videos.md#get-channelschannelvideos GET /channels/:channel/videos
100
117
  # @raise [ArgumentError] If `:type` is not one of `:broadcasts` or `:highlights`.
101
- # @return [Array<Video>] List of videos for the channel.
102
- def videos(options = {})
103
- params = {}
104
-
105
- type = options[:type] || :highlights
106
- if !type.nil?
107
- if ![:broadcasts, :highlights].include?(type)
108
- raise ArgumentError, 'type'
109
- end
110
-
111
- params[:broadcasts] = (type == :broadcasts)
112
- end
113
-
114
- return @query.connection.accumulate(
115
- :path => "channels/#{@name}/videos",
116
- :params => params,
117
- :json => 'videos',
118
- :create => -> hash { Video.new(hash, @query) },
119
- :limit => options[:limit],
120
- :offset => options[:offset]
121
- )
118
+ # @return [Array<Video>] Videos for the channel, if no block is given.
119
+ # @return [nil] If a block is given.
120
+ def videos(options = {}, &block)
121
+ @query.videos.for_channel(@name, options, &block)
122
122
  end
123
123
 
124
124
  # @example
@@ -170,7 +170,7 @@ module Twitch::V2
170
170
 
171
171
  # @example
172
172
  # 2013-07-21 05:27:58 UTC
173
- # @return [Time] When the channel was last updated (UTC). For example, when a stream is started, its channel is updated.
173
+ # @return [Time] When the channel was last updated (UTC). For example, when a stream is started or a channel's status is changed, the channel is updated.
174
174
  attr_reader :updated_at
175
175
 
176
176
  # @example
@@ -202,13 +202,11 @@ module Twitch::V2
202
202
  # @param channel_name [String] The name of the channel to get. This is the same as the stream or user name.
203
203
  # @return [Channel] A valid `Channel` object if the channel exists, `nil` otherwise.
204
204
  def get(channel_name)
205
- encoded_name = CGI.escape(channel_name)
206
- json = @query.connection.get("channels/#{encoded_name}")
205
+ name = CGI.escape(channel_name)
207
206
 
208
207
  # HTTP 422 can happen if the channel is associated with a Justin.tv account.
209
- if !json || json['status'] == 404 || json['status'] == 422
210
- nil
211
- else
208
+ Twitch::Status.map(404 => nil, 422 => nil) do
209
+ json = @query.connection.get("channels/#{name}")
212
210
  Channel.new(json, @query)
213
211
  end
214
212
  end
@@ -3,16 +3,48 @@ require 'securerandom'
3
3
  module Twitch
4
4
  @query = nil
5
5
 
6
- # Configure global settings for interacting with Twitch. Future requests will use these settings.
6
+ # Configure global settings for interacting with Twitch. Future requests
7
+ # through the `Twitch` module will use these settings.
7
8
  # @example
8
9
  # Twitch.configure do |config|
9
10
  # config.client_id = 'sc2daily-v1.0.0'
10
11
  # config.api = Twitch::V2
11
12
  # end
13
+ #
14
+ # streams = Twitch.streams.featured(:limit => 10)
15
+ # @param client_id [String] When making requests to Twitch,
16
+ # you must specify a client ID for your application. If you do not specify a client ID,
17
+ # Twitch reserves the right to rate-limit your application without warning. If unspecified,
18
+ # this defaults to a random string, but in real applications, you should set this explicitly.
19
+ # @param api [Module] The version of the Twitch API to use. Defaults to `Twitch::V2`, the only
20
+ # API version currently supported.
21
+ # @return [nil] nil
12
22
  def self.configure(&block)
13
23
  @query = instance(&block)
24
+ nil
14
25
  end
15
26
 
27
+ # Create a new interface to Twitch. This allows you to have multiple separate
28
+ # connections to Twitch in the same process, each with its own configuration.
29
+ # @example
30
+ # client_a = Twitch.instance do |config|
31
+ # config.client_id = 'App-A-v2.0.0'
32
+ # end
33
+ #
34
+ # client_b = Twitch.instance do |config|
35
+ # config.client_id = 'App-B-v3.0.0'
36
+ # end
37
+ #
38
+ # streams = client_a.streams.featured(:limit => 10)
39
+ # channel = client_b.channels.get('destiny')
40
+ # @param client_id [String] When making requests to Twitch,
41
+ # you must specify a client ID for your application. If you do not specify a client ID,
42
+ # Twitch reserves the right to rate-limit your application without warning. If unspecified,
43
+ # this defaults to a random string, but in real applications, you should set this explicitly.
44
+ # @param api [Module] The version of the Twitch API to use. Defaults to `Twitch::V2`, the only
45
+ # API version currently supported.
46
+ # @return [Object] A Twitch query object through which you can make requests. The methods on this
47
+ # object are the same as the methods on the default `Twitch` object.
16
48
  def self.instance(&block)
17
49
  config = Configuration.new
18
50
  config.instance_eval(&block)
@@ -20,6 +52,7 @@ module Twitch
20
52
  return config.create(:Query, connection)
21
53
  end
22
54
 
55
+ # @private
23
56
  def self.method_missing(*args)
24
57
  @query ||= create_default_query
25
58
  @query.send(*args)
@@ -46,6 +79,7 @@ module Twitch
46
79
  end
47
80
 
48
81
  private
82
+ # @private
49
83
  def self.create_default_query
50
84
  config = Configuration.new
51
85
  connection = config.create(:Connection, config.client_id)
@@ -9,11 +9,16 @@ module Twitch
9
9
  include HTTParty
10
10
 
11
11
  def initialize(client_id, base_url = DEFAULT_BASE_URL)
12
+ raise ArgumentError, 'client_id' if !client_id || client_id.empty?
13
+ raise ArgumentError, 'base_url' if !base_url || base_url.empty?
14
+
12
15
  @client_id = client_id
13
16
  @base_url = Addressable::URI.parse(base_url)
14
17
  end
15
18
 
16
19
  def get(path, query = nil)
20
+ raise ArgumentError, 'path' if !path || path.empty?
21
+
17
22
  request_url = @base_url + path
18
23
 
19
24
  all_headers = {
@@ -23,11 +28,27 @@ module Twitch
23
28
 
24
29
  response = self.class.get(request_url, :headers => all_headers, :query => query)
25
30
 
26
- json = response.body
27
- return JSON.parse(json)
31
+ url = response.request.last_uri.to_s
32
+ status = response.code
33
+ body = response.body
34
+
35
+ case status
36
+ when 400...500
37
+ raise Error::ClientError.new("HTTP client error, status #{status}.", url, status, body)
38
+ when 500...600
39
+ raise Error::ServerError.new("HTTP server error, status #{status}.", url, status, body)
40
+ else
41
+ # Ignore, assume success.
42
+ end
43
+
44
+ begin
45
+ return JSON.parse(body)
46
+ rescue JSON::ParserError => e
47
+ raise Error::FormatError.new(e, url, status, body)
48
+ end
28
49
  end
29
50
 
30
- def accumulate(options)
51
+ def accumulate(options, &block)
31
52
  path = options[:path]
32
53
  params = options[:params] || {}
33
54
  json = options[:json]
@@ -47,8 +68,13 @@ module Twitch
47
68
  page_limit = [total_limit || 100, 100].min
48
69
  offset = options[:offset] || 0
49
70
 
50
- objects = []
51
71
  ids = Set.new
72
+ objects = []
73
+ count = 0
74
+
75
+ block ||= -> object {
76
+ objects << object
77
+ }
52
78
 
53
79
  paginate(path, page_limit, offset, params) do |response_json|
54
80
  current_objects = response_json[json]
@@ -56,17 +82,18 @@ module Twitch
56
82
  object_json = object_json[sub_json] if sub_json
57
83
  object = create.call(object_json)
58
84
  if ids.add?(object.id)
59
- objects << object
60
- if !total_limit.nil? && (objects.count == total_limit)
61
- return objects
85
+ count += 1
86
+ block.call(object)
87
+ if count == total_limit
88
+ return block_given? ? nil : objects
62
89
  end
63
90
  end
64
91
  end
65
92
 
66
- !current_objects.empty? && (current_objects.count >= page_limit)
93
+ break if current_objects.empty? || (current_objects.count < page_limit)
67
94
  end
68
95
 
69
- return objects
96
+ return block_given? ? nil : objects
70
97
  end
71
98
 
72
99
  def paginate(path, limit, offset, params = {})
@@ -81,7 +108,7 @@ module Twitch
81
108
 
82
109
  loop do
83
110
  break if json['error'] && (json['status'] == 503)
84
- break if !yield(json)
111
+ yield json
85
112
 
86
113
  links = json['_links']
87
114
  next_url = links['next']
@@ -105,8 +132,8 @@ end
105
132
  module Twitch::V2
106
133
  # @private
107
134
  class Connection < Twitch::Connection
108
- def headers
109
- { 'Accept' => 'application/vnd.twitchtv.v2+json' }
110
- end
135
+ def headers
136
+ { 'Accept' => 'application/vnd.twitchtv.v2+json' }
137
+ end
111
138
  end
112
139
  end
@@ -0,0 +1,43 @@
1
+ module Twitch
2
+ # The base class for all `Twitch` errors.
3
+ class Error < StandardError
4
+ # An error that occurred as the result of a request to the Twitch.tv API.
5
+ class ResponseError < Error
6
+ # @private
7
+ def initialize(arg, url, status, body)
8
+ super(arg)
9
+ @url = url
10
+ @status = status
11
+ @body = body
12
+ end
13
+
14
+ # @example
15
+ # "https://api.twitch.tv/kraken/streams?limit=100&offset=0"
16
+ # @return [String] The request URL that resulted in this response error.
17
+ attr_reader :url
18
+
19
+ # @example
20
+ # 500
21
+ # @return [Fixnum] The HTTP status code for the response.
22
+ attr_reader :status
23
+
24
+ # @example
25
+ # '{"status":422,"message":"Channel desrow is not available on Twitch","error":"Unprocessable Entity"}'
26
+ # @return [String] The response body.
27
+ attr_reader :body
28
+ end
29
+
30
+ # An error indicating an HTTP client error code (4xx) from the Twitch.tv API.
31
+ class ClientError < ResponseError
32
+ end
33
+
34
+ # An error indicating an HTTP server error code (5xx) from the Twitch.tv API.
35
+ class ServerError < ResponseError
36
+ end
37
+
38
+ # An error indicating a malformed response from the Twitch.tv API.
39
+ # All Twitch.tv responses are expected to valid JSON objects.
40
+ class FormatError < ResponseError
41
+ end
42
+ end
43
+ end
data/lib/kappa/game.rb CHANGED
@@ -8,7 +8,8 @@ module Twitch::V2
8
8
  include Twitch::IdEquality
9
9
 
10
10
  # @private
11
- def initialize(hash)
11
+ def initialize(hash, query)
12
+ @query = query
12
13
  @channel_count = hash['channels']
13
14
  @viewer_count = hash['viewers']
14
15
 
@@ -20,6 +21,34 @@ module Twitch::V2
20
21
  @logo_images = Images.new(game['logo'])
21
22
  end
22
23
 
24
+ # Get streams for this game.
25
+ # @example
26
+ # game.streams
27
+ # @example
28
+ # game.streams(:embeddable => true, :limit => 20)
29
+ # @example
30
+ # game.streams do |stream|
31
+ # next if stream.viewer_count < 1000
32
+ # puts stream.url
33
+ # end
34
+ # @param options [Hash] Search criteria.
35
+ # @option options [Array<String, Channel, #name>] :channel Only return streams for these channels.
36
+ # If a channel is not currently streaming, it is omitted. You must specify an array of channels
37
+ # or channel names.
38
+ # @option options [Boolean] :embeddable (nil) If `true`, limit the streams to those that can be embedded. If `false` or `nil`, do not limit.
39
+ # @option options [Boolean] :hls (nil) If `true`, limit the streams to those using HLS (HTTP Live Streaming). If `false` or `nil`, do not limit.
40
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
41
+ # @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
42
+ # @yield Optional. If a block is given, each stream found is yielded.
43
+ # @yieldparam [Stream] stream Current stream.
44
+ # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streams GET /streams
45
+ # @raise [ArgumentError] If `:channel` is not an array.
46
+ # @return [Array<Stream>] Streams matching the specified criteria, if no block is given.
47
+ # @return [nil] If a block is given.
48
+ def streams(options = {}, &block)
49
+ @query.streams.find(options.merge(:game => @name), &block)
50
+ end
51
+
23
52
  # @example
24
53
  # 21799
25
54
  # @return [Fixnum] Unique Twitch ID.
@@ -108,14 +137,22 @@ module Twitch::V2
108
137
  # Twitch.games.top
109
138
  # @example
110
139
  # Twitch.games.top(:limit => 10)
140
+ # @example
141
+ # Twitch.games.top do |game|
142
+ # next if game.viewer_count < 10000
143
+ # puts game.name
144
+ # end
111
145
  # @param options [Hash] Filter criteria.
112
146
  # @option options [Boolean] :hls (nil) If `true`, limit the games to those that have any streams using HLS (HTTP Live Streaming). If `false` or `nil`, do not limit.
113
- # @option options [Fixnum] :limit (none) Limit on the number of results returned.
147
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
114
148
  # @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
149
+ # @yield Optional. If a block is given, each top game is yielded.
150
+ # @yieldparam [Game] game Current game.
115
151
  # @see Game Game
116
152
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/games.md#get-gamestop GET /games/top
117
- # @return [Array<Game>] List of games sorted by number of current viewers on Twitch, most popular first.
118
- def top(options = {})
153
+ # @return [Array<Game>] Games sorted by number of current viewers on Twitch, highest first, if no block is given.
154
+ # @return [nil] If a block is given.
155
+ def top(options = {}, &block)
119
156
  params = {}
120
157
 
121
158
  if options[:hls]
@@ -126,9 +163,10 @@ module Twitch::V2
126
163
  :path => 'games/top',
127
164
  :params => params,
128
165
  :json => 'top',
129
- :create => Game,
166
+ :create => -> hash { Game.new(hash, @query) },
130
167
  :limit => options[:limit],
131
- :offset => options[:offset]
168
+ :offset => options[:offset],
169
+ &block
132
170
  )
133
171
  end
134
172
 
@@ -137,14 +175,22 @@ module Twitch::V2
137
175
  # Twitch.games.find(:name => 'diablo')
138
176
  # @example
139
177
  # Twitch.games.find(:name => 'starcraft', :live => true)
178
+ # @example
179
+ # Twitch.games.find(:name => 'starcraft') do |suggestion|
180
+ # next if suggestion.name =~ /heart of the swarm/i
181
+ # puts suggestion.name
182
+ # end
140
183
  # @param options [Hash] Search criteria.
141
184
  # @option options [String] :name Game name search term. This can be a partial name, e.g. `"league"`.
142
185
  # @option options [Boolean] :live (false) If `true`, only returns games that are currently live on at least one channel.
143
- # @option options [Fixnum] :limit (none) Limit on the number of results returned.
186
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
187
+ # @yield Optional. If a block is given, each game suggestion is yielded.
188
+ # @yieldparam [GameSuggestion] suggestion Current game suggestion.
144
189
  # @see GameSuggestion GameSuggestion
145
190
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/search.md#get-searchgames GET /search/games
146
191
  # @raise [ArgumentError] If `:name` is not specified.
147
- # @return [Array<GameSuggestion>] List of games matching the criteria.
192
+ # @return [Array<GameSuggestion>] Games matching the criteria, if no block is given.
193
+ # @return [nil] If a block is given.
148
194
  def find(options)
149
195
  raise ArgumentError, 'options' if options.nil?
150
196
  raise ArgumentError, 'name' if options[:name].nil?
@@ -0,0 +1,16 @@
1
+ module Twitch
2
+ # @private
3
+ class Status
4
+ def self.map(status_map, &block)
5
+ begin
6
+ block.call
7
+ rescue Error::ClientError, Error::ServerError => e
8
+ if status_map.include? e.status
9
+ status_map[e.status]
10
+ else
11
+ raise
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
data/lib/kappa/stream.rb CHANGED
@@ -71,6 +71,26 @@ module Twitch::V2
71
71
  attr_reader :url
72
72
  end
73
73
 
74
+ # Site-wide stream summary statistics.
75
+ # @see Streams#summary Streams#summary
76
+ class StreamSummary
77
+ # @private
78
+ def initialize(hash)
79
+ @viewer_count = hash['viewers']
80
+ @channel_count = hash['channels']
81
+ end
82
+
83
+ # @example
84
+ # 194774
85
+ # @return [Fixnum] The sum of all viewers across all live streams.
86
+ attr_reader :viewer_count
87
+
88
+ # @example
89
+ # 4144
90
+ # @return [Fixnum] The count of all channels currently streaming.
91
+ attr_reader :channel_count
92
+ end
93
+
74
94
  # Query class for finding featured streams or streams meeting certain criteria.
75
95
  # @see Stream
76
96
  class Streams
@@ -91,40 +111,79 @@ module Twitch::V2
91
111
  # @param stream_name [String] The name of the stream to get. This is the same as the channel or user name.
92
112
  # @see #find
93
113
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streamschannel GET /streams/:channel
94
- # @return [Stream] A valid `Stream` object if the stream exists and is currently live, `nil` otherwise.
114
+ # @return [Stream] A valid `Stream` object, if the stream exists and is live.
115
+ # @return [nil] If the stream does not exist or is not live.
95
116
  def get(stream_name)
96
- encoded_name = CGI.escape(stream_name)
97
- json = @query.connection.get("streams/#{encoded_name}")
98
- stream = json['stream']
99
- if json['status'] == 404 || !stream
100
- nil
101
- else
102
- Stream.new(stream, @query)
117
+ name = CGI.escape(stream_name)
118
+
119
+ # HTTP 422 can happen if the stream is associated with a Justin.tv account.
120
+ Twitch::Status.map(404 => nil, 422 => nil) do
121
+ json = @query.connection.get("streams/#{name}")
122
+ stream = json['stream']
123
+ stream.nil? ? nil : Stream.new(stream, @query)
103
124
  end
104
125
  end
105
126
 
106
- # Get a list of streams for a specific game, for a set of channels, or by other criteria.
127
+ # Get all currently live streams.
128
+ # @example
129
+ # Twitch.streams.all
130
+ # @example
131
+ # Twitch.streams.all(:offset => 100, :limit => 10)
132
+ # @example
133
+ # Twitch.streams.all do |stream|
134
+ # next if stream.viewer_count < 1000
135
+ # puts stream.url
136
+ # end
137
+ # @param options [Hash] Limit criteria.
138
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
139
+ # @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
140
+ # @yield Optional. If a block is given, each stream is yielded.
141
+ # @yieldparam [Stream] stream Current stream.
142
+ # @see #get
143
+ # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streams GET /streams
144
+ # @return [Array<Stream>] Currently live streams, if no block is given.
145
+ # @return [nil] If a block is given.
146
+ def all(options = {}, &block)
147
+ return @query.connection.accumulate(
148
+ :path => 'streams',
149
+ :json => 'streams',
150
+ :create => -> hash { Stream.new(hash, @query) },
151
+ :limit => options[:limit],
152
+ :offset => options[:offset],
153
+ &block
154
+ )
155
+ end
156
+
157
+ # Get streams for a specific game, for a set of channels, or by other criteria.
107
158
  # @example
108
159
  # Twitch.streams.find(:game => 'League of Legends', :limit => 50)
109
160
  # @example
110
161
  # Twitch.streams.find(:channel => ['fgtvlive', 'incontroltv', 'destiny'])
111
162
  # @example
112
163
  # Twitch.streams.find(:game => 'Diablo III', :channel => ['nl_kripp', 'protech'])
164
+ # @example
165
+ # Twitch.streams.find(:game => 'League of Legends') do |stream|
166
+ # next if stream.viewer_count < 1000
167
+ # puts stream.url
168
+ # end
113
169
  # @param options [Hash] Search criteria.
114
- # @option options [String/Game/#name] :game Only return streams currently streaming the specified game.
115
- # @option options [Array<String/Channel/#name>] :channel Only return streams for these channels.
170
+ # @option options [String, Game, #name] :game Only return streams currently streaming the specified game.
171
+ # @option options [Array<String, Channel, #name>] :channel Only return streams for these channels.
116
172
  # If a channel is not currently streaming, it is omitted. You must specify an array of channels
117
173
  # or channel names. If you want to find the stream for a single channel, see {Streams#get}.
118
174
  # @option options [Boolean] :embeddable (nil) If `true`, limit the streams to those that can be embedded. If `false` or `nil`, do not limit.
119
175
  # @option options [Boolean] :hls (nil) If `true`, limit the streams to those using HLS (HTTP Live Streaming). If `false` or `nil`, do not limit.
120
- # @option options [Fixnum] :limit (none) Limit on the number of results returned.
176
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
121
177
  # @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
178
+ # @yield Optional. If a block is given, each stream found is yielded.
179
+ # @yieldparam [Stream] stream Current stream.
122
180
  # @see #get
123
181
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streams GET /streams
124
182
  # @raise [ArgumentError] If `options` does not specify a search criteria (`:game`, `:channel`, `:embeddable`, or `:hls`).
125
183
  # @raise [ArgumentError] If `:channel` is not an array.
126
- # @return [Array<Stream>] List of streams matching the specified criteria.
127
- def find(options)
184
+ # @return [Array<Stream>] Streams matching the specified criteria, if no block is given.
185
+ # @return [nil] If a block is given.
186
+ def find(options, &block)
128
187
  check = options.dup
129
188
  check.delete(:limit)
130
189
  check.delete(:offset)
@@ -170,23 +229,32 @@ module Twitch::V2
170
229
  :json => 'streams',
171
230
  :create => -> hash { Stream.new(hash, @query) },
172
231
  :limit => options[:limit],
173
- :offset => options[:offset]
232
+ :offset => options[:offset],
233
+ &block
174
234
  )
175
235
  end
176
236
 
177
- # Get the list of currently featured (promoted) streams. This includes the list of streams shown on the Twitch homepage.
237
+ # Get the currently featured (promoted) streams. This includes the streams shown on the Twitch homepage.
178
238
  # @note There is no guarantee of how many streams are featured at any given time.
179
239
  # @example
180
240
  # Twitch.streams.featured
181
241
  # @example
182
242
  # Twitch.streams.featured(:limit => 5)
243
+ # @example
244
+ # Twitch.streams.featured do |stream|
245
+ # next if stream.viewer_count < 1000
246
+ # puts stream.url
247
+ # end
183
248
  # @param options [Hash] Filter criteria.
184
249
  # @option options [Boolean] :hls (nil) If `true`, limit the streams to those using HLS (HTTP Live Streaming). If `false` or `nil`, do not limit.
185
- # @option options [Fixnum] :limit (none) Limit on the number of results returned.
250
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
186
251
  # @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
252
+ # @yield Optional. If a block is given, each featured stream is yielded.
253
+ # @yieldparam [Stream] stream Current stream.
187
254
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streamsfeatured GET /streams/featured
188
- # @return [Array<Stream>] List of currently featured streams.
189
- def featured(options = {})
255
+ # @return [Array<Stream>] Featured streams, if no block is given.
256
+ # @return [nil] If a block is given.
257
+ def featured(options = {}, &block)
190
258
  params = {}
191
259
 
192
260
  if options[:hls]
@@ -200,8 +268,21 @@ module Twitch::V2
200
268
  :sub_json => 'stream',
201
269
  :create => -> hash { Stream.new(hash, @query) },
202
270
  :limit => options[:limit],
203
- :offset => options[:offset]
271
+ :offset => options[:offset],
272
+ &block
204
273
  )
205
274
  end
275
+
276
+ # Get site-wide stream summary statistics.
277
+ # @example
278
+ # summary = Twitch.streams.summary
279
+ # summary.viewer_count # => 194774
280
+ # summary.channel_count # => 4144
281
+ # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#gedt-streamssummary GET /streams/summary
282
+ # @return [StreamSummary] Stream summary statistics.
283
+ def summary
284
+ json = @query.connection.get('streams/summary')
285
+ StreamSummary.new(json)
286
+ end
206
287
  end
207
288
  end
data/lib/kappa/team.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'cgi'
1
2
  require 'time'
2
3
 
3
4
  module Twitch::V2
@@ -20,7 +21,9 @@ module Twitch::V2
20
21
  @display_name = hash['display_name']
21
22
  @updated_at = Time.parse(hash['updated_at']).utc
22
23
  @created_at = Time.parse(hash['created_at']).utc
23
- @url = "http://www.twitch.tv/team/#{@name}"
24
+
25
+ name = CGI.escape(@name)
26
+ @url = "http://www.twitch.tv/team/#{name}"
24
27
  end
25
28
 
26
29
  # @example
@@ -91,10 +94,9 @@ module Twitch::V2
91
94
  # @return [Team] A valid `Team` object if the team exists, `nil` otherwise.
92
95
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/teams.md#get-teamsteam GET /teams/:team
93
96
  def get(team_name)
94
- json = @query.connection.get("teams/#{team_name}")
95
- if json['status'] == 404
96
- nil
97
- else
97
+ name = CGI.escape(team_name)
98
+ Twitch::Status.map(404 => nil) do
99
+ json = @query.connection.get("teams/#{name}")
98
100
  Team.new(json)
99
101
  end
100
102
  end
@@ -104,17 +106,26 @@ module Twitch::V2
104
106
  # Twitch.teams.all
105
107
  # @example
106
108
  # Twitch.teams.all(:limit => 10)
109
+ # @example
110
+ # Twitch.teams do |team|
111
+ # next if (Time.now - team.updated_at) > (60 * 60 * 24)
112
+ # puts team.url
113
+ # end
107
114
  # @param options [Hash] Filter criteria.
108
- # @option options [Fixnum] :limit (none) Limit on the number of results returned.
115
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
116
+ # @yield Optional. If a block is given, each team is yielded.
117
+ # @yieldparam [Team] team Current team.
109
118
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/teams.md#get-teams GET /teams
110
- # @return [Array<Team>] List of all active teams.
111
- def all(options = {})
119
+ # @return [Array<Team>] All active teams, if no block is given.
120
+ # @return [nil] If a block is given.
121
+ def all(options = {}, &block)
112
122
  return @query.connection.accumulate(
113
123
  :path => 'teams',
114
124
  :json => 'teams',
115
125
  :create => Team,
116
126
  :limit => options[:limit],
117
- :offset => options[:offset]
127
+ :offset => options[:offset],
128
+ &block
118
129
  )
119
130
  end
120
131
  end
data/lib/kappa/user.rb CHANGED
@@ -54,27 +54,39 @@ module Twitch::V2
54
54
  end
55
55
 
56
56
  # Get the channels the user is currently following.
57
+ # @example
58
+ # user.following(:limit => 10)
59
+ # @example
60
+ # user.following do |channel|
61
+ # next if channel.game_name !~ /starcraft/i
62
+ # puts channel.display_name
63
+ # end
57
64
  # @param options [Hash] Filter criteria.
58
- # @option options [Fixnum] :limit (none) Limit on the number of results returned.
65
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
59
66
  # @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
67
+ # @yield Optional. If a block is given, each followed channel is yielded.
68
+ # @yieldparam [Channel] channel Current channel.
60
69
  # @see #following?
61
70
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/follows.md#get-usersuserfollowschannels GET /users/:user/follows/channels
62
- # @return [Array<Channel>] List of channels the user is currently following.
63
- def following(options = {})
71
+ # @return [Array<Channel>] Channels the user is currently following, if no block is given.
72
+ # @return [nil] If a block is given.
73
+ def following(options = {}, &block)
74
+ name = CGI.escape(@name)
64
75
  return @query.connection.accumulate(
65
- :path => "users/#{@name}/follows/channels",
76
+ :path => "users/#{name}/follows/channels",
66
77
  :json => 'follows',
67
78
  :sub_json => 'channel',
68
79
  :create => -> hash { Channel.new(hash, @query) },
69
80
  :limit => options[:limit],
70
- :offset => options[:offset]
81
+ :offset => options[:offset],
82
+ &block
71
83
  )
72
84
  end
73
85
 
74
- # @param channel [String/Channel/User/Stream/#name] The name of the channel to check.
86
+ # @param target [String, Channel, User, Stream, #name] The name of the channel to check.
75
87
  # @return [Boolean] `true` if the user is following the channel, `false` otherwise.
76
88
  # @see #following
77
- # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/follows.md#get-usersuserfollowschannelstarget GET /users/:user/follows/:channels/:target
89
+ # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/follows.md#get-usersuserfollowschannelstarget GET /users/:user/follows/channels/:target
78
90
  def following?(target)
79
91
  name = if target.respond_to?(:name)
80
92
  target.name
@@ -82,11 +94,13 @@ module Twitch::V2
82
94
  target.to_s
83
95
  end
84
96
 
85
- name = CGI.escape(name)
97
+ user_name = CGI.escape(@name)
98
+ channel_name = CGI.escape(name)
86
99
 
87
- json = @query.connection.get("users/#{@name}/follows/channels/#{name}")
88
- status = json['status']
89
- return !status || (status != 404)
100
+ Twitch::Status.map(404 => false) do
101
+ @query.connection.get("users/#{user_name}/follows/channels/#{channel_name}")
102
+ true
103
+ end
90
104
  end
91
105
 
92
106
  # @example
@@ -135,11 +149,9 @@ module Twitch::V2
135
149
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/users.md#get-usersuser GET /users/:user
136
150
  # @return [User] A valid `User` object if the user exists, `nil` otherwise.
137
151
  def get(user_name)
138
- encoded_name = CGI.escape(user_name)
139
- json = @query.connection.get("users/#{encoded_name}")
140
- if !json || json['status'] == 404
141
- nil
142
- else
152
+ name = CGI.escape(user_name)
153
+ Twitch::Status.map(404 => nil) do
154
+ json = @query.connection.get("users/#{name}")
143
155
  User.new(json, @query)
144
156
  end
145
157
  end
data/lib/kappa/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Twitch
2
- VERSION = '0.4.0'
2
+ VERSION = '1.0.0'
3
3
  end
data/lib/kappa/video.rb CHANGED
@@ -120,11 +120,9 @@ module Twitch::V2
120
120
  def get(id)
121
121
  raise ArgumentError, 'id' if !id || id.strip.empty?
122
122
 
123
- encoded_id = CGI.escape(id)
124
- json = @query.connection.get("videos/#{encoded_id}")
125
- if !json || json['status'] == 404
126
- nil
127
- else
123
+ id = CGI.escape(id)
124
+ Twitch::Status.map(404 => nil) do
125
+ json = @query.connection.get("videos/#{id}")
128
126
  Video.new(json, @query)
129
127
  end
130
128
  end
@@ -137,15 +135,23 @@ module Twitch::V2
137
135
  # Twitch.videos.top(:period => :month, :game => 'Super Meat Boy')
138
136
  # @example
139
137
  # Twitch.videos.top(:period => :all, :limit => 10)
138
+ # @example
139
+ # Twitch.videos.top(:period => :all) do |video|
140
+ # next if video.view_count < 10000
141
+ # puts video.url
142
+ # end
140
143
  # @param options [Hash] Filter criteria.
141
144
  # @option options [Symbol] :period (:week) Return videos only in this time period. Valid values are `:week`, `:month`, `:all`.
142
145
  # @option options [String] :game (nil) Return videos only for this game.
143
- # @option options [Fixnum] :limit (none) Limit on the number of results returned.
146
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
144
147
  # @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
148
+ # @yield Optional. If a block is given, each top video is yielded.
149
+ # @yieldparam [Video] video Current video.
145
150
  # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/videos.md#get-videostop GET /videos/top
146
151
  # @raise [ArgumentError] If `:period` is not one of `:week`, `:month`, or `:all`.
147
- # @return [Array<Video>] List of top videos.
148
- def top(options = {})
152
+ # @return [Array<Video>] Top videos, if no block is given.
153
+ # @return [nil] If a block is given.
154
+ def top(options = {}, &block)
149
155
  params = {}
150
156
 
151
157
  if options[:game]
@@ -165,6 +171,57 @@ module Twitch::V2
165
171
  :json => 'videos',
166
172
  :create => -> hash { Video.new(hash, @query) },
167
173
  :limit => options[:limit],
174
+ :offset => options[:offset],
175
+ &block
176
+ )
177
+ end
178
+
179
+ # Get the videos for a channel, most recently created first.
180
+ # @example
181
+ # v = Twitch.videos.for_channel('dreamhacktv')
182
+ # @example
183
+ # v = Twitch.videos.for_channel('dreamhacktv', :type => :highlights, :limit => 10)
184
+ # @example
185
+ # Twitch.videos.for_channel('dreamhacktv') do |video|
186
+ # next if video.view_count < 10000
187
+ # puts video.url
188
+ # end
189
+ # @param options [Hash] Filter criteria.
190
+ # @option options [Symbol] :type (:highlights) The type of videos to return. Valid values are `:broadcasts`, `:highlights`.
191
+ # @option options [Fixnum] :limit (nil) Limit on the number of results returned.
192
+ # @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
193
+ # @yield Optional. If a block is given, each video is yielded.
194
+ # @yieldparam [Video] video Current video.
195
+ # @see Channel#videos Channel#videos
196
+ # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/videos.md#get-channelschannelvideos GET /channels/:channel/videos
197
+ # @raise [ArgumentError] If `:type` is not one of `:broadcasts` or `:highlights`.
198
+ # @return [Array<Video>] Videos for the channel, if no block is given.
199
+ # @return [nil] If a block is given.
200
+ def for_channel(channel, options = {})
201
+ if channel.respond_to?(:name)
202
+ channel_name = channel.name
203
+ else
204
+ channel_name = channel.to_s
205
+ end
206
+
207
+ params = {}
208
+
209
+ type = options[:type] || :highlights
210
+ if !type.nil?
211
+ if ![:broadcasts, :highlights].include?(type)
212
+ raise ArgumentError, 'type'
213
+ end
214
+
215
+ params[:broadcasts] = (type == :broadcasts)
216
+ end
217
+
218
+ name = CGI.escape(channel_name)
219
+ return @query.connection.accumulate(
220
+ :path => "channels/#{name}/videos",
221
+ :params => params,
222
+ :json => 'videos',
223
+ :create => -> hash { Video.new(hash, @query) },
224
+ :limit => options[:limit],
168
225
  :offset => options[:offset]
169
226
  )
170
227
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kappa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-22 00:00:00.000000000 Z
12
+ date: 2013-08-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
@@ -171,8 +171,8 @@ dependencies:
171
171
  - - ! '>='
172
172
  - !ruby/object:Gem::Version
173
173
  version: '0'
174
- description: ! " A Ruby library for interfacing with the Twitch.tv API\n including
175
- users, channels, streams, and followers.\n"
174
+ description: ! " The Ruby library for interfacing with the Twitch.tv API\n including
175
+ users, channels, streams, games, and videos.\n"
176
176
  email: schmch@gmail.com
177
177
  executables: []
178
178
  extensions: []
@@ -185,8 +185,10 @@ files:
185
185
  - lib/kappa/team.rb
186
186
  - lib/kappa/images.rb
187
187
  - lib/kappa/user.rb
188
+ - lib/kappa/status.rb
188
189
  - lib/kappa/id_equality.rb
189
190
  - lib/kappa/query.rb
191
+ - lib/kappa/errors.rb
190
192
  - lib/kappa/channel.rb
191
193
  - lib/kappa/proxy.rb
192
194
  - lib/kappa/game.rb