streamelements 0.1.0 → 0.5.0

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 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: []