kappa 0.1.1.pre → 0.1.2.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +3 -2
- data/lib/kappa.rb +12 -780
- data/lib/kappa/base.rb +9 -0
- data/lib/kappa/channel.rb +140 -0
- data/lib/kappa/connection.rb +119 -0
- data/lib/kappa/game.rb +122 -0
- data/lib/kappa/id_equality.rb +16 -0
- data/lib/kappa/images.rb +33 -0
- data/lib/kappa/stream.rb +151 -0
- data/lib/kappa/team.rb +83 -0
- data/lib/kappa/twitch.rb +11 -0
- data/lib/kappa/user.rb +113 -0
- data/lib/kappa/version.rb +1 -1
- data/lib/kappa/video.rb +66 -0
- metadata +45 -2
    
        data/lib/kappa/base.rb
    ADDED
    
    
| @@ -0,0 +1,140 @@ | |
| 1 | 
            +
            module Kappa
         | 
| 2 | 
            +
              class ChannelBase
         | 
| 3 | 
            +
                include IdEquality
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def initialize(arg, connection)
         | 
| 6 | 
            +
                  @connection = connection
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  case arg
         | 
| 9 | 
            +
                    when Hash
         | 
| 10 | 
            +
                      parse(arg)
         | 
| 11 | 
            +
                    when String
         | 
| 12 | 
            +
                      json = @connection.get("channels/#{arg}")
         | 
| 13 | 
            +
                      parse(json)
         | 
| 14 | 
            +
                    else
         | 
| 15 | 
            +
                      raise ArgumentError
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            module Kappa::V2
         | 
| 22 | 
            +
              # TODO:
         | 
| 23 | 
            +
              # c.subscriptions
         | 
| 24 | 
            +
              # c.start_commercial
         | 
| 25 | 
            +
              # c.reset_stream_key
         | 
| 26 | 
            +
              # c.foo = 'bar' ; c.save!
         | 
| 27 | 
            +
              # Current user's channel
         | 
| 28 | 
            +
              class Channel < Kappa::ChannelBase
         | 
| 29 | 
            +
                def initialize(arg, connection = Connection.instance)
         | 
| 30 | 
            +
                  super(arg, connection)
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def mature?
         | 
| 34 | 
            +
                  @mature
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                # TODO: Move these into derived classes?
         | 
| 38 | 
            +
                def stream
         | 
| 39 | 
            +
                  # TODO: Use _links instead of hard-coding.
         | 
| 40 | 
            +
                  json = @connection.get("streams/#{@name}")
         | 
| 41 | 
            +
                  stream_json = json['stream']
         | 
| 42 | 
            +
                  Stream.new(stream_json, @connection)
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def streaming?
         | 
| 46 | 
            +
                  stream.live?
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                #
         | 
| 50 | 
            +
                # GET /channels/:channel/editors
         | 
| 51 | 
            +
                # https://github.com/justintv/Twitch-API/blob/master/v2_resources/channels.md#get-channelschanneleditors
         | 
| 52 | 
            +
                #
         | 
| 53 | 
            +
                def editors
         | 
| 54 | 
            +
                  # TODO
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                #
         | 
| 58 | 
            +
                # GET /channels/:channels/videos
         | 
| 59 | 
            +
                # https://github.com/justintv/Twitch-API/blob/master/v2_resources/videos.md#get-channelschannelvideos
         | 
| 60 | 
            +
                #
         | 
| 61 | 
            +
                def videos(params = {})
         | 
| 62 | 
            +
                  # TODO
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                #
         | 
| 66 | 
            +
                # GET /channels/:channel/follows
         | 
| 67 | 
            +
                # https://github.com/justintv/Twitch-API/blob/master/v2_resources/channels.md#get-channelschannelfollows
         | 
| 68 | 
            +
                # TODO: Warning: this set can be very large, this can run for very long time, recommend using :limit/:offset.
         | 
| 69 | 
            +
                #
         | 
| 70 | 
            +
                def followers(params = {})
         | 
| 71 | 
            +
                  limit = params[:limit] || 0
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  followers = []
         | 
| 74 | 
            +
                  ids = Set.new
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  @connection.paginated("channels/#{@name}/follows", params) do |json|
         | 
