streamelements 0.1.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31160ff2ea22fd4ede0596df856320841537e8641f1578b12648ee9c9b918799
4
- data.tar.gz: d2a0068938a6f62b62e627165945324e4a41fddc8c58a805dbfe64bb474f16a7
3
+ metadata.gz: 83d2ea9888a42229e5016f02f1dc44bc4bbb6dcd8e2518f18f205665af4085d5
4
+ data.tar.gz: 693b8d5938293d15a82eada641f6f1f4de021eaad7a68457d9bc2e179d7bd3db
5
5
  SHA512:
6
- metadata.gz: f368ed8782747b19f755d31500b2b0c2c1d4e30d6a52fe6ac98fefc427be720ea87afa0fd3d8b02481f75b7093d7da7801ffb93539de61822960d4ff9fa19918
7
- data.tar.gz: 895c89c0e5f073caa1979d509014ea96146d109c9e443d7307968fb7f4f9449586d03e111576c20dc2ef92e040906474c54895623b3240e0bae99824af672947
6
+ metadata.gz: f76b12a8c58996a31cfdc3849e237c6d4b1c4ded028cfe7bcba7a60379aa2e864d5dfd7191cb8677fbf06594c0a3284cfa0a5039a903579e717378d328ef04dc
7
+ data.tar.gz: b71d769c436f467bf3405df589f2ac8d8eb2fa44e06b1e3a040b69a2ab7e2582d3203e7f21730bae46b2deac81d43f863e05316851765a37339eb99d21f7ab83
data/README.md CHANGED
@@ -12,30 +12,50 @@ gem "streamelements"
12
12
 
13
13
  ## Usage
14
14
 
15
- ### Authentication
15
+ ### Set Client Details
16
16
 
17
- Firstly you'll need to set either a JWT Token or an OAuth Access Token.
17
+ Firstly you'll need to the access token, which can be an oAuth Token or JWT.
18
18
 
19
19
  ```ruby
20
- # Set a JWT Token
21
- @client = StreamElements::Client.new(jwt_access_token: "")
20
+ @client = StreamElements::Client.new(access_token: "abc123")
21
+ ```
22
+
23
+ ### Resources
24
+
25
+ The gem maps as closely as we can to the StreamElements API so you can easily convert API examples to gem code.
26
+
27
+ Responses are created as objects like `StreamElements::Channel`. Having types like `StreamElements::User` is handy for understanding what
28
+ type of object you're working with. They're built using OpenStruct so you can easily access data in a Ruby-ish way.
29
+
30
+ ### Channels
31
+
32
+ ```ruby
33
+ # Get the current channel
34
+ @client.channels.me
35
+ ```
22
36
 
23
- # Or set an OAuth Access Token
24
- @client = StreamElements::Client.new(access_token: "")
37
+
38
+ ### Users
39
+
40
+ ```ruby
41
+ # Get the current user
42
+ @client.users.current
43
+
44
+ # Get the users Channels
45
+ @client.users.channels
25
46
  ```
26
47
 
27
- Most of the API requires the Channel ID to be passed as an argument.
28
48
 
29
49
  ### Activities
30
50
 
31
51
  ```ruby
32
52
  # Retrieve a list of Activities
33
53
  # https://dev.streamelements.com/docs/api-docs/861a5d5450bbb-channel
34
- @client.activities.list(channel: "channel-id")
54
+ @client.activities.list(channel: "channel-id", after:, before:, limit:, types:)
35
55
 
36
56
  # Retrieve the Top Activities
37
57
  # https://dev.streamelements.com/docs/api-docs/2ce44d058b16b-channel-top
38
- @client.actvitities.top(channel: "channel-id")
58
+ @client.activities.top(channel: "channel-id", period:, offset:, limit:, type:)
39
59
  ```
40
60
 
41
61
  ### Tips
