kappa 0.1.5.pre → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # <img src="https://raw.github.com/schmich/kappa/master/assets/kappa.png" /> Kappa
2
2
 
3
- Kappa is a Ruby library for interfacing with the [Twitch.tv API](https://github.com/justintv/Twitch-API).
3
+ Kappa is the Ruby library for interfacing with the [Twitch.tv API](https://github.com/justintv/Twitch-API).
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/kappa.png)](https://badge.fury.io/rb/kappa.png)
6
- [![Build Status](https://secure.travis-ci.org/schmich/tome.png)](http://travis-ci.org/schmich/tome)
5
+ [![Gem Version](https://badge.fury.io/rb/kappa.png)](http://rubygems.org/gems/kappa)
6
+ [![Build Status](https://secure.travis-ci.org/schmich/kappa.png)](http://travis-ci.org/schmich/kappa)
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
10
 
11
11
  ## Getting Started
12
12
 
13
- `gem install kappa --pre`
13
+ `gem install kappa`
14
14
 
15
15
  ```ruby
16
16
  require 'kappa'
@@ -23,60 +23,124 @@ puts grubby.streaming?
23
23
 
24
24
  ## Examples
25
25
 
26
- ### Channels
26
+ ### <a id="channels"></a>Channels
27
27
 
28
28
  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.
29
29
 
30
+ See also [`Kappa::V2::Channel`](http://rdoc.info/github/schmich/kappa/master/Kappa/V2/Channel) documentation.
31
+
30
32
  ```ruby
31
33
  c = Channel.get('destiny')
32
-
33
- c.nil? # Does the requested channel not exist? (ex: false)
34
- c.name # Unique Twitch name (ex: "destiny")
35
- c.display_name # Display name, e.g. name used for page title (ex: "Destiny")
36
- c.stream # The currently live stream for this channel (ex: #<Kappa::V2::Stream> object)
37
- c.url # The URL for the channel's main page (ex: "http://www.twitch.tv/destiny")
38
- c.status # Current status (ex: "Destiny - Diamond I ADC - Number 1 Draven player in the entire Omaha (NE) metro area -watch from http://www.destiny.gg")
39
- c.streaming? # Is the channel currently streaming? (ex: true)
40
- c.game_name # Name of the primary game for this channel (ex: "League of Legends")
41
- c.mature? # Does the channel have mature content? (ex: true)
42
- c.id # Unique Twitch ID (ex: 18074328)
43
- c.created_at # When the channel was created (ex: #<DateTime: 2010-11-22T04:14:56+00:00 ((2455523j,15296s,0n),+0s,2299161j)>)
44
- c.updated_at # When the channel was last updated, e.g. last stream time (ex: #<DateTime: 2013-05-11T19:57:29+00:00 ((2456424j,71849s,0n),+0s,2299161j)>)
45
- c.background_url # URL for background image (ex: "http://static-cdn.jtvnw.net/jtv_user_pictures/destiny-channel_background_image-ab706db77853e079.jpeg")
46
- c.banner_url # URL for banner image (ex: "http://static-cdn.jtvnw.net/jtv_user_pictures/destiny-channel_header_image-d2b9b2452f67ec00-640x125.jpeg")
47
- c.logo_url # URL for logo image (ex: "http://static-cdn.jtvnw.net/jtv_user_pictures/destiny-profile_image-168e66661c484c5e-300x300.jpeg")
48
- c.video_banner_url # URL for the image shown when the stream is offline (ex: "http://static-cdn.jtvnw.net/jtv_user_pictures/destiny-channel_offline_image-7a21fd1bd88c4ac3-640x360.jpeg")
49
-
50
- c.videos
51
- c.teams
52
- c.subscribers
53
- c.editors
54
- c.followers
55
- c.has_subscriber?
34
+ c.nil? # => false (channel exists)
35
+ c.stream # => #<Kappa::V2::Stream> (current live stream)
36
+ c.url # => "http://www.twitch.tv/destiny"
37
+ c.status # => "Destiny - Diamond I ADC - Number 1 Draven player..."
38
+ c.teams # => [#<Kappa::V2::Team>]
39
+ c.videos # => [#<Kappa::V2::Video>, ...]
40
+ c.followers # => [#<Kappa::V2::User>, ...]
56
41
  ```
57
42
 
58
- ### Streams
43
+ ### <a id="streams"></a>Streams
44
+
45
+ Streams are video broadcasts that are currently live. They belong to a [user](#users) and are part of a [channel](#channels).
59
46
 
60
- Streams are video broadcasts that are currently live. They have a [broadcaster](#users) and are part of a [channel](#channels).
47
+ See also [`Kappa::V2::Stream`](http://rdoc.info/github/schmich/kappa/master/Kappa/V2/Stream) and [`Kappa::V2::Streams`](http://rdoc.info/github/schmich/kappa/master/Kappa/V2/Streams) documentation.
61
48
 
62
- ### Users
49
+ ```ruby
50
+ s = Stream.get('idrajit')
51
+ s.nil? # => false (currently live)
52
+ s.game_name # => "StarCraft II: Heart of the Swarm"
53
+ s.viewer_count # => 7267
54
+ s.channel.url # => "http://www.twitch.tv/idrajit"
55
+ ```
56
+
57
+ ### <a id="users"></a>Users
63
58
 
64
59
  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.
65
60
 
66
- ### Videos
61
+ See also [`Kappa::V2::User`](http://rdoc.info/github/schmich/kappa/master/Kappa/V2/User) documentation.
62
+
63
+ ```ruby
64
+ u = User.get('snoopeh')
65
+ u.nil? # => false (user exists)
66
+ u.channel # => #<Kappa::V2::Channel>
67
+ u.following.map(&:name) # => ["national_esl1", "dreamhacklol", "riotgames"]
68
+ ```
69
+
70
+ ### <a id="videos"></a>Videos
67
71
 
68
72
  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.
69
73
 
70
- ### Teams
74
+ See also [`Kappa::V2::Video`](http://rdoc.info/github/schmich/kappa/master/Kappa/V2/Video) and [`Kappa::V2::Videos`](http://rdoc.info/github/schmich/kappa/master/Kappa/V2/Videos) documentation.
75
+
76
+ ```ruby
77
+ v = Video.get('a395995729')
78
+ v.nil? # => false (video exists)
79
+ v.title # => "DreamHack Open Stockholm 26-27 April"
80
+ v.game_name # => "StarCraft II: Heart of the Swarm"
81
+ v.recorded_at # => #<DateTime: 2013-04-26T18:33:48+00:00>
82
+ v.view_count # => 12506
83
+ ```
84
+
85
+ ### <a id="teams"></a>Teams
71
86
 
72
87
  Teams are an organization of [channels](#channels).
73
88
 
74
- ### Games
89
+ See also [`Kappa::V2::Team`](http://rdoc.info/github/schmich/kappa/master/Kappa/V2/Team) documentation.
90
+
91
+ ```ruby
92
+ t = Team.get('teamliquid')
93
+ t.display_name # => "TeamLiquid"
94
+ t.info # => "TeamLiquid is awesome. and esports. video games. \n\n"
95
+ t.updated_at # => #<DateTime: 2013-04-27T16:58:55+00:00>
96
+ ```
97
+
98
+ ### <a id="games"></a>Games
75
99
 
76
100
  Games are categories (e.g. League of Legends, Diablo 3) used by [streams](#streams) and [channels](#channels). Games can be searched for by query.
77
101
 
102
+ See also [`Kappa::V2::Game`](http://rdoc.info/github/schmich/kappa/master/Kappa/V2/Game), [`Kappa::V2::Games`](http://rdoc.info/github/schmich/kappa/master/Kappa/V2/Games), and [`Kappa::V2::GameSuggestion`](http://rdoc.info/github/schmich/kappa/master/Kappa/V2/GameSuggestion) documentation.
103
+
104
+ ```ruby
105
+ top = Games.top(:limit => 3)
106
+ top.map(&:name) # => ["League of Legends", "Dota 2", "StarCraft II: Heart of the Swarm"]
107
+ ```
108
+
109
+ ```ruby
110
+ g = Games.top(:limit => 1).first
111
+ g.name # => "League of Legends"
112
+ g.channel_count # => 906
113
+ g.viewer_count # => 79223
114
+ g.box_images.medium_url # =>"http://static-cdn.jtvnw.net/ttv-boxart/League%20of%20Legends-272x380.jpg"
115
+ ```
116
+
117
+ ```ruby
118
+ s = Games.find(:name => 'diablo', :live => true)
119
+ s.map(&:name) # => ["Diablo III", "Diablo II", "Diablo", "Diablo II: Lord of Destruction"]
120
+ s.map(&:popularity) # => [120, 4, 1, 1]
121
+ ```
122
+
123
+ ## Documentation
124
+
125
+ Detailed API documentation is available at [http://rdoc.info/github/schmich/kappa/master/frames](http://rdoc.info/github/schmich/kappa/master/frames).
126
+
127
+ ## Versioning
128
+
129
+ - TODO: Semantic versioning
130
+ - TODO: Twitch API versions
131
+
78
132
  ## Contributing
79
133
 
134
+ - [Fork and clone the repo.](http://help.github.com/fork-a-repo/)
135
+ - [Create a branch for your changes.](http://learn.github.com/p/branching.html)
136
+ - Run `bundle install` to install development requirements.
137
+ - Implement your feature or bug fix.
138
+ - Add specs under the `spec` folder to prevent regressions or to test new code.
139
+ - Add [YARD](http://rubydoc.info/docs/yard/file/docs/GettingStarted.md) documentation for new features. Run `rake yard` to view documentation.
140
+ - Run `rake coverage` to run specs with code coverage. All specs must pass; coverage must remain at 100%.
141
+ - Commit and push your changes.
142
+ - [Submit a pull request.](http://help.github.com/send-pull-requests/)
143
+
80
144
  ## License
81
145
 
82
146
  Copyright &copy; 2013 Chris Schmich
data/lib/kappa.rb CHANGED
@@ -9,81 +9,3 @@ require 'kappa/user'
9
9
  require 'kappa/images'
10
10
  require 'kappa/twitch'
11
11
  require 'kappa/version'
12
-
13
- # TODO
14
- # https://github.com/justintv/Twitch-API
15
- # Blocks
16
- # GET /users/:login/blocks
17
- # PUT /users/:user/blocks/:target
18
- # DELETE /users/:user/blocks/:target
19
- # Channels
20
- # - GET /channels/:channel
21
- # GET /channel
22
- # GET /channels/:channel/editors
23
- # PUT /channels/:channel
24
- # GET /channels/:channel/videos
25
- # GET /channels/:channel/follows
26
- # DELETE /channels/:channel/stream_key
27
- # POST /channels/:channel/commercial
28
- # Chat
29
- # GET /chat/:channel
30
- # GET /chat/emoticons
31
- # Follows
32
- # GET /channels/:channel/follows
33
- # GET /users/:user/follows/channels
34
- # GET /users/:user/follows/channels/:target
35
- # PUT /users/:user/follows/channels/:target
36
- # DELETE /users/:user/follows/channels/:target
37
- # Games
38
- # - GET /games/top
39
- # Ingests
40
- # GET /ingests
41
- # Root
42
- # GET /
43
- # Search
44
- # GET /search/streams
45
- # - GET /search/games
46
- # Streams
47
- # - GET /streams/:channel
48
- # - GET /streams
49
- # GET /streams/featured
50
- # GET /streams/summary
51
- # GET /streams/followed
52
- # Subscriptions
53
- # GET /channels/:channel/subscriptions
54
- # GET /channels/:channel/subscriptions/:user
55
- # Teams
56
- # GET /teams
57
- # GET /teams/:team
58
- # Users
59
- # GET /users/:user
60
- # GET /user
61
- # GET /streams/followed
62
- # Videos
63
- # GET /videos/:id
64
- # GET /videos/top
65
- # GET /channels/:channel/videos
66
-
67
- # Overarching
68
- # - Common query syntax
69
- # - Access to raw properties (e.g. stream['game'] or stream.raw('game'))
70
- # - Paginated results take a block to allow for intermediate processing/termination
71
-
72
- # t = Kappa::Client.new
73
- # c = t.channel('lagtvmaximusblack')
74
- # c.editors -> [...]
75
- # c.videos -> [...]
76
- # c.followers -> [...]
77
- # c.subscriptions
78
- # c.start_commercial
79
- # c.reset_stream_key
80
- # c... ; c.save!
81
- # TODO: current user channel
82
-
83
- # t = Kappa::Client.new
84
- # t.streams.all
85
- # t.streams.all(:limit => 10)
86
- # t.streams.featured
87
- # t.streams.where(:channel => 'lagtvmaximusblack')
88
- # t.streams.where(:channel => [...], :game => '...', :embeddable => t/f, :hls => t/f)
89
- # t.stream_summary
data/lib/kappa/channel.rb CHANGED
@@ -1,24 +1,13 @@
1
1
  require 'cgi'
2
2
 
3
- module Kappa
4
- # @private
5
- class ChannelBase
6
- include IdEquality
7
-
8
- def self.get(channel_name)
9
- encoded_name = CGI.escape(channel_name)
10
- json = connection.get("channels/#{encoded_name}")
11
- if !json || json['status'] == 404
12
- nil
13
- else
14
- new(json)
15
- end
16
- end
17
- end
18
- end
19
-
20
3
  module Kappa::V2
21
- class Channel < Kappa::ChannelBase
4
+ # Channels serve as the home location for a user's content. Channels have a stream, can run
5
+ # commercials, store videos, display information and status, and have a customized page including
6
+ # banners and backgrounds.
7
+ # @see .get Channel.get
8
+ # @see Stream
9
+ # @see User
10
+ class Channel
22
11
  # TODO:
23
12
  # c.subscriptions
24
13
  # c.start_commercial
@@ -26,7 +15,9 @@ module Kappa::V2
26
15
  # c.foo = 'bar' ; c.save!
27
16
  # Current user's channel
28
17
  include Connection
18
+ include Kappa::IdEquality
29
19
 
20
+ # @private
30
21
  def initialize(hash)
31
22
  @id = hash['_id']
32
23
  @background_url = hash['background']
@@ -49,7 +40,22 @@ module Kappa::V2
49
40
  end
50
41
  end
51
42
 
52
- # This flag is specified by the owner of the channel.
43
+ # Get a channel by name.
44
+ # @param channel_name [String] The name of the channel to get. This is the same as the stream or user name.
45
+ # @return [Channel] A valid `Channel` object if the channel exists, `nil` otherwise.
46
+ def self.get(channel_name)
47
+ encoded_name = CGI.escape(channel_name)
48
+ json = connection.get("channels/#{encoded_name}")
49
+
50
+ # HTTP 422 can happen if the channel is associated with a Justin.tv account.
51
+ if !json || json['status'] == 404 || json['status'] == 422
52
+ nil
53
+ else
54
+ new(json)
55
+ end
56
+ end
57
+
58
+ # Does this channel have mature content? This flag is specified by the owner of the channel.
53
59
  # @return [Boolean] `true` if the channel has mature content, `false` otherwise.
54
60
  def mature?
55
61
  @mature
@@ -62,8 +68,8 @@ module Kappa::V2
62
68
  Stream.get(@name)
63
69
  end
64
70
 
65
- # This makes a separate request to get the channel's stream. If you want to actually use
66
- # the stream object, you should call `#stream` instead.
71
+ # Does this channel currently have a live stream?
72
+ # @note This makes a separate request to get the channel's stream. If you want to actually use the stream object, you should call `#stream` instead.
67
73
  # @return [Boolean] `true` if the channel currently has a live stream, `false` otherwise.
68
74
  # @see #stream
69
75
  def streaming?
@@ -74,6 +80,8 @@ module Kappa::V2
74
80
  # GET /channels/:channel/editors
75
81
  # https://github.com/justintv/Twitch-API/blob/master/v2_resources/channels.md#get-channelschanneleditors
76
82
  #
83
+ # @private
84
+ # Private until implemented.
77
85
  def editors
78
86
  # TODO
79
87
  end
@@ -82,19 +90,41 @@ module Kappa::V2
82
90
  # GET /channels/:channels/videos
83
91
  # https://github.com/justintv/Twitch-API/blob/master/v2_resources/videos.md#get-channelschannelvideos
84
92
  #
93
+ # @private
94
+ # Private until implemented.
85
95
  def videos(params = {})
86
96
  # TODO
87
97
  end
88
98
 
99
+ # TODO: Requires authentication.
100
+ # @private
101
+ # Private until implemented.
102
+ def subscribers
103
+ end
104
+
89
105
  #
90
- # GET /channels/:channel/follows
91
- # https://github.com/justintv/Twitch-API/blob/master/v2_resources/channels.md#get-channelschannelfollows
92
- # TODO: Warning: this set can be very large, this can run for very long time, recommend using :limit/:offset.
106
+ # GET /channels/:channel/subscriptions/:user
107
+ # https://github.com/justintv/Twitch-API/blob/master/v2_resources/subscriptions.md#get-channelschannelsubscriptionsuser
93
108
  #
94
- def followers(args = {})
109
+ # TODO: Requires authentication.
110
+ # @private
111
+ # Private until implemented.
112
+ def has_subscriber?(user)
113
+ # Support User object or username (string)
114
+ end
115
+
116
+ # Get the users following this channel.
117
+ # @note The number of followers is potentially very large, so it's recommended that you specify a `:limit`.
118
+ # @param options [Hash] Filter criteria.
119
+ # @option options [Fixnum] :limit (none) Limit on the number of results returned.
120
+ # @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
121
+ # @see User
122
+ # @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/channels.md#get-channelschannelfollows GET /channels/:channel/follows
123
+ # @return [Array<User>] List of users following this channel.
124
+ def followers(options = {})
95
125
  params = {}
96
126
 
97
- limit = args[:limit]
127
+ limit = options[:limit]
98
128
  if limit && (limit < 100)
99
129
  params[:limit] = limit
100
130
  else
@@ -112,19 +142,6 @@ module Kappa::V2
112
142
  )
113
143
  end
114
144
 
115
- # TODO: Requires authentication.
116
- def subscribers
117
- end
118
-
119
- #
120
- # GET /channels/:channel/subscriptions/:user
121
- # https://github.com/justintv/Twitch-API/blob/master/v2_resources/subscriptions.md#get-channelschannelsubscriptionsuser
122
- #
123
- # TODO: Requires authentication.
124
- def has_subscriber?(user)
125
- # Support User object or username (string)
126
- end
127
-
128
145
  # @return [Fixnum] Unique Twitch ID.
129
146
  attr_reader :id
130
147
 
@@ -137,7 +154,7 @@ module Kappa::V2
137
154
  # @return [DateTime] When the channel was created.
138
155
  attr_reader :created_at
139
156
 
140
- # @return [String] Display name, e.g. name used for page title.
157
+ # @return [String] User-friendly display name. This name is used for the channel's page title.
141
158
  attr_reader :display_name
142
159
 
143
160
  # @return [String] Name of the primary game for this channel.
@@ -149,10 +166,10 @@ module Kappa::V2
149
166
  # @return [String] Unique Twitch name.
150
167
  attr_reader :name
151
168
 
152
- # @return [String] Current status.
169
+ # @return [String] Current status set by the channel's owner.
153
170
  attr_reader :status
154
171
 
155
- # @return [DateTime] When the channel was last updated, e.g. last stream time.
172
+ # @return [DateTime] When the channel was last updated. When a stream is started, its channel is updated.
156
173
  attr_reader :updated_at
157
174
 
158
175
  # @return [String] The URL for the channel's main page.
@@ -161,6 +178,7 @@ module Kappa::V2
161
178
  # @return [String] URL for the image shown when the stream is offline.
162
179
  attr_reader :video_banner_url
163
180
 
181
+ # @return [Array<Team>] The list of teams that this channel is associated with. Not all channels have associated teams.
164
182
  attr_reader :teams
165
183
  end
166
184
  end
@@ -13,11 +13,13 @@ module Kappa
13
13
  def initialize(base_url = DEFAULT_BASE_URL)
14
14
  @base_url = Addressable::URI.parse(base_url)
15
15
 
16
+ # TODO: Expose client_id so clients of the library can (optionally) set this
17
+ # themselves and avoid rate limiting. Clients should still have the option to
18
+ # not set this and use a randomly generated ID.
19
+
16
20
  uuid = SecureRandom.uuid
17
21
  # TODO: Use current library version.
18
22
  @client_id = "Kappa-v1-#{uuid}"
19
-
20
- @last_request_time = Time.now - RATE_LIMIT_SEC
21
23
  end
22
24
 
23
25
  def get(path, query = nil)
@@ -27,25 +29,26 @@ module Kappa
27
29
  'Client-ID' => @client_id,
28
30
  }.merge(custom_headers)
29
31
 
30
- response = rate_limit do
31
- self.class.get(request_url, :headers => headers, :query => query)
32
- end
32
+ response = self.class.get(request_url, :headers => headers, :query => query)
33
33
 
34
34
  # TODO: Handle non-JSON response
35
35
  # TODO: Handle invalid JSON
36
36
  # TODO: Handle non-200 codes
37
+ # TODO: Include HTTP status code in the return value
37
38
 
38
39
  json = response.body
39
40
  return JSON.parse(json)
40
41
  end
41
42
 
42
- def accumulate(args)
43
- path = args[:path]
44
- params = args[:params]
45
- json = args[:json]
46
- sub_json = args[:sub_json]
47
- klass = args[:class]
48
- limit = args[:limit]
43
+ def accumulate(options)
44
+ path = options[:path]
45
+ params = options[:params] || {}
46
+ json = options[:json]
47
+ sub_json = options[:sub_json]
48
+ klass = options[:class]
49
+
50
+ total_limit = options[:limit]
51
+ page_limit = params[:limit] || 100
49
52
 
50
53
  objects = []
51
54
  ids = Set.new
@@ -57,13 +60,13 @@ module Kappa
57
60
  object = klass.new(object_json)
58
61
  if ids.add?(object.id)
59
62
  objects << object
60
- if objects.count == limit
63
+ if objects.count == total_limit
61
64
  return objects
62
65
  end
63
66
  end
64
67
  end
65
68
 
66
- !current_objects.empty?
69
+ !current_objects.empty? && (current_objects.count >= page_limit)
67
70
  end
68
71
 
69
72
  return objects
@@ -106,20 +109,6 @@ module Kappa
106
109
  end
107
110
 
108
111
  private
109
- def rate_limit
110
- delta = Time.now - @last_request_time
111
- delay = [RATE_LIMIT_SEC - delta, 0].max
112
-
113
- sleep delay if delay > 0
114
-
115
- begin
116
- return yield
117
- ensure
118
- @last_request_time = Time.now
119
- end
120
- end
121
-
122
- RATE_LIMIT_SEC = 1
123
112
  DEFAULT_BASE_URL = 'https://api.twitch.tv/kraken/'
124
113
  end
125
114
  end