titanous-scrobbler 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/History.txt +3 -0
  2. data/MIT-LICENSE +19 -0
  3. data/Manifest +67 -0
  4. data/README.rdoc +107 -0
  5. data/Rakefile +36 -0
  6. data/examples/album.rb +17 -0
  7. data/examples/artist.rb +13 -0
  8. data/examples/scrobble.rb +31 -0
  9. data/examples/tag.rb +11 -0
  10. data/examples/track.rb +6 -0
  11. data/examples/user.rb +14 -0
  12. data/lib/scrobbler/album.rb +143 -0
  13. data/lib/scrobbler/artist.rb +127 -0
  14. data/lib/scrobbler/base.rb +29 -0
  15. data/lib/scrobbler/chart.rb +31 -0
  16. data/lib/scrobbler/playing.rb +49 -0
  17. data/lib/scrobbler/rest.rb +47 -0
  18. data/lib/scrobbler/scrobble.rb +66 -0
  19. data/lib/scrobbler/simpleauth.rb +59 -0
  20. data/lib/scrobbler/tag.rb +104 -0
  21. data/lib/scrobbler/track.rb +96 -0
  22. data/lib/scrobbler/user.rb +192 -0
  23. data/lib/scrobbler/version.rb +3 -0
  24. data/lib/scrobbler.rb +20 -0
  25. data/scrobbler.gemspec +41 -0
  26. data/setup.rb +1585 -0
  27. data/test/fixtures/xml/album/info.xml +70 -0
  28. data/test/fixtures/xml/artist/fans.xml +18 -0
  29. data/test/fixtures/xml/artist/similar.xml +39 -0
  30. data/test/fixtures/xml/artist/topalbums.xml +36 -0
  31. data/test/fixtures/xml/artist/toptags.xml +18 -0
  32. data/test/fixtures/xml/artist/toptracks.xml +27 -0
  33. data/test/fixtures/xml/tag/topalbums.xml +39 -0
  34. data/test/fixtures/xml/tag/topartists.xml +39 -0
  35. data/test/fixtures/xml/tag/toptags.xml +252 -0
  36. data/test/fixtures/xml/tag/toptracks.xml +30 -0
  37. data/test/fixtures/xml/track/fans.xml +28 -0
  38. data/test/fixtures/xml/track/toptags.xml +33 -0
  39. data/test/fixtures/xml/user/friends.xml +21 -0
  40. data/test/fixtures/xml/user/neighbours.xml +18 -0
  41. data/test/fixtures/xml/user/profile.xml +12 -0
  42. data/test/fixtures/xml/user/recentbannedtracks.xml +24 -0
  43. data/test/fixtures/xml/user/recentlovedtracks.xml +24 -0
  44. data/test/fixtures/xml/user/recenttracks.xml +27 -0
  45. data/test/fixtures/xml/user/systemrecs.xml +18 -0
  46. data/test/fixtures/xml/user/topalbums.xml +42 -0
  47. data/test/fixtures/xml/user/topartists.xml +30 -0
  48. data/test/fixtures/xml/user/toptags.xml +18 -0
  49. data/test/fixtures/xml/user/toptracks.xml +27 -0
  50. data/test/fixtures/xml/user/weeklyalbumchart.xml +35 -0
  51. data/test/fixtures/xml/user/weeklyalbumchart_from_1138536002_to_1139140802.xml +35 -0
  52. data/test/fixtures/xml/user/weeklyartistchart.xml +38 -0
  53. data/test/fixtures/xml/user/weeklyartistchart_from_1138536002_to_1139140802.xml +59 -0
  54. data/test/fixtures/xml/user/weeklychartlist.xml +74 -0
  55. data/test/fixtures/xml/user/weeklytrackchart.xml +35 -0
  56. data/test/fixtures/xml/user/weeklytrackchart_from_1138536002_to_1139140802.xml +35 -0
  57. data/test/mocks/rest.rb +50 -0
  58. data/test/test_helper.rb +17 -0
  59. data/test/unit/album_test.rb +86 -0
  60. data/test/unit/artist_test.rb +82 -0
  61. data/test/unit/chart_test.rb +34 -0
  62. data/test/unit/playing_test.rb +53 -0
  63. data/test/unit/scrobble_test.rb +69 -0
  64. data/test/unit/simpleauth_test.rb +45 -0
  65. data/test/unit/tag_test.rb +65 -0
  66. data/test/unit/track_test.rb +42 -0
  67. data/test/unit/user_test.rb +291 -0
  68. metadata +172 -0
