spotify-client 0.0.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 +7 -0
- data/lib/spotify-client.rb +1 -0
- data/lib/spotify/exceptions.rb +9 -0
- data/lib/spotify/utils.rb +11 -0
- data/lib/spotify/version.rb +3 -0
- data/lib/spotify_client.rb +190 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8369fd39e93441e6443010c7f9f4d3795fbef619
|
4
|
+
data.tar.gz: b8202b9abf4963f52ca4b0be762cc586a681ac21
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4f3bb1b197542fca61f12021e919e48626893c96b11987123c4232b1d7831ae78d679d706947fb787e34dc6a4200c7be5398335dc4f132e02c3fa81d3caa8f97
|
7
|
+
data.tar.gz: ed067b3f2c46a1aa0fc52ee959dea624fd19924938276d052a2949da17829489ac814f1f2ec1fbe4ebb4e9f7dd7e3d8688ec07ff8adf0e8cd643278e547d62d4
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spotify_client'
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Spotify
|
2
|
+
class ImplementationError < StandardError; end
|
3
|
+
class Error < StandardError; end
|
4
|
+
class AuthenticationError < Error; end
|
5
|
+
class HTTPError < Error; end
|
6
|
+
class InsufficientClienScopeError < Error; end
|
7
|
+
class BadRequest < Error; end
|
8
|
+
class ResourceNotFound < Error; end
|
9
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'excon'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + '/spotify/utils'
|
5
|
+
require File.dirname(__FILE__) + '/spotify/exceptions'
|
6
|
+
|
7
|
+
module Spotify
|
8
|
+
class Client
|
9
|
+
BASE_URI = 'https://api.spotify.com'.freeze
|
10
|
+
|
11
|
+
attr_accessor :access_token
|
12
|
+
|
13
|
+
# Initialize the client.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# client = Spotify::Client.new(:access_token => 'longtoken', retries: 0, raise_errors: true)
|
17
|
+
#
|
18
|
+
# @param [Hash] configuration.
|
19
|
+
def initialize(config = {})
|
20
|
+
@access_token = config[:access_token]
|
21
|
+
@raise_errors = config[:raise_errors] || false
|
22
|
+
@retries = config[:retries] || 0
|
23
|
+
@read_timeout = config[:read_timeout] || 10
|
24
|
+
@write_timeout = config[:write_timeout] || 10
|
25
|
+
@connection = Excon.new(BASE_URI, :persistent => config[:persistent] || false)
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
vars = self.instance_variables.map{ |v| "#{v}=#{instance_variable_get(v).inspect}"}.join(', ')
|
30
|
+
"<#{self.class}: #{vars}>"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Closes the connection underlying socket.
|
34
|
+
# Use when you employ persistent connections and are done with your requests.
|
35
|
+
def close_connection
|
36
|
+
@connection.reset
|
37
|
+
end
|
38
|
+
|
39
|
+
def me
|
40
|
+
run(:get, "/v1/me", [200])
|
41
|
+
end
|
42
|
+
|
43
|
+
def user(user_id)
|
44
|
+
run(:get, "/v1/users/#{user_id}", [200])
|
45
|
+
end
|
46
|
+
|
47
|
+
def user_playlists(user_id)
|
48
|
+
run(:get, "/v1/users/#{user_id}/playlists", [200])
|
49
|
+
end
|
50
|
+
|
51
|
+
def user_playlist(user_id, playlist_id)
|
52
|
+
run(:get, "/v1/users/#{user_id}/playlists/#{playlist_id}", [200])
|
53
|
+
end
|
54
|
+
|
55
|
+
def user_playlist_tracks(user_id, playlist_id)
|
56
|
+
run(:get, "/v1/users/#{user_id}/playlists/#{playlist_id}/tracks", [200])
|
57
|
+
end
|
58
|
+
|
59
|
+
# Create a playlist for a Spotify user. The playlist will be empty until you add tracks.
|
60
|
+
#
|
61
|
+
# Requires playlist-modify for a public playlist.
|
62
|
+
# Requires playlist-modify-private for a private playlist.
|
63
|
+
def create_user_playlist(user_id, name, is_public = true)
|
64
|
+
run(:post, "/v1/users/#{user_id}/playlists", [201], JSON.dump({ :name => name, :public => is_public }))
|
65
|
+
end
|
66
|
+
|
67
|
+
# Add an Array of track uris to an existing playlist.
|
68
|
+
#
|
69
|
+
# Adding tracks to a user's public playlist requires authorization of the playlist-modify scope;
|
70
|
+
# adding tracks to a private playlist requires the playlist-modify-private scope.
|
71
|
+
#
|
72
|
+
# client.add_user_tracks_to_playlist('1181346016', '7i3thJWDtmX04dJhFwYb0x', %w(spotify:track:4iV5W9uYEdYUVa79Axb7Rh spotify:track:2lzEz3A3XIFyhMDqzMdcss))
|
73
|
+
def add_user_tracks_to_playlist(user_id, playlist_id, uris = [], position = nil)
|
74
|
+
params = { :uris => Array.wrap(uris)[0..99].join(',') }
|
75
|
+
if position
|
76
|
+
params.merge!(:position => position)
|
77
|
+
end
|
78
|
+
run(:post, "/v1/users/#{user_id}/playlists/#{playlist_id}/tracks", [201], params)
|
79
|
+
end
|
80
|
+
|
81
|
+
def album(album_id)
|
82
|
+
run(:get, "/v1/albums/#{album_id}", [200])
|
83
|
+
end
|
84
|
+
|
85
|
+
def album_tracks(album_id)
|
86
|
+
run(:get, "/v1/albums/#{album_id}/tracks", [200])
|
87
|
+
end
|
88
|
+
|
89
|
+
def albums(album_ids)
|
90
|
+
params = { :ids => Array.wrap(album_ids).join(',') }
|
91
|
+
run(:get, "/v1/albums", [200], params)
|
92
|
+
end
|
93
|
+
|
94
|
+
def track(track_id)
|
95
|
+
run(:get, "/v1/tracks/#{track_id}", [200])
|
96
|
+
end
|
97
|
+
|
98
|
+
def tracks(track_ids)
|
99
|
+
params = { :ids => Array.wrap(track_ids).join(',') }
|
100
|
+
run(:get, "/v1/tracks", [200], params)
|
101
|
+
end
|
102
|
+
|
103
|
+
def artist(artist_id)
|
104
|
+
run(:get, "/v1/artists/#{artist_id}", [200])
|
105
|
+
end
|
106
|
+
|
107
|
+
def artists(artist_ids)
|
108
|
+
params = { :ids => Array.wrap(artist_ids).join(',') }
|
109
|
+
run(:get, "/v1/tracks", [200], params)
|
110
|
+
end
|
111
|
+
|
112
|
+
def artist_albums(artist_id)
|
113
|
+
run(:get, "/v1/artists/#{artist_id}/albums", [200])
|
114
|
+
end
|
115
|
+
|
116
|
+
def search(entity, term)
|
117
|
+
unless [:artist, :album, :track].include?(entity.to_sym)
|
118
|
+
raise(ImplementationError, "entity needs to be either artist, album or track, got: #{entity}")
|
119
|
+
end
|
120
|
+
run(:get, "/v1/search", [200], { :q => term.to_s, type: entity })
|
121
|
+
end
|
122
|
+
|
123
|
+
# Get Spotify catalog information about an artist’s top 10 tracks by country.
|
124
|
+
#
|
125
|
+
# +country_id+ is required. An ISO 3166-1 alpha-2 country code.
|
126
|
+
def artist_top_tracks(artist_id, country_id)
|
127
|
+
run(:get, "/v1/artists/#{artist_id}/top-tracks", [200], { :country => country_id })
|
128
|
+
end
|
129
|
+
|
130
|
+
protected
|
131
|
+
|
132
|
+
def run(verb, path, expected_status_codes, params = {}, idempotent = true)
|
133
|
+
begin
|
134
|
+
run!(verb, path, expected_status_codes, params)
|
135
|
+
rescue Error => e
|
136
|
+
if @raise_errors
|
137
|
+
raise e
|
138
|
+
else
|
139
|
+
false
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def run!(verb, path, expected_status_codes, params_or_body = nil, idempotent = true)
|
145
|
+
packet = {
|
146
|
+
:idempotent => idempotent,
|
147
|
+
:expects => expected_status_codes,
|
148
|
+
:method => verb,
|
149
|
+
:path => path,
|
150
|
+
:read_timeout => @read_timeout,
|
151
|
+
:write_timeout => @write_timeout,
|
152
|
+
:retry_limit => @retries,
|
153
|
+
:headers => {
|
154
|
+
'Content-Type' => 'application/json',
|
155
|
+
'User-Agent' => 'Spotify Ruby Client'
|
156
|
+
}
|
157
|
+
}
|
158
|
+
if params_or_body.is_a?(Hash)
|
159
|
+
packet.merge!(:query => params_or_body)
|
160
|
+
else
|
161
|
+
packet.merge!(:body => params_or_body)
|
162
|
+
end
|
163
|
+
|
164
|
+
if @access_token != nil && @access_token != ""
|
165
|
+
packet[:headers].merge!('Authorization' => "Bearer #{@access_token}")
|
166
|
+
end
|
167
|
+
|
168
|
+
# puts "\033[31m [Spotify] HTTP Request: #{verb.upcase} #{BASE_URI}#{path} #{packet[:headers].inspect} \e[0m"
|
169
|
+
response = @connection.request(packet)
|
170
|
+
::JSON.load(response.body)
|
171
|
+
|
172
|
+
rescue Excon::Errors::NotFound => exception
|
173
|
+
raise(ResourceNotFound, "Error: #{exception.message}")
|
174
|
+
rescue Excon::Errors::BadRequest => exception
|
175
|
+
raise(BadRequest, "Error: #{exception.message}")
|
176
|
+
rescue Excon::Errors::Forbidden => exception
|
177
|
+
raise(InsufficientClienScopeError, "Error: #{exception.message}")
|
178
|
+
rescue Excon::Errors::Unauthorized => exception
|
179
|
+
raise(AuthenticationError, "Error: #{exception.message}")
|
180
|
+
rescue Excon::Errors::Error => exception
|
181
|
+
# Catch all others errors. Samples:
|
182
|
+
#
|
183
|
+
#<Excon::Errors::SocketError: Connection refused - connect(2) (Errno::ECONNREFUSED)>
|
184
|
+
#<Excon::Errors::InternalServerError: Expected([200, 204, 404]) <=> Actual(500 InternalServerError)>
|
185
|
+
#<Excon::Errors::Timeout: read timeout reached>
|
186
|
+
#<Excon::Errors::BadGateway: Expected([200]) <=> Actual(502 Bad Gateway)>
|
187
|
+
raise(HTTPError, "Error: #{exception.message}")
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spotify-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Claudio Poli
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-06-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: excon
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.37'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.37'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: guard-rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Ruby client for the Spotify Web API
|
56
|
+
email:
|
57
|
+
- claudio@icorete.ch
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- lib/spotify-client.rb
|
63
|
+
- lib/spotify/exceptions.rb
|
64
|
+
- lib/spotify/utils.rb
|
65
|
+
- lib/spotify/version.rb
|
66
|
+
- lib/spotify_client.rb
|
67
|
+
homepage: https://github.com/icoretech/spotify-client
|
68
|
+
licenses: []
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project: "[none]"
|
86
|
+
rubygems_version: 2.2.2
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Ruby client for the Spotify Web API
|
90
|
+
test_files: []
|