118 lines
3.0 KiB
Ruby
118 lines
3.0 KiB
Ruby
require "rest-client"
|
|
require "base64"
|
|
require "json"
|
|
|
|
class SpotifyClient
|
|
SPOTIFY_REDIRECT_URI = "#{ENV['SPOTIFY_REDIRECT_URI']}/spotify_callback".freeze
|
|
SCOPE = "user-read-recently-played".freeze
|
|
|
|
BASE_URL = "https://api.spotify.com/v1/".freeze
|
|
|
|
attr_reader :login
|
|
|
|
def initialize(login = nil)
|
|
@login = login
|
|
end
|
|
|
|
def load_since(load_since)
|
|
params = {
|
|
"limit" => "50"
|
|
}
|
|
params["after"] = load_since unless load_since.nil?
|
|
get("me/player/recently-played", params)
|
|
end
|
|
|
|
def token_response_from_code(code)
|
|
auth_code_authorize(code)
|
|
end
|
|
|
|
def auth_redirect_url
|
|
"https://accounts.spotify.com/authorize?" \
|
|
"response_type=code&" \
|
|
"client_id=#{ENV['SPOTIFY_CLIENT_ID']}&" \
|
|
"scope=#{SCOPE}&" \
|
|
"redirect_uri=#{CGI.escape(SPOTIFY_REDIRECT_URI)}"
|
|
end
|
|
|
|
private
|
|
|
|
def get(path, params = {})
|
|
refresh_token!
|
|
begin
|
|
call(path, params)
|
|
rescue RestClient::ExceptionWithResponse => e
|
|
if e.response.code == 401
|
|
Rails.logger.info("token expired, forcing refresh")
|
|
refresh_token!(force: true)
|
|
begin
|
|
call(path, params)
|
|
rescue RestClient::ExceptionWithResponse
|
|
Rails.logger.info("token dead")
|
|
LogLoadFailedWorker.perform_async(login.id)
|
|
end
|
|
else
|
|
Rails.logger.error("SpotifyClient: #{e.message}")
|
|
Rails.logger.error("SpotifyClient body: #{e.http_body}")
|
|
raise e
|
|
end
|
|
end
|
|
end
|
|
|
|
def call(path, params)
|
|
headers = { "Authorization" => "Bearer #{login.credentials['access_token']}" }
|
|
headers[:params] = params if params.present?
|
|
JSON.parse RestClient.get("#{BASE_URL}#{path}", headers)
|
|
end
|
|
|
|
def refresh_token!(force: false)
|
|
return unless login.about_to_expire? || force
|
|
|
|
request_body = {
|
|
'refresh_token': login.credentials["refresh_token"],
|
|
'grant_type': "refresh_token"
|
|
}
|
|
|
|
begin
|
|
auth_response = RestClient.post(
|
|
"https://accounts.spotify.com/api/token",
|
|
request_body,
|
|
client_auth_headers
|
|
)
|
|
new_credentials = JSON.parse auth_response
|
|
login.update_access_token!(new_credentials)
|
|
rescue RestClient::ExceptionWithResponse => e
|
|
login.update(dead_since: Time.new)
|
|
raise e
|
|
end
|
|
end
|
|
|
|
def client_auth_headers
|
|
auth_plain = "#{ENV['SPOTIFY_CLIENT_ID']}:#{ENV['SPOTIFY_CLIENT_SECRET']}"
|
|
auth_string = Base64.strict_encode64 auth_plain
|
|
{
|
|
'Authorization': "Basic #{auth_string}"
|
|
}
|
|
end
|
|
|
|
def auth_code_authorize(code)
|
|
request_body = {
|
|
'code': code,
|
|
'redirect_uri': SPOTIFY_REDIRECT_URI,
|
|
'grant_type': "authorization_code"
|
|
}
|
|
begin
|
|
auth_response = RestClient.post(
|
|
"https://accounts.spotify.com/api/token",
|
|
request_body,
|
|
client_auth_headers
|
|
)
|
|
rescue RestClient::ExceptionWithResponse => e
|
|
raise e
|
|
end
|
|
|
|
raise StandardError.new("Authorization failed", auth_response) unless auth_response.code == 200
|
|
|
|
JSON.parse auth_response.body
|
|
end
|
|
end
|