spotify-ruby-api 0.7.0

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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE +21 -0
  7. data/README.md +119 -0
  8. data/Rakefile +7 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +7 -0
  11. data/lib/spotify/api/album.rb +164 -0
  12. data/lib/spotify/api/artist.rb +248 -0
  13. data/lib/spotify/api/base.rb +150 -0
  14. data/lib/spotify/api/track.rb +127 -0
  15. data/lib/spotify/api/user.rb +58 -0
  16. data/lib/spotify/api/version.rb +5 -0
  17. data/lib/spotify/api.rb +12 -0
  18. data/lib/spotify/models/album.rb +42 -0
  19. data/lib/spotify/models/artist.rb +34 -0
  20. data/lib/spotify/models/category.rb +23 -0
  21. data/lib/spotify/models/copyright.rb +27 -0
  22. data/lib/spotify/models/cursor.rb +19 -0
  23. data/lib/spotify/models/cursorbased_paging.rb +24 -0
  24. data/lib/spotify/models/error.rb +122 -0
  25. data/lib/spotify/models/external_id.rb +41 -0
  26. data/lib/spotify/models/external_url.rb +39 -0
  27. data/lib/spotify/models/follower.rb +27 -0
  28. data/lib/spotify/models/full/album.rb +46 -0
  29. data/lib/spotify/models/full/artist.rb +37 -0
  30. data/lib/spotify/models/full/track.rb +34 -0
  31. data/lib/spotify/models/full/user.rb +31 -0
  32. data/lib/spotify/models/full.rb +11 -0
  33. data/lib/spotify/models/image.rb +28 -0
  34. data/lib/spotify/models/paging.rb +38 -0
  35. data/lib/spotify/models/playlist_track.rb +24 -0
  36. data/lib/spotify/models/saved_album.rb +22 -0
  37. data/lib/spotify/models/saved_track.rb +22 -0
  38. data/lib/spotify/models/simplified/album.rb +23 -0
  39. data/lib/spotify/models/simplified/artist.rb +23 -0
  40. data/lib/spotify/models/simplified/track.rb +23 -0
  41. data/lib/spotify/models/simplified/user.rb +23 -0
  42. data/lib/spotify/models/simplified.rb +11 -0
  43. data/lib/spotify/models/track.rb +50 -0
  44. data/lib/spotify/models/track_link.rb +33 -0
  45. data/lib/spotify/models/user.rb +41 -0
  46. data/lib/spotify/models.rb +27 -0
  47. data/lib/spotify.rb +6 -0
  48. data/spotify-api.gemspec +34 -0
  49. metadata +160 -0