| 77 | 
            +
                    current_followers = json['follows']
         | 
| 78 | 
            +
                    current_followers.each do |follow_json|
         | 
| 79 | 
            +
                      user_json = follow_json['user']
         | 
| 80 | 
            +
                      user = User.new(user_json, @connection)
         | 
| 81 | 
            +
                      if ids.add?(user.id)
         | 
| 82 | 
            +
                        followers << user
         | 
| 83 | 
            +
                        if followers.count == limit
         | 
| 84 | 
            +
                          return followers
         | 
| 85 | 
            +
                        end
         | 
| 86 | 
            +
                      end
         | 
| 87 | 
            +
                    end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    !current_followers.empty?
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                  followers
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                # TODO: Requires authentication.
         | 
| 96 | 
            +
                def subscribers
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                #
         | 
| 100 | 
            +
                # GET /channels/:channel/subscriptions/:user
         | 
| 101 | 
            +
                # https://github.com/justintv/Twitch-API/blob/master/v2_resources/subscriptions.md#get-channelschannelsubscriptionsuser
         | 
| 102 | 
            +
                #
         | 
| 103 | 
            +
                # TODO: Requires authentication.
         | 
| 104 | 
            +
                def has_subscriber?(user)
         | 
| 105 | 
            +
                  # Support User object or username (string)
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                attr_reader :id
         | 
| 109 | 
            +
                attr_reader :background_url
         | 
| 110 | 
            +
                attr_reader :banner_url
         | 
| 111 | 
            +
                attr_reader :created_at
         | 
| 112 | 
            +
                attr_reader :stream_delay_sec
         | 
| 113 | 
            +
                attr_reader :display_name
         | 
| 114 | 
            +
                attr_reader :game_name
         | 
| 115 | 
            +
                attr_reader :logo_url
         | 
| 116 | 
            +
                attr_reader :name
         | 
| 117 | 
            +
                attr_reader :status
         | 
| 118 | 
            +
                attr_reader :updated_at
         | 
| 119 | 
            +
                attr_reader :url
         | 
| 120 | 
            +
                attr_reader :video_banner_url
         | 
| 121 | 
            +
             | 
| 122 | 
            +
              private
         | 
| 123 | 
            +
                def parse(hash)
         | 
| 124 | 
            +
                  @id = hash['_id']
         | 
| 125 | 
            +
                  @background_url = hash['background']
         | 
| 126 | 
            +
                  @banner_url = hash['banner']
         | 
| 127 | 
            +
                  @created_at = DateTime.parse(hash['created_at'])
         | 
| 128 | 
            +
                  @stream_delay_sec = hash['delay']
         | 
| 129 | 
            +
                  @display_name = hash['display_name']
         | 
| 130 | 
            +
                  @game_name = hash['game']
         | 
| 131 | 
            +
                  @logo_url = hash['logo']
         | 
| 132 | 
            +
                  @mature = hash['mature'] || false
         | 
| 133 | 
            +
                  @name = hash['name']
         | 
| 134 | 
            +
                  @status = hash['status']
         | 
| 135 | 
            +
                  @updated_at = DateTime.parse(hash['updated_at'])
         | 
| 136 | 
            +
                  @url = hash['url']
         | 
| 137 | 
            +
                  @video_banner_url = hash['video_banner']
         | 
| 138 | 
            +
                end
         | 
| 139 | 
            +
              end
         | 
| 140 | 
            +
            end
         | 
| @@ -0,0 +1,119 @@ | |
| 1 | 
            +
            require 'httparty'
         | 
| 2 | 
            +
            require 'addressable/uri'
         | 
| 3 | 
            +
            require 'securerandom'
         | 
| 4 | 
            +
            require 'json'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Kappa
         | 
| 7 | 
            +
              class ConnectionBase
         | 
| 8 | 
            +
                include HTTParty
         | 
| 9 | 
            +
                debug_output $stdout
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(base_url = DEFAULT_BASE_URL)
         | 
| 12 | 
            +
                  @base_url = Addressable::URI.parse(base_url)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  uuid = SecureRandom.uuid
         | 
| 15 | 
            +
                  # TODO: Use current library version.
         | 