@@ -43,7 +63,7 @@ Most of the API requires the Channel ID to be passed as an argument.
43
63
  ```ruby
44
64
  # Retrieve a list of Tips
45
65
  # https://dev.streamelements.com/docs/api-docs/704e5580be2d9-channel
46
- @client.tips.list(channel: "channel-id")
66
+ @client.tips.list(channel: "channel-id", after: "2024-01-01", sort: "createdAt", limit: 10)
47
67
 
48
68
  # Retrieve a Tip
49
69
  @client.tips.retrieve(channel: "channel-id", id: "tip-id")
@@ -62,9 +82,6 @@ Most of the API requires the Channel ID to be passed as an argument.
62
82
  # Retrieve a list of songs in the queue
63
83
  @client.song_requests.queue(channel: "channel-id")
64
84
 
65
- # Retrieve a list of previous songs
66
- @client.song_requests.queue(channel: "channel-id")
67
-
68
85
  # Add a song to the queue
69
86
  # video is the YouTube video ID or URL
70
87
  @client.song_requests.add(channel: "channel-id", video: "video-id")
@@ -81,6 +98,13 @@ Most of the API requires the Channel ID to be passed as an argument.
81
98
 
82
99
  # Skip the current song
83
100
  @client.song_requests.skip(channel: "channel-id")
101
+
102
+ # Get the current song request settings
103
+ @client.song_requests.settings(channel: "channel-id")
104
+
105
+ # Set the current song request settings
106
+ # settings is a hash of settings
107
+ @client.song_requests.update_settings(channel: "channel-id", settings: { max_requests: 5 })
84
108
  ```
85
109
 
86
110
  ## Contributing
@@ -1,13 +1,20 @@
1
1
  module StreamElements
2
2
  class Client
3
+
3
4
  BASE_URL = "https://api.streamelements.com/kappa/v2"
4
5
 
5
- attr_reader :jwt_access_token, :access_token, :adapter
6
+ attr_reader :access_token
6
7
 
7
- def initialize(jwt_access_token: nil, access_token: nil, adapter: Faraday.default_adapter)
8
- @jwt_access_token = jwt_access_token
8
+ def initialize(access_token:)
9
9
  @access_token = access_token
10
- @adapter = adapter
10
+ end
11
+
12
+ def channels
13
+ ChannelsResource.new(self)
14
+ end
15
+
16
+ def users
17
+ UsersResource.new(self)
11
18
  end
12
19
 
13
20
  def activities
@@ -22,25 +29,18 @@ module StreamElements
22
29
  SongRequestsResource.new(self)
23
30
  end
24
31
 
32
+
25
33
  def connection
26
34
  @connection ||= Faraday.new(BASE_URL) do |conn|
27
- if jwt_access_token
28
- conn.request :authorization, :Bearer, jwt_access_token
29
- elsif access_token
30
- conn.request :authorization, :Bearer, access_token
31
- else
32
- raise Error, "You must provide a jwt or access token."
33
- end
35
+ conn.request :authorization, :Bearer, access_token
34
36
 
35
37
  conn.headers = {
36
- "User-Agent" => "streamelements/v#{VERSION} (github.com/deanpcmad/streamelements)"
37
- }
38
+ "User-Agent" => "streamelements/v#{VERSION} (github.com/deanpcmad/streamelements)"
39
+ }
38
40
 
39
41
  conn.request :json
40
42
 
41
43
  conn.response :json, content_type: "application/json"
42
-
43
- conn.adapter adapter, @stubs
44
44
  end
45
45
  end
46
46
 
@@ -19,5 +19,17 @@ module StreamElements
19
19
  @data = data
20
20
  @total = total
21
21
  end
22
+
23
+ def each(&block)
24
+ data.each(&block)
25
+ end
26
+
27
+ def first
28
+ data.first
29
+ end
30
+
31
+ def last
32
+ data.last
33
+ end
22
34
  end
23
35
  end