@@ -0,0 +1,150 @@
1
+ require 'json'
2
+
3
+ module Spotify
4
+ module API
5
+
6
+ class Base
7
+
8
+ attr_reader :response, :retries, :timeout, :url, :params, :request
9
+
10
+ #
11
+ # The API base URL.
12
+ #
13
+ BASE_URL = "https://api.spotify.com/v1/"
14
+
15
+ #
16
+ # The API search endpoint.
17
+ #
18
+ SEARCH_URL = "#{BASE_URL}search"
19
+
20
+ #
21
+ # The max retries limit.
22
+ #
23
+ MAX_RETRIES = 5
24
+
25
+ #
26
+ # Restrict value for market variable on search methods.
27
+ #
28
+ FROM_TOKEN = :from_token
29
+
30
+ #
31
+ # Initializes the optional arguments.
32
+ #
33
+ # @param [Hash] the optional arguments.
34
+ # @option [Fixnum] :timeout the max time a request can take.
35
+ # @option [Fixnum] :retries the number of retries if necessary.
36
+ #
37
+ def initialize(args = {})
38
+ @args = args.except(:timeout, :retries)
39
+ @timeout = args[:timeout].to_i
40
+ @retries = args[:retries].to_i
41
+ end
42
+
43
+ #
44
+ # Performs a request on the given url with its arguments.
45
+ #
46
+ # @param [String] url the request API url.
47
+ # @param [Hash] params the request arguments.
48
+ #
49
+ def get(url, params = {})
50
+ @url = url
51
+ @params = params
52
+ @request = prepare_request
53
+
54
+ make_request
55
+ end
56
+
57
+ #
58
+ # Performs the request respecting the given timeout.
59
+ #
60
+ # @param [Proc] block a block of code to perform the request.
61
+ #
62
+ def run_with_timeout(&block)
63
+ Timeout.timeout(@timeout) do
64
+ yield
65
+ end
66
+ end
67
+
68
+ #
69
+ # Prepares the Proc instructions to perform the request.
70
+ #
71
+ def prepare_request
72
+ lambda do
73
+ sleep(3)
74
+ uri = URI(@url)
75
+ uri.query = URI.encode_www_form(@params)
76
+ @response = Net::HTTP.get(uri)
77
+ end
78
+ end
79
+
80
+ #
81
+ # Handles the request behavior.
82
+ #
83
+ # @param [Fixnum] attempts the current attempt number.
84
+ #
85
+ def make_request(attempts = 0)
86
+ @attempts = attempts
87
+
88
+ if attempts > MAX_RETRIES || attempts > @retries
89
+ set_response(Spotify::API::Errors::MAX_RETRIES, true)
90
+
91
+ else
92
+ begin
93
+ if @timeout > 0
94
+ run_with_timeout { request.call }
95
+ else
96
+ request.call
97
+ end
98
+
99
+ rescue Timeout::Error
100
+ set_response(Spotify::API::Errors::TIMEOUT)
101
+ rescue
102
+ set_response(Spotify::API::Errors::UNEXPECTED)
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ #
109
+ # Sets the response in case of something goes wrong during the
110
+ # extraction process.
111
+ #
112
+ # @param [String] error the raised error during the extraction.
113
+ # @param [Boolean] force if should return error independent of retries.
114
+ #
115
+ def set_response(error, force = false)
116
+ if force == false && @retries > 0
117
+ make_request(@attempts + 1)
118
+ else
119
+ @response = { error: error }.to_json
120
+ end
121
+ end
122
+
123
+ #
124
+ # Parses the response to JSON to get more flexible.
125
+ #
126
+ # @return [Hash] the parsed response.
127
+ #
128
+ def body
129
+ @response = JSON.parse(response)
130
+ end
131
+
132
+ def define_response(&block)
133
+ response = body
134
+
135
+ # The if statement covers a case for Users requests.
136
+ if response.class != Spotify::Models::Error
137
+ if response['error']
138
+ response = Spotify::Models::Error.default(response['error'])
139
+ else
140
+ response = yield
141
+ end
142
+ end
143
+
144
+ response
145
+ end
146
+
147
+ end
148
+
149
+ end
150
+ end
@@ -0,0 +1,127 @@
1
+ module Spotify
2
+ module API
3
+
4
+ class Track < Spotify::API::Base
5
+
6
+ #
7
+ # API endpoint for tracks.
8
+ #
9
+ TRACKS_URL = "#{BASE_URL}tracks"
10
+
11
+ #
12
+ # Gets the tracks related to the given parameters.
13
+ #
14
+ # @param [Hash] args the search arguments.
15
+ # @option [Fixnum] :timeout the max time a request can take.
16
+ # @option [Fixnum] :retries the number of retries if necessary.
17
+ #
18
+ # @return [Spotify::Models::Paging] the extracted tracks.
19
+ #
20
+ def self.search(args = {})
21
+ args[:type] = :track
22
+
23
+ service_params = args.slice(:timeout, :retries)
24
+ args = args.slice(:q, :market, :type, :limit, :offset)
25
+
26
+ self.new(service_params).search(args)
27
+ end
28
+
29
+ #
30
+ # Gets a track.
31
+ #
32
+ # @param [Hash] args the search arguments.
33
+ # @option [Fixnum] :timeout the max time a request can take.
34
+ # @option [Fixnum] :retries the number of retries if necessary.
35
+ #
36
+ # @return [Full::Track] the extracted track.
37
+ #
38
+ def self.search_by_id(args = {})
39
+ service_params = args.slice(:timeout, :retries)
40
+ args = args.slice(:id, :market)
41
+
42
+ self.new(service_params).search_by_id(args)
43
+ end
44
+
45
+ #
46
+ # Gets several tracks.
47
+ #
48
+ # @param [Hash] args the search arguments.
49
+ # @option [Fixnum] :timeout the max time a request can take.
50
+ # @option [Fixnum] :retries the number of retries if necessary.
51
+ #
52
+ # @return [Array<Full::Track>] an array containing
53
+ # the extracted tracks.
54
+ #
55
+ def self.search_by_ids(args = {})
56
+ args[:ids] = Array(args[:ids]).join(',')
57
+
58
+ service_params = args.slice(:timeout, :retries)
59
+ args = args.slice(:ids, :market)
60
+
61
+ self.new(service_params).search_by_ids(args)
62
+ end
63
+
64
+ #
65
+ # Gets the tracks related to the given parameters.
66
+ #
67
+ # @param [Hash] args the search arguments.
68
+ # @option [Fixnum] :timeout the max time a request can take.
69
+ # @option [Fixnum] :retries the number of retries if necessary.
70
+ #
71
+ # @return [Spotify::Models::Paging] the extracted tracks.
72
+ #
73
+ def search(args = {})
74
+ if args[:market].to_s.to_sym == FROM_TOKEN
75
+ # TODO: Authorization.
76
+ return Spotify::API::Errors::NOT_AVAILABLE
77
+ end
78
+
79
+ get(SEARCH_URL, args)
80
+
81
+ define_response do
82
+ klass = Spotify::Models::Full::Track
83
+
84
+ Spotify::Models::Paging.new(response["tracks"], klass)
85
+ end
86
+ end
87
+
88
+ #
89
+ # Gets a track.
90
+ #
91
+ # @param [Hash] args the search arguments.
92
+ # @option [String] :id the track id.
93
+ # @option [String] :market the market.
94
+ #
95
+ # @return [Full::Track] the extracted track.
96
+ #
97
+ def search_by_id(args = {})
98
+ get(TRACKS_URL + '/' + args[:id].to_s, args.slice(:market))
99
+
100
+ define_response do
101
+ Spotify::Models::Full::Track.new(response)
102
+ end
103
+ end
104
+
105
+ #
106
+ # Gets several tracks.
107
+ #
108
+ # @param [Hash] args the search arguments.
109
+ # @option [String] :ids the tracks ids between ",".
110
+ # @option [String] :market the market.
111
+ #
112
+ # @return [Array<Full::Track>] an array containing
113
+ # the extracted tracks.
114
+ #
115
+ def search_by_ids(args = {})
116
+ get(TRACKS_URL, args)
117
+
118
+ define_response do
119
+ response["tracks"].map do |track|
120
+ Spotify::Models::Full::Track.new(track)
121
+ end
122
+ end
123
+ end
124
+
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,58 @@
1
+ module Spotify
2
+ module API
3
+
4
+ class User < Spotify::API::Base
5
+
6
+ #
7
+ # API endpoint for users.
8
+ #
9
+ USERS_URL = "#{BASE_URL}users"
10
+
11
+ #
12
+ # Gets an user.
13
+ #
14
+ # @param [Hash] args the search arguments.
15
+ # @option [Fixnum] :timeout the max time a request can take.
16
+ # @option [Fixnum] :retries the number of retries if necessary.
17
+ #
18
+ # @return [Public::User] the extracted user.
19
+ #
20
+ def self.search_by_id(args = {})
21
+ service_params = args.slice(:timeout, :retries)
22
+ args = args.slice(:id)
23
+
24
+ self.new(service_params).search_by_id(args)
25
+ end
26
+
27
+ #
28
+ # Gets a track.
29
+ #
30
+ # @param [Hash] args the search arguments.
31
+ # @option [String] :id the track id.
32
+ # @option [String] :market the market.
33
+ #
34
+ # @return [Public::User] the extracted user.
35
+ #
36
+ def search_by_id(args = {})
37
+ get(USERS_URL + '/' + args[:id].to_s)
38
+
39
+ define_response do
40
+ Spotify::Models::Simplified::User.new(response)
41
+ end
42
+ end
43
+
44
+ #
45
+ # Parses the response to JSON to get more flexible.
46
+ #
47
+ # @return [Hash] the parsed response.
48
+ #
49
+ def body
50
+ @response = JSON.parse(response)
51
+ rescue
52
+ Spotify::Models::Error.parser_error
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,5 @@
1
+ module Spotify
2
+ module API
3
+ VERSION = "0.7.0"
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ require "spotify/api/base"
2
+ require "spotify/api/version"
3
+
4
+ require "spotify/api/album"
5
+ require "spotify/api/artist"
6
+ require "spotify/api/track"
7
+ require "spotify/api/user"
8
+
9
+ module Spotify
10
+ module API
11
+ end
12
+ end
@@ -0,0 +1,42 @@
1
+ module Spotify
2
+
3
+ module Models
4
+
5
+ class Album
6
+
7
+ attr_reader :album_type, :available_markets, :external_urls,
8
+ :genres, :href, :id, :images, :name, :type, :uri
9
+
10
+ #
11
+ # Sets the arguments to its variables.
12
+ #
13
+ # @param [Hash] args the arguments that will be placed on each variable.
14
+ #
15
+ # @return [Album] an album object.
16
+ #
17
+ def initialize(args = {})
18
+ args = Hash(args).with_indifferent_access
19
+
20
+ # Arrays
21
+ images = Array(args[:images]).map { |i| Spotify::Models::Image.new(i) }
22
+
23
+ # Objects
24
+ external_urls = Spotify::Models::ExternalURL.new(args[:external_urls])
25
+
26
+ @album_type = args[:album_type]
27
+ @available_markets = args[:available_markets]
28
+ @external_urls = external_urls
29
+ @genres = args[:genres]
30
+ @href = args[:href]
31
+ @id = args[:id]
32
+ @images = images
33
+ @name = args[:name]
34
+ @type = args[:type]
35
+ @uri = args[:uri]
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,34 @@
1
+ module Spotify
2
+
3
+ module Models
4
+
5
+ class Artist
6
+
7
+ attr_reader :external_urls, :href, :id, :name, :type, :uri
8
+
9
+ #
10
+ # Sets the arguments to its variables.
11
+ #
12
+ # @param [Hash] args the arguments that will be placed on each variable.
13
+ #
14
+ # @return [Album] an artist object.
15
+ #
16
+ def initialize(args = {})
17
+ args = Hash(args).with_indifferent_access
18
+
19
+ # Objects
20
+ external_urls = Spotify::Models::ExternalURL.new(args[:external_urls])
21
+
22
+ @external_urls = external_urls
23
+ @href = args[:href]
24
+ @id = args[:id]
25
+ @name = args[:name]
26
+ @type = args[:type]
27
+ @uri = args[:uri]
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,23 @@
1
+ module Spotify
2
+
3
+ module Models
4
+
5
+ class Category
6
+
7
+ attr_reader :href, :icons, :id, :name
8
+
9
+ def initialize(args = {})
10
+ args = args.with_indifferent_access
11
+ icons = args[:icons].map { |icon| Spotify::Models::Image.new(icon) }
12
+
13
+ @href = args[:href]
14
+ @icons = icons
15
+ @id = args[:id]
16
+ @name = args[:name]
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,27 @@
1
+ module Spotify
2
+
3
+ module Models
4
+
5
+ class Copyright
6
+
7
+ attr_reader :text, :type
8
+
9
+ #
10
+ # Sets the arguments to its variables.
11
+ #
12
+ # @param [Hash] args the arguments that will be placed on each variable.
13
+ #
14
+ # @return [Image] a copyright object.
15
+ #
16
+ def initialize(args = {})
17
+ args = Hash(args).with_indifferent_access
18
+
19
+ @text = args[:text]
20
+ @type = args[:type]
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,19 @@
1
+ module Spotify
2
+
3
+ module Models
4
+
5
+ class Cursor
6
+
7
+ attr_reader :after
8
+
9
+ def initialize(args = {})
10
+ args = args.with_indifferent_access
11
+
12
+ @after = args[:after]
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,24 @@
1
+ module Spotify
2
+
3
+ module Models
4
+
5
+ class CursorbasedPaging
6
+
7
+ attr_reader :href, :items, :limit, :next, :cursors, :total
8
+
9
+ def initialize(args = {}, klass)
10
+ args = args.with_indifferent_access
11
+
12
+ @href = args[:href]
13
+ @items = args[:items].map { |item| klass.new(item) }
14
+ @limit = args[:limit]
15
+ @next = args[:next]
16
+ @total = args[:total]
17
+ @cursors = Cursor.new(args[:cursors])
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,122 @@
1
+ module Spotify
2
+
3
+ module Models
4
+
5
+ class Error
6
+
7
+ attr_reader :status, :message
8
+
9
+ #
10
+ # Identifies that the error is returned from some request.
11
+ #
12
+ DEFAULT = :default
13
+
14
+ #
15
+ # Defines the text and status for each message known.
16
+ #
17
+ ERRORS = {
18
+ timeout: {
19
+ status: 700,
20
+ message: "Timed out."
21
+ },
22
+ unexpected: {
23
+ status: 710,
24
+ message: "Unexpected error."
25
+ },
26
+ max_retries: {
27
+ status: 720,
28
+ message: "Max retries exceeded."
29
+ },
30
+ not_available: {
31
+ status: 730,
32
+ message: "This feature is not available yet."
33
+ },
34
+ parser_error: {
35
+ status: 740,
36
+ message: "Something went wrong. Please verify the parameters"
37
+ }
38
+ }
39
+
40
+ #
41
+ # Creates the message.
42
+ #
43
+ # @param [Hash] type the type of the message to be shown.
44
+ #
45
+ # @return [Parsers::Error] a message to be shown to the user.
46
+ #
47
+ def initialize(type, args = {})
48
+ if type == DEFAULT
49
+ error = {
50
+ status: args[:status],
51
+ message: args[:message]
52
+ }
53
+ else
54
+ error = ERRORS[type]
55
+ end
56
+
57
+ @status = error[:status]
58
+ @message = error[:message]
59
+ end
60
+
61
+ #
62
+ # Creates an error representing a timeout error.
63
+ #
64
+ # @return [Parsers::Error] a message to be shown to the user.
65
+ #
66
+ def self.timeout
67
+ self.new(:timeout)
68
+ end
69
+
70
+ #
71
+ # Creates an error representing an unexpected error.
72
+ #
73
+ # @return [Parsers::Error] a message to be shown to the user.
74
+ #
75
+ def self.unexpected_error
76
+ self.new(:unexpected_error)
77
+ end
78
+
79
+ #
80
+ # Creates an error representing that the retries limit was reached.
81
+ #
82
+ # @return [Parsers::Error] a message to be shown to the user.
83
+ #
84
+ def self.max_retries
85
+ self.new(:max_retries)
86
+ end
87
+
88
+ #
89
+ # Creates an error representing that the requested feature is not
90
+ # available yet.
91
+ #
92
+ # @return [Parsers::Error] a message to be shown to the user.
93
+ #
94
+ def self.not_available
95
+ self.new(:not_available)
96
+ end
97
+
98
+ #
99
+ # Creates an error representing a parser error.
100
+ #
101
+ # @return [Parsers::Error] a message to be shown to the user.
102
+ #
103
+ def self.parser_error
104
+ self.new(:parser_error)
105
+ end
106
+
107
+ #
108
+ # Creates an error representing the site response error.
109
+ #
110
+ # @return [Parsers::Error] a message to be shown to the user.
111
+ #
112
+ def self.default(args = {})
113
+ args = Hash(args).with_indifferent_access
114
+
115
+ self.new(:default, args)
116
+ end
117
+
118
+ end
119
+
120
+ end
121
+
122
+ end
@@ -0,0 +1,41 @@
1
+ module Spotify
2
+
3
+ module Models
4
+
5
+ class ExternalID
6
+
7
+ #
8
+ # Sets the arguments to its variables.
9
+ #
10
+ # @param [Hash] args the arguments that will be placed on each variable.
11
+ #
12
+ # @return [ExternalID] an external id object.
13
+ #
14
+ def initialize(args = {})
15
+ args = Hash(args).with_indifferent_access
16
+
17
+ hsh = {
18
+ isrc: args[:isrc],
19
+ ean: args[:ean],
20
+ upc: args[:upc]
21
+ }
22
+
23
+ hsh = hsh.reject { |_, v| v.blank? }
24
+
25
+ if hsh.present?
26
+ # Generates the keys dynamically
27
+ hsh.each do |k, v|
28
+ key = k
29
+ value = v
30
+
31
+ eval("@#{key} = value")
32
+ class_eval { attr_reader key.to_sym }
33
+ end
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+
41
+ end