| 16 | 
            +
                  @client_id = "Kappa-v1-#{uuid}"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  @last_request_time = Time.now - RATE_LIMIT_SEC
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def self.instance
         | 
| 22 | 
            +
                  @connection ||= self.class_eval do
         | 
| 23 | 
            +
                    self.new
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def get(path, query = nil)
         | 
| 28 | 
            +
                  request_url = @base_url + path
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  # Handle non-JSON response
         | 
| 31 | 
            +
                  # Handle invalid JSON
         | 
| 32 | 
            +
                  # Handle non-200 codes
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  headers = {
         | 
| 35 | 
            +
                    'Client-ID' => @client_id,
         | 
| 36 | 
            +
                  }.merge(custom_headers)
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  response = rate_limit do
         | 
| 39 | 
            +
                    self.class.get(request_url, :headers => headers, :query => query)
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  json = response.body
         | 
| 43 | 
            +
                  return JSON.parse(json)
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def paginated(path, params = {})
         | 
| 47 | 
            +
                  limit = [params[:limit] || 100, 100].min
         | 
| 48 | 
            +
                  offset = params[:offset] || 0
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  path_uri = Addressable::URI.parse(path)
         | 
| 51 | 
            +
                  query = { 'limit' => limit, 'offset' => offset }
         | 
| 52 | 
            +
                  path_uri.query_values ||= {}
         | 
| 53 | 
            +
                  path_uri.query_values = path_uri.query_values.merge(query)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  request_url = path_uri.to_s
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  params = params.dup
         | 
| 58 | 
            +
                  params.delete(:limit)
         | 
| 59 | 
            +
                  params.delete(:offset)
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  # TODO: Hande request retry.
         | 
| 62 | 
            +
                  loop do
         | 
| 63 | 
            +
                    json = get(request_url, params)
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    if json['error'] && (json['status'] == 503)
         | 
| 66 | 
            +
                      break
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                    break if !yield(json)
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                    links = json['_links']
         | 
| 72 | 
            +
                    next_url = links['next']
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                    next_uri = Addressable::URI.parse(next_url)
         | 
| 75 | 
            +
                    offset = next_uri.query_values['offset'].to_i
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    total = json['_total']
         | 
| 78 | 
            +
                    break if total && (offset > total)
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                    request_url = next_url
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
              private
         | 
| 85 | 
            +
                def rate_limit
         | 
| 86 | 
            +
                  delta = Time.now - @last_request_time
         | 
| 87 | 
            +
                  delay = [RATE_LIMIT_SEC - delta, 0].max
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  sleep delay if delay > 0
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  begin
         | 
| 92 | 
            +
                    return yield
         | 
| 93 | 
            +
                  ensure
         | 
| 94 | 
            +
                    @last_request_time = Time.now
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                RATE_LIMIT_SEC = 1
         | 
| 99 | 
            +
                DEFAULT_BASE_URL = 'https://api.twitch.tv/kraken/'
         | 
| 100 | 
            +
              end
         | 
| 101 | 
            +
            end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            module Kappa::V2
         | 
| 104 | 
            +
              class Connection < Kappa::ConnectionBase
         | 
| 105 | 
            +
              private
         | 
| 106 | 
            +
                def custom_headers
         | 
| 107 | 
            +
                  { 'Accept' => 'application/vnd.twitchtv.v2+json' }
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
              end
         | 
| 110 | 
            +
            end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            module Kappa::V3
         | 
| 113 | 
            +
              class Connection < Kappa::ConnectionBase
         | 
| 114 | 
            +
              private
         | 
| 115 | 
            +
                def custom_headers
         | 
| 116 | 
            +
                  { 'Accept' => 'application/vnd.twitchtv.v3+json' }
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
              end
         | 
| 119 | 
            +
            end
         | 
    
        data/lib/kappa/game.rb
    ADDED
    
    | @@ -0,0 +1,122 @@ | |
| 1 | 
            +
            module Kappa
         | 
| 2 | 
            +
              class GameBase
         | 
| 3 | 
            +
                include IdEquality
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def initialize(arg)
         | 
| 6 | 
            +
                  case arg
         | 
| 7 | 
            +
                    when Hash
         | 
| 8 | 
            +
                      parse(arg)
         | 
