plays-hub/app/services/spotify_client.rb

114 lines
2.8 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
puts "token expired, forcing refresh"
refresh_token!(force: true)
begin
call(path, params)
rescue RestClient::ExceptionWithResponse
puts "token dead"
LogLoadFailedWorker.perform_async(login.id)
end
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