spotify-ruby 0.1.1 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|