scrobbler-ng 2.0.0 → 2.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.
- data/.gitignore +3 -0
- data/VERSION.yml +2 -1
- data/lib/scrobbler/album.rb +91 -113
- data/lib/scrobbler/artist.rb +174 -134
- data/lib/scrobbler/auth.rb +12 -0
- data/lib/scrobbler/base.rb +114 -64
- data/lib/scrobbler/basexml.rb +17 -0
- data/lib/scrobbler/event.rb +109 -74
- data/lib/scrobbler/geo.rb +3 -11
- data/lib/scrobbler/helper/image.rb +37 -12
- data/lib/scrobbler/helper/streamable.rb +11 -3
- data/lib/scrobbler/library.rb +49 -75
- data/lib/scrobbler/playlist.rb +74 -32
- data/lib/scrobbler/radio.rb +11 -0
- data/lib/scrobbler/shout.rb +40 -14
- data/lib/scrobbler/tag.rb +19 -2
- data/lib/scrobbler/track.rb +62 -67
- data/lib/scrobbler/user.rb +93 -111
- data/lib/scrobbler.rb +1 -2
- data/tasks/jeweler.rake +10 -6
- data/tasks/metric_fu.rake +27 -0
- data/tasks/reek.rake +13 -0
- data/tasks/roodi.rake +13 -0
- data/tasks/tests.rake +8 -0
- data/test/mocks/library.rb +35 -0
- data/test/mocks/rest.rb +91 -189
- data/test/test_helper.rb +2 -16
- data/test/unit/album_spec.rb +1 -1
- data/test/unit/artist_spec.rb +4 -2
- data/test/unit/event_spec.rb +2 -2
- data/test/unit/library_spec.rb +70 -70
- data/test/unit/playlist_spec.rb +1 -1
- data/test/unit/scrobble_spec.rb +1 -1
- data/test/unit/tag_spec.rb +3 -1
- data/test/unit/track_spec.rb +1 -1
- data/test/unit/user_spec.rb +1 -1
- metadata +38 -6
data/lib/scrobbler/user.rb
CHANGED
@@ -1,98 +1,79 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
# puts "=" * (user.username.length + 16)
|
6
|
-
# user.recent_tracks.each { |t| puts t.name }
|
7
|
-
#
|
8
|
-
# puts
|
9
|
-
# puts
|
10
|
-
#
|
11
|
-
# puts "#{user.username}'s Top Tracks"
|
12
|
-
# puts "=" * (user.username.length + 13)
|
13
|
-
# user.top_tracks.each { |t| puts "(#{t.playcount}) #{t.name}" }
|
14
|
-
#
|
15
|
-
# Which would output something like:
|
16
|
-
#
|
17
|
-
# jnunemaker's Recent Tracks
|
18
|
-
# ==========================
|
19
|
-
# Everything You Want
|
20
|
-
# You're a God
|
21
|
-
# Bitter Sweet Symphony [Original Version]
|
22
|
-
# Lord I Guess I'll Never Know
|
23
|
-
# Country Song
|
24
|
-
# Bitter Sweet Symphony (Radio Edit)
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# jnunemaker's Top Tracks
|
28
|
-
# =======================
|
29
|
-
# (62) Probably Wouldn't Be This Way
|
30
|
-
# (55) Not Ready To Make Nice
|
31
|
-
# (45) Easy Silence
|
32
|
-
# (43) Song 2
|
33
|
-
# (40) Everybody Knows
|
34
|
-
# (39) Before He Cheats
|
35
|
-
# (39) Something's Gotta Give
|
36
|
-
# (38) Hips Don't Lie (featuring Wyclef Jean)
|
37
|
-
# (37) Unwritten
|
38
|
-
# (37) Move Along
|
39
|
-
# (37) Dance, Dance
|
40
|
-
# (36) We Belong Together
|
41
|
-
# (36) Jesus, Take the Wheel
|
42
|
-
# (36) Black Horse and the Cherry Tree (radio version)
|
43
|
-
# (35) Photograph
|
44
|
-
# (35) You're Beautiful
|
45
|
-
# (35) Walk Away
|
46
|
-
# (34) Stickwitu
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require File.expand_path('basexml.rb', File.dirname(__FILE__))
|
4
|
+
|
47
5
|
module Scrobbler
|
48
|
-
class User <
|
6
|
+
class User < BaseXml
|
49
7
|
# Load Helper modules
|
50
8
|
include ImageObjectFuncs
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
data[:url] = child.content if child.name == 'url'
|
61
|
-
data[:weight] = child.content.to_i if child.name == 'weight'
|
62
|
-
data[:match] = child.content if child.name == 'match'
|
63
|
-
data[:realname] = child.content if child.name == 'realname'
|
64
|
-
maybe_image_node(data, child)
|
65
|
-
end
|
66
|
-
User.new(data[:name], data)
|
67
|
-
end
|
9
|
+
|
10
|
+
attr_reader :url, :weight, :match, :realname, :name
|
11
|
+
|
12
|
+
# Alias for User.new(:xml => xml)
|
13
|
+
#
|
14
|
+
# @deprecated
|
15
|
+
def self.new_from_libxml(xml)
|
16
|
+
User.new(:xml => xml)
|
17
|
+
end
|
68
18
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
19
|
+
def find(*args)
|
20
|
+
options = {:include_profile => false}
|
21
|
+
options.merge!(args.pop) if args.last.is_a?(Hash)
|
22
|
+
users = args.flatten.inject([]) { |users, u| users << User.new(u, options); users }
|
23
|
+
users.length == 1 ? users.pop : users
|
75
24
|
end
|
76
25
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
26
|
+
# Load the data for this object out of a XML-Node
|
27
|
+
#
|
28
|
+
# @param [LibXML::XML::Node] node The XML node containing the information
|
29
|
+
# @return [nil]
|
30
|
+
def load_from_xml(node)
|
31
|
+
# Get all information from the root's children nodes
|
32
|
+
node.children.each do |child|
|
33
|
+
case child.name.to_s
|
34
|
+
when 'name'
|
35
|
+
@name = child.content
|
36
|
+
when 'url'
|
37
|
+
@url = child.content
|
38
|
+
when 'weight'
|
39
|
+
@weight = child.content.to_i
|
40
|
+
when 'match'
|
41
|
+
@match = child.content
|
42
|
+
when 'realname'
|
43
|
+
@realname = child.content
|
44
|
+
when 'image'
|
45
|
+
check_image_node(child)
|
46
|
+
when 'text'
|
47
|
+
# ignore, these are only blanks
|
48
|
+
when '#text'
|
49
|
+
# libxml-jruby version of blanks
|
50
|
+
else
|
51
|
+
raise NotImplementedError, "Field '#{child.name}' not known (#{child.content})"
|
52
|
+
end #^ case
|
53
|
+
end #^ do |child|
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(data={})
|
57
|
+
raise ArgumentError unless data.kind_of?(Hash)
|
58
|
+
super(data)
|
59
|
+
data = {:include_info => false}.merge(data)
|
60
|
+
# Load data given as method-parameter
|
61
|
+
load_info() if data.delete(:include_info)
|
62
|
+
populate_data(data)
|
63
|
+
|
64
|
+
raise ArgumentError, "Name is required" if @name.empty?
|
84
65
|
end
|
85
66
|
|
86
67
|
# Get a list of upcoming events that this user is attending.
|
87
68
|
#
|
88
69
|
# Supports ical, ics or rss as its format
|
89
|
-
def events
|
90
|
-
|
70
|
+
def events
|
71
|
+
call('user.getevents', :events, :event, {:user => @name})
|
91
72
|
end
|
92
73
|
|
93
74
|
# Get a list of the user's friends on Last.fm.
|
94
|
-
def friends(
|
95
|
-
|
75
|
+
def friends(page=1, limit=50)
|
76
|
+
call('user.getfriends', :friends, :user, {:user => @name, :page => page, :limit => limit})
|
96
77
|
end
|
97
78
|
|
98
79
|
# Get information about a user profile.
|
@@ -102,13 +83,13 @@ module Scrobbler
|
|
102
83
|
end
|
103
84
|
|
104
85
|
# Get the last 50 tracks loved by a user.
|
105
|
-
def loved_tracks
|
106
|
-
|
86
|
+
def loved_tracks
|
87
|
+
call('user.getlovedtracks', :lovedtracks, :track, {:user => @name})
|
107
88
|
end
|
108
89
|
|
109
90
|
# Get a list of a user's neighbours on Last.fm.
|
110
|
-
def neighbours
|
111
|
-
|
91
|
+
def neighbours
|
92
|
+
call('user.getneighbours', :neighbours, :user, {:user => @name})
|
112
93
|
end
|
113
94
|
|
114
95
|
# Get a paginated list of all events a user has attended in the past.
|
@@ -118,9 +99,8 @@ module Scrobbler
|
|
118
99
|
end
|
119
100
|
|
120
101
|
# Get a list of a user's playlists on Last.fm.
|
121
|
-
def playlists
|
122
|
-
|
123
|
-
get_response('user.getplaylists', :playlist, 'playlists', 'playlist', {'user'=>@username}, force)
|
102
|
+
def playlists
|
103
|
+
call('user.getplaylists', :playlists, :playlist, {:user => @name})
|
124
104
|
end
|
125
105
|
|
126
106
|
# Get a list of the recent tracks listened to by this user. Indicates now
|
@@ -128,9 +108,9 @@ module Scrobbler
|
|
128
108
|
#
|
129
109
|
# Possible parameters:
|
130
110
|
# - limit: An integer used to limit the number of tracks returned.
|
131
|
-
def recent_tracks(
|
132
|
-
parameters.merge!({
|
133
|
-
|
111
|
+
def recent_tracks(parameters={})
|
112
|
+
parameters.merge!({:user => @name})
|
113
|
+
call('user.getrecenttracks', :recenttracks, :track, parameters)
|
134
114
|
end
|
135
115
|
|
136
116
|
# Get Last.fm artist recommendations for a user
|
@@ -154,45 +134,49 @@ module Scrobbler
|
|
154
134
|
|
155
135
|
# Get the top albums listened to by a user. You can stipulate a time period.
|
156
136
|
# Sends the overall chart by default.
|
157
|
-
def top_albums(
|
158
|
-
|
137
|
+
def top_albums(period=:overall)
|
138
|
+
call('user.gettopalbums', :topalbums, :album, {:user => @name, :period => period})
|
159
139
|
end
|
160
140
|
|
161
141
|
# Get the top artists listened to by a user. You can stipulate a time
|
162
142
|
# period. Sends the overall chart by default.
|
163
|
-
def top_artists(
|
164
|
-
|
143
|
+
def top_artists(period=:overall)
|
144
|
+
call('user.gettopartists', :topartists, :artist, {:user => @name, :period => period})
|
165
145
|
end
|
166
146
|
|
167
147
|
# Get the top tags used by this user.
|
168
|
-
def top_tags
|
169
|
-
|
148
|
+
def top_tags
|
149
|
+
call('user.gettoptags', :toptags, :tag, {:user => @name})
|
170
150
|
end
|
171
151
|
|
172
152
|
# Get the top tracks listened to by a user. You can stipulate a time period.
|
173
153
|
# Sends the overall chart by default.
|
174
|
-
def top_tracks(
|
175
|
-
|
154
|
+
def top_tracks(period=:overall)
|
155
|
+
call('user.gettoptracks', :toptracks, :track, {:user => @name, :period => period})
|
156
|
+
end
|
157
|
+
|
158
|
+
# Setup the parameters for a *chart API call
|
159
|
+
def setup_chart_params(from=nil, to=nil)
|
160
|
+
parameters = {:user => @name}
|
161
|
+
parameters[:from] = from unless from.nil?
|
162
|
+
parameters[:to] = to unless to.nil?
|
163
|
+
parameters
|
176
164
|
end
|
177
165
|
|
178
166
|
# Get an album chart for a user profile, for a given date range. If no date
|
179
167
|
# range is supplied, it will return the most recent album chart for this
|
180
168
|
# user.
|
181
169
|
def weekly_album_chart(from=nil, to=nil)
|
182
|
-
parameters =
|
183
|
-
|
184
|
-
parameters['to'] = to unless to.nil?
|
185
|
-
get_response('user.getweeklyalbumchart', nil, 'weeklyalbumchart', 'album', parameters, true)
|
170
|
+
parameters = setup_chart_params(from, to)
|
171
|
+
call('user.getweeklyalbumchart', :weeklyalbumchart, Album, parameters)
|
186
172
|
end
|
187
173
|
|
188
174
|
# Get an artist chart for a user profile, for a given date range. If no date
|
189
175
|
# range is supplied, it will return the most recent artist chart for this
|
190
176
|
# user.
|
191
177
|
def weekly_artist_chart(from=nil, to=nil)
|
192
|
-
parameters =
|
193
|
-
|
194
|
-
parameters['to'] = to unless to.nil?
|
195
|
-
get_response('user.getweeklyartistchart', nil, 'weeklyartistchart', 'artist', parameters, true)
|
178
|
+
parameters = setup_chart_params(from, to)
|
179
|
+
call('user.getweeklyartistchart', :weeklyartistchart, Artist, parameters)
|
196
180
|
end
|
197
181
|
|
198
182
|
# Get a list of available charts for this user, expressed as date ranges
|
@@ -206,10 +190,8 @@ module Scrobbler
|
|
206
190
|
# range is supplied, it will return the most recent track chart for this
|
207
191
|
# user.
|
208
192
|
def weekly_track_chart(from=nil, to=nil)
|
209
|
-
parameters =
|
210
|
-
|
211
|
-
parameters['to'] = to unless to.nil?
|
212
|
-
get_response('user.getweeklytrackchart', nil, 'weeklytrackchart', 'track', parameters, true)
|
193
|
+
parameters = setup_chart_params(from, to)
|
194
|
+
call('user.getweeklytrackchart', :weeklytrackchart, Track, parameters)
|
213
195
|
end
|
214
196
|
|
215
197
|
# Shout on this user's shoutbox
|
data/lib/scrobbler.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
|
2
2
|
%w{uri rubygems libxml time}.each { |x| require x }
|
3
|
-
require 'digest/md5'
|
4
3
|
|
5
4
|
$: << File.expand_path(File.dirname(__FILE__))
|
6
5
|
|
7
6
|
# Load base class
|
8
|
-
require 'scrobbler/base'
|
7
|
+
require File.expand_path('scrobbler/base.rb', File.dirname(__FILE__))
|
9
8
|
|
10
9
|
# Load helper modules
|
11
10
|
require 'scrobbler/helper/image'
|
data/tasks/jeweler.rake
CHANGED
@@ -7,12 +7,16 @@ begin
|
|
7
7
|
s.homepage = "http://github.com/xhochy/scrobbler"
|
8
8
|
s.description = "A ruby library for accessing the last.fm v2 webservices"
|
9
9
|
s.authors = ['John Nunemaker', 'Jonathan Rudenberg', 'Uwe L. Korn']
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
s.add_development_dependency "rspec", ">= 1.2.9"
|
11
|
+
s.add_development_dependency "yard", ">= 0"
|
12
|
+
s.add_development_dependency "fakeweb", ">= 0"
|
13
|
+
#if RUBY_PLATFORM =~ /\bjava\b/
|
14
|
+
# s.add_dependency 'libxml-jruby'
|
15
|
+
#else
|
16
|
+
# s.add_dependency 'libxml-ruby'
|
17
|
+
#end
|
15
18
|
end
|
19
|
+
Jeweler::GemcutterTasks.new
|
16
20
|
rescue LoadError
|
17
|
-
puts "Jeweler not available. Install it with:
|
21
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
18
22
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
begin
|
2
|
+
require 'metric_fu'
|
3
|
+
MetricFu::Configuration.run do |config|
|
4
|
+
# Deactivated: saikuro, stats, rcov
|
5
|
+
config.metrics = [:churn, :flog, :flay, :reek, :roodi]
|
6
|
+
config.graphs = [:flog, :flay, :reek, :roodi, :rcov]
|
7
|
+
config.flay = { :dirs_to_flay => ['lib'],
|
8
|
+
:minimum_score => 100 }
|
9
|
+
config.flog = { :dirs_to_flog => ['lib'] }
|
10
|
+
config.reek = { :dirs_to_reek => ['lib'] }
|
11
|
+
config.roodi = { :dirs_to_roodi => ['lib'] }
|
12
|
+
config.churn = { :start_date => "1 year ago", :minimum_churn_count => 10}
|
13
|
+
config.rcov = { :environment => 'test',
|
14
|
+
:test_files => ['test/**/*_test.rb',
|
15
|
+
'spec/**/*_spec.rb'],
|
16
|
+
:rcov_opts => ["--sort coverage",
|
17
|
+
"--no-html",
|
18
|
+
"--text-coverage",
|
19
|
+
"--no-color",
|
20
|
+
"--profile",
|
21
|
+
"--rails",
|
22
|
+
"--exclude /gems/,/Library/,spec"]}
|
23
|
+
config.graph_engine = :bluff
|
24
|
+
end
|
25
|
+
rescue LoadError
|
26
|
+
puts "metric_fu not available. Install it with: gem install metric_fu"
|
27
|
+
end
|
data/tasks/reek.rake
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
begin
|
2
|
+
require 'reek/rake/task'
|
3
|
+
Reek::Rake::Task.new do |t|
|
4
|
+
t.fail_on_error = true
|
5
|
+
t.verbose = false
|
6
|
+
t.source_files = 'lib/**/*.rb'
|
7
|
+
end
|
8
|
+
rescue LoadError
|
9
|
+
task :reek do
|
10
|
+
abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
data/tasks/roodi.rake
ADDED
data/tasks/tests.rake
CHANGED
@@ -9,5 +9,13 @@ Spec::Rake::SpecTask.new('test:unit') do |t|
|
|
9
9
|
end
|
10
10
|
t.spec_opts << '--format' << 'html:spec.html'
|
11
11
|
t.spec_opts << '--format' << 'progress'
|
12
|
+
t.spec_opts << '-b'
|
12
13
|
t.spec_files = FileList['test/unit/*_spec.rb']
|
13
14
|
end
|
15
|
+
|
16
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
17
|
+
spec.libs << 'lib' << 'spec'
|
18
|
+
spec.pattern = 'test/unit/*_spec.rb'
|
19
|
+
spec.rcov = true
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
## ## library.getartists
|
4
|
+
{
|
5
|
+
'api_key=foo123&user=xhochy' => 'artists-p1.xml',
|
6
|
+
'limit=30&api_key=foo123&user=xhochy' => 'artists-f30.xml'
|
7
|
+
}.each do |url, file|
|
8
|
+
register_fw('method=library.getartists&' + url, 'library', file)
|
9
|
+
end
|
10
|
+
(2..7).each do |n|
|
11
|
+
register_fw('method=library.getartists&page=' + n.to_s +
|
12
|
+
'&api_key=foo123&user=xhochy', 'library', "artists-p#{n}.xml")
|
13
|
+
end
|
14
|
+
|
15
|
+
## ## library.gettracks
|
16
|
+
{
|
17
|
+
'api_key=foo123&user=xhochy' => 'tracks-p1.xml',
|
18
|
+
'limit=30&api_key=foo123&user=xhochy' => 'tracks-f30.xml'
|
19
|
+
}.each do |url, file|
|
20
|
+
register_fw('method=library.gettracks&' + url, 'library', file)
|
21
|
+
end
|
22
|
+
(2..34).each do |n|
|
23
|
+
register_fw("user=xhochy&page=#{n}&api_key=foo123&method=library.gettracks",
|
24
|
+
'library', "tracks-p#{n}.xml")
|
25
|
+
end
|
26
|
+
|
27
|
+
## ## library.getalbums
|
28
|
+
FakeWeb.register_uri(:get, WEB_BASE + 'limit=30&user=xhochy&api_key=foo123&method=library.getalbums', :body => File.join([FIXTURES_BASE, 'library', 'albums-f30.xml']))
|
29
|
+
FakeWeb.register_uri(:get, WEB_BASE + 'user=xhochy&api_key=foo123&method=library.getalbums', :body => File.join([FIXTURES_BASE, 'library', 'albums-p1.xml']))
|
30
|
+
(2..8).each do |n|
|
31
|
+
FakeWeb.register_uri(:get, WEB_BASE + 'method=library.getalbums&page=' +
|
32
|
+
n.to_s + '&api_key=foo123&user=xhochy',
|
33
|
+
:body => File.join([FIXTURES_BASE, 'library', 'albums-p' +
|
34
|
+
n.to_s + '.xml']))
|
35
|
+
end
|