| 9 | 
            +
                    else
         | 
| 10 | 
            +
                      raise ArgumentError
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              class GameSuggestionBase
         | 
| 16 | 
            +
                include IdEquality
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def initialize(arg)
         | 
| 19 | 
            +
                  case arg
         | 
| 20 | 
            +
                    when Hash
         | 
| 21 | 
            +
                      parse(arg)
         | 
| 22 | 
            +
                    else
         | 
| 23 | 
            +
                      raise ArgumentError
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            module Kappa::V2
         | 
| 30 | 
            +
              class Game < Kappa::GameBase
         | 
| 31 | 
            +
                attr_reader :id
         | 
| 32 | 
            +
                attr_reader :name
         | 
| 33 | 
            +
                attr_reader :giantbomb_id
         | 
| 34 | 
            +
                attr_reader :box_images
         | 
| 35 | 
            +
                attr_reader :logo_images
         | 
| 36 | 
            +
                attr_reader :channel_count
         | 
| 37 | 
            +
                attr_reader :viewer_count
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              private
         | 
| 40 | 
            +
                def parse(hash)
         | 
| 41 | 
            +
                  @channel_count = hash['channels']
         | 
| 42 | 
            +
                  @viewer_count = hash['viewers']
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  game = hash['game']
         | 
| 45 | 
            +
                  @id = game['_id']
         | 
| 46 | 
            +
                  @name = game['name']
         | 
| 47 | 
            +
                  @giantbomb_id = game['giantbomb_id']
         | 
| 48 | 
            +
                  @box_images = Images.new(game['box'])
         | 
| 49 | 
            +
                  @logo_images = Images.new(game['logo'])
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              class GameSuggestion < Kappa::GameSuggestionBase
         | 
| 54 | 
            +
                attr_reader :id
         | 
| 55 | 
            +
                attr_reader :name
         | 
| 56 | 
            +
                attr_reader :giantbomb_id
         | 
| 57 | 
            +
                attr_reader :popularity
         | 
| 58 | 
            +
                attr_reader :box_images
         | 
| 59 | 
            +
                attr_reader :logo_images
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              private
         | 
| 62 | 
            +
                def parse(hash)
         | 
| 63 | 
            +
                  @id = hash['_id']
         | 
| 64 | 
            +
                  @name = hash['name']
         | 
| 65 | 
            +
                  @giantbomb_id = hash['giantbomb_id']
         | 
| 66 | 
            +
                  @popularity = hash['popularity']
         | 
| 67 | 
            +
                  @box_images = Images.new(hash['box'])
         | 
| 68 | 
            +
                  @logo_images = Images.new(hash['logo'])
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
              class Games
         | 
| 73 | 
            +
                #
         | 
| 74 | 
            +
                # GET /games/top
         | 
| 75 | 
            +
                # https://github.com/justintv/Twitch-API/blob/master/v2_resources/games.md#get-gamestop
         | 
| 76 | 
            +
                #
         | 
| 77 | 
            +
                def top(params = {})
         | 
| 78 | 
            +
                  limit = params[:limit] || 0
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  games = []
         | 
| 81 | 
            +
                  ids = Set.new
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  @conn.paginated('games/top', params) do |json|
         | 
| 84 | 
            +
                    current_games = json['top']
         | 
| 85 | 
            +
                    current_games.each do |game_json|
         | 
| 86 | 
            +
                      game = Game.new(game_json)
         | 
| 87 | 
            +
                      if ids.add?(game.id)
         | 
| 88 | 
            +
                        games << game
         | 
| 89 | 
            +
                        if games.count == limit
         | 
| 90 | 
            +
                          return games
         | 
| 91 | 
            +
                        end
         | 
| 92 | 
            +
                      end
         | 
| 93 | 
            +
                    end
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  games
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
                
         | 
| 99 | 
            +
                #
         | 
| 100 | 
            +
                # GET /search/games
         | 
| 101 | 
            +
                # https://github.com/justintv/Twitch-API/blob/master/v2_resources/search.md#get-searchgames
         | 
| 102 | 
            +
                #
         | 
| 103 | 
            +
                def search(params = {})
         | 
| 104 | 
            +
                  live = params[:live] || false
         | 
