xhochy-scrobbler 0.2.14
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +5 -0
- data/MIT-LICENSE +19 -0
- data/Manifest +65 -0
- data/README.rdoc +114 -0
- data/Rakefile +36 -0
- data/examples/album.rb +17 -0
- data/examples/artist.rb +13 -0
- data/examples/scrobble.rb +31 -0
- data/examples/tag.rb +11 -0
- data/examples/track.rb +6 -0
- data/examples/user.rb +14 -0
- data/lib/scrobbler.rb +22 -0
- data/lib/scrobbler/album.rb +140 -0
- data/lib/scrobbler/artist.rb +134 -0
- data/lib/scrobbler/base.rb +82 -0
- data/lib/scrobbler/chart.rb +31 -0
- data/lib/scrobbler/playing.rb +49 -0
- data/lib/scrobbler/rest.rb +47 -0
- data/lib/scrobbler/scrobble.rb +66 -0
- data/lib/scrobbler/search.rb +60 -0
- data/lib/scrobbler/simpleauth.rb +59 -0
- data/lib/scrobbler/tag.rb +93 -0
- data/lib/scrobbler/track.rb +89 -0
- data/lib/scrobbler/user.rb +173 -0
- data/lib/scrobbler/version.rb +3 -0
- data/scrobbler.gemspec +41 -0
- data/setup.rb +1585 -0
- data/test/fixtures/xml/album/info.xml +43 -0
- data/test/fixtures/xml/artist/fans.xml +52 -0
- data/test/fixtures/xml/artist/similar.xml +1004 -0
- data/test/fixtures/xml/artist/topalbums.xml +61 -0
- data/test/fixtures/xml/artist/toptags.xml +19 -0
- data/test/fixtures/xml/artist/toptracks.xml +62 -0
- data/test/fixtures/xml/search/album.xml +241 -0
- data/test/fixtures/xml/search/artist.xml +215 -0
- data/test/fixtures/xml/search/track.xml +209 -0
- data/test/fixtures/xml/tag/topalbums.xml +805 -0
- data/test/fixtures/xml/tag/topartists.xml +605 -0
- data/test/fixtures/xml/tag/toptags.xml +1254 -0
- data/test/fixtures/xml/tag/toptracks.xml +852 -0
- data/test/fixtures/xml/track/fans.xml +34 -0
- data/test/fixtures/xml/track/toptags.xml +33 -0
- data/test/fixtures/xml/user/friends.xml +30 -0
- data/test/fixtures/xml/user/neighbours.xml +23 -0
- data/test/fixtures/xml/user/profile.xml +12 -0
- data/test/fixtures/xml/user/recentbannedtracks.xml +24 -0
- data/test/fixtures/xml/user/recentlovedtracks.xml +24 -0
- data/test/fixtures/xml/user/recenttracks.xml +47 -0
- data/test/fixtures/xml/user/systemrecs.xml +18 -0
- data/test/fixtures/xml/user/topalbums.xml +61 -0
- data/test/fixtures/xml/user/topartists.xml +41 -0
- data/test/fixtures/xml/user/toptags.xml +44 -0
- data/test/fixtures/xml/user/toptracks.xml +65 -0
- data/test/mocks/rest.rb +102 -0
- data/test/test_helper.rb +20 -0
- data/test/unit/album_test.rb +73 -0
- data/test/unit/artist_test.rb +106 -0
- data/test/unit/chart_test.rb +34 -0
- data/test/unit/playing_test.rb +53 -0
- data/test/unit/scrobble_test.rb +69 -0
- data/test/unit/search_test.rb +55 -0
- data/test/unit/simpleauth_test.rb +45 -0
- data/test/unit/tag_test.rb +58 -0
- data/test/unit/track_test.rb +37 -0
- data/test/unit/user_test.rb +201 -0
- metadata +175 -0
@@ -0,0 +1,134 @@
|
|
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
|
+
# @todo Add missing functions that require authentication
|
61
|
+
# @todo Integrate search functionality into this class which is already implemented in Scrobbler::Search
|
62
|
+
class Artist < Base
|
63
|
+
attr_accessor :name, :mbid, :playcount, :rank, :url, :count, :streamable
|
64
|
+
attr_accessor :chartposition, :image_small, :image_medium, :image_large
|
65
|
+
|
66
|
+
# used for similar artists
|
67
|
+
attr_accessor :match
|
68
|
+
|
69
|
+
class << self
|
70
|
+
def new_from_xml(xml, doc=nil)
|
71
|
+
# occasionally name can be found in root of artist element (<artist name="">) rather than as an element (<name>)
|
72
|
+
name = Base::sanitize(xml['name']) if name.nil? && xml['name']
|
73
|
+
name = Base::sanitize(xml.at('/name').inner_html) if name.nil? && (xml).at(:name)
|
74
|
+
a = Artist.new(name)
|
75
|
+
a.mbid = xml.at(:mbid).inner_html if xml.at(:mbid)
|
76
|
+
a.playcount = xml.at(:playcount).inner_html if xml.at(:playcount)
|
77
|
+
a.rank = Base::sanitize(xml['rank']) if xml['rank']
|
78
|
+
a.url = xml.at(:url).inner_html if xml.at(:url)
|
79
|
+
a.image_small = xml.at("image[@size='small']").inner_html if xml.at("image[@size='small']")
|
80
|
+
a.image_medium = xml.at("image[@size='medium']'").inner_html if xml.at("image[@size='medium']'")
|
81
|
+
a.image_large = xml.at("image[@size='large']'").inner_html if xml.at("image[@size='large']'")
|
82
|
+
a.match = xml.at(:match).inner_html if xml.at(:match)
|
83
|
+
a.chartposition = xml.at(:chartposition).inner_html if xml.at(:chartposition)
|
84
|
+
|
85
|
+
# in top artists for tag
|
86
|
+
a.count = xml.at('/tagcount').inner_html if xml.at('/tagcount')
|
87
|
+
a.streamable = xml['streamable'] if xml['streamable']
|
88
|
+
a.streamable = xml.at(:streamable).inner_html == '1' ? 'yes' : 'no' if a.streamable.nil? && xml.at(:streamable)
|
89
|
+
a
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def initialize(name)
|
94
|
+
raise ArgumentError, "Name is required" if name.blank?
|
95
|
+
@name = name
|
96
|
+
end
|
97
|
+
|
98
|
+
# Get the URL to the ical or rss representation of the current events that
|
99
|
+
# a artist will play
|
100
|
+
#
|
101
|
+
# @todo Use the API function and parse that into a common ruby structure
|
102
|
+
def current_events(format=:ics)
|
103
|
+
format = :ics if format.to_s == 'ical'
|
104
|
+
raise ArgumentError unless ['ics', 'rss'].include?(format.to_s)
|
105
|
+
"#{API_URL.chop}/2.0/artist/#{CGI::escape(name)}/events.#{format}"
|
106
|
+
end
|
107
|
+
|
108
|
+
def image(which=:small)
|
109
|
+
which = which.to_s
|
110
|
+
raise ArgumentError unless ['small', 'medium', 'large'].include?(which)
|
111
|
+
instance_variable_get("@image_#{which}")
|
112
|
+
end
|
113
|
+
|
114
|
+
def similar(force=false)
|
115
|
+
get_instance2('artist.getsimilar', :similar, :artist, {'artist'=>@name}, force)
|
116
|
+
end
|
117
|
+
|
118
|
+
def top_fans(force=false)
|
119
|
+
get_instance2('artist.gettopfans', :top_fans, :user, {'artist'=>@name}, force)
|
120
|
+
end
|
121
|
+
|
122
|
+
def top_tracks(force=false)
|
123
|
+
get_instance2('artist.gettoptracks', :top_tracks, :track, {'artist'=>@name}, force)
|
124
|
+
end
|
125
|
+
|
126
|
+
def top_albums(force=false)
|
127
|
+
get_instance2('artist.gettopalbums', :top_albums, :album, {'artist'=>@name}, force)
|
128
|
+
end
|
129
|
+
|
130
|
+
def top_tags(force=false)
|
131
|
+
get_instance2('artist.gettoptags', :top_tags, :tag, {'artist'=>@name}, force)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'cgi'
|
3
|
+
require 'htmlentities'
|
4
|
+
|
5
|
+
$KCODE = 'u'
|
6
|
+
|
7
|
+
module Scrobbler
|
8
|
+
|
9
|
+
API_URL = 'http://ws.audioscrobbler.com/'
|
10
|
+
API_VERSION = '1.0'
|
11
|
+
|
12
|
+
class Base
|
13
|
+
def Base.api_key=(api_key)
|
14
|
+
@@api_key = api_key
|
15
|
+
end
|
16
|
+
|
17
|
+
@@coder = HTMLEntities.new
|
18
|
+
|
19
|
+
# Decode HTML Entities so that we have plain strings in out code
|
20
|
+
def Base.sanitize(string)
|
21
|
+
@@coder.decode(string)
|
22
|
+
end
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def connection
|
26
|
+
@connection ||= REST::Connection.new(API_URL)
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch_and_parse(resource)
|
30
|
+
Hpricot::XML(connection.get(resource))
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def request(api_method, parameters)
|
37
|
+
parameters['api_key'] = @@api_key
|
38
|
+
parameters['method'] = api_method.to_s
|
39
|
+
paramlist = []
|
40
|
+
parameters.each do |key, value|
|
41
|
+
paramlist << "#{CGI::escape(key)}=#{CGI::escape(value)}"
|
42
|
+
end
|
43
|
+
|
44
|
+
self.class.fetch_and_parse('/2.0/?' + paramlist.join('&'))
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_instance2(api_method, instance_name, element, parameters = {}, force=false)
|
48
|
+
scrobbler_class = "scrobbler/#{element.to_s}".camelize.constantize
|
49
|
+
if instance_variable_get("@#{instance_name}").nil? || force
|
50
|
+
# Add the API key and the method to the parameters, they are always required
|
51
|
+
parameters['api_key'] = @@api_key
|
52
|
+
parameters['method'] = api_method.to_s
|
53
|
+
|
54
|
+
# url-escape all parameters
|
55
|
+
paramlist = []
|
56
|
+
parameters.each do |key, value|
|
57
|
+
paramlist << "#{CGI::escape(key)}=#{CGI::escape(value)}"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Fetch data
|
61
|
+
doc = self.class.fetch_and_parse('/2.0/?' + paramlist.join('&'));
|
62
|
+
elements = (doc/element).inject([]) do |elements, el|
|
63
|
+
elements << scrobbler_class.new_from_xml(el, doc);
|
64
|
+
elements
|
65
|
+
end
|
66
|
+
instance_variable_set("@#{instance_name}", elements)
|
67
|
+
end
|
68
|
+
instance_variable_get("@#{instance_name}")
|
69
|
+
end
|
70
|
+
|
71
|
+
# in order for subclass to use, it must have api_path method
|
72
|
+
def get_instance(api_method, instance_name, element, force=false)
|
73
|
+
scrobbler_class = "scrobbler/#{element.to_s}".camelize.constantize
|
74
|
+
if instance_variable_get("@#{instance_name}").nil? || force
|
75
|
+
doc = self.class.fetch_and_parse("#{api_path}/#{api_method}.xml")
|
76
|
+
elements = (doc/element).inject([]) { |elements, el| elements << scrobbler_class.new_from_xml(el, doc); elements }
|
77
|
+
instance_variable_set("@#{instance_name}", elements)
|
78
|
+
end
|
79
|
+
instance_variable_get("@#{instance_name}")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
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
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Scrobbler
|
2
|
+
class Playing
|
3
|
+
# you should read last.fm/api/submissions#np first!
|
4
|
+
|
5
|
+
attr_accessor :session_id, :now_playing_url, :artist, :track,
|
6
|
+
:album, :length, :track_number, :mb_track_id
|
7
|
+
attr_reader :status
|
8
|
+
|
9
|
+
def initialize(args = {})
|
10
|
+
@session_id = args[:session_id] # from Scrobbler::SimpleAuth
|
11
|
+
@now_playing_url = args[:now_playing_url] # from Scrobbler::SimpleAuth (can change)
|
12
|
+
@artist = args[:artist] # track artist
|
13
|
+
@track = args[:track] # track name
|
14
|
+
@album = args[:album] || '' # track album (optional)
|
15
|
+
@length = args[:length] || '' # track length in seconds (optional)
|
16
|
+
@track_number = args[:track_number] || '' # track number (optional)
|
17
|
+
@mb_track_id = args[:mb_track_id] || '' # MusicBrainz track ID (optional)
|
18
|
+
|
19
|
+
if [@session_id, @now_playing_url, @artist, @track].any?(&:blank?)
|
20
|
+
raise ArgumentError, 'Missing required argument'
|
21
|
+
elsif !@length.to_s.empty? && @length.to_i <= 30 # see last.fm/api
|
22
|
+
raise ArgumentError, 'Length must be greater than 30 seconds'
|
23
|
+
end
|
24
|
+
|
25
|
+
@connection = REST::Connection.new(@now_playing_url)
|
26
|
+
end
|
27
|
+
|
28
|
+
def submit!
|
29
|
+
query = { :s => @session_id,
|
30
|
+
:a => @artist,
|
31
|
+
:t => @track,
|
32
|
+
:b => @album,
|
33
|
+
:l => @length,
|
34
|
+
:n => @track_number,
|
35
|
+
:m => @mb_track_id }
|
36
|
+
|
37
|
+
@status = @connection.post('', query)
|
38
|
+
|
39
|
+
case @status
|
40
|
+
when /OK/
|
41
|
+
|
42
|
+
when /BADSESSION/
|
43
|
+
raise BadSessionError # rerun Scrobbler::SimpleAuth#handshake!
|
44
|
+
else
|
45
|
+
raise RequestFailedError
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
|
3
|
+
module Scrobbler
|
4
|
+
module REST
|
5
|
+
class Connection
|
6
|
+
def initialize(base_url, args = {})
|
7
|
+
@base_url = base_url
|
8
|
+
@username = args[:username]
|
9
|
+
@password = args[:password]
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(resource, args = nil)
|
13
|
+
request(resource, "get", args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def post(resource, args = nil)
|
17
|
+
request(resource, "post", args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def request(resource, method = "get", args = nil)
|
21
|
+
url = URI.join(@base_url, resource)
|
22
|
+
|
23
|
+
if args
|
24
|
+
# TODO: What about keys without value?
|
25
|
+
url.query = args.map { |k,v| "%s=%s" % [URI.encode(k.to_s), URI.encode(v.to_s)] }.join("&")
|
26
|
+
end
|
27
|
+
|
28
|
+
case method
|
29
|
+
when "get"
|
30
|
+
req = Net::HTTP::Get.new(url.request_uri)
|
31
|
+
when "post"
|
32
|
+
req = Net::HTTP::Post.new(url.request_uri)
|
33
|
+
end
|
34
|
+
|
35
|
+
if @username and @password
|
36
|
+
req.basic_auth(@username, @password)
|
37
|
+
end
|
38
|
+
|
39
|
+
http = Net::HTTP.new(url.host, url.port)
|
40
|
+
http.use_ssl = (url.port == 443)
|
41
|
+
|
42
|
+
res = http.start() { |conn| conn.request(req) }
|
43
|
+
res.body
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# exception definitions
|
2
|
+
class BadSessionError < StandardError; end
|
3
|
+
class RequestFailedError < StandardError; end
|
4
|
+
|
5
|
+
module Scrobbler
|
6
|
+
class Scrobble
|
7
|
+
# you need to read last.fm/api/submissions#subs first!
|
8
|
+
|
9
|
+
attr_accessor :session_id, :submission_url, :artist, :track, :time,
|
10
|
+
:source, :length, :album, :track_number, :mb_track_id
|
11
|
+
attr_reader :status
|
12
|
+
|
13
|
+
def initialize(args = {})
|
14
|
+
@session_id = args[:session_id] # from Scrobbler::SimpleAuth
|
15
|
+
@submission_url = args[:submission_url] # from Scrobbler::SimpleAuth (can change)
|
16
|
+
@artist = args[:artist] # track artist
|
17
|
+
@track = args[:track] # track name
|
18
|
+
@time = args[:time] # a Time object set to the time the track started playing
|
19
|
+
@source = args[:source] || 'P' # track source, see last.fm/api/submissions#subs
|
20
|
+
@length = args[:length].to_s || '' # track length in seconds
|
21
|
+
@album = args[:album] || '' # track album name (optional)
|
22
|
+
@track_number = args[:track_number] || '' # track number (optional)
|
23
|
+
@mb_track_id = args[:mb_track_id] || '' # MusicBrainz track ID (optional)
|
24
|
+
|
25
|
+
if [@session_id, @submission_url, @artist, @track].any?(&:blank?)
|
26
|
+
raise ArgumentError, 'Missing required argument'
|
27
|
+
elsif @time.class.to_s != 'Time'
|
28
|
+
raise ArgumentError, ":time must be a Time object"
|
29
|
+
elsif !['P','R','E','U'].include?(@source) # see last.fm/api/submissions#subs
|
30
|
+
raise ArgumentError, "Invalid source"
|
31
|
+
elsif @source == 'P' && @length.blank? # length is not optional if source is P
|
32
|
+
raise ArgumentError, 'Length must be set'
|
33
|
+
elsif !@length.blank? && @length.to_i <= 30 # see last.fm/api/submissions#subs
|
34
|
+
raise ArgumentError, 'Length must be greater than 30 seconds'
|
35
|
+
end
|
36
|
+
|
37
|
+
@connection = REST::Connection.new(@submission_url)
|
38
|
+
end
|
39
|
+
|
40
|
+
def submit!
|
41
|
+
query = { :s => @session_id,
|
42
|
+
'a[0]' => @artist,
|
43
|
+
't[0]' => @track,
|
44
|
+
'i[0]' => @time.utc.to_i,
|
45
|
+
'o[0]' => @source,
|
46
|
+
'r[0]' => '',
|
47
|
+
'l[0]' => @length,
|
48
|
+
'b[0]' => @album,
|
49
|
+
'n[0]' => @track_number,
|
50
|
+
'm[0]' => @mb_track_id }
|
51
|
+
|
52
|
+
@status = @connection.post('', query)
|
53
|
+
|
54
|
+
case @status
|
55
|
+
when /OK/
|
56
|
+
|
57
|
+
when /BADSESSION/
|
58
|
+
raise BadSessionError # rerun Scrobbler::SimpleAuth#handshake!
|
59
|
+
when /FAILED/
|
60
|
+
raise RequestFailedError, @status
|
61
|
+
else
|
62
|
+
raise RequestFailedError
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#
|
2
|
+
# This is an interface to the Last.FM Search API.
|
3
|
+
# It currently allows you to search by album, artist, or track.
|
4
|
+
#
|
5
|
+
|
6
|
+
module Scrobbler
|
7
|
+
class Search < Base
|
8
|
+
attr_accessor :type, :query, :api_key
|
9
|
+
|
10
|
+
def initialize(api_key)
|
11
|
+
@api_key = api_key
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute
|
15
|
+
doc = self.class.fetch_and_parse(api_path)
|
16
|
+
results = []
|
17
|
+
if type == 'album'
|
18
|
+
(doc/"//album").each do |album|
|
19
|
+
artist = album/"artist"
|
20
|
+
name = album/"name"
|
21
|
+
results << Album.new(artist.inner_html, name.inner_html, :include_info => true)
|
22
|
+
end
|
23
|
+
elsif type == 'artist'
|
24
|
+
(doc/"//artist/name").each do |name|
|
25
|
+
results << Artist.new(name.inner_html)
|
26
|
+
end
|
27
|
+
elsif type == 'track'
|
28
|
+
(doc/"//track").each do |track|
|
29
|
+
artist = track/"artist"
|
30
|
+
name = track/"name"
|
31
|
+
results << Track.new(artist.inner_html, name.inner_html)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
results
|
35
|
+
end
|
36
|
+
|
37
|
+
def by_album(album_name)
|
38
|
+
@type = 'album'
|
39
|
+
@query = album_name
|
40
|
+
execute
|
41
|
+
end
|
42
|
+
|
43
|
+
def by_artist(artist_name)
|
44
|
+
@type = 'artist'
|
45
|
+
@query = artist_name
|
46
|
+
execute
|
47
|
+
end
|
48
|
+
|
49
|
+
def by_track(track_name)
|
50
|
+
@type = 'track'
|
51
|
+
@query = track_name
|
52
|
+
execute
|
53
|
+
end
|
54
|
+
|
55
|
+
def api_path
|
56
|
+
"/2.0/?method=#{type}.search&#{type}=#{CGI::escape(query)}&api_key=#{api_key}"
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|