simplespotify 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f4e69e9cf083380d99cf868d5c0a923e6317c96e
4
+ data.tar.gz: 5449320aa6f300cdccb61c8bb87a55e9c1eaf769
5
+ SHA512:
6
+ metadata.gz: aa3794582c59de6c88cf09b043aef105715838cd0624fb2db0a1a2a893e3c4956d384f049abb058440436262ab2a2a681c6fe09361bbaf204cb2328f8eb6407c
7
+ data.tar.gz: 672fc08dc3ddbfebd102f9b416e835f238e86cb182a38a455fc642cf5539053987147cbbfc614b95b85845d865c0578ef77c93147a437219fed518796441f74d
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ local-test.rb
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in spotify-api.gemspec
4
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,17 @@
1
+ LICENCIA PATITO
2
+ Versión 0.0.1; Septiembre, 2014
3
+
4
+ Copyright (c) 2015, Roberto Hidalgo, Partido Surrealista Mexicano
5
+ Todos los derechos reservados.
6
+
7
+ La redistribución y uso como código fuente y/u objeto, con o sin modificaciones, está permitida siempre y cuando todas las siguientes condiciones sean respetadas:
8
+
9
+ * La redistribución del código fuente debe mantener la nota de copyright antes mencionada, esta lista de condiciones y la renuncia de responsabilidades que acompaña esta licencia.
10
+ La redistribución del código objeto debe mantener la nota de copyright antes mencionada, esta lista de condiciones y la renuncia de responsabilidades que acompaña esta licencia en la documentación y en cualquier otro material que se ofrezca con el código objeto.
11
+ * El nombre "SimpleSpotify", ni el nombre de loas colaboradoreas originales podrá ser usado para promocionar o endosar productos derivados de este software sin un consentimiento previo por escrito de los mismos.
12
+ * Todo uso de este código fuente y archivos relacionados, en su conjunto o de manera individual, así como el material publicitario que mencione las funciones del mismo deberá incluir la leyenda: "Este producto incluye software desarrollado por el Roberto Hidalgo, el Partido Surrealista Mexicano y Colaboradoreas", así como un enlace a esta licencia, y deberá indicar si se han hecho cambios al mismo.
13
+ * Cualquier uso o implementación de este código fuente y archivos relacionados, en su conjunto o de manera individual, deberá extender los mismos derechos y obligaciones que menciona esta licencia.
14
+ * Se prohibe el uso de este código cuándo el uso mismo incite o resulte en la discriminación de cualquier individuo o grupo de individuos, en función de su género, orientación sexual, educación y/o poder adquisitivo.
15
+ * El uso de este código sugiere, más no exige, a los usuarioas del mismo a invitar al Partido Surrealista Mexicano y a cada uno de los Colaboradoreas unos mezcales ó bebidas no-alcoholicas de su elección, como muestra de compañerismo y buena voluntad.
16
+
17
+ Este software se ofrece por los titulares de derechos de autor y colaboradores "tal cual", y cualquier garantía explícita o implícita, por ejemplo, de manera enunciativa más no limitativa, la garantía implícita de comercialización y aptitud para un propósito determinado son rechazadas. Bajo ninguna circunstancia serán responsables los titulares de derechos de autor ni colaboradores por cualquier daño directo, indirecto, incidental, especial, ejemplar o consecuente —incluyendo, pero no limitado a, la adquisición de bienes o servicios; la pérdida uso, datos o beneficios; o interrupción de la actividad empresarial—, o por cualquier teoría de responsabilidad estricta ó agravio (incluyendo negligencia, o cualquier otra causa) que surja de la posibilidad de tales daños.
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new(:spec)
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "spotify"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,30 @@
1
+ module SimpleSpotify
2
+ module Actions
3
+ module Albums
4
+
5
+ def album album, market: nil
6
+ response = get "albums/#{id_for(album)}", options_with_market(market, {})
7
+ Model::Album.new(response.body)
8
+ end
9
+
10
+
11
+ def albums *albums, market: nil
12
+ albums = albums.map {|a|
13
+ id_for(a)
14
+ }.join(',')
15
+
16
+ response = get "albums", options_with_market(market, {ids: albums})
17
+ Model::Collection.of(:albums, response.body)
18
+ end
19
+
20
+
21
+ def album_tracks album, limit: 20, offset: 0, market: nil
22
+ options = options_with_market(market, {limit: limit, offset: offset})
23
+ response = get "albums/#{id_for(album)}/tracks", options
24
+ Model::Collection.of(:tracks, response.body)
25
+ end
26
+
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,47 @@
1
+ module SimpleSpotify
2
+ module Actions
3
+ module Artists
4
+
5
+
6
+ def artist artist
7
+ response = get "artist/#{id_for(artist)}"
8
+ Model::Artist.new(response.body)
9
+ end
10
+
11
+
12
+ def artists *artists
13
+ artists = artists.map {|a|
14
+ id_for(a)
15
+ }.join(',')
16
+
17
+ response = get "artists", {ids: artists}
18
+ Model::Collection.of(:artists, response.body)
19
+ end
20
+
21
+
22
+ def artist_albums artist, album_type: nil, market: nil, limit: 20, offset: 0
23
+ options = {album_type: album_type, limit: limit, offset: offset}
24
+ response = get "artists/#{id_for(artist)}/albums", options_with_market(market, options)
25
+ Model::Collection.of(:artists, response.body)
26
+ end
27
+
28
+
29
+ def top_tracks artist, market=nil
30
+ id = id_for(artist)
31
+ market = market || @market
32
+ raise "Market required for top tracks" unless market
33
+
34
+ response = get "artists/#{id}/top-tracks", {country: market}
35
+ Model::Collection.of(:tracks, response.body)
36
+ end
37
+
38
+
39
+ def related_artists artist
40
+ response = get "artists/#{id_for(artist)}/related-artists"
41
+ Model::Collection.of(:artists, response.body)
42
+ end
43
+
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,74 @@
1
+ module SimpleSpotify
2
+ module Actions
3
+ module Browse
4
+
5
+
6
+ def featured_playlists locale: nil, country: nil, timestamp: nil, limit: 20, offset: 0
7
+ locale ||= ENV['LANG'].split('.').first if ENV['LANG']
8
+ timestamp = timestamp.to_time if timestamp.is_a Date
9
+ timestamp = timestamp.iso8601 if timestamp.is_a? Time
10
+
11
+ options = {
12
+ locale: locale,
13
+ country: country || @market,
14
+ timestamp: timestamp,
15
+ limit: limit,
16
+ offset: offset
17
+ }.reject {|k,v| v.nil? || v==''}.to_h
18
+
19
+ response = get "browse/featured-playlists", options
20
+ Model::Collection.of(:playlists, response.body[:playlists])
21
+ end
22
+
23
+
24
+ def new_releases country: nil, limit: 20, offset: 0
25
+ options = {limit: limit, offset: offset}
26
+ market = country || @market
27
+ options[:country] = market if market
28
+
29
+ response = get "browse/new-releases", options
30
+ Model::Collection.of(:albums, response.body[:albums])
31
+ end
32
+
33
+
34
+ def categories country: nil, locale: nil, limit: 20, offset: 0
35
+ options = {limit: limit, offset: offset}
36
+
37
+ market = country || @market
38
+ options[:country] = market if market
39
+
40
+ locale ||= ENV['LANG'].split('.').first if ENV['LANG']
41
+ options[:locale] = locale if locale
42
+
43
+ response = get "browse/categories", options
44
+ Model::Collection.of(Model::Category, response.body[:categories])
45
+ end
46
+
47
+
48
+ def category category, country: nil, locale: nil
49
+ options = {}
50
+ market = country || @market
51
+ options[:country] = market if market
52
+
53
+ locale ||= ENV['LANG'].split('.').first if ENV['LANG']
54
+ options[:locale] = locale if locale
55
+
56
+ response = get "browse/categories/#{id_for(category)}"
57
+ Model::Category.new(response)
58
+ end
59
+
60
+
61
+ def category_playlists category, country: nil, limit: 20, offset: 0
62
+ options = {limit: limit, offset: offset}
63
+
64
+ market = country || @market
65
+ options[:country] = market if market
66
+
67
+ response = get "browse/categories/#{id_for(category)}/playlists", options
68
+ Model::Collection.of(:playlists, response.body[:playlists])
69
+ end
70
+
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,187 @@
1
+ module SimpleSpotify
2
+ module Actions
3
+ module Playlists
4
+
5
+
6
+ def playlist owner, playlist=nil, fields:{}, market: nil
7
+ fields = fields.join(',') if fields.is_a? Array
8
+ options = {
9
+ fields: fields
10
+ }
11
+
12
+ if owner.is_a? Model::Playlist
13
+ playlist = owner
14
+ owner = playlist.owner
15
+ end
16
+
17
+ res = get "users/#{id_for(owner)}/playlists/#{id_for(playlist)}", options_with_market(market, options)
18
+ Model::Playlist.new(res.body)
19
+ end
20
+
21
+
22
+ def playlists owner, limit: 20, offset: 0
23
+ Model::Collection.for(:playlists, get("users/#{id_for(owner)}/playlists", {limit: limit, offset: offset}))
24
+ end
25
+
26
+
27
+ #--------------
28
+ # Creation/Update
29
+ #--------------
30
+ def playlist_create user, name, public: true
31
+ res = post "users/#{id_for(user)}/playlists", {name: name, public: public}
32
+ Model::Playlist.new(res.body)
33
+ end
34
+
35
+
36
+ def playlist_change_details owner, playlist=nil, name: nil, public: nil
37
+ data = {}
38
+ data[:name] = name if name
39
+ data[:public] = public if public
40
+
41
+ if owner.is_a? Model::Playlist
42
+ playlist = owner
43
+ owner = playlist.owner
44
+ end
45
+
46
+ put "users/#{id_for(owner)}/playlists/#{id_for(playlist)}", data
47
+ end
48
+
49
+
50
+ #--------------
51
+ # Tracks
52
+ #--------------
53
+ def playlist_tracks owner, playlist=nil, fields: {}, limit: 20, offset: 0, market: nil
54
+ fields = fields.join(',') if fields.is_a? Array
55
+ options = {
56
+ fields: fields,
57
+ limit: limit,
58
+ offset: offset
59
+ }
60
+
61
+ if owner.is_a? Model::Playlist
62
+ playlist = owner
63
+ owner = playlist.owner
64
+ end
65
+
66
+ res = get "users/#{id_for(owner)}/playlists/#{id_for(playlist)}/tracks", options_with_market(market, options)
67
+ Model::Playlist.new(res.body)
68
+ end
69
+
70
+
71
+ def playlist_tracks_add owner, playlist=nil, tracks: [], position: nil
72
+ if owner.is_a? Model::Playlist
73
+ playlist = owner
74
+ owner = playlist.owner
75
+ end
76
+
77
+ tracks = case tracks
78
+ when Array then tracks.map {|t|
79
+ t.is_a?(Model::Track) ? t.id : t
80
+ }
81
+ when String then tracks.split(',')
82
+ end.map {|t| "spotify:track:#{t.split(':').last}" }
83
+
84
+
85
+ data = {}
86
+ data[:position] = position if position
87
+ data[:uris] = tracks
88
+
89
+ res = post "users/#{id_for(owner)}/playlists/#{id_for(playlist)}/tracks", data
90
+ res.body[:snapshot_id]
91
+ end
92
+
93
+
94
+ def playlist_tracks_remove owner, playlist=nil, tracks: nil, positions: nil, snapshot_id: nil
95
+ if owner.is_a? Model::Playlist
96
+ playlist = owner
97
+ owner = playlist.owner
98
+ end
99
+
100
+ data = {}
101
+ tracks = case tracks
102
+ when Array then tracks.map {|t|
103
+ case t
104
+ when Model::Track then {uri: t.uri}
105
+ when String then {uri: "spotify:track:#{t.split(':').last}"}
106
+ when Hash
107
+ t[:positions] = [t[:positions]].flatten if t[:positions]
108
+ t[:uri] = "spotify:track:#{t[:uri].split(':').last}"
109
+ end
110
+ }
111
+ when String then tracks.split(',')
112
+ else nil
113
+ end
114
+
115
+ data[:tracks] = tracks if tracks
116
+ data[:positions] = [positions].flatten if positions
117
+ data[:snapshot_id] = snapshot_id if snapshot_id
118
+
119
+ puts data
120
+
121
+ res = delete "users/#{id_for(owner)}/playlists/#{id_for(playlist)}/tracks", data
122
+ res.body[:snapshot_id]
123
+ end
124
+
125
+
126
+ def playlist_tracks_reorder owner, playlist=nil, start: 0, length: 1, before: nil, snapshot_id: nil
127
+ if owner.is_a? Model::Playlist
128
+ playlist = owner
129
+ owner = playlist.owner
130
+ end
131
+
132
+ raise "Must set `before` option when reordering playlist tracks" unless before
133
+
134
+ data = {
135
+ range_start: start,
136
+ range_length: length,
137
+ insert_before: before
138
+ }
139
+ data[:snapshot_id] = snapshot_id unless snapshot_id.nil?
140
+
141
+ res = put "users/#{id_for(owner)}/playlists/#{id_for(playlist)}/tracks", data
142
+ res.body[:snapshot_id]
143
+ end
144
+
145
+
146
+ def playlist_tracks_replace owner, playlist=nil, tracks: []
147
+ if owner.is_a? Model::Playlist
148
+ playlist = owner
149
+ owner = playlist.owner
150
+ end
151
+
152
+ data[:uris] = tracks.map { |t|
153
+ case t
154
+ when Model::Track then t.uri
155
+ when String then "spotify:track:#{t.split(':').last}"
156
+ end
157
+ }
158
+
159
+ res = put "users/#{id_for(owner)}/playlists/#{id_for(playlist)}/tracks", data
160
+ res.body[:snapshot_id]
161
+ end
162
+
163
+
164
+
165
+ #--------------
166
+ # Follows
167
+ #--------------
168
+ def playlist_follow owner, playlist=nil, public: true
169
+ if owner.is_a? Model::Playlist
170
+ playlist = owner
171
+ owner = playlist.owner
172
+ end
173
+ put "users/#{id_for(owner)}/playlists/#{id_for(playlist)}/followers", {public: public}
174
+ end
175
+
176
+
177
+ def playlist_unfollow owner, playlist=nil
178
+ if owner.is_a? Model::Playlist
179
+ playlist = owner
180
+ owner = playlist.owner
181
+ end
182
+ delete "users/#{id_for(owner)}/playlists/#{id_for(playlist)}/followers"
183
+ end
184
+
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,67 @@
1
+ module SimpleSpotify
2
+ module Actions
3
+ module Tracks
4
+
5
+ def track id, market: nil
6
+ res = get "tracks/#{id_for(id)}", options_with_market(market)
7
+ Model::Track.new(res.body)
8
+ end
9
+
10
+
11
+ def tracks ids, market: nil
12
+ if ids.is_a? Array
13
+ ids.map { |i|
14
+ id_for(i)
15
+ }.join(',')
16
+ end
17
+
18
+ Model::Collection.of(:tracks, response.body)
19
+ end
20
+
21
+
22
+ #--------------
23
+ # Saved tracks
24
+ #--------------
25
+ def saved_tracks limit: 20, offset: 0, market: nil
26
+ response = get "me/tracks", options_with_market(market, {limit: limit, offset: offset})
27
+ Model::Collection.of(Model::PlaylistTrack, response.body)
28
+ end
29
+
30
+
31
+ def saved_tracks_include? ids
32
+ if ids.is_a? Array
33
+ ids.map { |i|
34
+ i.is_a?(Resource) ? i.id : i;
35
+ }.join(',')
36
+ end
37
+
38
+ res = get "me/tracks/contains", {ids: ids}
39
+ ids.zip(res.body).to_h
40
+ end
41
+
42
+
43
+ def save_tracks ids
44
+ if ids.is_a? Array
45
+ ids.map { |i|
46
+ i.is_a?(Resource) ? i.id : i;
47
+ }.join(',')
48
+ end
49
+
50
+ put "me/tracks", {ids: ids}
51
+ end
52
+
53
+
54
+ def remove_tracks ids
55
+ if ids.is_a? Array
56
+ ids.map { |i|
57
+ i.is_a?(Resource) ? i.id : i;
58
+ }.join(',')
59
+ end
60
+
61
+ delete "me/tracks", {ids: ids}
62
+ end
63
+
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,68 @@
1
+ module SimpleSpotify
2
+ module Actions
3
+ module Users
4
+
5
+ def me
6
+ Model::User.new (get :me).body
7
+ end
8
+
9
+
10
+ def user id
11
+ Model::User.new (get "user/#{id}").body
12
+ end
13
+
14
+
15
+ #--------------
16
+ # Follows
17
+ #--------------
18
+ def user_follow type, ids
19
+ if ids.is_a? Array
20
+ ids.map { |i|
21
+ i.is_a?(Resource) ? i.id : i;
22
+ }.join(',')
23
+ end
24
+
25
+ req = SimpleSpotify::Request.new("me/following", {
26
+ json: true,
27
+ query: {type: type},
28
+ data: {ids: ids},
29
+ method: :put
30
+ })
31
+
32
+ put req
33
+ end
34
+
35
+
36
+ def user_unfollow type, ids
37
+ if ids.is_a? Array
38
+ ids.map { |i|
39
+ i.is_a?(Resource) ? i.id : i;
40
+ }.join(',')
41
+ end
42
+
43
+ req = SimpleSpotify::Request.new("me/following", {
44
+ json: true,
45
+ query: {type: type},
46
+ data: {ids: ids},
47
+ method: :delete
48
+ })
49
+
50
+ delete req
51
+ end
52
+
53
+
54
+ def user_following type, ids
55
+ if ids.is_a? Array
56
+ ids.map { |i|
57
+ i.is_a?(Resource) ? i.id : i;
58
+ }.join(',')
59
+ end
60
+
61
+ res = get "me/following/contains", {ids: ids, type: type}
62
+ ids.zip(res.body).to_h
63
+ end
64
+
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,91 @@
1
+ module SimpleSpotify
2
+ class Authorization
3
+
4
+ attr_accessor :access_token, :refresh_token
5
+ attr_reader :client_id
6
+
7
+ def self.login_uri redirect, client, state: nil, scope: nil, dialog: false
8
+ params = {
9
+ client_id: client.to_h[:client_id],
10
+ response_type: 'code',
11
+ redirect_uri: redirect,
12
+ }
13
+
14
+ params[:state] = state unless state.nil?
15
+ if scope
16
+ scope = scope.join(' ') if scope.is_a? Array
17
+ params[:scope] = scope
18
+ end
19
+ params[:show_dialog] = dialog.to_s
20
+
21
+ params_qs = params.map {|k,v|
22
+ "#{k}=#{URI::encode(v)}"
23
+ }.join('&')
24
+ return SimpleSpotify::AUTHORIZATION_URL + '?' + params_qs
25
+ end
26
+
27
+
28
+ def self.from_code code, client: {}, redirect: nil
29
+ params = {
30
+ grant_type: 'authorization_code',
31
+ redirect_uri: redirect,
32
+ code: code,
33
+ }.merge(client.to_h)
34
+
35
+ response = HTTParty.post SimpleSpotify::TOKEN_URL, query: params
36
+
37
+ body = JSON.parse(response.body, symbolize_names: true)
38
+ if response.code != 200
39
+ raise SimpleSpotify::Error::AuthorizationError.new(body)
40
+ end
41
+
42
+ return Authorization.new(body)
43
+ end
44
+
45
+
46
+ def initialize access_token: nil, refresh_token:nil, client: {}, token_type: nil, expires_in: nil
47
+ @access_token = access_token
48
+ @refresh_token = refresh_token
49
+ @client = client.to_h
50
+ @client_id = @client[:client_id]
51
+ end
52
+
53
+
54
+ def headers
55
+ {'Authorization' => "Bearer #{@access_token}"}
56
+ end
57
+
58
+
59
+ def refresh!
60
+ params = {
61
+ grant_type: 'refresh_token',
62
+ refresh_token: @refresh_token
63
+ }.merge(@client)
64
+
65
+ response = HTTParty.post SimpleSpotify::TOKEN_URL, query: params
66
+
67
+ body = JSON.parse(response.body, symbolize_names: true)
68
+ if response.code != 200
69
+ raise SimpleSpotify::Error::AuthorizationError.new(body)
70
+ end
71
+
72
+ @access_token = body[:access_token]
73
+ @callback.call(self) if @callback
74
+ end
75
+
76
+
77
+ def on_refresh &block
78
+ @callback = block
79
+ end
80
+
81
+
82
+ def to_h
83
+ {
84
+ access_token: access_token,
85
+ refresh_token: refresh_token
86
+ }
87
+ end
88
+
89
+
90
+ end
91
+ end