| 105 | 
            +
                  name = params[:name]
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  games = []
         | 
| 108 | 
            +
                  ids = Set.new
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                  json = @conn.get('search/games', :query => name, :type => 'suggest', :live => live)
         | 
| 111 | 
            +
                  all_games = json['games']
         | 
| 112 | 
            +
                  all_games.each do |game_json|
         | 
| 113 | 
            +
                    game = GameSuggestion.new(game_json)
         | 
| 114 | 
            +
                    if ids.add?(game.id)
         | 
| 115 | 
            +
                      games << game
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  games
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
              end
         | 
| 122 | 
            +
            end
         | 
    
        data/lib/kappa/images.rb
    ADDED
    
    | @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            module Kappa
         | 
| 2 | 
            +
              class ImagesBase
         | 
| 3 | 
            +
                def initialize(arg)
         | 
| 4 | 
            +
                  case arg
         | 
| 5 | 
            +
                    when Hash
         | 
| 6 | 
            +
                      parse(arg)
         | 
| 7 | 
            +
                    else
         | 
| 8 | 
            +
                      raise ArgumentError
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            module Kappa::V2
         | 
| 15 | 
            +
              class Images < Kappa::ImagesBase
         | 
| 16 | 
            +
                def url(width, height)
         | 
| 17 | 
            +
                  @template_url.gsub('{width}', width.to_s, '{height}', height.to_s)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                attr_reader :large_url
         | 
| 21 | 
            +
                attr_reader :medium_url
         | 
| 22 | 
            +
                attr_reader :small_url
         | 
| 23 | 
            +
                attr_reader :template_url
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              private
         | 
| 26 | 
            +
                def parse(hash)
         | 
| 27 | 
            +
                  @large_url = hash['large']
         | 
| 28 | 
            +
                  @medium_url = hash['medium']
         | 
| 29 | 
            +
                  @small_url = hash['small']
         | 
| 30 | 
            +
                  @template_url = hash['template']
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
    
        data/lib/kappa/stream.rb
    ADDED
    
    | @@ -0,0 +1,151 @@ | |
| 1 | 
            +
            require 'set'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Kappa
         | 
| 4 | 
            +
              class StreamBase
         | 
| 5 | 
            +
                include IdEquality
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize(hash, connection = self.class.default_connection)
         | 
| 8 | 
            +
                  @connection = connection
         | 
| 9 | 
            +
                  parse(hash)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def self.get(stream_name, connection = default_connection)
         | 
| 13 | 
            +
                  json = connection.get("streams/#{stream_name}")
         | 
| 14 | 
            +
                  stream = json['stream']
         | 
| 15 | 
            +
                  if json['status'] == 404 || !stream
         | 
| 16 | 
            +
                    nil
         | 
| 17 | 
            +
                  else
         | 
| 18 | 
            +
                    new(stream, connection)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              private
         | 
| 23 | 
            +
                def self.default_connection
         | 
| 24 | 
            +
                  self.class.module_class(:Connection).instance
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            module Kappa::V2
         | 
| 30 | 
            +
              class Stream < Kappa::StreamBase
         | 
| 31 | 
            +
                attr_reader :id
         | 
| 32 | 
            +
                attr_reader :broadcaster
         | 
| 33 | 
            +
                attr_reader :game_name
         | 
| 34 | 
            +
                attr_reader :name
         | 
| 35 | 
            +
                attr_reader :viewer_count
         | 
| 36 | 
            +
                attr_reader :preview_url
         | 
| 37 | 
            +
                attr_reader :channel
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              private
         | 
| 40 | 
            +
                def parse(hash)
         | 
| 41 | 
            +
                  @id = hash['_id']
         | 
| 42 | 
            +
                  @broadcaster = hash['broadcaster']
         | 
| 43 | 
            +
                  @game_name = hash['game']
         | 
| 44 | 
            +
                  @name = hash['name']
         | 
| 45 | 
            +
                  @viewer_count = hash['viewers']
         | 
| 46 | 
            +
                  @preview_url = hash['preview']
         | 
| 47 | 
            +
                  @channel = Channel.new(hash['channel'], @connection)
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              class Streams
         | 
| 52 | 
            +
                def self.all
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                #
         | 