@@ -0,0 +1,128 @@
1
+ module StreamElements
2
+ class ErrorGenerator < StandardError
3
+ attr_reader :http_status_code
4
+ attr_reader :error_code
5
+ attr_reader :error_message
6
+
7
+ def initialize(response_body, http_status_code)
8
+ @response_body = response_body
9
+ @http_status_code = http_status_code
10
+ set_error_values
11
+ super(build_message)
12
+ end
13
+
14
+ private
15
+
16
+ def set_error_values
17
+ @error_code = @response_body.dig("error")
18
+ @error_message = @response_body.dig("message")
19
+ end
20
+
21
+ def error_message
22
+ @error_message || @response_body.dig("error")
23
+ rescue NoMethodError
24
+ "An unknown error occurred."
25
+ end
26
+
27
+ def build_message
28
+ if error_code.nil?
29
+ return "Error #{@http_status_code}: #{error_message}"
30
+ end
31
+ "Error #{@http_status_code}: #{error_message} '#{error_message}'"
32
+ end
33
+ end
34
+
35
+ module Errors
36
+ class BadRequestError < ErrorGenerator
37
+ private
38
+
39
+ def error_message
40
+ "Your request was malformed."
41
+ end
42
+ end
43
+
44
+ class AuthenticationMissingError < ErrorGenerator
45
+ private
46
+
47
+ def error_message
48
+ "You did not supply valid authentication credentials."
49
+ end
50
+ end
51
+
52
+ class ForbiddenError < ErrorGenerator
53
+ private
54
+
55
+ def error_message
56
+ "You are not allowed to perform that action."
57
+ end
58
+ end
59
+
60
+ class EntityNotFoundError < ErrorGenerator
61
+ private
62
+
63
+ def error_message
64
+ "No results were found for your request."
65
+ end
66
+ end
67
+
68
+ class ConflictError < ErrorGenerator
69
+ private
70
+
71
+ def error_message
72
+ "Your request was a conflict."
73
+ end
74
+ end
75
+
76
+ class TooManyRequestsError < ErrorGenerator
77
+ private
78
+
79
+ def error_message
80
+ "Your request exceeded the API rate limit."
81
+ end
82
+ end
83
+
84
+ class InternalError < ErrorGenerator
85
+ private
86
+
87
+ def error_message
88
+ "We were unable to perform the request due to server-side problems."
89
+ end
90
+ end
91
+
92
+ class ServiceUnavailableError < ErrorGenerator
93
+ private
94
+
95
+ def error_message
96
+ "You have been rate limited for sending more than 20 requests per second."
97
+ end
98
+ end
99
+
100
+ class NotImplementedError < ErrorGenerator
101
+ private
102
+
103
+ def error_message
104
+ "This resource has not been implemented."
105
+ end
106
+ end
107
+ end
108
+
109
+ class ErrorFactory
110
+ HTTP_ERROR_MAP = {
111
+ 400 => Errors::BadRequestError,
112
+ 401 => Errors::AuthenticationMissingError,
113
+ 403 => Errors::ForbiddenError,
114
+ 404 => Errors::EntityNotFoundError,
115
+ 409 => Errors::ConflictError,
116
+ 429 => Errors::TooManyRequestsError,
117
+ 500 => Errors::InternalError,
118
+ 503 => Errors::ServiceUnavailableError,
119
+ 501 => Errors::NotImplementedError
120
+ }.freeze
121
+
122
+ def self.create(response_body, http_status_code)
123
+ status = http_status_code
124
+ error_class = HTTP_ERROR_MAP[status] || ErrorGenerator
125
+ error_class.new(response_body, http_status_code) if error_class
126
+ end
127
+ end
128
+ end
@@ -3,6 +3,7 @@ require "ostruct"
3
3
  module StreamElements
4
4
  class Object < OpenStruct
5
5
  def initialize(attributes)
6
+ attributes["id"] = attributes.delete("_id") if attributes["_id"]
6
7
  super to_ostruct(attributes)
7
8
  end
8
9
 
@@ -1,10 +1,4 @@
1
1
  module StreamElements
2
2
  class Activity < Object
3
-
4
- def initialize(attributes = {})
5
- attributes["id"] = attributes.delete("_id") if attributes["_id"]
6
- super
7
- end
8
-
9
3
  end
10
4
  end
@@ -1,4 +1,4 @@
1
1
  module StreamElements
2
- class TopActivity < Object
2
+ class Channel < Object
3
3
  end
4
4
  end
@@ -1,10 +1,4 @@
1
1
  module StreamElements
2
2
  class SongRequest < Object
3
-
4
- def initialize(attributes = {})
5
- attributes["id"] = attributes.delete("_id") if attributes["_id"]
6
- super
7
- end
8
-
9
3
  end
10
4
  end
@@ -1,10 +1,4 @@
1
1
  module StreamElements
2
2
  class Tip < Object
3
-
4
- def initialize(attributes = {})
5
- attributes["id"] = attributes.delete("_id") if attributes["_id"]
6
- super
7
- end
8
-
9
3
  end
10
4
  end
@@ -0,0 +1,4 @@
1
+ module StreamElements
2
+ class User < Object
3
+ end
4
+ end
@@ -12,47 +12,36 @@ module StreamElements
12
12
  handle_response client.connection.get(url, params, headers)
13
13
  end
14
14
 
