spotify-ruby 0.1.1 → 0.2.1
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 +4 -4
- data/.gitignore +10 -2
- data/.rubocop.yml +16 -5
- data/.travis.yml +10 -1
- data/CODE_OF_CONDUCT.md +1 -1
- data/COVERAGE.md +98 -92
- data/LICENSE +1 -1
- data/README.md +223 -63
- data/Rakefile +5 -12
- data/lib/spotify.rb +2 -2
- data/lib/spotify/accounts.rb +130 -0
- data/lib/spotify/accounts/session.rb +173 -0
- data/lib/spotify/sdk.rb +43 -60
- data/lib/spotify/sdk/album.rb +84 -0
- data/lib/spotify/sdk/artist.rb +162 -0
- data/lib/spotify/sdk/base.rb +34 -16
- data/lib/spotify/sdk/connect.rb +51 -2
- data/lib/spotify/sdk/connect/device.rb +282 -7
- data/lib/spotify/sdk/connect/playback_state.rb +141 -0
- data/lib/spotify/sdk/image.rb +44 -0
- data/lib/spotify/sdk/item.rb +134 -0
- data/lib/spotify/sdk/me.rb +83 -0
- data/lib/spotify/sdk/me/info.rb +108 -0
- data/lib/spotify/sdk/model.rb +40 -23
- data/lib/spotify/version.rb +8 -5
- data/spotify-ruby.gemspec +24 -9
- metadata +87 -38
- data/bin/console +0 -15
- data/bin/setup +0 -8
- data/lib/spotify/auth.rb +0 -111
- data/lib/spotify/sdk/initialization.rb +0 -76
- data/lib/spotify/sdk/initialization/base.rb +0 -74
- data/lib/spotify/sdk/initialization/oauth_access_token.rb +0 -34
- data/lib/spotify/sdk/initialization/plain_string.rb +0 -26
- data/lib/spotify/sdk/initialization/query_hash.rb +0 -45
- data/lib/spotify/sdk/initialization/query_string.rb +0 -51
- data/lib/spotify/sdk/initialization/url_string.rb +0 -49
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Connect
|
6
|
+
class PlaybackState < Model
|
7
|
+
##
|
8
|
+
# Get the device the current playback is on.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# device = @sdk.connect.devices[0]
|
12
|
+
# device.playback.device
|
13
|
+
#
|
14
|
+
# @return [Spotify::SDK::Connect::Device] self Return the device object.
|
15
|
+
#
|
16
|
+
def device
|
17
|
+
Spotify::SDK::Connect::Device.new(super, parent)
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Is the current user playing a track?
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# playback = @sdk.connect.playback
|
25
|
+
# playback.playing?
|
26
|
+
#
|
27
|
+
# @return [FalseClass,TrueClass] is_playing True if user is currently performing playback.
|
28
|
+
#
|
29
|
+
alias_attribute :playing?, :is_playing
|
30
|
+
|
31
|
+
##
|
32
|
+
# Is the current playback set to shuffle?
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# playback = @sdk.connect.playback
|
36
|
+
# playback.shuffling?
|
37
|
+
#
|
38
|
+
# @return [FalseClass,TrueClass] is_shuffling True if shuffle is set.
|
39
|
+
#
|
40
|
+
alias_attribute :shuffling?, :shuffle_state
|
41
|
+
|
42
|
+
##
|
43
|
+
# What repeat mode is the current playback set to?
|
44
|
+
#
|
45
|
+
# Options:
|
46
|
+
# :off => This means no repeat is set.
|
47
|
+
# :context => This means it will repeat within the same context.
|
48
|
+
# :track => This will repeat the same track.
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# playback = @sdk.connect.playback
|
52
|
+
# playback.repeat # :off, :context, or :track
|
53
|
+
#
|
54
|
+
# @return [Symbol] repeat_mode Either :off, :context, or :track
|
55
|
+
#
|
56
|
+
def repeat_mode
|
57
|
+
repeat_state.to_sym
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# The current timestamp of the playback state
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# playback = @sdk.connect.playback
|
65
|
+
# playback.time
|
66
|
+
#
|
67
|
+
# @return [Time] time The accuracy time of the playback state.
|
68
|
+
#
|
69
|
+
def time
|
70
|
+
Time.at(timestamp / 1000)
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# What is the current position of the track?
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# playback = @sdk.connect.playback
|
78
|
+
# playback.position
|
79
|
+
#
|
80
|
+
# @return [Integer] position_ms In milliseconds, the position of the track.
|
81
|
+
#
|
82
|
+
alias_attribute :position, :progress_ms
|
83
|
+
|
84
|
+
##
|
85
|
+
# How much percentage of the track is the position currently in?
|
86
|
+
#
|
87
|
+
# @example
|
88
|
+
# playback = @sdk.connect.playback
|
89
|
+
# playback.position_percentage # => 7.30
|
90
|
+
# playback.position_percentage(4) # => 7.3039
|
91
|
+
#
|
92
|
+
# @param [Integer] decimal_points How many decimal points to return
|
93
|
+
# @return [Float] percentage Completion percentage. Rounded to 2 decimal places.
|
94
|
+
#
|
95
|
+
def position_percentage(decimal_points=2)
|
96
|
+
return nil if position.nil?
|
97
|
+
((position.to_f / item.duration.to_f) * 100).ceil(decimal_points)
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# Get the artists for the currently playing track.
|
102
|
+
#
|
103
|
+
# @example
|
104
|
+
# @sdk.connect.playback.artists
|
105
|
+
#
|
106
|
+
# @return [Array] artists An array of artists wrapped in Spotify::SDK::Artist
|
107
|
+
#
|
108
|
+
def artists
|
109
|
+
item[:artists].map do |artist|
|
110
|
+
Spotify::SDK::Artist.new(artist, parent)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# Get the main artist for the currently playing track.
|
116
|
+
#
|
117
|
+
# @example
|
118
|
+
# @sdk.connect.playback.artist
|
119
|
+
#
|
120
|
+
# @return [Spotify::SDK::Artist] artist The main artist of the track.
|
121
|
+
#
|
122
|
+
def artist
|
123
|
+
artists.first
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# Get the item for the currently playing track.
|
128
|
+
#
|
129
|
+
# @example
|
130
|
+
# @sdk.connect.playback.item
|
131
|
+
#
|
132
|
+
# @return [Spotify::SDK::Item] item The currently playing track, wrapped in Spotify::SDK::Item
|
133
|
+
#
|
134
|
+
def item
|
135
|
+
raise "Playback information is not available if user has a private session enabled" if device.private_session?
|
136
|
+
Spotify::SDK::Item.new(super, parent)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Image < Model
|
6
|
+
##
|
7
|
+
# Get the ID of the image.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# artist = @sdk.connect.playback.artist
|
11
|
+
# artist.images[0].id # => "941223d904f006c4d998598272d43d94"
|
12
|
+
#
|
13
|
+
# @return [String] image_id The image ID generated from Spotify.
|
14
|
+
#
|
15
|
+
def id
|
16
|
+
url.match(/[a-z0-9]+$/i)[0]
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Get the mobile-related link for the image. Designed for offline mobile apps.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# artist = @sdk.connect.playback.artist
|
24
|
+
# artist.images[0].spotify_uri # => "spoitfy:image:..."
|
25
|
+
#
|
26
|
+
# @return [String] spotify_uri The mobile-embeddable image for the item.
|
27
|
+
#
|
28
|
+
def spotify_uri
|
29
|
+
"spotify:image:%s" % id
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Get the HTTP link for the image. Designed for web apps.
|
34
|
+
#
|
35
|
+
# @example
|
36
|
+
# artist = @sdk.connect.playback.artist
|
37
|
+
# artist.images[0].spotify_url # => "https://i.scdn.co/image/..."
|
38
|
+
#
|
39
|
+
# @return [String] spotify_url The web-embeddable HTTP image for the item.
|
40
|
+
#
|
41
|
+
alias_attribute :spotify_url, :url
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Item < Model
|
6
|
+
##
|
7
|
+
# Get the album for this item.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# @sdk.connect.playback.item.album
|
11
|
+
#
|
12
|
+
# @return [Spotify::SDK::Album] album The album object, wrapped in Spotify::SDK::Album
|
13
|
+
#
|
14
|
+
def album
|
15
|
+
Spotify::SDK::Album.new(super, parent)
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Get the artists/creators for this item.
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# @sdk.connect.playback.item.artists
|
23
|
+
#
|
24
|
+
# @return [Array] artists A list of artists, wrapped in Spotify::SDK::Artist
|
25
|
+
#
|
26
|
+
def artists
|
27
|
+
super.map do |artist|
|
28
|
+
Spotify::SDK::Artist.new(artist, parent)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Get the primary artist/creator for this item.
|
34
|
+
#
|
35
|
+
# @example
|
36
|
+
# @sdk.connect.playback.item.artist
|
37
|
+
#
|
38
|
+
# @return [Spotify::SDK::Artist] artist The primary artist, wrapped in Spotify::SDK::Artist
|
39
|
+
#
|
40
|
+
def artist
|
41
|
+
artists.first
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Get the duration.
|
46
|
+
# Alias to self.duration_ms
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
# @sdk.connect.playback.item.duration # => 10331
|
50
|
+
#
|
51
|
+
# @return [Integer] duration_ms In milliseconds, how long the item is.
|
52
|
+
#
|
53
|
+
alias_attribute :duration, :duration_ms
|
54
|
+
|
55
|
+
##
|
56
|
+
# Is this track explicit?
|
57
|
+
# Alias to self.explicit
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# @sdk.connect.playback.item.explicit? # => true
|
61
|
+
#
|
62
|
+
# @return [TrueClass,FalseClass] is_explicit Returns true if item contains explicit content.
|
63
|
+
#
|
64
|
+
alias_attribute :explicit?, :explicit
|
65
|
+
|
66
|
+
##
|
67
|
+
# Is this a local track, not a Spotify track?
|
68
|
+
# Alias to self.is_local
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# @sdk.connect.playback.item.local? # => false
|
72
|
+
#
|
73
|
+
# @return [TrueClass,FalseClass] is_local Returns true if item is local to the user.
|
74
|
+
#
|
75
|
+
alias_attribute :local?, :is_local
|
76
|
+
|
77
|
+
##
|
78
|
+
# Is this a playable track?
|
79
|
+
# Alias to self.is_playable
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# @sdk.connect.playback.item.playable? # => false
|
83
|
+
#
|
84
|
+
# @return [TrueClass,FalseClass] is_playable Returns true if item is playable.
|
85
|
+
#
|
86
|
+
alias_attribute :playable?, :is_playable
|
87
|
+
|
88
|
+
##
|
89
|
+
# Is this a track?
|
90
|
+
# Alias to self.type == "track"
|
91
|
+
#
|
92
|
+
# @example
|
93
|
+
# @sdk.connect.playback.item.track? # => true
|
94
|
+
#
|
95
|
+
# @return [TrueClass,FalseClass] is_track Returns true if item is an music track.
|
96
|
+
#
|
97
|
+
def track?
|
98
|
+
type == "track"
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Get the Spotify URI for this item.
|
103
|
+
# Alias to self.uri
|
104
|
+
#
|
105
|
+
# @example
|
106
|
+
# @sdk.connect.playback.item.spotify_uri # => "spotify:track:..."
|
107
|
+
#
|
108
|
+
# @return [String] spotify_uri The direct URI to this Spotify resource.
|
109
|
+
#
|
110
|
+
alias_attribute :spotify_uri, :uri
|
111
|
+
|
112
|
+
##
|
113
|
+
# Get the Spotify HTTP URL for this item.
|
114
|
+
# Alias to self.external_urls[:spotify]
|
115
|
+
#
|
116
|
+
# @example
|
117
|
+
# @sdk.connect.playback.item.spotify_url # => "https://open.spotify.com/..."
|
118
|
+
#
|
119
|
+
# @return [String] spotify_url The direct HTTP URL to this Spotify resource.
|
120
|
+
#
|
121
|
+
alias_attribute :spotify_url, "external_urls.spotify"
|
122
|
+
|
123
|
+
##
|
124
|
+
# Get the ISRC for this track.
|
125
|
+
#
|
126
|
+
# @example
|
127
|
+
# @sdk.connect.playback.item.isrc # => "USUM00000000"
|
128
|
+
#
|
129
|
+
# @return [String] isrc The ISRC string for this track.
|
130
|
+
#
|
131
|
+
alias_attribute :isrc, "external_ids.isrc"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Me < Base
|
6
|
+
##
|
7
|
+
# Get the current user's information.
|
8
|
+
# Respective information requires the `user-read-private user-read-email user-read-birthdate` scopes.
|
9
|
+
# GET /v1/me
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# me = @sdk.me.info
|
13
|
+
#
|
14
|
+
# @see https://developer.spotify.com/console/get-current-user/
|
15
|
+
# @see https://developer.spotify.com/documentation/web-api/reference/users-profile/get-current-users-profile/
|
16
|
+
#
|
17
|
+
# @param [Hash] override_opts Custom options for HTTParty.
|
18
|
+
# @return [Spotify::SDK::Me::Info] user_info Return the user's information.
|
19
|
+
#
|
20
|
+
def info(override_opts={})
|
21
|
+
me_info = send_http_request(:get, "/v1/me", override_opts)
|
22
|
+
Spotify::SDK::Me::Info.new(me_info, self)
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Check if the current user is following N users.
|
27
|
+
#
|
28
|
+
def following?(list, type=:artist, override_opts={})
|
29
|
+
raise "Must contain an array" unless list.is_a?(Array)
|
30
|
+
raise "Must contain an array of String or Spotify::SDK::Artist" if any_of?(list, [String, Spotify::SDK::Artist])
|
31
|
+
raise "type must be either 'artist' or 'user'" unless %i[artist user].include?(type)
|
32
|
+
send_is_following_http_requests(list.map {|id| id.try(:id) || id }, type, override_opts)
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Get the current user's followed artists. Requires the `user-read-follow` scope.
|
37
|
+
# GET /v1/me/following
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# @sdk.me.following
|
41
|
+
#
|
42
|
+
# @param [Hash] override_opts Custom options for HTTParty.
|
43
|
+
# @return [Array] artists A list of followed artists, wrapped in Spotify::SDK::Artist
|
44
|
+
#
|
45
|
+
def following(override_opts={})
|
46
|
+
artists = send_following_http_requests("/v1/me/following?type=artist&limit=50", override_opts)
|
47
|
+
artists.map do |artist|
|
48
|
+
Spotify::SDK::Artist.new(artist, self)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def any_of?(array, klasses)
|
55
|
+
(array.map(&:class) - klasses).any?
|
56
|
+
end
|
57
|
+
|
58
|
+
def send_is_following_http_requests(list, type, override_opts) # :nodoc:
|
59
|
+
max_ids = list.first(50)
|
60
|
+
remaining_ids = list - max_ids
|
61
|
+
|
62
|
+
ids = max_ids.map {|id| {id.strip => nil} }.inject(&:merge)
|
63
|
+
following = send_http_request(
|
64
|
+
:get,
|
65
|
+
"/v1/me/following/contains?type=%s&ids=%s" % [type, ids.keys.join(",")],
|
66
|
+
override_opts
|
67
|
+
)
|
68
|
+
ids.each_key {|id| ids[id] = following.shift }
|
69
|
+
|
70
|
+
if remaining_ids.any?
|
71
|
+
ids.merge(send_is_following_http_requests(remaining_ids, type, override_opts))
|
72
|
+
end || ids
|
73
|
+
end
|
74
|
+
|
75
|
+
def send_following_http_requests(http_path, override_opts) # :nodoc:
|
76
|
+
request = send_http_request(:get, http_path, override_opts)[:artists]
|
77
|
+
artists = request[:items]
|
78
|
+
artists << send_following_http_requests(request[:next][23..-1], override_opts) if request[:next]
|
79
|
+
artists.flatten
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spotify
|
4
|
+
class SDK
|
5
|
+
class Me
|
6
|
+
class Info < Model
|
7
|
+
##
|
8
|
+
# Is the user currently on Spotify Free?
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# @sdk.me.info.free?
|
12
|
+
#
|
13
|
+
# @return [TrueClass,FalseClass] is_free Return true if user is on Spotify Free.
|
14
|
+
#
|
15
|
+
def free?
|
16
|
+
product == "free"
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Is the user currently on Spotify Premium?
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# @sdk.me.info.premium?
|
24
|
+
#
|
25
|
+
# @return [TrueClass,FalseClass] is_premium Return true if user is on Spotify Premium.
|
26
|
+
#
|
27
|
+
def premium?
|
28
|
+
product == "premium"
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Get the user's birthdate.
|
33
|
+
# Requires the `user-read-birthdate` scope, otherwise it will return nil.
|
34
|
+
#
|
35
|
+
# @example
|
36
|
+
# @sdk.me.info.birthdate # => Wed, 10 May 1985
|
37
|
+
#
|
38
|
+
# @return [Date,NilClass] birthdate Return the user's birthdate, otherwise return nil.
|
39
|
+
#
|
40
|
+
def birthdate
|
41
|
+
Date.parse(super) if super
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Does the user have a valid display_name?
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# @sdk.me.info.display_name? # => false
|
49
|
+
#
|
50
|
+
# @return [TrueClass,FalseClass] has_display_name Return true if the user has a non-empty display name.
|
51
|
+
#
|
52
|
+
def display_name?
|
53
|
+
!display_name.to_s.empty?
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Get the images for the user.
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# @sdk.me.info.images[0].spotify_uri # => "spotify:image:..."
|
61
|
+
# @sdk.me.info.images[0].spotify_url # => "https://profile-images.scdn.co/..."
|
62
|
+
#
|
63
|
+
# @return [Array] images A list of all user photos wrapped in Spotify::SDK::Image
|
64
|
+
#
|
65
|
+
def images
|
66
|
+
super.map do |image|
|
67
|
+
Spotify::SDK::Image.new(image, parent)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Return the followers on Spotify for this user.
|
73
|
+
#
|
74
|
+
# @example
|
75
|
+
# me = @sdk.me.info
|
76
|
+
# me.followers # => 13913
|
77
|
+
#
|
78
|
+
# @return [Integer] followers The number of users following this user.
|
79
|
+
#
|
80
|
+
def followers
|
81
|
+
super[:total]
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Get the Spotify URI for this user.
|
86
|
+
# Alias to self.uri
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# @sdk.me.info.spotify_uri # => "spotify:user:..."
|
90
|
+
#
|
91
|
+
# @return [String] spotify_uri The direct URI to this Spotify resource.
|
92
|
+
#
|
93
|
+
alias_attribute :spotify_uri, :uri
|
94
|
+
|
95
|
+
##
|
96
|
+
# Get the Spotify HTTP URL for this user.
|
97
|
+
# Alias to self.external_urls[:spotify]
|
98
|
+
#
|
99
|
+
# @example
|
100
|
+
# @sdk.me.info.spotify_url # => "https://open.spotify.com/..."
|
101
|
+
#
|
102
|
+
# @return [String] spotify_url The direct HTTP URL to this Spotify resource.
|
103
|
+
#
|
104
|
+
alias_attribute :spotify_url, "external_urls.spotify"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|