spotify-api 0.0.5 → 0.0.6
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.
- data/CHANGELOG +3 -0
- data/LICENSE +1 -1
- data/README.md +8 -4
- data/Rakefile +1 -0
- data/VERSION.yml +1 -1
- data/examples/lastfm2spotify_loved_tracks +31 -0
- data/examples/lastfm2spotify_metrochart +35 -0
- data/examples/lastfm_metro_playlists +87 -0
- data/lib/clients/lastfm.rb +81 -0
- data/{examples → lib/clients}/spotify.rb +15 -5
- data/lib/jars/jotify.jar +0 -0
- data/lib/jotify/api.rb +42 -13
- data/spec/jotify/api_spec.rb +3 -2
- data/spotify-api.gemspec +14 -9
- metadata +17 -8
- data/examples/lastfm.rb +0 -43
- data/examples/lastfm2spotify.rb +0 -20
data/CHANGELOG
CHANGED
data/LICENSE
CHANGED
@@ -15,7 +15,7 @@ modification, are permitted provided that the following conditions are met:
|
|
15
15
|
THIS SOFTWARE IS PROVIDED BY Jan Berkel 'AS IS'' AND ANY
|
16
16
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
17
17
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
-
DISCLAIMED. IN NO EVENT SHALL
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL Jan Berkel BE LIABLE FOR ANY
|
19
19
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
20
20
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
21
21
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
data/README.md
CHANGED
@@ -20,8 +20,7 @@ At the moment the following features are implemented:
|
|
20
20
|
|
21
21
|
Prerequisites: *Java 6+*, JRuby 1.3.x.
|
22
22
|
|
23
|
-
$ jruby -S gem
|
24
|
-
$ jruby -S gem install jberkel-spotify-api
|
23
|
+
$ jruby -S gem install spotify-api --source http://gemcutter.org
|
25
24
|
$ jruby -S spotify-api-server --account login:password
|
26
25
|
== Sinatra/0.9.4 has taken the stage on 3000 for development with backup from WEBrick
|
27
26
|
[2009-08-04 01:21:03] INFO WEBrick 1.3.1
|
@@ -38,14 +37,19 @@ Prerequisites: *Java 6+*, JRuby 1.3.x.
|
|
38
37
|
"url": "http:\/\/open.spotify.com\/user\/jberkel\/playlist\/5EXLGE7HPVPjvlxPmIfrDe",
|
39
38
|
"revision": 2,
|
40
39
|
"id": "b9fe3dcf88945d146ef18117faa61ab4",
|
40
|
+
"size": 1,
|
41
41
|
"collaborative": false
|
42
42
|
}
|
43
43
|
]
|
44
44
|
},
|
45
45
|
"status": "OK"
|
46
46
|
}
|
47
|
-
|
48
|
-
|
47
|
+
|
48
|
+
## Examples
|
49
|
+
|
50
|
+
See examples directory for usage. The demo application ([lastfm2spotify_loved_tracks](/jberkel/spotify-api/blob/master/examples/lastfm2spotify_loved_tracks)) will
|
51
|
+
grab all recently loved tracks by your last.fm friends to create a new
|
52
|
+
spotify playlist. A nice way to listen to some good new music (if you share a similar music taste with most of your friends :)).
|
49
53
|
|
50
54
|
## Credits
|
51
55
|
|
data/Rakefile
CHANGED
@@ -15,6 +15,7 @@ begin
|
|
15
15
|
gem.add_dependency "rack-test"
|
16
16
|
gem.add_dependency "sinatra"
|
17
17
|
gem.add_dependency "json-jruby"
|
18
|
+
gem.add_dependency "httparty"
|
18
19
|
end
|
19
20
|
rescue LoadError
|
20
21
|
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
data/VERSION.yml
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
gem 'spotify-api'
|
7
|
+
|
8
|
+
require 'clients/lastfm'
|
9
|
+
require 'clients/spotify'
|
10
|
+
|
11
|
+
# a demo app which grabs tracks from last.fm and creates a spotify
|
12
|
+
# playlist based on friends loved tracks
|
13
|
+
if __FILE__ == $0
|
14
|
+
username = ARGV.shift or raise "#{$0} <username>"
|
15
|
+
|
16
|
+
puts "fetching last.fm tracks (friends/recently_loved)"
|
17
|
+
limit = 10 # 10 tracks per friend
|
18
|
+
tracks = LastFM.friends_loved_tracks(username, limit).values.flatten
|
19
|
+
|
20
|
+
puts "resolving spotify ids"
|
21
|
+
spotify_tracks = begin
|
22
|
+
Spotify.resolve(tracks.map {|t| [t["title"], t["artist"]] })
|
23
|
+
rescue Errno::ECONNREFUSED
|
24
|
+
fail "Could not connect to spotify-api server. Make sure it it running."
|
25
|
+
end
|
26
|
+
|
27
|
+
if spotify_tracks.size > 0
|
28
|
+
puts "creating playlist with #{spotify_tracks.size} tracks"
|
29
|
+
puts Spotify.create_playlist("loved by friends of #{username}", spotify_tracks.map { |t| t['id'] })
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
gem 'spotify-api'
|
7
|
+
|
8
|
+
require 'clients/lastfm'
|
9
|
+
require 'clients/spotify'
|
10
|
+
|
11
|
+
# a demo app which grabs tracks from last.fm and creates a spotify
|
12
|
+
# playlist based on tracks popular in a city
|
13
|
+
|
14
|
+
# to batch create playlists, use lastfm_metro_playlists.rb
|
15
|
+
if __FILE__ == $0
|
16
|
+
city = ARGV.shift or raise "#{$0} <city,country>"
|
17
|
+
|
18
|
+
metro,country = *city.split(',')
|
19
|
+
|
20
|
+
puts "fetching last.fm tracks for #{metro}, #{country}"
|
21
|
+
unique = true
|
22
|
+
tracks = LastFM.metro_track_chart(metro,country, unique)
|
23
|
+
|
24
|
+
puts "resolving spotify ids"
|
25
|
+
spotify_tracks = begin
|
26
|
+
Spotify.resolve(tracks.map { |t| [t["name"], t["artist"]["name"]] })
|
27
|
+
rescue Errno::ECONNREFUSED
|
28
|
+
fail "Could not connect to spotify-api server. Make sure it it running."
|
29
|
+
end
|
30
|
+
|
31
|
+
if spotify_tracks.size > 0
|
32
|
+
puts "creating playlist with #{spotify_tracks.size} tracks"
|
33
|
+
puts Spotify.create_playlist("chart for #{metro}, #{country}", spotify_tracks.map { |t| t['id'] })
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
gem 'spotify-api'
|
7
|
+
|
8
|
+
require 'clients/lastfm'
|
9
|
+
require 'clients/spotify'
|
10
|
+
|
11
|
+
require 'json'
|
12
|
+
|
13
|
+
metro_areas = [
|
14
|
+
["Berlin", "Germany"],
|
15
|
+
["London", "United Kingdom"],
|
16
|
+
["Barcelona", "Spain"],
|
17
|
+
["Paris", "France"],
|
18
|
+
["Rome", "Italy"],
|
19
|
+
["Los Angeles", "United States"],
|
20
|
+
["Istanbul", "Turkey"],
|
21
|
+
["Vienna", "Austria"],
|
22
|
+
["Zurich", "Switzerland"],
|
23
|
+
["New York", "United States"],
|
24
|
+
["Oslo", "Norway"],
|
25
|
+
["Stockholm", "Sweden"],
|
26
|
+
["Melbourne", "Australia"],
|
27
|
+
["Montreal", "Canada"],
|
28
|
+
["Auckland", "New Zealand"]
|
29
|
+
]
|
30
|
+
|
31
|
+
def fetch_existing_playlists
|
32
|
+
Spotify.playlists['playlists'].inject({}) do |h, p|
|
33
|
+
if p['name'] =~ /chart for ([\w\s]+), ([\w\s]+) (\([\d-]+\))\Z/
|
34
|
+
city, metro = $1, $2
|
35
|
+
h[[city, metro]] = p
|
36
|
+
end
|
37
|
+
h
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def generate_playlists(areas, update=false, unique=true)
|
42
|
+
puts "fetching existing playlists"
|
43
|
+
existing_playlists = fetch_existing_playlists
|
44
|
+
time_period = LastFM.metro_weekly_chartlist.first
|
45
|
+
|
46
|
+
areas.each do |(metro, country)|
|
47
|
+
if existing_playlists[[metro, country]] && !update
|
48
|
+
puts "#{metro}, #{country} already exists, skipping"
|
49
|
+
next
|
50
|
+
end
|
51
|
+
|
52
|
+
puts "fetching last.fm tracks for #{metro}, #{country}"
|
53
|
+
tracks = LastFM.metro_track_chart(metro, country, unique, time_period['from'], time_period['to'])
|
54
|
+
puts "resolving spotify ids"
|
55
|
+
spotify_tracks = Spotify.resolve(tracks.map { |t| [t["name"], t["artist"]["name"]] })
|
56
|
+
|
57
|
+
next if spotify_tracks.empty?
|
58
|
+
|
59
|
+
if playlist = existing_playlists[[metro, country]]
|
60
|
+
puts "update existing playlist #{playlist['id']} with #{spotify_tracks.size} tracks"
|
61
|
+
Spotify.update_playlist(playlist['id'], nil, spotify_tracks.map { |t| t['id'] })
|
62
|
+
else
|
63
|
+
tstamp = Time.new.strftime("%m-%d-%Y")
|
64
|
+
puts "creating new playlist with #{spotify_tracks.size} tracks"
|
65
|
+
puts Spotify.create_playlist("last.fm chart for #{metro}, #{country} (#{tstamp})", spotify_tracks.map { |t| t['id'] })
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def dump_playlists
|
71
|
+
puts fetch_existing_playlists.values.to_json
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
if __FILE__ == $0
|
76
|
+
if ARGV.empty?
|
77
|
+
STDERR.puts "#{$0} [create|update|dump]"
|
78
|
+
exit(1)
|
79
|
+
end
|
80
|
+
|
81
|
+
case cmd = ARGV.shift
|
82
|
+
when 'update': generate_playlists(metro_areas, true)
|
83
|
+
when 'create': generate_playlists(metro_areas)
|
84
|
+
when 'dump': dump_playlists
|
85
|
+
else raise ArgumentError, "invalid command #{cmd}"
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'httparty'
|
5
|
+
|
6
|
+
#Last.fm API client, implemented
|
7
|
+
#using httparty (http://github.com/jnunemaker/httparty/)
|
8
|
+
#
|
9
|
+
#NOTE: you need to set the LAST_FM_API_KEY environment variable to your API key
|
10
|
+
#before you can use this class.
|
11
|
+
class LastFM
|
12
|
+
include HTTParty
|
13
|
+
|
14
|
+
base_uri 'ws.audioscrobbler.com'
|
15
|
+
default_params :api_key => (ENV['LAST_FM_API_KEY'] or raise "You need to set the LAST_FM_API_KEY environment variable")
|
16
|
+
|
17
|
+
class <<self
|
18
|
+
def loved_tracks(user_id, limit=5)
|
19
|
+
if tracks = query('user.getLovedTracks', :user=>user_id, :limit=>limit)['lovedtracks']['track']
|
20
|
+
tracks.map do |r|
|
21
|
+
{ 'artist' => r['artist']['name'], 'title'=>r['name'], 'mbid' => r['mbid'] }
|
22
|
+
end
|
23
|
+
else
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def recent_tracks(user_id)
|
29
|
+
query('user.getRecentTracks', :user=>user_id, :limit=>100)['recenttracks']['track'].map do |r|
|
30
|
+
{ 'artist' => r['artist'], 'title'=>r['name'], 'mbid' => r['mbid'] }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def top_tracks(user_id, period='overall')
|
35
|
+
unless ['overall', '7day', '3month', '6month', '12month'].include?(period)
|
36
|
+
raise ArgumentError, "invalid period"
|
37
|
+
end
|
38
|
+
|
39
|
+
query('user.getTopTracks', :period=>period, :user=>user_id)['toptracks']['track'].map do |r|
|
40
|
+
{ 'artist' => r['artist']['name'], 'title'=>r['name'], 'mbid' => r['mbid'] }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def friends(user_id)
|
45
|
+
query('user.getfriends', :user=>user_id, :recenttracks=>false)['friends']['user']
|
46
|
+
end
|
47
|
+
|
48
|
+
def neighbours(user_id, max=10)
|
49
|
+
query('user.getneighbours', :user=>user_id, :limit=>10)#['friends']['user']
|
50
|
+
end
|
51
|
+
|
52
|
+
# retrieve tracks recently loved by friends
|
53
|
+
def friends_loved_tracks(user_id, limit=5)
|
54
|
+
friends(user_id).inject({}) do |h, u|
|
55
|
+
h[u['name']] = loved_tracks(u['name'], limit)
|
56
|
+
sleep 0.5
|
57
|
+
h
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def metro_weekly_chartlist
|
62
|
+
query("geo.getMetroWeeklyChartlist")['weeklychartlist']['chart'].reverse
|
63
|
+
end
|
64
|
+
|
65
|
+
def metro_track_chart(city, country, unique=false, from=nil, to=nil)
|
66
|
+
args = { :country=>country, :metro=>city }
|
67
|
+
args.merge!(:start=>from, :end=>to) if from && to
|
68
|
+
|
69
|
+
res = query("geo.getMetro#{unique ? 'Unique' : ''}TrackChart", args)
|
70
|
+
return [] unless res['toptracks'] && res['toptracks']['track']
|
71
|
+
res['toptracks']['track']
|
72
|
+
end
|
73
|
+
|
74
|
+
def query(method, args={})
|
75
|
+
result = get("/2.0/", :query => { :method => method }.merge(args))
|
76
|
+
raise result['lfm']['error'] if result['lfm'] && result['lfm']['status'] == 'failed'
|
77
|
+
result['lfm']
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -5,8 +5,7 @@ require 'httparty'
|
|
5
5
|
require 'json'
|
6
6
|
require 'pp'
|
7
7
|
|
8
|
-
#A
|
9
|
-
#using httparty (http://github.com/jnunemaker/httparty/)
|
8
|
+
#A spotify-api API client.
|
10
9
|
class Spotify
|
11
10
|
include HTTParty
|
12
11
|
|
@@ -42,12 +41,12 @@ class Spotify
|
|
42
41
|
get_or_bail("/playlists")
|
43
42
|
end
|
44
43
|
|
45
|
-
def self.update_playlist(
|
44
|
+
def self.update_playlist(playlist_id, name=nil, track_ids=[])
|
46
45
|
data = {}
|
47
|
-
data["tracks"] = track_ids.map { |
|
46
|
+
data["tracks"] = track_ids.map { |t_id| { 'id' => t_id } } unless track_ids.empty?
|
48
47
|
data["name"] = name if name
|
49
48
|
|
50
|
-
resp = put("/playlists/#{
|
49
|
+
resp = put("/playlists/#{playlist_id}", :body => data.to_json)
|
51
50
|
raise resp.inspect if resp['status'] != 'OK'
|
52
51
|
end
|
53
52
|
|
@@ -64,6 +63,17 @@ class Spotify
|
|
64
63
|
raise resp.inspect
|
65
64
|
end
|
66
65
|
end
|
66
|
+
|
67
|
+
def self.resolve(tracks)
|
68
|
+
tracks.map do |(title, artist)|
|
69
|
+
begin
|
70
|
+
Spotify.tracks(title, artist).first
|
71
|
+
rescue RuntimeError
|
72
|
+
nil
|
73
|
+
#raise
|
74
|
+
end
|
75
|
+
end.flatten.compact
|
76
|
+
end
|
67
77
|
end
|
68
78
|
|
69
79
|
if __FILE__ == $0
|
data/lib/jars/jotify.jar
CHANGED
Binary file
|
data/lib/jotify/api.rb
CHANGED
@@ -16,6 +16,11 @@ class Sinatra::Application
|
|
16
16
|
def query(what, p=what)
|
17
17
|
params[p] ? "#{what}:" + params[p] : ''
|
18
18
|
end
|
19
|
+
|
20
|
+
def error(code, message)
|
21
|
+
[code, { 'status' => 'ERROR', 'message' => message }.to_json]
|
22
|
+
end
|
23
|
+
|
19
24
|
end
|
20
25
|
|
21
26
|
Sinatra::Application.error ArgumentError do
|
@@ -65,20 +70,28 @@ Sinatra::Application.get('/playlists') do
|
|
65
70
|
'status'=>'OK',
|
66
71
|
'result'=> { 'playlists' => jotify.playlists.map do |p|
|
67
72
|
p.to_h
|
68
|
-
end.each { |h|
|
73
|
+
end.each { |h|
|
74
|
+
h['size'] = h.delete(:tracks).size
|
75
|
+
}
|
69
76
|
}
|
70
77
|
}.to_json
|
71
78
|
end
|
72
79
|
|
73
80
|
Sinatra::Application.get('/playlists/:id') do
|
74
81
|
content_type :json
|
75
|
-
|
82
|
+
playlist = begin
|
83
|
+
jotify.playlist(params[:id])
|
84
|
+
rescue Exception => e
|
85
|
+
return error(500, "error getting playlist: #{e.message}")
|
86
|
+
end
|
87
|
+
|
88
|
+
if playlist
|
76
89
|
{
|
77
90
|
'status'=>'OK',
|
78
91
|
'result'=>playlist.to_h
|
79
92
|
}.to_json
|
80
93
|
else
|
81
|
-
|
94
|
+
error(404, 'playlist not found')
|
82
95
|
end
|
83
96
|
end
|
84
97
|
|
@@ -86,25 +99,36 @@ Sinatra::Application.post('/playlists') do
|
|
86
99
|
content_type :json
|
87
100
|
body = request.body.read
|
88
101
|
data = JSON.parse(body)
|
89
|
-
|
102
|
+
|
103
|
+
playlist = begin
|
104
|
+
jotify.create_playlist(data['name'], !!data['collaborative'])
|
105
|
+
rescue Exception => e
|
106
|
+
return error(500, "error creating playlist: #{e.message}")
|
107
|
+
end
|
108
|
+
|
90
109
|
if playlist
|
91
110
|
if data['tracks']
|
92
111
|
ids = data['tracks'].map { |t| t['id'] }
|
93
112
|
unless jotify.set_tracks_on_playlist(playlist, ids)
|
94
|
-
return 500, '
|
113
|
+
return error(500, 'playlist created but tracks could not be added')
|
95
114
|
end
|
96
115
|
end
|
97
116
|
redirect playlist.link, 201 # created
|
98
117
|
else
|
99
|
-
|
118
|
+
error(500, 'playlist could not be created')
|
100
119
|
end
|
101
120
|
end
|
102
121
|
|
103
122
|
Sinatra::Application.put('/playlists/:id') do
|
104
123
|
content_type :json
|
105
|
-
|
124
|
+
|
125
|
+
playlist = begin
|
126
|
+
jotify.playlist(params[:id])
|
127
|
+
rescue Exception => e
|
128
|
+
return error(500, "error getting playlist: #{e.message}")
|
129
|
+
end
|
106
130
|
|
107
|
-
return 404,
|
131
|
+
return error(404, 'playlist not found') unless playlist
|
108
132
|
body = request.body.read
|
109
133
|
data = JSON.parse(body)
|
110
134
|
|
@@ -112,21 +136,26 @@ Sinatra::Application.put('/playlists/:id') do
|
|
112
136
|
|
113
137
|
if data.has_key?('name') && data['name'] != playlist.name
|
114
138
|
unless jotify.rename_playlist(playlist, data['name'])
|
115
|
-
return 500,
|
139
|
+
return error(500, 'could rename playlist')
|
116
140
|
end
|
117
141
|
end
|
118
142
|
|
119
143
|
if data.has_key?('collaborative') && data['collaborative'] != playlist.collaborative?
|
120
144
|
unless jotify.set_collaborative_flag(playlist, data['collaborative'])
|
121
|
-
return 500,
|
145
|
+
return error(500, 'could not change collaborative flag')
|
122
146
|
end
|
123
147
|
end
|
124
148
|
|
125
149
|
if data['tracks'].is_a?(Array)
|
126
150
|
ids = data['tracks'].map { |t| t['id'] }
|
127
|
-
|
128
|
-
|
129
|
-
|
151
|
+
begin
|
152
|
+
unless jotify.set_tracks_on_playlist(playlist, ids)
|
153
|
+
return error(500, 'could not update tracks')
|
154
|
+
end
|
155
|
+
rescue Exception => e
|
156
|
+
return error(500, e.to_s)
|
157
|
+
end
|
158
|
+
|
130
159
|
end
|
131
160
|
return 200, { 'status' => 'OK', 'message' => "update successful" }.to_json
|
132
161
|
end
|
data/spec/jotify/api_spec.rb
CHANGED
@@ -99,6 +99,7 @@ describe 'Api' do
|
|
99
99
|
"id"=>"4d921ebcdd8c80f32ce1ed5acafbb9c8",
|
100
100
|
"url"=>"http://open.spotify.com/user/test/playlist/2mnbxTkghYtlHMdX3jdP9C",
|
101
101
|
"name"=>"my shiny playlist",
|
102
|
+
"size"=>0,
|
102
103
|
"author"=>"test", "revision"=>-1, "collaborative"=>false
|
103
104
|
]
|
104
105
|
}
|
@@ -204,7 +205,7 @@ describe 'Api' do
|
|
204
205
|
@jotify.should_receive(:set_tracks_on_playlist).with(@playlist, ['1','2']).and_return(false)
|
205
206
|
put '/playlists/foo', { 'tracks' => [ {'id'=>'1' }, { 'id'=>'2' } ] }.to_json
|
206
207
|
last_response.status.should == 500
|
207
|
-
json_response.should == {"status"=>"ERROR", "message"=>"could update tracks"}
|
208
|
+
json_response.should == {"status"=>"ERROR", "message"=>"could not update tracks"}
|
208
209
|
end
|
209
210
|
|
210
211
|
# it "should return 403 if invalid data is supplied" do
|
@@ -219,4 +220,4 @@ describe 'Api' do
|
|
219
220
|
end
|
220
221
|
end
|
221
222
|
end
|
222
|
-
end
|
223
|
+
end
|
data/spotify-api.gemspec
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
1
4
|
# -*- encoding: utf-8 -*-
|
2
5
|
|
3
6
|
Gem::Specification.new do |s|
|
4
7
|
s.name = %q{spotify-api}
|
5
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.6"
|
6
9
|
|
7
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
11
|
s.authors = ["Jan Berkel"]
|
9
|
-
s.date = %q{2009-10-
|
12
|
+
s.date = %q{2009-10-26}
|
10
13
|
s.default_executable = %q{spotify-api-server}
|
11
14
|
s.description = %q{an api for spotify, based on jotify}
|
12
15
|
s.email = %q{jan.berkel@gmail.com}
|
@@ -23,9 +26,11 @@ Gem::Specification.new do |s|
|
|
23
26
|
"Rakefile",
|
24
27
|
"VERSION.yml",
|
25
28
|
"bin/spotify-api-server",
|
26
|
-
"examples/
|
27
|
-
"examples/
|
28
|
-
"examples/
|
29
|
+
"examples/lastfm2spotify_loved_tracks",
|
30
|
+
"examples/lastfm2spotify_metrochart",
|
31
|
+
"examples/lastfm_metro_playlists",
|
32
|
+
"lib/clients/lastfm.rb",
|
33
|
+
"lib/clients/spotify.rb",
|
29
34
|
"lib/jars/jotify.jar",
|
30
35
|
"lib/jotify.rb",
|
31
36
|
"lib/jotify/api.rb",
|
@@ -47,10 +52,7 @@ Gem::Specification.new do |s|
|
|
47
52
|
"spec/jotify/api_spec.rb",
|
48
53
|
"spec/jotify/media_spec.rb",
|
49
54
|
"spec/jotify_spec.rb",
|
50
|
-
"spec/spec_helper.rb"
|
51
|
-
"examples/lastfm.rb",
|
52
|
-
"examples/lastfm2spotify.rb",
|
53
|
-
"examples/spotify.rb"
|
55
|
+
"spec/spec_helper.rb"
|
54
56
|
]
|
55
57
|
|
56
58
|
if s.respond_to? :specification_version then
|
@@ -62,16 +64,19 @@ Gem::Specification.new do |s|
|
|
62
64
|
s.add_runtime_dependency(%q<rack-test>, [">= 0"])
|
63
65
|
s.add_runtime_dependency(%q<sinatra>, [">= 0"])
|
64
66
|
s.add_runtime_dependency(%q<json-jruby>, [">= 0"])
|
67
|
+
s.add_runtime_dependency(%q<httparty>, [">= 0"])
|
65
68
|
else
|
66
69
|
s.add_dependency(%q<rack>, [">= 0"])
|
67
70
|
s.add_dependency(%q<rack-test>, [">= 0"])
|
68
71
|
s.add_dependency(%q<sinatra>, [">= 0"])
|
69
72
|
s.add_dependency(%q<json-jruby>, [">= 0"])
|
73
|
+
s.add_dependency(%q<httparty>, [">= 0"])
|
70
74
|
end
|
71
75
|
else
|
72
76
|
s.add_dependency(%q<rack>, [">= 0"])
|
73
77
|
s.add_dependency(%q<rack-test>, [">= 0"])
|
74
78
|
s.add_dependency(%q<sinatra>, [">= 0"])
|
75
79
|
s.add_dependency(%q<json-jruby>, [">= 0"])
|
80
|
+
s.add_dependency(%q<httparty>, [">= 0"])
|
76
81
|
end
|
77
82
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spotify-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Berkel
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-26 00:00:00 +01:00
|
13
13
|
default_executable: spotify-api-server
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -52,6 +52,16 @@ dependencies:
|
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: "0"
|
54
54
|
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: httparty
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
55
65
|
description: an api for spotify, based on jotify
|
56
66
|
email: jan.berkel@gmail.com
|
57
67
|
executables:
|
@@ -69,9 +79,11 @@ files:
|
|
69
79
|
- Rakefile
|
70
80
|
- VERSION.yml
|
71
81
|
- bin/spotify-api-server
|
72
|
-
- examples/
|
73
|
-
- examples/
|
74
|
-
- examples/
|
82
|
+
- examples/lastfm2spotify_loved_tracks
|
83
|
+
- examples/lastfm2spotify_metrochart
|
84
|
+
- examples/lastfm_metro_playlists
|
85
|
+
- lib/clients/lastfm.rb
|
86
|
+
- lib/clients/spotify.rb
|
75
87
|
- lib/jars/jotify.jar
|
76
88
|
- lib/jotify.rb
|
77
89
|
- lib/jotify/api.rb
|
@@ -116,6 +128,3 @@ test_files:
|
|
116
128
|
- spec/jotify/media_spec.rb
|
117
129
|
- spec/jotify_spec.rb
|
118
130
|
- spec/spec_helper.rb
|
119
|
-
- examples/lastfm.rb
|
120
|
-
- examples/lastfm2spotify.rb
|
121
|
-
- examples/spotify.rb
|
data/examples/lastfm.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'httparty'
|
5
|
-
|
6
|
-
#A demo Last.fm API client, implemented
|
7
|
-
#using httparty (http://github.com/jnunemaker/httparty/)
|
8
|
-
class Lastfm
|
9
|
-
include HTTParty
|
10
|
-
|
11
|
-
base_uri 'ws.audioscrobbler.com'
|
12
|
-
default_params :api_key => "PUT_API_KEY_HERE"
|
13
|
-
|
14
|
-
class <<self
|
15
|
-
def loved_tracks(user_id)
|
16
|
-
query('user.getLovedTracks', :user=>user_id, :limit=>10)['lovedtracks']['track'].map do |r|
|
17
|
-
{ 'artist' => r['artist']['name'], 'title'=>r['name'], 'mbid' => r['mbid'] }
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def recent_tracks(user_id)
|
22
|
-
query('user.getRecentTracks', :user=>user_id, :limit=>100)['recenttracks']['track'].map do |r|
|
23
|
-
{ 'artist' => r['artist'], 'title'=>r['name'], 'mbid' => r['mbid'] }
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def top_tracks(user_id, period='overall')
|
28
|
-
unless ['overall', '7day', '3month', '6month', '12month'].include?(period)
|
29
|
-
raise ArgumentError, "invalid period"
|
30
|
-
end
|
31
|
-
|
32
|
-
query('user.getTopTracks', :period=>period, :user=>user_id)['toptracks']['track'].map do |r|
|
33
|
-
{ 'artist' => r['artist']['name'], 'title'=>r['name'], 'mbid' => r['mbid'] }
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def query(method, args={})
|
38
|
-
result = get("/2.0/", :query => { :method => method }.merge(args))
|
39
|
-
raise result['lfm']['error'] if result['lfm'] && result['lfm']['status'] == 'failed'
|
40
|
-
result['lfm']
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/examples/lastfm2spotify.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require File.join(File.dirname(__FILE__), *%w[lastfm])
|
4
|
-
require File.join(File.dirname(__FILE__), *%w[spotify])
|
5
|
-
|
6
|
-
# a demo app which grabs tracks from last.fm and creates a spotify
|
7
|
-
# playlist
|
8
|
-
if __FILE__ == $0
|
9
|
-
username = ARGV.shift or raise "#{$0} <username> [period=overall|7day|3month|6month|12month]"
|
10
|
-
period = ARGV.shift || '7day'
|
11
|
-
|
12
|
-
puts "fetching last.fm tracks (period=#{period})"
|
13
|
-
tracks = Lastfm.top_tracks(username, period).map do |track|
|
14
|
-
Spotify.tracks(track["title"], track["artist"]).first
|
15
|
-
end.flatten.compact
|
16
|
-
|
17
|
-
#puts "found tracks: #{tracks.inspect}"
|
18
|
-
puts "creating playlist with #{tracks.size} tracks"
|
19
|
-
puts Spotify.create_playlist(username, tracks.map { |t| t['id'] })
|
20
|
-
end
|