titanous-scrobbler 0.2.2

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 (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