jonaustin-rockstar 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +8 -0
  3. data/Gemfile +10 -0
  4. data/Gemfile.lock +62 -0
  5. data/History.txt +6 -0
  6. data/MIT-LICENSE +19 -0
  7. data/Manifest +72 -0
  8. data/README.md +173 -0
  9. data/Rakefile +32 -0
  10. data/VERSION +1 -0
  11. data/examples/.gitignore +1 -0
  12. data/examples/album.rb +16 -0
  13. data/examples/artist.rb +25 -0
  14. data/examples/geo.rb +60 -0
  15. data/examples/lastfm.yml_example +3 -0
  16. data/examples/scrobble.rb +45 -0
  17. data/examples/tag.rb +20 -0
  18. data/examples/track.rb +14 -0
  19. data/examples/user.rb +18 -0
  20. data/lib/rockstar.rb +46 -0
  21. data/lib/rockstar/album.rb +104 -0
  22. data/lib/rockstar/artist.rb +183 -0
  23. data/lib/rockstar/auth.rb +38 -0
  24. data/lib/rockstar/base.rb +48 -0
  25. data/lib/rockstar/chart.rb +31 -0
  26. data/lib/rockstar/event.rb +73 -0
  27. data/lib/rockstar/geo.rb +47 -0
  28. data/lib/rockstar/library.rb +13 -0
  29. data/lib/rockstar/metro.rb +26 -0
  30. data/lib/rockstar/rest.rb +66 -0
  31. data/lib/rockstar/session.rb +19 -0
  32. data/lib/rockstar/tag.rb +100 -0
  33. data/lib/rockstar/track.rb +265 -0
  34. data/lib/rockstar/user.rb +205 -0
  35. data/lib/rockstar/venue.rb +59 -0
  36. data/lib/rockstar/version.rb +3 -0
  37. data/rockstar.gemspec +176 -0
  38. data/test/fixtures/xml/album/getinfo_album_Radio_Retalation_artist_Thievery_Corporation.xml +21 -0
  39. data/test/fixtures/xml/album/getinfo_album_Some_Hearts_artist_Carrie_Underwood.xml +63 -0
  40. data/test/fixtures/xml/artist/getevents_artist_Metallica.xml +1064 -0
  41. data/test/fixtures/xml/artist/getimages_artist_Metallica_page_2.xml +1074 -0
  42. data/test/fixtures/xml/artist/getinfo_artist_Metallica.xml +115 -0
  43. data/test/fixtures/xml/artist/getinfo_mbid_65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab.xml +115 -0
  44. data/test/fixtures/xml/artist/getsimilar_artist_Metallica.xml +1203 -0
  45. data/test/fixtures/xml/artist/gettopalbums_artist_Metallica.xml +704 -0
  46. data/test/fixtures/xml/artist/gettopfans_artist_Metallica.xml +504 -0
  47. data/test/fixtures/xml/artist/gettoptags_artist_Metallica.xml +403 -0
  48. data/test/fixtures/xml/artist/gettoptracks_artist_Metallica.xml +800 -0
  49. data/test/fixtures/xml/geo/getevents_location_london.xml +531 -0
  50. data/test/fixtures/xml/geo/getmetros_country_germany.xml +44 -0
  51. data/test/fixtures/xml/geo/gettopartists_country_spain_limit_50_page_.xml +561 -0
  52. data/test/fixtures/xml/geo/gettoptracks_country_spain_limit_50_page_.xml +1004 -0
  53. data/test/fixtures/xml/library/getalbums_user_jnunemaker.xml +704 -0
  54. data/test/fixtures/xml/library/getartists_user_jnunemaker.xml +554 -0
  55. data/test/fixtures/xml/tag/gettopalbums_tag_rock.xml +654 -0
  56. data/test/fixtures/xml/tag/gettopartists_tag_rock.xml +504 -0
  57. data/test/fixtures/xml/tag/gettoptags.xml +1253 -0
  58. data/test/fixtures/xml/tag/gettoptracks_tag_rock.xml +704 -0
  59. data/test/fixtures/xml/track/getinfo_artist_Carrie_Underwood_track_Before_He_Cheats.xml +55 -0
  60. data/test/fixtures/xml/track/getinfo_artist_Karrie_Underwood_track_Before_He_Cheats.xml +55 -0
  61. data/test/fixtures/xml/track/getsimilar_artist_Carrie_Underwood_limit_10_track_Before_He_Cheats.xml +185 -0
  62. data/test/fixtures/xml/track/gettopfans_artist_Carrie_Underwood_track_Before_He_Cheats.xml +504 -0
  63. data/test/fixtures/xml/track/gettoptags_artist_Carrie_Underwood_track_Before_He_Cheats.xml +403 -0
  64. data/test/fixtures/xml/track/gettoptags_artist_Carrie_Underwood_track_Wasted.xml +405 -0
  65. data/test/fixtures/xml/track/love_artist_Carrie_Underwood_sk_tag_track_Before_He_Cheats.xml +2 -0
  66. data/test/fixtures/xml/track/updatenowplaying_artist_Carrie_Underwood_sk_tag_track_Before_He_Cheats.xml +10 -0
  67. data/test/fixtures/xml/user/getevents_sk_token_user_bodot.xml +513 -0
  68. data/test/fixtures/xml/user/getfriends_user_jnunemaker.xml +173 -0
  69. data/test/fixtures/xml/user/getinfo_user_jnunemaker.xml +22 -0
  70. data/test/fixtures/xml/user/getinfo_user_oaknd1.xml +22 -0
  71. data/test/fixtures/xml/user/getinfo_user_wharle.xml +22 -0
  72. data/test/fixtures/xml/user/getlovedtracks_user_jnunemaker.xml +775 -0
  73. data/test/fixtures/xml/user/getneighbours_user_jnunemaker.xml +503 -0
  74. data/test/fixtures/xml/user/getrecenttracks_user_jnunemaker.xml +133 -0
  75. data/test/fixtures/xml/user/getrecommendedartists_sk_token_user_jnunemaker.xml +553 -0
  76. data/test/fixtures/xml/user/gettopalbums_user_jnunemaker.xml +704 -0
  77. data/test/fixtures/xml/user/gettopartists_period_3month_user_jnunemaker.xml +710 -0
  78. data/test/fixtures/xml/user/gettopartists_period_overall_user_jnunemaker.xml +554 -0
  79. data/test/fixtures/xml/user/gettoptags_user_jnunemaker.xml +63 -0
  80. data/test/fixtures/xml/user/gettoptracks_user_jnunemaker.xml +750 -0
  81. data/test/fixtures/xml/user/getweeklyalbumchart_from_1138536002_to_1139140802_user_jnunemaker.xml +143 -0
  82. data/test/fixtures/xml/user/getweeklyalbumchart_from__to__user_jnunemaker.xml +31 -0
  83. data/test/fixtures/xml/user/getweeklyartistchart_from_1138536002_to_1139140802_user_jnunemaker.xml +201 -0
  84. data/test/fixtures/xml/user/getweeklyartistchart_from__to__user_jnunemaker.xml +21 -0
  85. data/test/fixtures/xml/user/getweeklychartlist_user_jnunemaker.xml +232 -0
  86. data/test/fixtures/xml/user/getweeklytrackchart_from_1138536002_to_1139140802_user_jnunemaker.xml +883 -0
  87. data/test/fixtures/xml/user/getweeklytrackchart_from__to__user_jnunemaker.xml +423 -0
  88. data/test/fixtures/xml/venue/getevents_venue_8807850.xml +280 -0
  89. data/test/fixtures/xml/venue/search_country__limit__page__venue_country_DE_venue_cotton.xml +72 -0
  90. data/test/mocks/rest.rb +50 -0
  91. data/test/test_helper.rb +18 -0
  92. data/test/unit/test_album.rb +76 -0
  93. data/test/unit/test_artist.rb +123 -0
  94. data/test/unit/test_chart.rb +35 -0
  95. data/test/unit/test_geo.rb +51 -0
  96. data/test/unit/test_library.rb +65 -0
  97. data/test/unit/test_rockstar.rb +15 -0
  98. data/test/unit/test_tag.rb +57 -0
  99. data/test/unit/test_track.rb +93 -0
  100. data/test/unit/test_user.rb +309 -0
  101. data/test/unit/test_venue.rb +20 -0
  102. metadata +243 -0
