spotted 0.10.0 → 0.11.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: 42e1ad1df8e63d25d83161a691c8b44f5806e197caeaec2ab2be59fcfe20b705
4
- data.tar.gz: c42b9da1fe7f6a1bcc7d5dcd9f9eaf8a86b7af6e1d8889eab6889a0080fa4863
3
+ metadata.gz: 53171d2924e8b65667348df43a8315b13834283411bcc57260a3dee25ed1b5bb
4
+ data.tar.gz: 4a987cf805446e513e6d977a00aa999f48d64ca881e7adc6f7a3ae9352169348
5
5
  SHA512:
6
- metadata.gz: bbc654721de4db44e31f987e312f63413c3df4a147e9c185dc7f296c18437ad95330f76f915ef0386c0045a1b51d691b4ae5796d2ffbe1a1f2a2eaf46a13e689
7
- data.tar.gz: 2a2412d27f2c20cf7b807deaf9e2a766ee46db29782f06bf8c45424895ffc89815817b6af4a91f8b15729d3749a59f8b558e0b8485962e6000679addb5ca986f
6
+ metadata.gz: 13b3fab4d5ead1e934399769d8556ba0521e2bebcbe5a0da61fc4cefba97ebd92801afc3d4136bc70f7efea09b7a3ac0689e41e8633968d4f983d11a7f4bc1b2
7
+ data.tar.gz: 0ce09546710593e818c08530438f4ab6918fd9e103ad54d3376af6362da5bb197298bdec2a931cc6868259aa49eacd08a827108d4375a5075922a1295594667e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.11.0 (2025-11-10)
4
+
5
+ Full Changelog: [v0.10.0...v0.11.0](https://github.com/cjavdev/spotted/compare/v0.10.0...v0.11.0)
6
+
7
+ ### Features
8
+
9
+ * **api:** manual updates ([feb8221](https://github.com/cjavdev/spotted/commit/feb822194d2e961c6469ca5e36c8d0cccdb0cb5a))
10
+
3
11
  ## 0.10.0 (2025-11-10)
4
12
 
5
13
  Full Changelog: [v0.9.0...v0.10.0](https://github.com/cjavdev/spotted/compare/v0.9.0...v0.10.0)
data/README.md CHANGED
@@ -17,7 +17,7 @@ To use this gem, install via Bundler by adding the following to your application
17
17
  <!-- x-release-please-start-version -->
18
18
 
19
19
  ```ruby
20
- gem "spotted", "~> 0.10.0"
20
+ gem "spotted", "~> 0.11.0"
21
21
  ```
22
22
 
23
23
  <!-- x-release-please-end -->
@@ -15,12 +15,15 @@ module Spotted
15
15
  # Default max retry delay in seconds.
16
16
  DEFAULT_MAX_RETRY_DELAY = 8.0
17
17
 
18
- # @return [String]
18
+ # @return [String, nil]
19
19
  attr_reader :client_id
20
20
 
21
- # @return [String]
21
+ # @return [String, nil]
22
22
  attr_reader :client_secret
23
23
 
24
+ # @return [String, nil]
25
+ attr_reader :access_token
26
+
24
27
  # @return [Spotted::Resources::Albums]
25
28
  attr_reader :albums
26
29
 
@@ -69,6 +72,22 @@ module Spotted
69
72
  # @return [Spotted::Resources::Markets]
70
73
  attr_reader :markets
71
74
 
75
+ # @api private
76
+ #
77
+ # @return [Hash{String=>String}]
78
+ private def auth_headers
79
+ {**bearer_auth, **oauth_2_0}
80
+ end
81
+
82
+ # @api private
83
+ #
84
+ # @return [Hash{String=>String}]
85
+ private def bearer_auth
86
+ return {} if @access_token.nil?
87
+
88
+ {"authorization" => "Bearer #{@access_token}"}
89
+ end
90
+
72
91
  # @api private
73
92
  # @return [Spotted::Internal::OAuth2ClientCredentials]
74
93
  attr_reader :oauth_2_0_state
@@ -76,7 +95,7 @@ module Spotted
76
95
  # @api private
77
96
  #
78
97
  # @return [Hash{String=>String}]
79
- private def auth_headers
98
+ private def oauth_2_0
80
99
  return @oauth_2_0_state.auth_headers if @oauth_2_0_state
81
100
 
82
101
  return {} unless @client_id && @client_secret
@@ -106,6 +125,8 @@ module Spotted
106
125
  #
107
126
  # @param client_secret [String, nil] Defaults to `ENV["SPOTIFY_CLIENT_SECRET"]`
108
127
  #
128
+ # @param access_token [String, nil] Defaults to `ENV["SPOTIFY_ACCESS_TOKEN"]`
129
+ #
109
130
  # @param base_url [String, nil] Override the default base URL for the API, e.g.,
110
131
  # `"https://api.example.com/v2/"`. Defaults to `ENV["SPOTTED_BASE_URL"]`
111
132
  #
@@ -119,6 +140,7 @@ module Spotted
119
140
  def initialize(
120
141
  client_id: ENV["SPOTIFY_CLIENT_ID"],
121
142
  client_secret: ENV["SPOTIFY_CLIENT_SECRET"],
143
+ access_token: ENV["SPOTIFY_ACCESS_TOKEN"],
122
144
  base_url: ENV["SPOTTED_BASE_URL"],
123
145
  max_retries: self.class::DEFAULT_MAX_RETRIES,
124
146
  timeout: self.class::DEFAULT_TIMEOUT_IN_SECONDS,
@@ -127,18 +149,9 @@ module Spotted
127
149
  )
128
150
  base_url ||= "https://api.spotify.com/v1"
129
151
 
130
- if client_id.nil?
131
- raise ArgumentError.new("client_id is required, and can be set via environ: \"SPOTIFY_CLIENT_ID\"")
132
- end
133
- if client_secret.nil?
134
- # Ignore Layout/LineLength
135
- # rubocop:disable Layout/LineLength
136
- raise ArgumentError.new("client_secret is required, and can be set via environ: \"SPOTIFY_CLIENT_SECRET\"")
137
- # rubocop:enable Layout/LineLength
138
- end
139
-
140
- @client_id = client_id.to_s
141
- @client_secret = client_secret.to_s
152
+ @client_id = client_id&.to_s
153
+ @client_secret = client_secret&.to_s
154
+ @access_token = access_token&.to_s
142
155
 
143
156
  super(
144
157
  base_url: base_url,
@@ -165,5 +178,39 @@ module Spotted
165
178
  @recommendations = Spotted::Resources::Recommendations.new(client: self)
166
179
  @markets = Spotted::Resources::Markets.new(client: self)
167
180
  end
181
+
182
+ # Generates the Spotify authorization URL for OAuth2 authorization code flow.
183
+ #
184
+ # @param redirect_uri [String] The URI to redirect to after authorization
185
+ # @param scope [String, Array<String>, nil] Space-delimited string or array of authorization scopes
186
+ # @param state [String, nil] Optional state parameter for CSRF protection
187
+ # @param show_dialog [Boolean] Whether to force the user to approve the app again
188
+ #
189
+ # @return [String] The authorization URL to redirect the user to
190
+ #
191
+ # @example Basic usage
192
+ # client = Spotted::Client.new(client_id: "...", client_secret: "...")
193
+ # url = client.authorization_url(redirect_uri: "http://localhost:3000/callback")
194
+ #
195
+ # @example With scopes and state
196
+ # url = client.authorization_url(
197
+ # redirect_uri: "http://localhost:3000/callback",
198
+ # scope: ["user-read-private", "user-read-email"],
199
+ # state: "random_state_string"
200
+ # )
201
+ def authorization_url(redirect_uri:, scope: nil, state: nil, show_dialog: false)
202
+ params = {
203
+ client_id: @client_id,
204
+ response_type: "code",
205
+ redirect_uri: redirect_uri
206
+ }
207
+
208
+ params[:scope] = scope.is_a?(Array) ? scope.join(" ") : scope if scope
209
+ params[:state] = state if state
210
+ params[:show_dialog] = "true" if show_dialog
211
+
212
+ query_string = URI.encode_www_form(params)
213
+ "https://accounts.spotify.com/authorize?#{query_string}"
214
+ end
168
215
  end
169
216
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Spotted
4
- VERSION = "0.10.0"
4
+ VERSION = "0.11.0"
5
5
  end
@@ -10,12 +10,15 @@ module Spotted
10
10
 
11
11
  DEFAULT_MAX_RETRY_DELAY = T.let(8.0, Float)
12
12
 
13
- sig { returns(String) }
13
+ sig { returns(T.nilable(String)) }
14
14
  attr_reader :client_id
15
15
 
16
- sig { returns(String) }
16
+ sig { returns(T.nilable(String)) }
17
17
  attr_reader :client_secret
18
18
 
19
+ sig { returns(T.nilable(String)) }
20
+ attr_reader :access_token
21
+
19
22
  sig { returns(Spotted::Resources::Albums) }
20
23
  attr_reader :albums
21
24
 
@@ -64,13 +67,23 @@ module Spotted
64
67
  sig { returns(Spotted::Resources::Markets) }
65
68
  attr_reader :markets
66
69
 
70
+ # @api private
71
+ sig { override.returns(T::Hash[String, String]) }
72
+ private def auth_headers
73
+ end
74
+
75
+ # @api private
76
+ sig { returns(T::Hash[String, String]) }
77
+ private def bearer_auth
78
+ end
79
+
67
80
  # @api private
68
81
  sig { returns(Spotted::Internal::OAuth2ClientCredentials) }
69
82
  attr_reader :oauth_2_0_state
70
83
 
71
84
  # @api private
72
- sig { override.returns(T::Hash[String, String]) }
73
- private def auth_headers
85
+ sig { returns(T::Hash[String, String]) }
86
+ private def oauth_2_0
74
87
  end
75
88
 
76
89
  # Creates and returns a new client for interacting with the API.
@@ -78,6 +91,7 @@ module Spotted
78
91
  params(
79
92
  client_id: T.nilable(String),
80
93
  client_secret: T.nilable(String),
94
+ access_token: T.nilable(String),
81
95
  base_url: T.nilable(String),
82
96
  max_retries: Integer,
83
97
  timeout: Float,
@@ -90,6 +104,8 @@ module Spotted
90
104
  client_id: ENV["SPOTIFY_CLIENT_ID"],
91
105
  # Defaults to `ENV["SPOTIFY_CLIENT_SECRET"]`
92
106
  client_secret: ENV["SPOTIFY_CLIENT_SECRET"],
107
+ # Defaults to `ENV["SPOTIFY_ACCESS_TOKEN"]`
108
+ access_token: ENV["SPOTIFY_ACCESS_TOKEN"],
93
109
  # Override the default base URL for the API, e.g.,
94
110
  # `"https://api.example.com/v2/"`. Defaults to `ENV["SPOTTED_BASE_URL"]`
95
111
  base_url: ENV["SPOTTED_BASE_URL"],
@@ -8,9 +8,11 @@ module Spotted
8
8
 
9
9
  DEFAULT_MAX_RETRY_DELAY: Float
10
10
 
11
- attr_reader client_id: String
11
+ attr_reader client_id: String?
12
12
 
13
- attr_reader client_secret: String
13
+ attr_reader client_secret: String?
14
+
15
+ attr_reader access_token: String?
14
16
 
15
17
  attr_reader albums: Spotted::Resources::Albums
16
18
 
@@ -44,14 +46,19 @@ module Spotted
44
46
 
45
47
  attr_reader markets: Spotted::Resources::Markets
46
48
 
49
+ private def auth_headers: -> ::Hash[String, String]
50
+
51
+ private def bearer_auth: -> ::Hash[String, String]
52
+
47
53
  # @api private
48
54
  attr_reader oauth_2_0_state: Spotted::Internal::OAuth2ClientCredentials
49
55
 
50
- private def auth_headers: -> ::Hash[String, String]
56
+ private def oauth_2_0: -> ::Hash[String, String]
51
57
 
52
58
  def initialize: (
53
59
  ?client_id: String?,
54
60
  ?client_secret: String?,
61
+ ?access_token: String?,
55
62
  ?base_url: String?,
56
63
  ?max_retries: Integer,
57
64
  ?timeout: Float,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spotted
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Spotted