kappa 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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