@@ -0,0 +1,38 @@
1
+ module Rockstar
2
+
3
+ # = Authentification
4
+ #
5
+ # There are 2 ways to get an auth token :
6
+ #
7
+ # == Desktop-App
8
+ # 1. Get a new token to request authorisation:
9
+ # token = Rockstar::Auth.new.token
10
+ # 2. Open a webbrowser with http://www.last.fm/api/auth/?api_key=xxxxxxxxxxx&token=xxxxxxxx
11
+ # 3. Wait for the User to confirm that he accepted your request.
12
+ # 4. Continue with "Get the session token"
13
+ #
14
+ # == Web-App
15
+ # 1. Redirect the user to http://www.last.fm/api/auth/?api_key={YOUR_API_KEY}&cb={YOUR_RETURN_URL}
16
+ # 2. If the user accepts, lastfm will redirect to YOUR_RETURN_URL?token=TOKEN
17
+ # token = params[:token]
18
+ # 3. Continue with "Get the session token"
19
+ #
20
+ # == Get the session token
21
+ # 1. Use the previous token and call
22
+ # session = Rockstar::Auth.new.session(token)
23
+ # 2. Store the session.key and session.username returned. The session.key will not
24
+ # expire. It is save to store it into your database.
25
+ class Auth < Base
26
+
27
+ def session(token)
28
+ doc = self.class.fetch_and_parse("auth.getSession", {:token => token}, true)
29
+ Rockstar::Session.new_from_xml(doc)
30
+ end
31
+
32
+ def token
33
+ doc = self.class.fetch_and_parse("auth.getToken", {}, true)
34
+ token = (doc).at(:token).inner_html if (doc).at(:token)
35
+ token
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,48 @@
1
+ module Rockstar
2
+
3
+ API_URL = 'http://ws.audioscrobbler.com/'
4
+ API_VERSION = '2.0'
5
+
6
+ class Base
7
+ class << self
8
+ def connection
9
+ @connection ||= REST::Connection.new(API_URL + API_VERSION + "/")
10
+ end
11
+
12
+ def fetch_and_parse(resource, params = {}, sign_request = false)
13
+ Hpricot::XML(connection.get(resource, sign_request, params))
14
+ end
15
+
16
+ def get_instance(api_method, instance_name, element, params, sign_request = false)
17
+ rockstar_class = "rockstar/#{element.to_s}".camelize.constantize
18
+ doc = self.fetch_and_parse(api_method, params, sign_request)
19
+ (doc/element).inject([]) { |elements, el| elements << rockstar_class.new_from_xml(el, doc); elements }
20
+ end
21
+ end
22
+
23
+ private
24
+ # in order for subclass to use, it must have api_path method
25
+ def get_instance(api_method, instance_name, element, params, force = false, sign_request = false)
26
+ rockstar_class = "rockstar/#{element.to_s}".camelize.constantize
27
+
28
+ if instance_variable_get("@#{instance_name}").nil? || force
29
+ doc = self.class.fetch_and_parse(api_method, params, sign_request)
30
+ elements = (doc/element).inject([]) { |elements, el| elements << rockstar_class.new_from_xml(el, doc); elements }
31
+ instance_variable_set("@#{instance_name}", elements)
32
+ end
33
+ instance_variable_get("@#{instance_name}")
34
+ end
35
+
36
+ def self.fix_url(url)
37
+ if (!url.blank? && !url.match("^http://"))
38
+ url = "http://#{url}"
39
+ end
40
+ url
41
+ end
42
+
43
+ def self.parse_time(time_str)
44
+ return nil if time_str.blank?
45
+ Time.parse(time_str)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,31 @@
1
+ module Rockstar
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
@@ -0,0 +1,73 @@
1
+ module Rockstar
2
+ class Event < Base
3
+
4
+ attr_accessor :eid, :title, :artists, :headliners, :start_date, :end_date,
5
+ :description, :attendance, :reviews, :tag, :url, :website, :tickets,
6
+ :cancelled, :tags, :images, :venue
7
+
8
+ class << self
9
+ def new_from_xml(xml, doc)
10
+ e = Event.new(
11
+ (xml).at(:id).inner_html,
12
+ (xml).at(:title).inner_html
13
+ )
14
+
15
+ e.artists = []
16
+ xml.search("/artists/artist").each {|a|
17
+ e.artists << a.inner_html
18
+ }
19
+
20
+ e.headliners = []
21
+ xml.search("/artists/headliner").each{|h|
22
+ e.headliners << h.inner_html
23
+ }
24
+
25
+ e.start_date = Base.parse_time(xml.search("/startDate").inner_html.strip)
26
+ e.end_date = Base.parse_time(xml.search("/endDate").inner_html.strip)
27
+ e.description = xml.search("/description").inner_html.strip
28
+ e.attendance = xml.search("/attendance").inner_html.strip.to_i
29
+ e.reviews = xml.search("/reviews").inner_html.strip.to_i
30
+ e.tag = xml.search("/tag").inner_html.strip
31
+ e.url = xml.search("/url").inner_html.strip
32
+ e.website = xml.search("/website").inner_html.strip
33
+ e.cancelled = xml.search("/cancelled").inner_html.strip == 1
34
+
35
+ e.tickets = []
36
+ xml.search("/tickets/ticket").each{|t|
37
+ e.tickets << t.inner_html
38
+ }
39
+
40
+ e.tags = []
41
+ xml.search("/tags/tag").each{|t|
42
+ e.tags << t.inner_html
43
+ }
44
+
45
+ e.images = {}
46
+ xml.search('/image').each {|image|
47
+ e.images[image['size']] = image.inner_html if e.images[image['size']].nil?
48
+ }
49
+
50
+ e.venue = Venue.new_from_xml(xml.search('/venue'), doc) if xml.search('/venue')
51
+
52
+ e
53
+ end
54
+ end
55
+
56
+ def initialize(id, title)
57
+ raise ArgumentError, "ID is required" if id.blank?
58
+ raise ArgumentError, "Title is required" if title.blank?
59
+ @eid = id
60
+ @title = title
61
+ end
62
+
63
+ def image(which=:medium)
64
+ which = which.to_s
65
+ raise ArgumentError unless ['small', 'medium', 'large', 'extralarge', 'mega'].include?(which)
66
+ if (self.images.nil?)
67
+ load_info
68
+ end
69
+ self.images[which]
70
+ end
71
+ end
72
+ end
73
+
@@ -0,0 +1,47 @@
1
+ module Rockstar
2
+ class Geo < Base
3
+ # Get events in a specific location. Opts can be
4
+ #
5
+ # * :location => 'madrid' # A city name from geo.metros
6
+ # * :lat => 50.0, :long => 14.0 # A geo point
7
+ #
8
+ # Additionally you can set the distance from that point with
9
+ # :distance => 50 # 50 km from the given location
10
+ #
11
+ def events(opts = {}, force = false)
12
+ get_instance("geo.getEvents", :events, :event, opts, force)
13
+ end
14
+
15
+ def metros(country, force = false)
16
+ get_instance("geo.getMetros", :metros, :metro, {:country => country}, force)
17
+ end
18
+
19
+
20
+
21
+ # Get a list of the Top Artists for a specified country
22
+ #
23
+ # Country is specified in last.fm API docs as 'A country name, as defined by the ISO 3166-1 country names standard'
24
+ # Not sure of the coverage
25
+ #
26
+ # Also specify limit and page to page through full resultset
27
+ #
28
+ # returns array of Artist instances
29
+ def topartists(country, limit = nil, page = nil, force = false)
30
+ get_instance("geo.getTopArtists", :topartists, :artist, {:country => country, :limit => limit, :page => page}, force)
31
+ end
32
+
33
+ # Get a list of the Top Tracks for a specified country
34
+ #
35
+ # Country is specified in last.fm API docs as 'A country name, as defined by the ISO 3166-1 country names standard'
36
+ # Not sure of the coverage
37
+ #
38
+ # Also specify limit and page to page through full resultset
39
+ #
40
+ # returns array of Track instances
41
+ # TODO: is this the correct object to return? We dont have the full data so is this really best
42
+ def toptracks(country, limit = nil, page = nil, force = false)
43
+ get_instance("geo.getTopTracks", :toptracks, :track, {:country => country, :limit => limit, :page => page}, force)
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,13 @@
1
+ module Rockstar
2
+ class Library < Base
3
+
4
+ def artists(force=false, options = {})
5
+ get_instance("library.getArtists", :artists, :artist, options, force)
6
+ end
7
+
8
+ def albums(force=false, options = {})
9
+ get_instance("library.getAlbums", :albums, :album, options, force)
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ module Rockstar
2
+ class Metro < Base
3
+
4
+ attr_accessor :name, :country
5
+
6
+ class << self
7
+ def new_from_xml(xml, doc)
8
+ Metro.new(
9
+ (xml).at(:name).inner_html,
10
+ (xml).at(:country).inner_html
11
+ )
12
+ end
13
+ end
14
+
15
+ def initialize(name, country)
16
+ raise ArgumentError, "Name is required" if name.blank?
17
+ raise ArgumentError, "Country is required" if country.blank?
18
+ @name = name
19
+ @country = country
20
+ end
21
+
22
+ end
23
+ end
24
+
25
+
26
+
@@ -0,0 +1,66 @@
1
+ require 'net/https'
2
+ require 'digest/md5'
3
+
4
+ module Rockstar
5
+ module REST
6
+ class Connection
7
+ def initialize(base_url, args = {})
8
+ @base_url = base_url
9
+ @username = args[:username]
10
+ @password = args[:password]
11
+ end
12
+
13
+ def get(resource, sign_request, args = {})
14
+ request(resource, "get", args, sign_request)
15
+ end
16
+
17
+ def post(resource, sign_request, args = nil)
18
+ request(resource, "post", args, sign_request)
19
+ end
20
+
21
+ def request(resource, method = "get", args = {}, sign_request=false)
22
+ url = URI.parse(@base_url)
23
+
24
+ if (!resource.blank?)
25
+ args[:method] = resource
26
+ args[:api_key]= Rockstar.lastfm_api_key
27
+ end
28
+
29
+ if args
30
+ sorted_keys = args.keys.sort_by{|k|k.to_s}
31
+ query = sorted_keys.collect { |k| "%s=%s" % [escape(k.to_s), escape(args[k].to_s)] }.join("&")
32
+
33
+ if !args[:sk].nil? ||sign_request # Session Key available => sign the request or sign_request = true?
34
+ signed = sorted_keys.collect {|k| "%s%s" % [k.to_s, args[k].to_s]}.join()
35
+
36
+ auth = Digest::MD5.hexdigest("#{signed}#{Rockstar.lastfm_api_secret}")
37
+ query += "&api_sig=#{auth}"
38
+ end
39
+ url.query = query
40
+ end
41
+
42
+ case method
43
+ when "get"
44
+ req = Net::HTTP::Get.new(url.request_uri)
45
+ when "post"
46
+ req = Net::HTTP::Post.new(url.request_uri)
47
+ end
48
+
49
+ if @username and @password
50
+ req.basic_auth(@username, @password)
51
+ end
52
+
53
+ http = Net::HTTP.new(url.host, url.port)
54
+ http.use_ssl = (url.port == 443)
55
+
56
+ res = http.start() { |conn| conn.request(req) }
57
+ res.body
58
+ end
59
+
60
+ private
61
+ def escape(str)
62
+ URI.escape(str, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,19 @@
1
+ module Rockstar
2
+ class Session < Base
3
+ attr_accessor :username, :key, :subscriber
4
+
5
+ class << self
6
+ def new_from_xml(xml, doc=nil)
7
+ t = Session.new()
8
+ t.username = (xml).at(:name).inner_html
9
+ t.key = (xml).at(:key).inner_html
10
+ t.subscriber = (xml).at(:subscriber).inner_html
11
+ t
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+
18
+
19
+
@@ -0,0 +1,100 @@
1
+ # Below is code samples for how to find the top albums and tracks for a tag.
2
+ #
3
+ # tag = Rockstar::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}" }
12
+ #
13
+ # Which would output something similar to:
14
+ #
15
+ # Top Albums
16
+ # (29) American IV: The Man Comes Around by Johnny Cash
17
+ # (14) Folks Pop In at the Waterhouse by Various Artists
18
+ # (13) Hapless by Flowers From The Man Who Shot Your Cousin
19
+ # (9) Taking The Long Way by Dixie Chicks
20
+ # (8) Unchained by Johnny Cash
21
+ # (8) American III: Solitary Man by Johnny Cash
22
+ # (8) Wide Open Spaces by Dixie Chicks
23
+ # (7) It's Now or Later by Tangled Star
24
+ # (7) Greatest Hits by Hank Williams
25
+ # (7) American Recordings by Johnny Cash
26
+ # (6) Forgotten Landscape by theNoLifeKing
27
+ # (6) At Folsom Prison by Johnny Cash
28
+ # (6) Fox Confessor Brings the Flood by Neko Case
29
+ # (6) Murder by Johnny Cash
30
+ # (5) Gloom by theNoLifeKing
31
+ # (5) Set This Circus Down by Tim McGraw
32
+ # (5) Blacklisted by Neko Case
33
+ # (5) Breathe by Faith Hill
34
+ # (5) Unearthed (disc 4: My Mother's Hymn Book) by Johnny Cash
35
+ # (4) Home by Dixie Chicks
36
+ #
37
+ # Top Tracks
38
+ # (221) Hurt by Johnny Cash
39
+ # (152) I Walk the Line by Johnny Cash
40
+ # (147) Ring of Fire by Johnny Cash
41
+ # (125) Folsom Prison Blues by Johnny Cash
42
+ # (77) The Man Comes Around by Johnny Cash
43
+ # (67) Personal Jesus by Johnny Cash
44
+ # (65) Not Ready To Make Nice by Dixie Chicks
45
+ # (63) Before He Cheats by Carrie Underwood
46
+ # (62) Give My Love to Rose by Johnny Cash
47
+ # (49) Jackson by Johnny Cash
48
+ # (49) What Hurts The Most by Rascal Flatts
49
+ # (48) Big River by Johnny Cash
50
+ # (46) Man in Black by Johnny Cash
51
+ # (46) Jolene by Dolly Parton
52
+ # (46) Friends in Low Places by Garth Brooks
53
+ # (46) One by Johnny Cash
54
+ # (44) Cocaine Blues by Johnny Cash
55
+ # (41) Get Rhythm by Johnny Cash
56
+ # (41) I Still Miss Someone by Johnny Cash
57
+ # (40) The Devil Went Down to Georgia by Charlie Daniels Band
58
+ module Rockstar
59
+ class Tag < Base
60
+ attr_accessor :name, :count, :url
61
+
62
+ class << self
63
+ def new_from_xml(xml, doc=nil)
64
+ name = (xml).at(:name).inner_html
65
+ t = Tag.new(name)
66
+ t.count = (xml).at(:count).inner_html
67
+ t.url = Base.fix_url((xml).at(:url).inner_html)
68
+ t
69
+ end
70
+
71
+ def top_tags
72
+ doc = fetch_and_parse("tag.getTopTags")
73
+ @top_tags = (doc/"toptags/tag").collect do |tag|
74
+ t = Tag.new((tag/'name').inner_html)
75
+ t.count = (tag/'count').inner_html
76
+ t.url = Base.fix_url((tag/'url').inner_html)
77
+ t
78
+ end
79
+ end
80
+ end
81
+
82
+ def initialize(name)
83
+ raise ArgumentError, "Name is required" if name.blank?
84
+ @name = name
85
+ end
86
+
87
+
88
+ def top_artists(force=false)
89
+ get_instance("tag.getTopArtists", :top_artists, :artist, {:tag => @name}, force)
90
+ end
91
+
92
+ def top_albums(force=false)
93
+ get_instance("tag.getTopAlbums", :top_albums, :album, {:tag => @name}, force)
94
+ end
95
+
96
+ def top_tracks(force=false)
97
+ get_instance("tag.getTopTracks", :top_tracks, :track, {:tag => @name}, force)
98
+ end
99
+ end
100
+ end