spotify-ruby 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/COVERAGE.md +142 -0
- data/README.md +60 -5
- data/lib/spotify.rb +7 -0
- data/lib/spotify/auth.rb +10 -18
- data/lib/spotify/sdk.rb +109 -0
- data/lib/spotify/sdk/base.rb +58 -0
- data/lib/spotify/sdk/connect.rb +26 -0
- data/lib/spotify/sdk/connect/device.rb +55 -0
- data/lib/spotify/sdk/initialization.rb +76 -0
- data/lib/spotify/sdk/initialization/base.rb +74 -0
- data/lib/spotify/sdk/initialization/oauth_access_token.rb +34 -0
- data/lib/spotify/sdk/initialization/plain_string.rb +26 -0
- data/lib/spotify/sdk/initialization/query_hash.rb +45 -0
- data/lib/spotify/sdk/initialization/query_string.rb +51 -0
- data/lib/spotify/sdk/initialization/url_string.rb +49 -0
- data/lib/spotify/sdk/model.rb +53 -0
- data/lib/spotify/version.rb +1 -1
- data/spotify-ruby.gemspec +5 -3
- metadata +45 -55
- data/SPEC.md +0 -18
- data/html/README_md.html +0 -189
- data/html/Spotify.html +0 -115
- data/html/Spotify/Auth.html +0 -281
- data/html/Spotify/Errors.html +0 -103
- data/html/Spotify/Errors/AuthClientCredentialsError.html +0 -106
- data/html/created.rid +0 -5
- data/html/css/fonts.css +0 -167
- data/html/css/rdoc.css +0 -590
- data/html/fonts/Lato-Light.ttf +0 -0
- data/html/fonts/Lato-LightItalic.ttf +0 -0
- data/html/fonts/Lato-Regular.ttf +0 -0
- data/html/fonts/Lato-RegularItalic.ttf +0 -0
- data/html/fonts/SourceCodePro-Bold.ttf +0 -0
- data/html/fonts/SourceCodePro-Regular.ttf +0 -0
- data/html/images/add.png +0 -0
- data/html/images/arrow_up.png +0 -0
- data/html/images/brick.png +0 -0
- data/html/images/brick_link.png +0 -0
- data/html/images/bug.png +0 -0
- data/html/images/bullet_black.png +0 -0
- data/html/images/bullet_toggle_minus.png +0 -0
- data/html/images/bullet_toggle_plus.png +0 -0
- data/html/images/date.png +0 -0
- data/html/images/delete.png +0 -0
- data/html/images/find.png +0 -0
- data/html/images/loadingAnimation.gif +0 -0
- data/html/images/macFFBgHack.png +0 -0
- data/html/images/package.png +0 -0
- data/html/images/page_green.png +0 -0
- data/html/images/page_white_text.png +0 -0
- data/html/images/page_white_width.png +0 -0
- data/html/images/plugin.png +0 -0
- data/html/images/ruby.png +0 -0
- data/html/images/tag_blue.png +0 -0
- data/html/images/tag_green.png +0 -0
- data/html/images/transparent.png +0 -0
- data/html/images/wrench.png +0 -0
- data/html/images/wrench_orange.png +0 -0
- data/html/images/zoom.png +0 -0
- data/html/index.html +0 -189
- data/html/js/darkfish.js +0 -161
- data/html/js/jquery.js +0 -4
- data/html/js/navigation.js +0 -142
- data/html/js/navigation.js.gz +0 -0
- data/html/js/search.js +0 -109
- data/html/js/search_index.js +0 -1
- data/html/js/search_index.js.gz +0 -0
- data/html/js/searcher.js +0 -229
- data/html/js/searcher.js.gz +0 -0
- data/html/table_of_contents.html +0 -83
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
##
|
6
|
+
# For each SDK component, we have a Base class. We're using HTTParty.
|
7
|
+
#
|
8
|
+
class Base
|
9
|
+
include HTTParty
|
10
|
+
base_uri "api.spotify.com:443"
|
11
|
+
|
12
|
+
##
|
13
|
+
# Initiate a Spotify SDK Base component.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# @sdk = Spotify::SDK.new("access_token")
|
17
|
+
# @auth = Spotify::SDK::Base.new(@sdk)
|
18
|
+
#
|
19
|
+
# @sdk = Spotify::SDK.new("access_token_here")
|
20
|
+
# @sdk.to_hash # => { access_token: ..., expires_at: ... }
|
21
|
+
#
|
22
|
+
# @param [Spotify::SDK] sdk An instance of Spotify::SDK as a reference point.
|
23
|
+
#
|
24
|
+
def initialize(sdk)
|
25
|
+
@sdk = sdk
|
26
|
+
@options = {
|
27
|
+
headers: {
|
28
|
+
Authorization: "Bearer %s" % sdk.access_token
|
29
|
+
}
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Handle HTTParty responses.
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# # Return the Hash from the JSON response.
|
38
|
+
# send_http_request(:get, "/v1/me/player/devices", @options)
|
39
|
+
#
|
40
|
+
# # Return the raw HTTParty::Response object.
|
41
|
+
# send_http_request(:get, "/v1/me/player/devices", @options.merge(raw: true))
|
42
|
+
#
|
43
|
+
# @param [Hash,HTTParty::Response] response The response from the HTTP request.
|
44
|
+
# @return
|
45
|
+
#
|
46
|
+
def send_http_request(method, endpoint, opts={}, &_block)
|
47
|
+
sdk_opts = opts[:_sdk_opts].presence || {}
|
48
|
+
opts_sdk = {raw: false, expect_nil: false}.merge(sdk_opts)
|
49
|
+
response = self.class.send(method, endpoint, @options.merge(opts))
|
50
|
+
response = response.parsed_response.try(:deep_symbolize_keys) if opts_sdk[:raw] == false
|
51
|
+
response = true if opts_sdk[:expect_nil] == true && response.nil?
|
52
|
+
response
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_reader :sdk
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Connect < Base
|
6
|
+
##
|
7
|
+
# Collect all the user's available devices.
|
8
|
+
# GET /v1/me/player/devices
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# @sdk.connect.devices # => [#<Spotify::SDK::Connect::Device:...>, ...]
|
12
|
+
#
|
13
|
+
# @see https://developer.spotify.com/web-api/console/get-users-available-devices/
|
14
|
+
#
|
15
|
+
# @param [Hash] override_opts Custom options for HTTParty.
|
16
|
+
# @return
|
17
|
+
#
|
18
|
+
def devices(override_opts={})
|
19
|
+
response = send_http_request(:get, "/v1/me/player/devices", override_opts)
|
20
|
+
response[:devices].map do |device|
|
21
|
+
Spotify::SDK::Connect::Device.new(device, self)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Connect
|
6
|
+
class Device < Model
|
7
|
+
##
|
8
|
+
# Transfer a user's playback to another device, and continue playing.
|
9
|
+
# PUT /v1/me/player
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# device = @sdk.connect.transfer_playback!
|
13
|
+
#
|
14
|
+
# @see https://developer.spotify.com/web-api/transfer-a-users-playback/
|
15
|
+
#
|
16
|
+
# @return [Spotify::SDK::Connect::Device] self Return itself, so chained methods can be supported.
|
17
|
+
#
|
18
|
+
def transfer_playback!
|
19
|
+
transfer_playback_method(playing: true)
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Transfer a user's playback to another device, and pause.
|
25
|
+
# PUT /v1/me/player
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# device = @sdk.connect.transfer_state!
|
29
|
+
#
|
30
|
+
# @see https://developer.spotify.com/web-api/transfer-a-users-playback/
|
31
|
+
#
|
32
|
+
# @return [Spotify::SDK::Connect::Device] self Return itself, so chained methods can be supported.
|
33
|
+
#
|
34
|
+
def transfer_state!
|
35
|
+
transfer_playback_method(playing: false)
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def transfer_playback_method(playing:)
|
42
|
+
override_opts = {
|
43
|
+
_sdk_opts: {expect_nil: true},
|
44
|
+
body: {
|
45
|
+
device_ids: [id],
|
46
|
+
play: playing
|
47
|
+
}.to_json
|
48
|
+
}
|
49
|
+
|
50
|
+
parent.send_http_request(:put, "/v1/me/player", override_opts)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
##
|
6
|
+
# Spotify::SDK::Initialization deals with parsing input for the
|
7
|
+
# following code block `Spotify::SDK.new(input)` and extracting
|
8
|
+
# the access token, expiry and refresh token.
|
9
|
+
#
|
10
|
+
# You'll never have to interact with this, unless you have other
|
11
|
+
# objects you want us to parse the aforementioned variables from.
|
12
|
+
#
|
13
|
+
class Initialization
|
14
|
+
##
|
15
|
+
# This is where you mount new Initialization objects.
|
16
|
+
# Don't worry, we prefix Spotify::SDK::Initialization for you.
|
17
|
+
#
|
18
|
+
# @see /lib/spotify/sdk/initialization/url_string.rb
|
19
|
+
#
|
20
|
+
CLASSES = %i[
|
21
|
+
OAuthAccessToken
|
22
|
+
QueryString
|
23
|
+
URLString
|
24
|
+
PlainString
|
25
|
+
QueryHash
|
26
|
+
].freeze
|
27
|
+
|
28
|
+
class << self
|
29
|
+
##
|
30
|
+
# Initiate a new Spotify SDK Initialization object
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# begin
|
34
|
+
# hash = Spotify::SDK::Initialization.detect("access_token")
|
35
|
+
# puts "Access Token: #{hash[:access_token]}"
|
36
|
+
# puts "Expires in: #{hash[:expires_in]}"
|
37
|
+
# puts "Refresh Token: #{hash[:refresh_token]}"
|
38
|
+
# rescue Spotify::Errors::InitializationObjectInvalidError => e
|
39
|
+
# puts "Can't recognise the input because: #{e.inspect}"
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# @param [String,Hash,OAuth2::AccessToken] subject An instance of Spotify::SDK as a reference point.
|
43
|
+
#
|
44
|
+
def detect(subject)
|
45
|
+
klasses = CLASSES.map do |klass_name|
|
46
|
+
("Spotify::SDK::Initialization::%s" % klass_name).constantize.new(subject)
|
47
|
+
end
|
48
|
+
|
49
|
+
matches = klasses.select(&:should_perform?)
|
50
|
+
|
51
|
+
case matches.size
|
52
|
+
when 1
|
53
|
+
matches.first.perform
|
54
|
+
when 0
|
55
|
+
raise Spotify::Errors::InitializationObjectInvalidError.new
|
56
|
+
else
|
57
|
+
raise Spotify::Errors::InitializationObjectDuplicationError.new
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Errors
|
65
|
+
##
|
66
|
+
# A Error class for when the initialization subject is not valid (see `initialize(subject)` for more info).
|
67
|
+
#
|
68
|
+
class InitializationObjectInvalidError < StandardError; end
|
69
|
+
|
70
|
+
##
|
71
|
+
# A Error class for when the initialization subject matches against multiple selectors.
|
72
|
+
# When this Error occurs, this becomes an internal bug. It should be filed on the GitHub issue tracker.
|
73
|
+
#
|
74
|
+
class InitializationObjectDuplicationError < StandardError; end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Initialization
|
6
|
+
##
|
7
|
+
# For each SDK Initialization type, we have a base class to inherit from.
|
8
|
+
#
|
9
|
+
class Base
|
10
|
+
##
|
11
|
+
# Initiate a Spotify SDK Initialization Base class.
|
12
|
+
# Note: You would not ever initiate this class, but rather inherit from it.
|
13
|
+
# See /lib/spotify/sdk/initialization/query_string.rb as an example.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# Spotify::SDK::Initialization::Base.new("access_token")
|
17
|
+
#
|
18
|
+
# @param [Object] subject Any object that can be used to identify an access token.
|
19
|
+
#
|
20
|
+
def initialize(subject)
|
21
|
+
@subject = subject
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Determine whether this initialization type is valid, and should be performed.
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# instance = Spotify::SDK::Initialization::Base.new("access_token")
|
29
|
+
# instance.should_perform?
|
30
|
+
#
|
31
|
+
# @return [Boolean] A true or false answer as to whether to perform this initialization type.
|
32
|
+
#
|
33
|
+
def should_perform?
|
34
|
+
false
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Perform the class to extract the authentication details needed for the SDK class to run.
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# instance = Spotify::SDK::Initialization::Base.new("access_token")
|
42
|
+
# instance.perform if instance.should_perform?
|
43
|
+
#
|
44
|
+
# @return [Hash] A hash containing only access_token, expires_in and refresh_token.
|
45
|
+
#
|
46
|
+
def perform
|
47
|
+
{
|
48
|
+
access_token: nil,
|
49
|
+
expires_in: nil,
|
50
|
+
refresh_token: nil
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# The subject of the class. Usually what has been sent to Spotify::SDK.new() is the subject.
|
56
|
+
#
|
57
|
+
attr_reader :subject
|
58
|
+
|
59
|
+
# TODO: Delete this when tests are written.
|
60
|
+
# def sample_inputs
|
61
|
+
# nil
|
62
|
+
# end
|
63
|
+
|
64
|
+
# SAMPLE_TOKEN = """
|
65
|
+
# AQBjjlIYyEuyK2HuzqfA2ldj0B88d63KX2pgdOC0N4Pg4Iuw232M7gEgXjQS0Zdt3Y1r2J3G
|
66
|
+
# rCOf4fs1JndDbyGY_uaPWj5hpYE_dMS0G5ouJKLaapDT50EysfV3XdW6aQlbw51dYjgZU-Ce
|
67
|
+
# NCnj7bPsq4nXhZzbUkr0aTuR8MKEOXuW7-xaz1h8et-ZFYQDa788LTS08pLu--1waspBsmqh
|
68
|
+
# SxbOl0xG5QBQ0NnTbCn1SWi-T1B7J_6twmv7GWXsR9RqeBg_U5KcT6ciz85YFrkRQ6n47PpP
|
69
|
+
# HBfTFjmJxB91plroOOIZAE3fQ37-RDqdK7YzSw6gAm0
|
70
|
+
# """.strip
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Initialization
|
6
|
+
##
|
7
|
+
# This class implements accepting OAuth2::AccessToken as an initializer.
|
8
|
+
#
|
9
|
+
class OAuthAccessToken < Base
|
10
|
+
##
|
11
|
+
# This implements the #should_perform? method from the Base class.
|
12
|
+
#
|
13
|
+
# @see /lib/spotify/sdk/authorization/base.rb
|
14
|
+
#
|
15
|
+
def should_perform?
|
16
|
+
subject.instance_of? OAuth2::AccessToken
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# This implements the #perform method from the Base class.
|
21
|
+
#
|
22
|
+
# @see /lib/spotify/sdk/authorization/base.rb
|
23
|
+
#
|
24
|
+
def perform
|
25
|
+
{
|
26
|
+
access_token: subject.token,
|
27
|
+
expires_in: subject.expires_in,
|
28
|
+
refresh_token: subject.refresh_token
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Initialization
|
6
|
+
class PlainString < Base
|
7
|
+
def should_perform?
|
8
|
+
subject.is_a?(String) && subject =~ /^[a-zA-Z0-9_-]+$/
|
9
|
+
end
|
10
|
+
|
11
|
+
def perform
|
12
|
+
{
|
13
|
+
access_token: subject,
|
14
|
+
expires_in: nil,
|
15
|
+
refresh_token: nil
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
# TODO: Delete this when tests are written.
|
20
|
+
# def sample_inputs
|
21
|
+
# [ SAMPLE_TOKEN ]
|
22
|
+
# end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Initialization
|
6
|
+
class QueryHash < Base
|
7
|
+
def subject_hash
|
8
|
+
subject.try(:with_indifferent_access) || {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def should_perform?
|
12
|
+
subject_hash.has_key?(:token) || subject_hash.has_key?(:access_token)
|
13
|
+
end
|
14
|
+
|
15
|
+
def perform
|
16
|
+
subject_hash[:access_token] = subject_hash[:token] if subject_hash.has_key?(:token)
|
17
|
+
subject_hash.slice(:access_token, :expires_in, :refresh_token).symbolize_keys
|
18
|
+
end
|
19
|
+
|
20
|
+
# TODO: Delete this when tests are written.
|
21
|
+
# def sample_inputs
|
22
|
+
# [{
|
23
|
+
# token: SAMPLE_TOKEN
|
24
|
+
# }, {
|
25
|
+
# token: SAMPLE_TOKEN,
|
26
|
+
# expires_in: 1234567890
|
27
|
+
# }, {
|
28
|
+
# token: SAMPLE_TOKEN,
|
29
|
+
# expires_in: 1234567890,
|
30
|
+
# refresh_token: SAMPLE_TOKEN
|
31
|
+
# }, {
|
32
|
+
# access_token: SAMPLE_TOKEN
|
33
|
+
# }, {
|
34
|
+
# access_token: SAMPLE_TOKEN,
|
35
|
+
# expires_in: 1234567890
|
36
|
+
# }, {
|
37
|
+
# access_token: SAMPLE_TOKEN,
|
38
|
+
# expires_in: 1234567890,
|
39
|
+
# refresh_token: SAMPLE_TOKEN
|
40
|
+
# }]
|
41
|
+
# end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Initialization
|
6
|
+
class QueryString < Base
|
7
|
+
def params
|
8
|
+
CGI.parse(subject).with_indifferent_access
|
9
|
+
rescue NoMethodError
|
10
|
+
{}
|
11
|
+
end
|
12
|
+
|
13
|
+
def should_perform?
|
14
|
+
subject.is_a?(String) && (
|
15
|
+
params.has_key?(:token) && params.has_key?(:access_token)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def perform
|
20
|
+
{
|
21
|
+
access_token: params[access_token_key].to_a[0],
|
22
|
+
expires_in: params[:expires_in].to_a[0],
|
23
|
+
refresh_token: params[:refresh_token].to_a[0]
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def access_token_key
|
30
|
+
if params.has_key?(:token)
|
31
|
+
:token
|
32
|
+
elsif params.has_key?(:access_token)
|
33
|
+
:access_token
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# TODO: Delete this when tests are written.
|
38
|
+
# def sample_inputs
|
39
|
+
# [
|
40
|
+
# "token=#{SAMPLE_TOKEN}",
|
41
|
+
# "token=#{SAMPLE_TOKEN}&expires_in=1234567890",
|
42
|
+
# "token=#{SAMPLE_TOKEN}&expires_in=1234567890&refresh_token=#{SAMPLE_TOKEN}",
|
43
|
+
# "access_token=#{SAMPLE_TOKEN}",
|
44
|
+
# "access_token=#{SAMPLE_TOKEN}&expires_in=1234567890",
|
45
|
+
# "access_token=#{SAMPLE_TOKEN}&expires_in=1234567890&refresh_token=#{SAMPLE_TOKEN}"
|
46
|
+
# ]
|
47
|
+
# end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|