| 56 | 
            +
                # GET /streams
         | 
| 57 | 
            +
                # https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md
         | 
| 58 | 
            +
                # :game (single, string), :channel (string array), :limit (int), :offset (int), :embeddable (bool), :hls (bool)
         | 
| 59 | 
            +
                # TODO: Support Kappa::Vx::Game object for the :game param.
         | 
| 60 | 
            +
                # TODO: Support Kappa::Vx::Channel object for the :channel param.
         | 
| 61 | 
            +
                #
         | 
| 62 | 
            +
                def self.where(args)
         | 
| 63 | 
            +
                  check = args.dup
         | 
| 64 | 
            +
                  check.delete(:limit)
         | 
| 65 | 
            +
                  check.delete(:offset)
         | 
| 66 | 
            +
                  raise ArgumentError if check.empty?
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  params = {}
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  if args[:channel]
         | 
| 71 | 
            +
                    params[:channel] = args[:channel].join(',')
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  if args[:game]
         | 
| 75 | 
            +
                    params[:game] = args[:game]
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  limit = args[:limit]
         | 
| 79 | 
            +
                  if limit && (limit < 25)
         | 
| 80 | 
            +
                    params[:limit] = limit
         | 
| 81 | 
            +
                  else
         | 
| 82 | 
            +
                    params[:limit] = 25
         | 
| 83 | 
            +
                    limit = 0
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  streams = []
         | 
| 87 | 
            +
                  ids = Set.new
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  connection = Connection.instance
         | 
| 90 | 
            +
                  connection.paginated('streams', params) do |json|
         | 
| 91 | 
            +
                    current_streams = json['streams']
         | 
| 92 | 
            +
                    current_streams.each do |stream_json|
         | 
| 93 | 
            +
                      stream = Stream.new(stream_json, connection)
         | 
| 94 | 
            +
                      if ids.add?(stream.id)
         | 
| 95 | 
            +
                        streams << stream
         | 
| 96 | 
            +
                        if streams.count == limit
         | 
| 97 | 
            +
                          return streams
         | 
| 98 | 
            +
                        end
         | 
| 99 | 
            +
                      end
         | 
| 100 | 
            +
                    end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                    !current_streams.empty?
         | 
| 103 | 
            +
                  end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  streams
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                #
         | 
| 109 | 
            +
                # GET /streams/featured
         | 
| 110 | 
            +
                # https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streamsfeatured
         | 
| 111 | 
            +
                #
         | 
| 112 | 
            +
                def self.featured(params = {})
         | 
| 113 | 
            +
                  limit = params[:limit] || 0
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  streams = []
         | 
| 116 | 
            +
                  ids = Set.new
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  connection = Connection.instance
         | 
| 119 | 
            +
                  connection.paginated('streams/featured', params) do |json|
         | 
| 120 | 
            +
                    current_streams = json['featured']
         | 
| 121 | 
            +
                    current_streams.each do |featured_json|
         | 
| 122 | 
            +
                      # TODO: Capture more information from the featured_json structure (need a FeaturedStream class?)
         | 
| 123 | 
            +
                      stream_json = featured_json['stream']
         | 
| 124 | 
            +
                      stream = Stream.new(stream_json, connection)
         | 
| 125 | 
            +
                      if ids.add?(stream.id)
         | 
| 126 | 
            +
                        streams << stream
         | 
| 127 | 
            +
                        if streams.count == limit
         | 
| 128 | 
            +
                          return streams
         | 
| 129 | 
            +
                        end
         | 
| 130 | 
            +
                      end
         | 
| 131 | 
            +
                    end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                    !current_streams.empty?
         | 
| 134 | 
            +
                  end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                  streams
         | 
| 137 | 
            +
                end
         | 
| 138 | 
            +
              end
         | 
| 139 | 
            +
            end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
            module Kappa::V3
         | 
| 142 | 
            +
              class Stream < Kappa::StreamBase
         | 
| 143 | 
            +
                def initialize(arg, connection = Connection.instance)
         | 
| 144 | 
            +
                  super(arg, connection)
         | 
| 145 | 
            +
                end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
              private
         | 
| 148 | 
            +
                def parse(hash)
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
              end
         | 
| 151 | 
            +
            end
         |