data/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ * v 0.2.2: a bunch of changes from titanous, mostly refactoring
2
+ * v 0.2.0: added support for scrobbling tracks and now playing submission (Titanous)
3
+ * v 0.1.0: initial release
data/MIT-LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2007 John Nunemaker
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,67 @@
1
+ examples/album.rb
2
+ examples/artist.rb
3
+ examples/scrobble.rb
4
+ examples/tag.rb
5
+ examples/track.rb
6
+ examples/user.rb
7
+ History.txt
8
+ lib/scrobbler/album.rb
9
+ lib/scrobbler/artist.rb
10
+ lib/scrobbler/base.rb
11
+ lib/scrobbler/chart.rb
12
+ lib/scrobbler/playing.rb
13
+ lib/scrobbler/rest.rb
14
+ lib/scrobbler/scrobble.rb
15
+ lib/scrobbler/simpleauth.rb
16
+ lib/scrobbler/tag.rb
17
+ lib/scrobbler/track.rb
18
+ lib/scrobbler/user.rb
19
+ lib/scrobbler/version.rb
20
+ lib/scrobbler.rb
21
+ Manifest
22
+ MIT-LICENSE
23
+ Rakefile
24
+ README.rdoc
25
+ scrobbler.gemspec
26
+ setup.rb
27
+ test/fixtures/xml/album/info.xml
28
+ test/fixtures/xml/artist/fans.xml
29
+ test/fixtures/xml/artist/similar.xml
30
+ test/fixtures/xml/artist/topalbums.xml
31
+ test/fixtures/xml/artist/toptags.xml
32
+ test/fixtures/xml/artist/toptracks.xml
33
+ test/fixtures/xml/tag/topalbums.xml
34
+ test/fixtures/xml/tag/topartists.xml
35
+ test/fixtures/xml/tag/toptags.xml
36
+ test/fixtures/xml/tag/toptracks.xml
37
+ test/fixtures/xml/track/fans.xml
38
+ test/fixtures/xml/track/toptags.xml
39
+ test/fixtures/xml/user/friends.xml
40
+ test/fixtures/xml/user/neighbours.xml
41
+ test/fixtures/xml/user/profile.xml
42
+ test/fixtures/xml/user/recentbannedtracks.xml
43
+ test/fixtures/xml/user/recentlovedtracks.xml
44
+ test/fixtures/xml/user/recenttracks.xml
45
+ test/fixtures/xml/user/systemrecs.xml
46
+ test/fixtures/xml/user/topalbums.xml
47
+ test/fixtures/xml/user/topartists.xml
48
+ test/fixtures/xml/user/toptags.xml
49
+ test/fixtures/xml/user/toptracks.xml
50
+ test/fixtures/xml/user/weeklyalbumchart.xml
51
+ test/fixtures/xml/user/weeklyalbumchart_from_1138536002_to_1139140802.xml
52
+ test/fixtures/xml/user/weeklyartistchart.xml
53
+ test/fixtures/xml/user/weeklyartistchart_from_1138536002_to_1139140802.xml
54
+ test/fixtures/xml/user/weeklychartlist.xml
55
+ test/fixtures/xml/user/weeklytrackchart.xml
56
+ test/fixtures/xml/user/weeklytrackchart_from_1138536002_to_1139140802.xml
57
+ test/mocks/rest.rb
58
+ test/test_helper.rb
59
+ test/unit/album_test.rb
60
+ test/unit/artist_test.rb
61
+ test/unit/chart_test.rb
62
+ test/unit/playing_test.rb
63
+ test/unit/scrobble_test.rb
64
+ test/unit/simpleauth_test.rb
65
+ test/unit/tag_test.rb
66
+ test/unit/track_test.rb
67
+ test/unit/user_test.rb
data/README.rdoc ADDED
@@ -0,0 +1,107 @@
1
+ =Scrobbler
2
+
3
+ Scrobbler is a wrapper for the audioscrobbler web services (http://www.audioscrobbler.net/data/webservices/).
4
+
5
+ Below is just a sampling of how easy this lib is to use.
6
+
7
+ == Users
8
+
9
+ user = Scrobbler::User.new('jnunemaker')
10
+
11
+ puts "#{user.username}'s Recent Tracks"
12
+ puts "=" * (user.username.length + 16)
13
+ user.recent_tracks.each { |t| puts t.name }
14
+
15
+ puts
16
+ puts
17
+
18
+ puts "#{user.username}'s Top Tracks"
19
+ puts "=" * (user.username.length + 13)
20
+ user.top_tracks.each { |t| puts "(#{t.playcount}) #{t.name}" }
21
+
22
+ == Albums
23
+
24
+ album = Scrobbler::Album.new('Carrie Underwood', 'Some Hearts', :include_info => true)
25
+
26
+ puts "Album: #{album.name}"
27
+ puts "Artist: #{album.artist}"
28
+ puts "Reach: #{album.reach}"
29
+ puts "URL: #{album.url}"
30
+ puts "Release Date: #{album.release_date.strftime('%m/%d/%Y')}"
31
+
32
+ puts
33
+ puts
34
+
35
+ puts "Tracks"
36
+ longest_track_name = album.tracks.collect(&:name).sort { |x, y| y.length <=> x.length }.first.length
37
+ puts "=" * longest_track_name
38
+ album.tracks.each { |t| puts t.name }
39
+
40
+ ==Artists
41
+
42
+ artist = Scrobbler::Artist.new('Carrie Underwood')
43
+
44
+ puts 'Top Tracks'
45
+ puts "=" * 10
46
+ artist.top_tracks.each { |t| puts "(#{t.reach}) #{t.name}" }
47
+
48
+ puts
49
+
50
+ puts 'Similar Artists'
51
+ puts "=" * 15
52
+ artist.similar.each { |a| puts "(#{a.match}%) #{a.name}" }
53
+
54
+ ==Tags
55
+
56
+ tag = Scrobbler::Tag.new('country')
57
+
58
+ puts 'Top Albums'
59
+ tag.top_albums.each { |a| puts "(#{a.count}) #{a.name} by #{a.artist}" }
60
+
61
+ puts
62
+
63
+ puts 'Top Tracks'
64
+ tag.top_tracks.each { |t| puts "(#{t.count}) #{t.name} by #{t.artist}" }
65
+
66
+ ==Tracks
67
+
68
+ track = Scrobbler::Track.new('Carrie Underwood', 'Before He Cheats')
69
+ puts 'Fans'
70
+ puts "=" * 4
71
+ track.fans.each { |u| puts "(#{u.weight}) #{u.username}" }
72
+
73
+ == Simple Authentication (for Scrobbling)
74
+
75
+ auth = Scrobbler::SimpleAuth.new(:user => 'chunky', :password => 'bacon')
76
+ auth.handshake!
77
+
78
+ puts "Auth Status: #{auth.status}"
79
+ puts "Session ID: #{auth.session_id}"
80
+ puts "Now Playing URL: #{auth.now_playing_url}"
81
+ puts "Submission URL: #{auth.submission_url}"
82
+
83
+ == Scrobbling
84
+
85
+ scrobble = Scrobbler::Scrobble.new(:session_id => auth.session_id,
86
+ :submission_url => auth.submission_url,
87
+ :artist => 'Coldplay',
88
+ :track => 'Viva La Vida',
89
+ :album => "Viva La Vida",
90
+ :time => Time.new,
91
+ :length => 244,
92
+ :track_number => 7)
93
+ scrobble.submit!
94
+ puts "Scrobbler Submission Status: #{scrobble.status}"
95
+
96
+ == Now Playing Submission
97
+
98
+ playing = Scrobbler::Playing.new(:session_id => auth.session_id,
99
+ :now_playing_url => auth.now_playing_url,
100
+ :artist => 'Anberlin',
101
+ :track => 'Readyfuels',
102
+ :album => 'Blueprints For the Black Market',
103
+ :length => 218,
104
+ :track_number => 1)
105
+
106
+ playing.submit!
107
+ puts "Playing Submission Status: #{playing.status}"
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ # Rakefile
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'echoe'
5
+ require 'lib/scrobbler/version'
6
+
7
+ WEBSITE_PATH = 'jnunemaker@rubyforge.org:/var/www/gforge-projects/scrobbler'
8
+
9
+ Echoe.new('scrobbler', Scrobbler::Version) do |p|
10
+ p.description = "wrapper for audioscrobbler (last.fm) web services"
11
+ p.url = "http://scrobbler.rubyforge.org"
12
+ p.author = ['John Nunemaker', 'Jonathan Rudenberg']
13
+ p.email = "nunemaker@gmail.com"
14
+ p.extra_deps = [['hpricot', '>=0.4.86'], ['activesupport', '>=1.4.2']]
15
+ p.need_tar_gz = false
16
+ p.docs_host = WEBSITE_PATH
17
+ p.ignore_pattern = /website/
18
+ end
19
+
20
+ desc 'Upload website files to rubyforge'
21
+ task :website do
22
+ sh %{rsync -av website/ #{WEBSITE_PATH}}
23
+ Rake::Task['website_docs'].invoke
24
+ end
25
+
26
+ task :website_docs do
27
+ Rake::Task['redocs'].invoke
28
+ sh %{rsync -av doc/ #{WEBSITE_PATH}/docs}
29
+ end
30
+
31
+ desc 'Preps the gem for a new release'
32
+ task :prepare do
33
+ %w[manifest build_gemspec].each do |task|
34
+ Rake::Task[task].invoke
35
+ end
36
+ end
data/examples/album.rb ADDED
@@ -0,0 +1,17 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'scrobbler'))
2
+
3
+ album = Scrobbler::Album.new('Carrie Underwood', 'Some Hearts', :include_info => true)
4
+
5
+ puts "Album: #{album.name}"
6
+ puts "Artist: #{album.artist}"
7
+ puts "Reach: #{album.reach}"
8
+ puts "URL: #{album.url}"
9
+ puts "Release Date: #{album.release_date.strftime('%m/%d/%Y')}"
10
+
11
+ puts
12
+ puts
13
+
14
+ puts "Tracks"
15
+ longest_track_name = album.tracks.collect(&:name).sort { |x, y| y.length <=> x.length }.first.length
16
+ puts "=" * longest_track_name
17
+ album.tracks.each { |t| puts t.name }
@@ -0,0 +1,13 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'scrobbler'))
2
+
3
+ artist = Scrobbler::Artist.new('Carrie Underwood')
4
+
5
+ puts 'Top Tracks'
6
+ puts "=" * 10
7
+ artist.top_tracks.each { |t| puts "(#{t.reach}) #{t.name}" }
8
+
9
+ puts
10
+
11
+ puts 'Similar Artists'
12
+ puts "=" * 15
13
+ artist.similar.each { |a| puts "(#{a.match}%) #{a.name}" }
@@ -0,0 +1,31 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'scrobbler'))
2
+
3
+ auth = Scrobbler::SimpleAuth.new(:user => 'chunky', :password => 'bacon')
4
+ auth.handshake!
5
+
6
+ puts "Auth Status: #{auth.status}"
7
+ puts "Session ID: #{auth.session_id}"
8
+ puts "Now Playing URL: #{auth.now_playing_url}"
9
+ puts "Submission URL: #{auth.submission_url}"
10
+
11
+ scrobble = Scrobbler::Scrobble.new(:session_id => auth.session_id,
12
+ :submission_url => auth.submission_url,
13
+ :artist => 'Coldplay',
14
+ :track => 'Viva La Vida',
15
+ :album => 'Viva La Vida',
16
+ :time => Time.new,
17
+ :length => 244,
18
+ :track_number => 7)
19
+ scrobble.submit!
20
+ puts "Scrobbler Submission Status: #{scrobble.status}"
21
+
22
+ playing = Scrobbler::Playing.new(:session_id => auth.session_id,
23
+ :now_playing_url => auth.now_playing_url,
24
+ :artist => 'Anberlin',
25
+ :track => 'A Day Late',
26
+ :album => 'Never Take Friendship Personal',
27
+ :length => 214,
28
+ :track_number => 5)
29
+
30
+ playing.submit!
31
+ puts "Playing Submission Status: #{playing.status}"
data/examples/tag.rb ADDED
@@ -0,0 +1,11 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'scrobbler'))
2
+
3
+ tag = Scrobbler::Tag.new('country')
4
+
5
+ puts 'Top Albums'
6
+ tag.top_albums.each { |a| puts "(#{a.count}) #{a.name} by #{a.artist}" }
7
+
8
+ puts
9
+
10
+ puts 'Top Tracks'
11
+ tag.top_tracks.each { |t| puts "(#{t.count}) #{t.name} by #{t.artist}" }
data/examples/track.rb ADDED
@@ -0,0 +1,6 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'scrobbler'))
2
+
3
+ track = Scrobbler::Track.new('Carrie Underwood', 'Before He Cheats')
4
+ puts 'Fans'
5
+ puts "=" * 4
6
+ track.fans.each { |u| puts "(#{u.weight}) #{u.username}" }
data/examples/user.rb ADDED
@@ -0,0 +1,14 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'scrobbler'))
2
+
3
+ user = Scrobbler::User.new('jnunemaker')
4
+
5
+ puts "#{user.username}'s Recent Tracks"
6
+ puts "=" * (user.username.length + 16)
7
+ user.recent_tracks.each { |t| puts t.name }
8
+
9
+ puts
10
+ puts
11
+
12
+ puts "#{user.username}'s Top Tracks"
13
+ puts "=" * (user.username.length + 13)
14
+ user.top_tracks.each { |t| puts "(#{t.playcount}) #{t.name}" }
@@ -0,0 +1,143 @@
1
+ # Getting information about an album such as release date and the tracks on it is very easy.
2
+ #
3
+ # album = Scrobbler::Album.new('Carrie Underwood', 'Some Hearts', :include_info => true)
4
+ #
5
+ # puts "Album: #{album.name}"
6
+ # puts "Artist: #{album.artist}"
7
+ # puts "Reach: #{album.reach}"
8
+ # puts "URL: #{album.url}"
9
+ # puts "Release Date: #{album.release_date.strftime('%m/%d/%Y')}"
10
+ #
11
+ # puts
12
+ # puts
13
+ #
14
+ # puts "Tracks"
15
+ # longest_track_name = album.tracks.collect(&:name).sort { |x, y| y.length <=> x.length }.first.length
16
+ # puts "=" * longest_track_name
17
+ # album.tracks.each { |t| puts t.name }
18
+ #
19
+ # Would output:
20
+ #
21
+ # Album: Some Hearts
22
+ # Artist: Carrie Underwood
23
+ # Reach: 18729
24
+ # URL: http://www.last.fm/music/Carrie+Underwood/Some+Hearts
25
+ # Release Date: 11/15/2005
26
+ #
27
+ #
28
+ # Tracks
29
+ # ===============================
30
+ # Wasted
31
+ # Don't Forget to Remember Me
32
+ # Some Hearts
33
+ # Jesus, Take the Wheel
34
+ # The Night Before (Life Goes On)
35
+ # Lessons Learned
36
+ # Before He Cheats
37
+ # Starts With Goodbye
38
+ # I Just Can't Live a Lie
39
+ # We're Young and Beautiful
40
+ # That's Where It Is
41
+ # Whenever You Remember
42
+ # I Ain't in Checotah Anymore
43
+ # Inside Your Heaven
44
+ module Scrobbler
45
+ class Album < Base
46
+ attr_accessor :artist, :artist_mbid, :name, :mbid, :playcount, :rank, :url, :reach, :release_date
47
+ attr_accessor :image_large, :image_medium, :image_small
48
+ attr_writer :tracks
49
+
50
+ # needed on top albums for tag
51
+ attr_accessor :count, :streamable
52
+
53
+ # needed for weekly album charts
54
+ attr_accessor :chartposition
55
+
56
+ class << self
57
+ def find(artist, name, o={})
58
+ new(artist, name, o)
59
+ end
60
+
61
+ def new_from_xml(xml, doc=nil)
62
+ name = (xml).at(:name).inner_html if (xml).at(:name)
63
+ name = xml['name'] if name.nil? && xml['name']
64
+ artist = (xml).at(:artist)['name'] if (xml).at(:artist) && (xml).at(:artist)['name']
65
+ artist = (xml).at(:artist).inner_html if artist.nil? && (xml).at(:artist)
66
+ artist = doc.root['artist'] if artist.nil? && doc.root['artist']
67
+ a = Album.new(artist, name)
68
+ a.artist_mbid = (xml).at(:artist)['mbid'] if (xml).at(:artist) && (xml).at(:artist)['mbid']
69
+ a.artist_mbid = (xml).at(:artist).at(:mbid).inner_html if a.artist_mbid.nil? && (xml).at(:artist) && (xml).at(:artist).at(:mbid)
70
+ a.mbid = (xml).at(:mbid).inner_html if (xml).at(:mbid)
71
+ a.playcount = (xml).at(:playcount).inner_html if (xml).at(:playcount)
72
+ a.chartposition = (xml).at(:chartposition).inner_html if (xml).at(:chartposition)
73
+ a.rank = (xml).at(:rank).inner_html if (xml).at(:rank)
74
+ a.url = (xml/:url).last.inner_html if (xml/:url).size > 1
75
+ a.url = (xml).at(:url).inner_html if a.url.nil? && (xml).at(:url)
76
+ a.reach = (xml).at(:reach).inner_html if (xml).at(:reach)
77
+ a.image_large = (xml).at(:image).at(:large).inner_html if (xml).at(:image) && (xml).at(:image).at(:large)
78
+ a.image_medium = (xml).at(:image).at(:medium).inner_html if (xml).at(:image) && (xml).at(:image).at(:medium)
79
+ a.image_small = (xml).at(:image).at(:small).inner_html if (xml).at(:image) && (xml).at(:image).at(:small)
80
+
81
+ # coverart element used on top albums for tag
82
+ a.image_large = (xml).at(:coverart).at(:large).inner_html if a.image_large.nil? && (xml).at(:coverart) && (xml).at(:coverart).at(:large)
83
+ a.image_medium = (xml).at(:coverart).at(:medium).inner_html if a.image_medium.nil? && (xml).at(:coverart) && (xml).at(:coverart).at(:medium)
84
+ a.image_small = (xml).at(:coverart).at(:small).inner_html if a.image_small.nil? && (xml).at(:coverart) && (xml).at(:coverart).at(:small)
85
+
86
+ # needed on top albums for tag
87
+ a.count = xml['count'] if xml['count']
88
+ a.streamable = xml['streamable'] if xml['streamable']
89
+ a
90
+ end
91
+ end
92
+
93
+ def initialize(artist, name, o={})
94
+ raise ArgumentError, "Artist is required" if artist.blank?
95
+ raise ArgumentError, "Name is required" if name.blank?
96
+ @artist = artist
97
+ @name = name
98
+ options = {:include_info => false}.merge(o)
99
+ load_info() if options[:include_info]
100
+ end
101
+
102
+ def api_path
103
+ "/#{API_VERSION}/album/#{CGI::escape(artist)}/#{CGI::escape(name)}"
104
+ end
105
+
106
+ def load_info
107
+ doc = self.class.fetch_and_parse("#{api_path}/info.xml")
108
+ @reach = (doc).at(:reach).inner_html
109
+ @url = (doc).at(:url).inner_html
110
+ @release_date = Time.parse((doc).at(:releasedate).inner_html.strip)
111
+ @image_large = (doc).at(:coverart).at(:large).inner_html
112
+ @image_medium = (doc).at(:coverart).at(:medium).inner_html
113
+ @image_small = (doc).at(:coverart).at(:small).inner_html
114
+ @mbid = (doc).at(:mbid).inner_html
115
+ @tracks = (doc/:track).inject([]) do |tracks, track|
116
+ t = Track.new(artist, track['title'])
117
+ t.artist_mbid = artist_mbid
118
+ t.album = name
119
+ t.album_mbid = mbid
120
+ t.url = (track).at(:url).inner_html
121
+ t.reach = (track).at(:reach).inner_html
122
+ tracks << t
123
+ tracks
124
+ end
125
+ end
126
+
127
+ def tracks
128
+ load_info if @tracks.nil?
129
+ @tracks
130
+ end
131
+
132
+ def image(which=:small)
133
+ which = which.to_s
134
+ raise ArgumentError unless ['small', 'medium', 'large'].include?(which)
135
+ img_url = instance_variable_get("@image_#{which}")
136
+ if img_url.nil?
137
+ load_info
138
+ img_url = instance_variable_get("@image_#{which}")
139
+ end
140
+ img_url
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,127 @@
1
+ # Below are examples of how to find an artists top tracks and similar artists.
2
+ #
3
+ # artist = Scrobbler::Artist.new('Carrie Underwood')
4
+ #
5
+ # puts 'Top Tracks'
6
+ # puts "=" * 10
7
+ # artist.top_tracks.each { |t| puts "(#{t.reach}) #{t.name}" }
8
+ #
9
+ # puts
10
+ #
11
+ # puts 'Similar Artists'
12
+ # puts "=" * 15
13
+ # artist.similar.each { |a| puts "(#{a.match}%) #{a.name}" }
14
+ #
15
+ # Would output something similar to:
16
+ #
17
+ # Top Tracks
18
+ # ==========
19
+ # (8797) Before He Cheats
20
+ # (3574) Don't Forget to Remember Me
21
+ # (3569) Wasted
22
+ # (3246) Some Hearts
23
+ # (3142) Jesus, Take the Wheel
24
+ # (2600) Starts With Goodbye
25
+ # (2511) Jesus Take The Wheel
26
+ # (2423) Inside Your Heaven
27
+ # (2328) Lessons Learned
28
+ # (2040) I Just Can't Live a Lie
29
+ # (1899) Whenever You Remember
30
+ # (1882) We're Young and Beautiful
31
+ # (1854) That's Where It Is
32
+ # (1786) I Ain't in Checotah Anymore
33
+ # (1596) The Night Before (Life Goes On)
34
+ #
35
+ # Similar Artists
36
+ # ===============
37
+ # (100%) Rascal Flatts
38
+ # (84.985%) Keith Urban
39
+ # (84.007%) Kellie Pickler
40
+ # (82.694%) Katharine McPhee
41
+ # (81.213%) Martina McBride
42
+ # (79.397%) Faith Hill
43
+ # (77.121%) Tim McGraw
44
+ # (75.191%) Jessica Simpson
45
+ # (75.182%) Sara Evans
46
+ # (75.144%) The Wreckers
47
+ # (73.034%) Kenny Chesney
48
+ # (71.765%) Dixie Chicks
49
+ # (71.084%) Kelly Clarkson
50
+ # (69.535%) Miranda Lambert
51
+ # (66.952%) LeAnn Rimes
52
+ # (66.398%) Mandy Moore
53
+ # (65.817%) Bo Bice
54
+ # (65.279%) Diana DeGarmo
55
+ # (65.115%) Gretchen Wilson
56
+ # (62.982%) Clay Aiken
57
+ # (62.436%) Ashlee Simpson
58
+ # (62.160%) Christina Aguilera
59
+ module Scrobbler
60
+ class Artist < Base
61
+ attr_accessor :name, :mbid, :playcount, :rank, :url, :thumbnail, :image, :reach, :count, :streamable
62
+ attr_accessor :chartposition
63
+
64
+ # used for similar artists
65
+ attr_accessor :match
66
+
67
+ class << self
68
+ def new_from_xml(xml, doc=nil)
69
+ name = (xml).at(:name).inner_html if (xml).at(:name)
70
+ # occasionally name can be found in root of artist element (<artist name="">) rather than as an element (<name>)
71
+ name = xml['name'] if name.nil? && xml['name']
72
+ a = Artist.new(name)
73
+ a.mbid = (xml).at(:mbid).inner_html if (xml).at(:mbid)
74
+ a.playcount = (xml).at(:playcount).inner_html if (xml).at(:playcount)
75
+ a.rank = (xml).at(:rank).inner_html if (xml).at(:rank)
76
+ a.url = (xml).at(:url).inner_html if (xml).at(:url)
77
+ a.thumbnail = (xml).at(:thumbnail).inner_html if (xml).at(:thumbnail)
78
+ a.thumbnail = (xml).at(:image_small).inner_html if a.thumbnail.nil? && (xml).at(:image_small)
79
+ a.image = (xml).at(:image).inner_html if (xml).at(:image)
80
+ a.reach = (xml).at(:reach).inner_html if (xml).at(:reach)
81
+ a.match = (xml).at(:match).inner_html if (xml).at(:match)
82
+ a.chartposition = (xml).at(:chartposition).inner_html if (xml).at(:chartposition)
83
+
84
+ # in top artists for tag
85
+ a.count = xml['count'] if xml['count']
86
+ a.streamable = xml['streamable'] if xml['streamable']
87
+ a.streamable = (xml).at(:streamable).inner_html == '1' ? 'yes' : 'no' if a.streamable.nil? && (xml).at(:streamable)
88
+ a
89
+ end
90
+ end
91
+
92
+ def initialize(name)
93
+ raise ArgumentError, "Name is required" if name.blank?
94
+ @name = name
95
+ end
96
+
97
+ def api_path
98
+ "/#{API_VERSION}/artist/#{CGI::escape(name)}"
99
+ end
100
+
101
+ def current_events(format=:ics)
102
+ format = :ics if format.to_s == 'ical'
103
+ raise ArgumentError unless ['ics', 'rss'].include?(format.to_s)
104
+ "#{API_URL.chop}#{api_path}/events.#{format}"
105
+ end
106
+
107
+ def similar(force=false)
108
+ get_instance(:similar, :similar, :artist, force)
109
+ end
110
+
111
+ def top_fans(force=false)
112
+ get_instance(:fans, :top_fans, :user, force)
113
+ end
114
+
115
+ def top_tracks(force=false)
116
+ get_instance(:toptracks, :top_tracks, :track, force)
117
+ end
118
+
119
+ def top_albums(force=false)
120
+ get_instance(:topalbums, :top_albums, :album, force)
121
+ end
122
+
123
+ def top_tags(force=false)
124
+ get_instance(:toptags, :top_tags, :tag, force)
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,29 @@
1
+ module Scrobbler
2
+
3
+ API_URL = 'http://ws.audioscrobbler.com/'
4
+ API_VERSION = '1.0'
5
+
6
+ class Base
7
+ class << self
8
+ def connection
9
+ @connection ||= REST::Connection.new(API_URL)
10
+ end
11
+
12
+ def fetch_and_parse(resource)
13
+ Hpricot::XML(connection.get(resource))
14
+ end
15
+ end
16
+
17
+ private
18
+ # in order for subclass to use, it must have api_path method
19
+ def get_instance(api_method, instance_name, element, force=false)
20
+ scrobbler_class = "scrobbler/#{element.to_s}".camelize.constantize
21
+ if instance_variable_get("@#{instance_name}").nil? || force
22
+ doc = self.class.fetch_and_parse("#{api_path}/#{api_method}.xml")
23
+ elements = (doc/element).inject([]) { |elements, el| elements << scrobbler_class.new_from_xml(el, doc); elements }
24
+ instance_variable_set("@#{instance_name}", elements)
25
+ end
26
+ instance_variable_get("@#{instance_name}")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ module Scrobbler
2
+ class Chart < Base
3
+ class << self
4
+ def new_from_xml(xml, doc)
5
+ Chart.new(xml['from'], xml['to'])
6
+ end
7
+ end
8
+ def initialize(from, to)
9
+ raise ArgumentError, "From is required" if from.blank?
10
+ raise ArgumentError, "To is required" if to.blank?
11
+ @from = from
12
+ @to = to
13
+ end
14
+
15
+ def from=(value)
16
+ @from = value.to_i
17
+ end
18
+
19
+ def to=(value)
20
+ @to = value.to_i
21
+ end
22
+
23
+ def from
24
+ @from.to_i
25
+ end
26
+
27
+ def to
28
+ @to.to_i
29
+ end
30
+ end
31
+ end