kappa 1.0.1 → 1.0.2
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.
- checksums.yaml +7 -0
- data/.yardopts +6 -6
- data/LICENSE +19 -19
- data/README.md +285 -285
- data/lib/kappa.rb +15 -15
- data/lib/kappa/channel.rb +214 -214
- data/lib/kappa/configuration.rb +88 -88
- data/lib/kappa/connection.rb +139 -139
- data/lib/kappa/errors.rb +43 -43
- data/lib/kappa/game.rb +216 -216
- data/lib/kappa/id_equality.rb +17 -17
- data/lib/kappa/images.rb +44 -44
- data/lib/kappa/proxy.rb +32 -32
- data/lib/kappa/query.rb +22 -22
- data/lib/kappa/status.rb +16 -16
- data/lib/kappa/stream.rb +289 -288
- data/lib/kappa/team.rb +132 -132
- data/lib/kappa/user.rb +159 -159
- data/lib/kappa/version.rb +3 -3
- data/lib/kappa/video.rb +229 -229
- metadata +23 -44
data/lib/kappa/id_equality.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
module Twitch
|
2
|
-
# @private
|
3
|
-
module IdEquality
|
4
|
-
def hash
|
5
|
-
@id.hash
|
6
|
-
end
|
7
|
-
|
8
|
-
def eql?(other)
|
9
|
-
other && (self.class == other.class) && (self.id == other.id)
|
10
|
-
end
|
11
|
-
|
12
|
-
def ==(other)
|
13
|
-
eql?(other)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
1
|
+
module Twitch
|
2
|
+
# @private
|
3
|
+
module IdEquality
|
4
|
+
def hash
|
5
|
+
@id.hash
|
6
|
+
end
|
7
|
+
|
8
|
+
def eql?(other)
|
9
|
+
other && (self.class == other.class) && (self.id == other.id)
|
10
|
+
end
|
11
|
+
|
12
|
+
def ==(other)
|
13
|
+
eql?(other)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
data/lib/kappa/images.rb
CHANGED
@@ -1,44 +1,44 @@
|
|
1
|
-
module Twitch::V2
|
2
|
-
# A group of URLs pointing to variously-sized versions of the same image.
|
3
|
-
class Images
|
4
|
-
# @private
|
5
|
-
def initialize(hash)
|
6
|
-
@large_url = hash['large']
|
7
|
-
@medium_url = hash['medium']
|
8
|
-
@small_url = hash['small']
|
9
|
-
@template_url = hash['template']
|
10
|
-
end
|
11
|
-
|
12
|
-
# Get a URL pointing to an image with a specific size.
|
13
|
-
# @example
|
14
|
-
# url = images.url(320, 200)
|
15
|
-
# @param width [Fixnum] Desired width of the image.
|
16
|
-
# @param height [Fixnum] Desired height of the image.
|
17
|
-
# @return [String] URL pointing to the image with the specified size.
|
18
|
-
def url(width, height)
|
19
|
-
@template_url.gsub('{width}', width.to_s).gsub('{height}', height.to_s)
|
20
|
-
end
|
21
|
-
|
22
|
-
# @example
|
23
|
-
# "http://static-cdn.jtvnw.net/ttv-logoart/League%20of%20Legends-240x144.jpg"
|
24
|
-
# @return [String] URL for the large-sized version of this image.
|
25
|
-
attr_reader :large_url
|
26
|
-
|
27
|
-
# @example
|
28
|
-
# "http://static-cdn.jtvnw.net/ttv-logoart/League%20of%20Legends-120x72.jpg"
|
29
|
-
# @return [String] URL for the medium-sized version of this image.
|
30
|
-
attr_reader :medium_url
|
31
|
-
|
32
|
-
# @example
|
33
|
-
# "http://static-cdn.jtvnw.net/ttv-logoart/League%20of%20Legends-60x36.jpg"
|
34
|
-
# @return [String] URL for the small-sized version of this image.
|
35
|
-
attr_reader :small_url
|
36
|
-
|
37
|
-
# @note You shouldn't need to use this property directly. See #url for getting a formatted URL instead.
|
38
|
-
# @example
|
39
|
-
# "http://static-cdn.jtvnw.net/ttv-logoart/League%20of%20Legends-{width}x{height}.jpg"
|
40
|
-
# @return [String] Template image URL with placeholders for width and height.
|
41
|
-
# @see #url
|
42
|
-
attr_reader :template_url
|
43
|
-
end
|
44
|
-
end
|
1
|
+
module Twitch::V2
|
2
|
+
# A group of URLs pointing to variously-sized versions of the same image.
|
3
|
+
class Images
|
4
|
+
# @private
|
5
|
+
def initialize(hash)
|
6
|
+
@large_url = hash['large']
|
7
|
+
@medium_url = hash['medium']
|
8
|
+
@small_url = hash['small']
|
9
|
+
@template_url = hash['template']
|
10
|
+
end
|
11
|
+
|
12
|
+
# Get a URL pointing to an image with a specific size.
|
13
|
+
# @example
|
14
|
+
# url = images.url(320, 200)
|
15
|
+
# @param width [Fixnum] Desired width of the image.
|
16
|
+
# @param height [Fixnum] Desired height of the image.
|
17
|
+
# @return [String] URL pointing to the image with the specified size.
|
18
|
+
def url(width, height)
|
19
|
+
@template_url.gsub('{width}', width.to_s).gsub('{height}', height.to_s)
|
20
|
+
end
|
21
|
+
|
22
|
+
# @example
|
23
|
+
# "http://static-cdn.jtvnw.net/ttv-logoart/League%20of%20Legends-240x144.jpg"
|
24
|
+
# @return [String] URL for the large-sized version of this image.
|
25
|
+
attr_reader :large_url
|
26
|
+
|
27
|
+
# @example
|
28
|
+
# "http://static-cdn.jtvnw.net/ttv-logoart/League%20of%20Legends-120x72.jpg"
|
29
|
+
# @return [String] URL for the medium-sized version of this image.
|
30
|
+
attr_reader :medium_url
|
31
|
+
|
32
|
+
# @example
|
33
|
+
# "http://static-cdn.jtvnw.net/ttv-logoart/League%20of%20Legends-60x36.jpg"
|
34
|
+
# @return [String] URL for the small-sized version of this image.
|
35
|
+
attr_reader :small_url
|
36
|
+
|
37
|
+
# @note You shouldn't need to use this property directly. See #url for getting a formatted URL instead.
|
38
|
+
# @example
|
39
|
+
# "http://static-cdn.jtvnw.net/ttv-logoart/League%20of%20Legends-{width}x{height}.jpg"
|
40
|
+
# @return [String] Template image URL with placeholders for width and height.
|
41
|
+
# @see #url
|
42
|
+
attr_reader :template_url
|
43
|
+
end
|
44
|
+
end
|
data/lib/kappa/proxy.rb
CHANGED
@@ -1,32 +1,32 @@
|
|
1
|
-
# @private
|
2
|
-
module Proxy
|
3
|
-
def self.included(base)
|
4
|
-
base.extend(ClassMethods)
|
5
|
-
end
|
6
|
-
|
7
|
-
module ClassMethods
|
8
|
-
def proxy(&create_block)
|
9
|
-
self.class_variable_set(:@@creator, create_block)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def method_missing(*args)
|
14
|
-
real.send(*args)
|
15
|
-
end
|
16
|
-
|
17
|
-
def respond_to?(sym, include_private = false)
|
18
|
-
real.respond_to?(sym, include_private) || super
|
19
|
-
end
|
20
|
-
|
21
|
-
def respond_to_missing?(method_name, include_private = false)
|
22
|
-
real.respond_to?(method_name, include_private) || super
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
def real
|
27
|
-
@real ||= begin
|
28
|
-
creator = self.class.class_variable_get(:@@creator)
|
29
|
-
self.instance_eval(&creator)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
1
|
+
# @private
|
2
|
+
module Proxy
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def proxy(&create_block)
|
9
|
+
self.class_variable_set(:@@creator, create_block)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(*args)
|
14
|
+
real.send(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def respond_to?(sym, include_private = false)
|
18
|
+
real.respond_to?(sym, include_private) || super
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_to_missing?(method_name, include_private = false)
|
22
|
+
real.respond_to?(method_name, include_private) || super
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def real
|
27
|
+
@real ||= begin
|
28
|
+
creator = self.class.class_variable_get(:@@creator)
|
29
|
+
self.instance_eval(&creator)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/kappa/query.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
module Twitch::V2
|
2
|
-
# @private
|
3
|
-
class Query
|
4
|
-
def initialize(connection)
|
5
|
-
@connection = connection
|
6
|
-
@channels = Channels.new(self)
|
7
|
-
@streams = Streams.new(self)
|
8
|
-
@users = Users.new(self)
|
9
|
-
@games = Games.new(self)
|
10
|
-
@teams = Teams.new(self)
|
11
|
-
@videos = Videos.new(self)
|
12
|
-
end
|
13
|
-
|
14
|
-
attr_reader :connection
|
15
|
-
attr_reader :channels
|
16
|
-
attr_reader :streams
|
17
|
-
attr_reader :users
|
18
|
-
attr_reader :games
|
19
|
-
attr_reader :teams
|
20
|
-
attr_reader :videos
|
21
|
-
end
|
22
|
-
end
|
1
|
+
module Twitch::V2
|
2
|
+
# @private
|
3
|
+
class Query
|
4
|
+
def initialize(connection)
|
5
|
+
@connection = connection
|
6
|
+
@channels = Channels.new(self)
|
7
|
+
@streams = Streams.new(self)
|
8
|
+
@users = Users.new(self)
|
9
|
+
@games = Games.new(self)
|
10
|
+
@teams = Teams.new(self)
|
11
|
+
@videos = Videos.new(self)
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :connection
|
15
|
+
attr_reader :channels
|
16
|
+
attr_reader :streams
|
17
|
+
attr_reader :users
|
18
|
+
attr_reader :games
|
19
|
+
attr_reader :teams
|
20
|
+
attr_reader :videos
|
21
|
+
end
|
22
|
+
end
|
data/lib/kappa/status.rb
CHANGED
@@ -1,16 +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
|
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
@@ -1,288 +1,289 @@
|
|
1
|
-
require 'cgi'
|
2
|
-
|
3
|
-
module Twitch::V2
|
4
|
-
# Streams are video broadcasts that are currently live. They belong to a user and are part of a channel.
|
5
|
-
# @see Streams#get Streams#get
|
6
|
-
# @see Streams#find Streams#find
|
7
|
-
# @see Streams#featured Streams#featured
|
8
|
-
# @see Streams
|
9
|
-
# @see Channel
|
10
|
-
class Stream
|
11
|
-
include Twitch::IdEquality
|
12
|
-
|
13
|
-
# @private
|
14
|
-
def initialize(hash, query)
|
15
|
-
@query = query
|
16
|
-
@id = hash['_id']
|
17
|
-
@broadcaster = hash['broadcaster']
|
18
|
-
@game_name = hash['game']
|
19
|
-
@name = hash['name']
|
20
|
-
@viewer_count = hash['viewers']
|
21
|
-
@preview_url = hash['preview']
|
22
|
-
@channel = Channel.new(hash['channel'], @query)
|
23
|
-
@url = @channel.url
|
24
|
-
end
|
25
|
-
|
26
|
-
# Get the owner of this stream.
|
27
|
-
# @note This incurs an additional web request.
|
28
|
-
# @return [User] The user that owns this stream.
|
29
|
-
def user
|
30
|
-
@query.users.get(@channel.name)
|
31
|
-
end
|
32
|
-
|
33
|
-
# @example
|
34
|
-
# 6226912672
|
35
|
-
# @return [Fixnum] Unique Twitch ID.
|
36
|
-
attr_reader :id
|
37
|
-
|
38
|
-
# @example
|
39
|
-
# "fme", "xsplit", "obs", "rebroadcast", "delay", "unknown rtmp"
|
40
|
-
# @deprecated This attribute is not present in the V3 API.
|
41
|
-
# @return [String] The broadcasting software used for this stream.
|
42
|
-
attr_reader :broadcaster
|
43
|
-
|
44
|
-
# @example
|
45
|
-
# "Super Meat Boy"
|
46
|
-
# @return [String] The name of the game currently being streamed.
|
47
|
-
attr_reader :game_name
|
48
|
-
|
49
|
-
# @example
|
50
|
-
# "live_user_lethalfrag"
|
51
|
-
# @return [String] The unique Twitch name for this stream.
|
52
|
-
attr_reader :name
|
53
|
-
|
54
|
-
# @example
|
55
|
-
# 2342
|
56
|
-
# @return [Fixnum] The number of viewers currently watching the stream.
|
57
|
-
attr_reader :viewer_count
|
58
|
-
|
59
|
-
# @example
|
60
|
-
# "http://static-cdn.jtvnw.net/previews-ttv/live_user_lethalfrag-320x200.jpg"
|
61
|
-
# @return [String] URL of a preview screenshot taken from the video stream.
|
62
|
-
attr_reader :preview_url
|
63
|
-
|
64
|
-
# @note This does not incur any web requests.
|
65
|
-
# @return [Channel] The `Channel` associated with this stream.
|
66
|
-
attr_reader :channel
|
67
|
-
|
68
|
-
# @example
|
69
|
-
# "http://www.twitch.tv/lethalfrag"
|
70
|
-
# @return [String] The URL for this stream.
|
71
|
-
attr_reader :url
|
72
|
-
end
|
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
|
-
|
94
|
-
# Query class for finding featured streams or streams meeting certain criteria.
|
95
|
-
# @see Stream
|
96
|
-
class Streams
|
97
|
-
# @private
|
98
|
-
def initialize(query)
|
99
|
-
@query = query
|
100
|
-
end
|
101
|
-
|
102
|
-
# Get a live stream by name.
|
103
|
-
# @example
|
104
|
-
# s = Twitch.streams.get('lagtvmaximusblack')
|
105
|
-
# s.nil? # => false (stream is live)
|
106
|
-
# s.game_name # => "StarCraft II: Heart of the Swarm"
|
107
|
-
# s.viewer_count # => 2403
|
108
|
-
# @example
|
109
|
-
# s = Twitch.streams.get('destiny')
|
110
|
-
# s.nil? # => true (stream is offline)
|
111
|
-
# @param stream_name [String] The name of the stream to get. This is the same as the channel or user name.
|
112
|
-
# @see #find
|
113
|
-
# @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streamschannel GET /streams/:channel
|
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.
|
116
|
-
def get(stream_name)
|
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)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
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.
|
158
|
-
# @example
|
159
|
-
# Twitch.streams.find(:game => 'League of Legends', :limit => 50)
|
160
|
-
# @example
|
161
|
-
# Twitch.streams.find(:channel => ['fgtvlive', 'incontroltv', 'destiny'])
|
162
|
-
# @example
|
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
|
169
|
-
# @param options [Hash] Search criteria.
|
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.
|
172
|
-
# If a channel is not currently streaming, it is omitted. You must specify an array of channels
|
173
|
-
# or channel names. If you want to find the stream for a single channel, see {Streams#get}.
|
174
|
-
# @option options [Boolean] :embeddable (nil) If `true`, limit the streams to those that can be embedded. If `false` or `nil`, do not limit.
|
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.
|
176
|
-
# @option options [Fixnum] :limit (nil) Limit on the number of results returned.
|
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.
|
180
|
-
# @see #get
|
181
|
-
# @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streams GET /streams
|
182
|
-
# @raise [ArgumentError] If `options` does not specify a search criteria (`:game`, `:channel`, `:embeddable`, or `:hls`).
|
183
|
-
# @raise [ArgumentError] If `:channel` is not an array.
|
184
|
-
# @return [Array<Stream>] Streams matching the specified criteria,
|
185
|
-
#
|
186
|
-
|
187
|
-
|
188
|
-
check.
|
189
|
-
check.delete(:
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
:
|
229
|
-
:
|
230
|
-
:
|
231
|
-
:
|
232
|
-
:
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
#
|
239
|
-
# @
|
240
|
-
#
|
241
|
-
#
|
242
|
-
#
|
243
|
-
#
|
244
|
-
#
|
245
|
-
#
|
246
|
-
#
|
247
|
-
#
|
248
|
-
#
|
249
|
-
# @
|
250
|
-
# @option options [
|
251
|
-
# @option options [Fixnum] :
|
252
|
-
# @
|
253
|
-
# @
|
254
|
-
# @
|
255
|
-
# @
|
256
|
-
# @return [
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
:
|
267
|
-
:
|
268
|
-
:
|
269
|
-
:
|
270
|
-
:
|
271
|
-
:
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
#
|
278
|
-
#
|
279
|
-
# summary
|
280
|
-
# summary.
|
281
|
-
#
|
282
|
-
# @
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
end
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Twitch::V2
|
4
|
+
# Streams are video broadcasts that are currently live. They belong to a user and are part of a channel.
|
5
|
+
# @see Streams#get Streams#get
|
6
|
+
# @see Streams#find Streams#find
|
7
|
+
# @see Streams#featured Streams#featured
|
8
|
+
# @see Streams
|
9
|
+
# @see Channel
|
10
|
+
class Stream
|
11
|
+
include Twitch::IdEquality
|
12
|
+
|
13
|
+
# @private
|
14
|
+
def initialize(hash, query)
|
15
|
+
@query = query
|
16
|
+
@id = hash['_id']
|
17
|
+
@broadcaster = hash['broadcaster']
|
18
|
+
@game_name = hash['game']
|
19
|
+
@name = hash['name']
|
20
|
+
@viewer_count = hash['viewers']
|
21
|
+
@preview_url = hash['preview']
|
22
|
+
@channel = Channel.new(hash['channel'], @query)
|
23
|
+
@url = @channel.url
|
24
|
+
end
|
25
|
+
|
26
|
+
# Get the owner of this stream.
|
27
|
+
# @note This incurs an additional web request.
|
28
|
+
# @return [User] The user that owns this stream.
|
29
|
+
def user
|
30
|
+
@query.users.get(@channel.name)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @example
|
34
|
+
# 6226912672
|
35
|
+
# @return [Fixnum] Unique Twitch ID.
|
36
|
+
attr_reader :id
|
37
|
+
|
38
|
+
# @example
|
39
|
+
# "fme", "xsplit", "obs", "rebroadcast", "delay", "unknown rtmp"
|
40
|
+
# @deprecated This attribute is not present in the V3 API.
|
41
|
+
# @return [String] The broadcasting software used for this stream.
|
42
|
+
attr_reader :broadcaster
|
43
|
+
|
44
|
+
# @example
|
45
|
+
# "Super Meat Boy"
|
46
|
+
# @return [String] The name of the game currently being streamed.
|
47
|
+
attr_reader :game_name
|
48
|
+
|
49
|
+
# @example
|
50
|
+
# "live_user_lethalfrag"
|
51
|
+
# @return [String] The unique Twitch name for this stream.
|
52
|
+
attr_reader :name
|
53
|
+
|
54
|
+
# @example
|
55
|
+
# 2342
|
56
|
+
# @return [Fixnum] The number of viewers currently watching the stream.
|
57
|
+
attr_reader :viewer_count
|
58
|
+
|
59
|
+
# @example
|
60
|
+
# "http://static-cdn.jtvnw.net/previews-ttv/live_user_lethalfrag-320x200.jpg"
|
61
|
+
# @return [String] URL of a preview screenshot taken from the video stream.
|
62
|
+
attr_reader :preview_url
|
63
|
+
|
64
|
+
# @note This does not incur any web requests.
|
65
|
+
# @return [Channel] The `Channel` associated with this stream.
|
66
|
+
attr_reader :channel
|
67
|
+
|
68
|
+
# @example
|
69
|
+
# "http://www.twitch.tv/lethalfrag"
|
70
|
+
# @return [String] The URL for this stream.
|
71
|
+
attr_reader :url
|
72
|
+
end
|
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
|
+
|
94
|
+
# Query class for finding featured streams or streams meeting certain criteria.
|
95
|
+
# @see Stream
|
96
|
+
class Streams
|
97
|
+
# @private
|
98
|
+
def initialize(query)
|
99
|
+
@query = query
|
100
|
+
end
|
101
|
+
|
102
|
+
# Get a live stream by name.
|
103
|
+
# @example
|
104
|
+
# s = Twitch.streams.get('lagtvmaximusblack')
|
105
|
+
# s.nil? # => false (stream is live)
|
106
|
+
# s.game_name # => "StarCraft II: Heart of the Swarm"
|
107
|
+
# s.viewer_count # => 2403
|
108
|
+
# @example
|
109
|
+
# s = Twitch.streams.get('destiny')
|
110
|
+
# s.nil? # => true (stream is offline)
|
111
|
+
# @param stream_name [String] The name of the stream to get. This is the same as the channel or user name.
|
112
|
+
# @see #find
|
113
|
+
# @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streamschannel GET /streams/:channel
|
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.
|
116
|
+
def get(stream_name)
|
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)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Get all currently live streams sorted by descending viewer count.
|
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, sorted by descending viewer count, 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, sorted by descending viewer count.
|
158
|
+
# @example
|
159
|
+
# Twitch.streams.find(:game => 'League of Legends', :limit => 50)
|
160
|
+
# @example
|
161
|
+
# Twitch.streams.find(:channel => ['fgtvlive', 'incontroltv', 'destiny'])
|
162
|
+
# @example
|
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
|
169
|
+
# @param options [Hash] Search criteria.
|
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.
|
172
|
+
# If a channel is not currently streaming, it is omitted. You must specify an array of channels
|
173
|
+
# or channel names. If you want to find the stream for a single channel, see {Streams#get}.
|
174
|
+
# @option options [Boolean] :embeddable (nil) If `true`, limit the streams to those that can be embedded. If `false` or `nil`, do not limit.
|
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.
|
176
|
+
# @option options [Fixnum] :limit (nil) Limit on the number of results returned.
|
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.
|
180
|
+
# @see #get
|
181
|
+
# @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streams GET /streams
|
182
|
+
# @raise [ArgumentError] If `options` does not specify a search criteria (`:game`, `:channel`, `:embeddable`, or `:hls`).
|
183
|
+
# @raise [ArgumentError] If `:channel` is not an array.
|
184
|
+
# @return [Array<Stream>] Streams matching the specified criteria, sorted by
|
185
|
+
# descending viewer count, if no block is given.
|
186
|
+
# @return [nil] If a block is given.
|
187
|
+
def find(options, &block)
|
188
|
+
check = options.dup
|
189
|
+
check.delete(:limit)
|
190
|
+
check.delete(:offset)
|
191
|
+
raise ArgumentError, 'options' if check.empty?
|
192
|
+
|
193
|
+
params = {}
|
194
|
+
|
195
|
+
channels = options[:channel]
|
196
|
+
if channels
|
197
|
+
if !channels.respond_to?(:map)
|
198
|
+
raise ArgumentError, ':channel'
|
199
|
+
end
|
200
|
+
|
201
|
+
params[:channel] = channels.map { |channel|
|
202
|
+
if channel.respond_to?(:name)
|
203
|
+
channel.name
|
204
|
+
else
|
205
|
+
channel.to_s
|
206
|
+
end
|
207
|
+
}.join(',')
|
208
|
+
end
|
209
|
+
|
210
|
+
game = options[:game]
|
211
|
+
if game
|
212
|
+
if game.respond_to?(:name)
|
213
|
+
params[:game] = game.name
|
214
|
+
else
|
215
|
+
params[:game] = game.to_s
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
if options[:hls]
|
220
|
+
params[:hls] = true
|
221
|
+
end
|
222
|
+
|
223
|
+
if options[:embeddable]
|
224
|
+
params[:embeddable] = true
|
225
|
+
end
|
226
|
+
|
227
|
+
return @query.connection.accumulate(
|
228
|
+
:path => 'streams',
|
229
|
+
:params => params,
|
230
|
+
:json => 'streams',
|
231
|
+
:create => -> hash { Stream.new(hash, @query) },
|
232
|
+
:limit => options[:limit],
|
233
|
+
:offset => options[:offset],
|
234
|
+
&block
|
235
|
+
)
|
236
|
+
end
|
237
|
+
|
238
|
+
# Get the currently featured (promoted) streams. This includes the streams shown on the Twitch homepage.
|
239
|
+
# @note There is no guarantee of how many streams are featured at any given time.
|
240
|
+
# @example
|
241
|
+
# Twitch.streams.featured
|
242
|
+
# @example
|
243
|
+
# Twitch.streams.featured(:limit => 5)
|
244
|
+
# @example
|
245
|
+
# Twitch.streams.featured do |stream|
|
246
|
+
# next if stream.viewer_count < 1000
|
247
|
+
# puts stream.url
|
248
|
+
# end
|
249
|
+
# @param options [Hash] Filter criteria.
|
250
|
+
# @option options [Boolean] :hls (nil) If `true`, limit the streams to those using HLS (HTTP Live Streaming). If `false` or `nil`, do not limit.
|
251
|
+
# @option options [Fixnum] :limit (nil) Limit on the number of results returned.
|
252
|
+
# @option options [Fixnum] :offset (0) Offset into the result set to begin enumeration.
|
253
|
+
# @yield Optional. If a block is given, each featured stream is yielded.
|
254
|
+
# @yieldparam [Stream] stream Current stream.
|
255
|
+
# @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streamsfeatured GET /streams/featured
|
256
|
+
# @return [Array<Stream>] Featured streams, if no block is given.
|
257
|
+
# @return [nil] If a block is given.
|
258
|
+
def featured(options = {}, &block)
|
259
|
+
params = {}
|
260
|
+
|
261
|
+
if options[:hls]
|
262
|
+
params[:hls] = true
|
263
|
+
end
|
264
|
+
|
265
|
+
return @query.connection.accumulate(
|
266
|
+
:path => 'streams/featured',
|
267
|
+
:params => params,
|
268
|
+
:json => 'featured',
|
269
|
+
:sub_json => 'stream',
|
270
|
+
:create => -> hash { Stream.new(hash, @query) },
|
271
|
+
:limit => options[:limit],
|
272
|
+
:offset => options[:offset],
|
273
|
+
&block
|
274
|
+
)
|
275
|
+
end
|
276
|
+
|
277
|
+
# Get site-wide stream summary statistics.
|
278
|
+
# @example
|
279
|
+
# summary = Twitch.streams.summary
|
280
|
+
# summary.viewer_count # => 194774
|
281
|
+
# summary.channel_count # => 4144
|
282
|
+
# @see https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#gedt-streamssummary GET /streams/summary
|
283
|
+
# @return [StreamSummary] Stream summary statistics.
|
284
|
+
def summary
|
285
|
+
json = @query.connection.get('streams/summary')
|
286
|
+
StreamSummary.new(json)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|