15
- def post_request(url, body:, headers: {})
15
+ def post_request(url, body: {}, headers: {})
16
16
  handle_response client.connection.post(url, body, headers)
17
17
  end
18
18
 
19
+ def put_request(url, body: {}, headers: {})
20
+ handle_response client.connection.put(url, body, headers)
21
+ end
22
+
19
23
  def patch_request(url, body:, headers: {})
20
24
  handle_response client.connection.patch(url, body, headers)
21
25
  end
22
26
 
23
- def put_request(url, body:, headers: {})
24
- handle_response client.connection.put(url, body, headers)
27
+ def delete_request(url, headers: {})
28
+ handle_response client.connection.delete(url, headers)
25
29
  end
26
30
 
27
- def delete_request(url, params: {}, headers: {})
28
- handle_response client.connection.delete(url, params, headers)
31
+ def handle_response(response)
32
+ return true if response.status == 204
33
+ return response unless error?(response)
34
+
35
+ raise_error(response)
29
36
  end
30
37
 
31
- def handle_response(response)
32
- case response.status
33
- when 400
34
- raise Error, "Error 400: Your request was malformed. '#{response.body["message"]}'"
35
- when 401
36
- raise Error, "Error 401: You did not supply valid authentication credentials. '#{response.body["error"]}'"
37
- when 403
38
- raise Error, "Error 403: You are not allowed to perform that action. '#{response.body["error"]}'"
39
- when 404
40
- raise Error, "Error 404: No results were found for your request. '#{response.body["error"]}'"
41
- when 409
42
- raise Error, "Error 409: Your request was a conflict. '#{response.body["message"]}'"
43
- when 422
44
- raise Error, "Error 422: Unprocessable Entity. '#{response.body["message"]}"
45
- when 429
46
- raise Error, "Error 429: Your request exceeded the API rate limit. '#{response.body["error"]}'"
47
- when 500
48
- raise Error, "Error 500: We were unable to perform the request due to server-side problems. '#{response.body["error"]}'"
49
- when 503
50
- raise Error, "Error 503: You have been rate limited for sending more than 20 requests per second. '#{response.body["error"]}'"
51
- when 204
52
- return true
53
- end
54
-
55
- response
38
+ def error?(response)
39
+ [ 400, 401, 403, 404, 409, 429, 500, 501, 503 ].include?(response.status) #|| response.body&.key?("error")
40
+ end
41
+
42
+ def raise_error(response)
43
+ error = StreamElements::ErrorFactory.create(response.body, response.status)
44
+ raise error if error
56
45
  end
57
46
  end
58
47
  end
@@ -10,7 +10,7 @@ module StreamElements
10
10
  def top(channel:, period:, offset:, limit:, type:)
11
11
  attrs = { period: period, offset: offset, limit: limit, type: type }
12
12
  response = get_request("activities/#{channel}/top", params: attrs)
13
- Collection.from_response(response, type: TopActivity)
13
+ # Collection.from_response(response, type: TopActivity)
14
14
  end
15
15
 
16
16
  end
@@ -0,0 +1,10 @@
1
+ module StreamElements
2
+ class ChannelsResource < Resource
3
+
4
+ def me
5
+ response = get_request("channels/me")
6
+ Channel.new response.body
7
+ end
8
+
9
+ end
10
+ end
@@ -15,6 +15,15 @@ module StreamElements
15
15
  Collection.from_response(response, type: SongRequest, name: "history")
16
16
  end
17
17
 
18
+ def settings(channel:)
19
+ get_request("songrequest/#{channel}/settings").body
20
+ end
21
+
22
+ def update_settings(channel:, settings:)
23
+ response = put_request("songrequest/#{channel}/settings", body: settings)
24
+ response.success?
25
+ end
26
+
18
27
  def add(channel:, video:)
19
28
  SongRequest.new post_request("songrequest/#{channel}/queue", body: { video: video }).body
20
29
  end
@@ -1,8 +1,9 @@
1
1
  module StreamElements
2
2
  class TipsResource < Resource
3
3
 
4
- def list(channel:, **params)
5
- response = get_request("tips/#{channel}", params: params)
4
+ def list(channel:, after:, sort:, limit:, **params)
5
+ attrs = { after: after, sort: sort, limit: limit }.merge(params)
6
+ response = get_request("tips/#{channel}", params: attrs)
6
7
  Collection.from_response(response, type: Tip, name: "docs")
7
8
  end
8
9
 
