jonaustin-rockstar 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +8 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +62 -0
- data/History.txt +6 -0
- data/MIT-LICENSE +19 -0
- data/Manifest +72 -0
- data/README.md +173 -0
- data/Rakefile +32 -0
- data/VERSION +1 -0
- data/examples/.gitignore +1 -0
- data/examples/album.rb +16 -0
- data/examples/artist.rb +25 -0
- data/examples/geo.rb +60 -0
- data/examples/lastfm.yml_example +3 -0
- data/examples/scrobble.rb +45 -0
- data/examples/tag.rb +20 -0
- data/examples/track.rb +14 -0
- data/examples/user.rb +18 -0
- data/lib/rockstar.rb +46 -0
- data/lib/rockstar/album.rb +104 -0
- data/lib/rockstar/artist.rb +183 -0
- data/lib/rockstar/auth.rb +38 -0
- data/lib/rockstar/base.rb +48 -0
- data/lib/rockstar/chart.rb +31 -0
- data/lib/rockstar/event.rb +73 -0
- data/lib/rockstar/geo.rb +47 -0
- data/lib/rockstar/library.rb +13 -0
- data/lib/rockstar/metro.rb +26 -0
- data/lib/rockstar/rest.rb +66 -0
- data/lib/rockstar/session.rb +19 -0
- data/lib/rockstar/tag.rb +100 -0
- data/lib/rockstar/track.rb +265 -0
- data/lib/rockstar/user.rb +205 -0
- data/lib/rockstar/venue.rb +59 -0
- data/lib/rockstar/version.rb +3 -0
- data/rockstar.gemspec +176 -0
- data/test/fixtures/xml/album/getinfo_album_Radio_Retalation_artist_Thievery_Corporation.xml +21 -0
- data/test/fixtures/xml/album/getinfo_album_Some_Hearts_artist_Carrie_Underwood.xml +63 -0
- data/test/fixtures/xml/artist/getevents_artist_Metallica.xml +1064 -0
- data/test/fixtures/xml/artist/getimages_artist_Metallica_page_2.xml +1074 -0
- data/test/fixtures/xml/artist/getinfo_artist_Metallica.xml +115 -0
- data/test/fixtures/xml/artist/getinfo_mbid_65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab.xml +115 -0
- data/test/fixtures/xml/artist/getsimilar_artist_Metallica.xml +1203 -0
- data/test/fixtures/xml/artist/gettopalbums_artist_Metallica.xml +704 -0
- data/test/fixtures/xml/artist/gettopfans_artist_Metallica.xml +504 -0
- data/test/fixtures/xml/artist/gettoptags_artist_Metallica.xml +403 -0
- data/test/fixtures/xml/artist/gettoptracks_artist_Metallica.xml +800 -0
- data/test/fixtures/xml/geo/getevents_location_london.xml +531 -0
- data/test/fixtures/xml/geo/getmetros_country_germany.xml +44 -0
- data/test/fixtures/xml/geo/gettopartists_country_spain_limit_50_page_.xml +561 -0
- data/test/fixtures/xml/geo/gettoptracks_country_spain_limit_50_page_.xml +1004 -0
- data/test/fixtures/xml/library/getalbums_user_jnunemaker.xml +704 -0
- data/test/fixtures/xml/library/getartists_user_jnunemaker.xml +554 -0
- data/test/fixtures/xml/tag/gettopalbums_tag_rock.xml +654 -0
- data/test/fixtures/xml/tag/gettopartists_tag_rock.xml +504 -0
- data/test/fixtures/xml/tag/gettoptags.xml +1253 -0
- data/test/fixtures/xml/tag/gettoptracks_tag_rock.xml +704 -0
- data/test/fixtures/xml/track/getinfo_artist_Carrie_Underwood_track_Before_He_Cheats.xml +55 -0
- data/test/fixtures/xml/track/getinfo_artist_Karrie_Underwood_track_Before_He_Cheats.xml +55 -0
- data/test/fixtures/xml/track/getsimilar_artist_Carrie_Underwood_limit_10_track_Before_He_Cheats.xml +185 -0
- data/test/fixtures/xml/track/gettopfans_artist_Carrie_Underwood_track_Before_He_Cheats.xml +504 -0
- data/test/fixtures/xml/track/gettoptags_artist_Carrie_Underwood_track_Before_He_Cheats.xml +403 -0
- data/test/fixtures/xml/track/gettoptags_artist_Carrie_Underwood_track_Wasted.xml +405 -0
- data/test/fixtures/xml/track/love_artist_Carrie_Underwood_sk_tag_track_Before_He_Cheats.xml +2 -0
- data/test/fixtures/xml/track/updatenowplaying_artist_Carrie_Underwood_sk_tag_track_Before_He_Cheats.xml +10 -0
- data/test/fixtures/xml/user/getevents_sk_token_user_bodot.xml +513 -0
- data/test/fixtures/xml/user/getfriends_user_jnunemaker.xml +173 -0
- data/test/fixtures/xml/user/getinfo_user_jnunemaker.xml +22 -0
- data/test/fixtures/xml/user/getinfo_user_oaknd1.xml +22 -0
- data/test/fixtures/xml/user/getinfo_user_wharle.xml +22 -0
- data/test/fixtures/xml/user/getlovedtracks_user_jnunemaker.xml +775 -0
- data/test/fixtures/xml/user/getneighbours_user_jnunemaker.xml +503 -0
- data/test/fixtures/xml/user/getrecenttracks_user_jnunemaker.xml +133 -0
- data/test/fixtures/xml/user/getrecommendedartists_sk_token_user_jnunemaker.xml +553 -0
- data/test/fixtures/xml/user/gettopalbums_user_jnunemaker.xml +704 -0
- data/test/fixtures/xml/user/gettopartists_period_3month_user_jnunemaker.xml +710 -0
- data/test/fixtures/xml/user/gettopartists_period_overall_user_jnunemaker.xml +554 -0
- data/test/fixtures/xml/user/gettoptags_user_jnunemaker.xml +63 -0
- data/test/fixtures/xml/user/gettoptracks_user_jnunemaker.xml +750 -0
- data/test/fixtures/xml/user/getweeklyalbumchart_from_1138536002_to_1139140802_user_jnunemaker.xml +143 -0
- data/test/fixtures/xml/user/getweeklyalbumchart_from__to__user_jnunemaker.xml +31 -0
- data/test/fixtures/xml/user/getweeklyartistchart_from_1138536002_to_1139140802_user_jnunemaker.xml +201 -0
- data/test/fixtures/xml/user/getweeklyartistchart_from__to__user_jnunemaker.xml +21 -0
- data/test/fixtures/xml/user/getweeklychartlist_user_jnunemaker.xml +232 -0
- data/test/fixtures/xml/user/getweeklytrackchart_from_1138536002_to_1139140802_user_jnunemaker.xml +883 -0
- data/test/fixtures/xml/user/getweeklytrackchart_from__to__user_jnunemaker.xml +423 -0
- data/test/fixtures/xml/venue/getevents_venue_8807850.xml +280 -0
- data/test/fixtures/xml/venue/search_country__limit__page__venue_country_DE_venue_cotton.xml +72 -0
- data/test/mocks/rest.rb +50 -0
- data/test/test_helper.rb +18 -0
- data/test/unit/test_album.rb +76 -0
- data/test/unit/test_artist.rb +123 -0
- data/test/unit/test_chart.rb +35 -0
- data/test/unit/test_geo.rb +51 -0
- data/test/unit/test_library.rb +65 -0
- data/test/unit/test_rockstar.rb +15 -0
- data/test/unit/test_tag.rb +57 -0
- data/test/unit/test_track.rb +93 -0
- data/test/unit/test_user.rb +309 -0
- data/test/unit/test_venue.rb +20 -0
- 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
|
+
|
data/lib/rockstar/geo.rb
ADDED
@@ -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
|
+
|
data/lib/rockstar/tag.rb
ADDED
@@ -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
|