@@ -0,0 +1,15 @@
1
+ module StreamElements
2
+ class UsersResource < Resource
3
+
4
+ def current
5
+ response = get_request("users/current")
6
+ User.new response.body
7
+ end
8
+
9
+ def channels
10
+ response = get_request("users/channels")
11
+ Collection.from_response(response, type: Channel)
12
+ end
13
+
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StreamElements
4
- VERSION = "0.1.0"
4
+ VERSION = "0.5.0"
5
5
  end
@@ -6,20 +6,27 @@ require "stream_elements/version"
6
6
 
7
7
  module StreamElements
8
8
 
9
+ autoload :Error, "stream_elements/error"
10
+ autoload :Errors, "stream_elements/error_generator"
11
+ autoload :ErrorGenerator, "stream_elements/error_generator"
12
+ autoload :ErrorFactory, "stream_elements/error_generator"
13
+
9
14
  autoload :Client, "stream_elements/client"
10
15
  autoload :Collection, "stream_elements/collection"
11
- autoload :Error, "stream_elements/error"
12
16
  autoload :Resource, "stream_elements/resource"
13
17
  autoload :Object, "stream_elements/object"
14
18
 
15
- autoload :ActivitiesResource, "stream_elements/resources/activities"
19
+ autoload :ActivitiesResource, "stream_elements/resources/activitys"
16
20
  autoload :TipsResource, "stream_elements/resources/tips"
17
21
  autoload :SongRequestsResource, "stream_elements/resources/song_requests"
22
+ autoload :UsersResource, "stream_elements/resources/users"
23
+ autoload :ChannelsResource, "stream_elements/resources/channels"
18
24
 
19
25
  autoload :Activity, "stream_elements/objects/activity"
20
- autoload :TopActivity, "stream_elements/objects/top_activity"
21
26
  autoload :Tip, "stream_elements/objects/tip"
22
- autoload :TopTip, "stream_elements/objects/top_tip"
23
27
  autoload :SongRequest, "stream_elements/objects/song_request"
28
+ autoload :User, "stream_elements/objects/user"
29
+ autoload :Channel, "stream_elements/objects/channel"
30
+ autoload :TopTip, "stream_elements/objects/top_tip"
24
31
 
25
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: streamelements
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dean Perry
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-09 00:00:00.000000000 Z
11
+ date: 2024-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -24,7 +24,7 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2'
27
- description:
27
+ description:
28
28
  email:
29
29
  - deanperry@fastmail.com
30
30
  executables: []
@@ -39,16 +39,20 @@ files:
39
39
  - lib/stream_elements/client.rb
40
40
  - lib/stream_elements/collection.rb
41
41
  - lib/stream_elements/error.rb
42
+ - lib/stream_elements/error_generator.rb
42
43
  - lib/stream_elements/object.rb
43
44
  - lib/stream_elements/objects/activity.rb
45
+ - lib/stream_elements/objects/channel.rb
44
46
  - lib/stream_elements/objects/song_request.rb
45
47
  - lib/stream_elements/objects/tip.rb
46
- - lib/stream_elements/objects/top_activity.rb
47
48
  - lib/stream_elements/objects/top_tip.rb
49
+ - lib/stream_elements/objects/user.rb
48
50
  - lib/stream_elements/resource.rb
49
51
  - lib/stream_elements/resources/activities.rb
52
+ - lib/stream_elements/resources/channels.rb
50
53
  - lib/stream_elements/resources/song_requests.rb
51
54
  - lib/stream_elements/resources/tips.rb
55
+ - lib/stream_elements/resources/users.rb
52
56
  - lib/stream_elements/version.rb
53
57
  - lib/streamelements.rb
54
58
  - sig/streamelements.rbs
@@ -56,7 +60,7 @@ homepage: https://github.com/deanpcmad/streamelements
56
60
  licenses:
57
61
  - MIT
58
62
  metadata: {}
59
- post_install_message:
63
+ post_install_message:
60
64
  rdoc_options: []
61
65
  require_paths:
62
66
  - lib
@@ -71,8 +75,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
75
  - !ruby/object:Gem::Version
72
76
  version: '0'
73
77
  requirements: []
74
- rubygems_version: 3.4.22
75
- signing_key:
78
+ rubygems_version: 3.5.11
79
+ signing_key:
76
80
  specification_version: 4
77
81
  summary: Ruby library for the StreamElements API
78
82
  test_files: []