hornairs-scrobbler 0.2.3
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.
- data/.gitignore +13 -0
- data/.loadpath +5 -0
- data/History.txt +5 -0
- data/MIT-LICENSE +19 -0
- data/Manifest +75 -0
- data/README.rdoc +104 -0
- data/Rakefile +10 -0
- data/VERSION.yml +5 -0
- data/examples/album.rb +20 -0
- data/examples/artist.rb +13 -0
- data/examples/playlist.rb +7 -0
- data/examples/scrobble.rb +31 -0
- data/examples/tag.rb +11 -0
- data/examples/track.rb +12 -0
- data/examples/user.rb +15 -0
- data/lib/scrobbler.rb +33 -0
- data/lib/scrobbler/album.rb +181 -0
- data/lib/scrobbler/artist.rb +165 -0
- data/lib/scrobbler/auth.rb +47 -0
- data/lib/scrobbler/base.rb +105 -0
- data/lib/scrobbler/event.rb +105 -0
- data/lib/scrobbler/geo.rb +27 -0
- data/lib/scrobbler/helper/image.rb +52 -0
- data/lib/scrobbler/helper/streamable.rb +40 -0
- data/lib/scrobbler/library.rb +112 -0
- data/lib/scrobbler/playing.rb +49 -0
- data/lib/scrobbler/playlist.rb +87 -0
- data/lib/scrobbler/radio.rb +12 -0
- data/lib/scrobbler/rest.rb +47 -0
- data/lib/scrobbler/scrobble.rb +116 -0
- data/lib/scrobbler/session.rb +9 -0
- data/lib/scrobbler/shout.rb +21 -0
- data/lib/scrobbler/simpleauth.rb +60 -0
- data/lib/scrobbler/tag.rb +113 -0
- data/lib/scrobbler/track.rb +152 -0
- data/lib/scrobbler/user.rb +222 -0
- data/lib/scrobbler/venue.rb +67 -0
- data/setup.rb +1585 -0
- data/tasks/jeweler.rake +15 -0
- data/tasks/rdoc.rake +7 -0
- data/tasks/tests.rake +13 -0
- data/tasks/yardoc.rake +8 -0
- data/test/fixtures/xml/album/info.xml +43 -0
- data/test/fixtures/xml/artist/fans.xml +52 -0
- data/test/fixtures/xml/artist/info.xml +58 -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/auth/session.xml +7 -0
- data/test/fixtures/xml/auth/token.xml +3 -0
- data/test/fixtures/xml/event/attend.xml +3 -0
- data/test/fixtures/xml/event/attendees.xml +53 -0
- data/test/fixtures/xml/event/event.xml +35 -0
- data/test/fixtures/xml/event/shouts.xml +35 -0
- data/test/fixtures/xml/geo/events-distance-p1.xml +151 -0
- data/test/fixtures/xml/geo/events-lat-long.xml +167 -0
- data/test/fixtures/xml/geo/events-p1.xml +152 -0
- data/test/fixtures/xml/geo/events-p2.xml +380 -0
- data/test/fixtures/xml/geo/events-p3.xml +427 -0
- data/test/fixtures/xml/geo/top_artists-p1.xml +76 -0
- data/test/fixtures/xml/geo/top_tracks-p1.xml +77 -0
- data/test/fixtures/xml/library/albums-f30.xml +454 -0
- data/test/fixtures/xml/library/albums-p1.xml +754 -0
- data/test/fixtures/xml/library/albums-p2.xml +754 -0
- data/test/fixtures/xml/library/albums-p3.xml +754 -0
- data/test/fixtures/xml/library/albums-p4.xml +739 -0
- data/test/fixtures/xml/library/albums-p5.xml +754 -0
- data/test/fixtures/xml/library/albums-p6.xml +754 -0
- data/test/fixtures/xml/library/albums-p7.xml +739 -0
- data/test/fixtures/xml/library/albums-p8.xml +724 -0
- data/test/fixtures/xml/library/artists-f30.xml +334 -0
- data/test/fixtures/xml/library/artists-p1.xml +554 -0
- data/test/fixtures/xml/library/artists-p2.xml +554 -0
- data/test/fixtures/xml/library/artists-p3.xml +554 -0
- data/test/fixtures/xml/library/artists-p4.xml +554 -0
- data/test/fixtures/xml/library/artists-p5.xml +554 -0
- data/test/fixtures/xml/library/artists-p6.xml +554 -0
- data/test/fixtures/xml/library/artists-p7.xml +444 -0
- data/test/fixtures/xml/library/tracks-f30.xml +472 -0
- data/test/fixtures/xml/library/tracks-p1.xml +789 -0
- data/test/fixtures/xml/library/tracks-p10.xml +771 -0
- data/test/fixtures/xml/library/tracks-p11.xml +792 -0
- data/test/fixtures/xml/library/tracks-p12.xml +777 -0
- data/test/fixtures/xml/library/tracks-p13.xml +762 -0
- data/test/fixtures/xml/library/tracks-p14.xml +759 -0
- data/test/fixtures/xml/library/tracks-p15.xml +762 -0
- data/test/fixtures/xml/library/tracks-p16.xml +756 -0
- data/test/fixtures/xml/library/tracks-p17.xml +780 -0
- data/test/fixtures/xml/library/tracks-p18.xml +756 -0
- data/test/fixtures/xml/library/tracks-p19.xml +774 -0
- data/test/fixtures/xml/library/tracks-p2.xml +765 -0
- data/test/fixtures/xml/library/tracks-p20.xml +777 -0
- data/test/fixtures/xml/library/tracks-p21.xml +777 -0
- data/test/fixtures/xml/library/tracks-p22.xml +771 -0
- data/test/fixtures/xml/library/tracks-p23.xml +765 -0
- data/test/fixtures/xml/library/tracks-p24.xml +783 -0
- data/test/fixtures/xml/library/tracks-p25.xml +777 -0
- data/test/fixtures/xml/library/tracks-p26.xml +777 -0
- data/test/fixtures/xml/library/tracks-p27.xml +756 -0
- data/test/fixtures/xml/library/tracks-p28.xml +771 -0
- data/test/fixtures/xml/library/tracks-p29.xml +753 -0
- data/test/fixtures/xml/library/tracks-p3.xml +771 -0
- data/test/fixtures/xml/library/tracks-p30.xml +780 -0
- data/test/fixtures/xml/library/tracks-p31.xml +753 -0
- data/test/fixtures/xml/library/tracks-p32.xml +771 -0
- data/test/fixtures/xml/library/tracks-p33.xml +762 -0
- data/test/fixtures/xml/library/tracks-p34.xml +538 -0
- data/test/fixtures/xml/library/tracks-p4.xml +792 -0
- data/test/fixtures/xml/library/tracks-p5.xml +780 -0
- data/test/fixtures/xml/library/tracks-p6.xml +789 -0
- data/test/fixtures/xml/library/tracks-p7.xml +789 -0
- data/test/fixtures/xml/library/tracks-p8.xml +780 -0
- data/test/fixtures/xml/library/tracks-p9.xml +774 -0
- data/test/fixtures/xml/tag/similar.xml +254 -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/info.xml +53 -0
- data/test/fixtures/xml/track/toptags.xml +504 -0
- data/test/fixtures/xml/user/events.xml +401 -0
- data/test/fixtures/xml/user/friends.xml +30 -0
- data/test/fixtures/xml/user/lovedtracks.xml +678 -0
- data/test/fixtures/xml/user/neighbours.xml +23 -0
- data/test/fixtures/xml/user/playlists.xml +61 -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 +124 -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/fixtures/xml/user/weeklyalbumchart.xml +256 -0
- data/test/fixtures/xml/user/weeklyartistchart.xml +220 -0
- data/test/fixtures/xml/user/weeklytrackchart.xml +746 -0
- data/test/fixtures/xml/venue/events.xml +151 -0
- data/test/fixtures/xml/venue/venue.xml +16 -0
- data/test/mocks/rest.rb +212 -0
- data/test/spec_helper.rb +7 -0
- data/test/test_helper.rb +20 -0
- data/test/unit/album_spec.rb +52 -0
- data/test/unit/artist_spec.rb +130 -0
- data/test/unit/auth_spec.rb +36 -0
- data/test/unit/event_spec.rb +109 -0
- data/test/unit/geo_spec.rb +148 -0
- data/test/unit/library_spec.rb +133 -0
- data/test/unit/playing_test.rb +53 -0
- data/test/unit/playlist_spec.rb +25 -0
- data/test/unit/radio_spec.rb +22 -0
- data/test/unit/scrobble_spec.rb +55 -0
- data/test/unit/scrobble_test.rb +69 -0
- data/test/unit/simpleauth_test.rb +45 -0
- data/test/unit/tag_spec.rb +101 -0
- data/test/unit/track_spec.rb +95 -0
- data/test/unit/user_spec.rb +264 -0
- data/test/unit/venue_spec.rb +104 -0
- metadata +265 -0
|
@@ -0,0 +1,165 @@
|
|
|
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
|
+
mixins :image, :streamable
|
|
64
|
+
|
|
65
|
+
attr_accessor :name, :mbid, :playcount, :rank, :url, :count
|
|
66
|
+
attr_accessor :chartposition
|
|
67
|
+
attr_accessor :match, :tagcount, :listeners
|
|
68
|
+
|
|
69
|
+
class << self
|
|
70
|
+
def new_from_xml(xml, o={})
|
|
71
|
+
data = data_from_xml(xml, o)
|
|
72
|
+
return nil if data[:name].nil?
|
|
73
|
+
Artist.new(data[:name], data)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def data_from_xml(xml, o={})
|
|
77
|
+
data = {}
|
|
78
|
+
|
|
79
|
+
# Get all information from the root's children nodes
|
|
80
|
+
xml.children.each do |child|
|
|
81
|
+
data[:playcount] = child.content.to_i if child.name == 'playcount'
|
|
82
|
+
data[:mbid] = child.content if child.name == 'mbid'
|
|
83
|
+
data[:url] = child.content if child.name == 'url'
|
|
84
|
+
data[:match] = child.content.to_i if child.name == 'match'
|
|
85
|
+
data[:tagcount] = child.content.to_i if child.name == 'tagcount'
|
|
86
|
+
data[:chartposition] = child.content if child.name == 'chartposition'
|
|
87
|
+
data[:name] = child.content if child.name == 'name'
|
|
88
|
+
maybe_streamable_node(data, child)
|
|
89
|
+
maybe_image_node(data, child)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# If we have not found anything in the content of this node yet then
|
|
93
|
+
# this must be a simple artist node which has the name of the artist
|
|
94
|
+
# as its content
|
|
95
|
+
data[:name] = xml.content if data == {}
|
|
96
|
+
|
|
97
|
+
# Get all information from the root's attributes
|
|
98
|
+
data[:name] = xml['name'] if xml['name']
|
|
99
|
+
data[:rank] = xml['rank'].to_i if xml['rank']
|
|
100
|
+
maybe_streamable_attribute data, xml
|
|
101
|
+
data[:mbid] = xml['mbid'] if xml['mbid']
|
|
102
|
+
data
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def initialize(name, data = {})
|
|
107
|
+
super()
|
|
108
|
+
raise ArgumentError, "Name is required" if name.blank?
|
|
109
|
+
@name = name
|
|
110
|
+
populate_data(data)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
@info_loaded = false
|
|
114
|
+
# Get the metadata
|
|
115
|
+
def load_info
|
|
116
|
+
doc = Base.request('artist.getinfo', {'artist' => @name})
|
|
117
|
+
doc.root.children.each do |child|
|
|
118
|
+
next unless child.name == 'artist'
|
|
119
|
+
data = self.class.data_from_xml(child)
|
|
120
|
+
populate_data(data)
|
|
121
|
+
@info_loaded = true
|
|
122
|
+
break
|
|
123
|
+
end
|
|
124
|
+
end # load_info
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# Get the URL to the ical or rss representation of the current events that
|
|
128
|
+
# a artist will play
|
|
129
|
+
#
|
|
130
|
+
# @todo Use the API function and parse that into a common ruby structure
|
|
131
|
+
def current_events(format=:ics)
|
|
132
|
+
format = :ics if format.to_s == 'ical'
|
|
133
|
+
raise ArgumentError unless ['ics', 'rss'].include?(format.to_s)
|
|
134
|
+
"#{API_URL.chop}/2.0/artist/#{CGI::escape(@name)}/events.#{format}"
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def similar(force=false)
|
|
138
|
+
get_response('artist.getsimilar', :similar, 'similarartists', 'artist', {'artist' => @name}, force)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def top_fans(force=false)
|
|
142
|
+
get_response('artist.gettopfans', :top_fans, 'topfans', 'user', {'artist' => @name}, force)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def top_tracks(force=false)
|
|
146
|
+
get_response('artist.gettoptracks', :top_tracks, 'toptracks', 'track', {'artist'=>@name}, force)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def top_albums(force=false)
|
|
150
|
+
get_response('artist.gettopalbums', :top_albums, 'topalbums', 'album', {'artist'=>@name}, force)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def top_tags(force=false)
|
|
154
|
+
get_response('artist.gettoptags', :top_tags, 'toptags', 'tag', {'artist' => @name}, force)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def ==(otherArtist)
|
|
158
|
+
if otherArtist.is_a?(Scrobbler::Artist)
|
|
159
|
+
return (@name == otherArtist.name)
|
|
160
|
+
end
|
|
161
|
+
false
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Scrobbler
|
|
2
|
+
# @todo everything
|
|
3
|
+
class Auth < Base
|
|
4
|
+
|
|
5
|
+
def initialize(username)
|
|
6
|
+
super()
|
|
7
|
+
@username = username
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def session(token)
|
|
11
|
+
doc = Base.request('auth.getsession', :signed => true, :token => token)
|
|
12
|
+
asession = {}
|
|
13
|
+
doc.root.children.each do |child1|
|
|
14
|
+
next unless child1.name == 'session'
|
|
15
|
+
child1.children.each do |child2|
|
|
16
|
+
if child2.name == 'name'
|
|
17
|
+
asession[:name] = child2.content
|
|
18
|
+
elsif child2.name == 'key'
|
|
19
|
+
asession[:key] = child2.content
|
|
20
|
+
elsif child2.name == 'subscriber'
|
|
21
|
+
asession[:subscriber] = true if child2.content == '1'
|
|
22
|
+
asession[:subscriber] = false unless child2.content == '1'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
Scrobbler::Session.new(asession)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def token
|
|
30
|
+
doc = Base.request('auth.gettoken', :signed => true)
|
|
31
|
+
stoken = ''
|
|
32
|
+
doc.root.children.each do |child|
|
|
33
|
+
next unless child.name == 'token'
|
|
34
|
+
stoken = child.content
|
|
35
|
+
end
|
|
36
|
+
stoken
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def url(options={})
|
|
40
|
+
options[:token] = token if options[:token].nil?
|
|
41
|
+
options[:api_key] = @@api_key
|
|
42
|
+
"http://www.last.fm/api/auth/?api_key=#{options[:api_key]}&token=#{options[:token]}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require 'digest/md5'
|
|
2
|
+
|
|
3
|
+
$KCODE = 'u'
|
|
4
|
+
|
|
5
|
+
include LibXML
|
|
6
|
+
|
|
7
|
+
module Scrobbler
|
|
8
|
+
|
|
9
|
+
API_URL = 'http://ws.audioscrobbler.com/'
|
|
10
|
+
|
|
11
|
+
class Base
|
|
12
|
+
def Base.api_key=(api_key)
|
|
13
|
+
@@api_key = api_key
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def Base.secret=(secret)
|
|
17
|
+
@@secret = secret
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def Base.connection
|
|
21
|
+
@connection ||= REST::Connection.new(API_URL)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def Base.sanitize(param)
|
|
25
|
+
URI.escape(param.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def Base.get(api_method, parent, element, parameters = {})
|
|
29
|
+
scrobbler_class = "scrobbler/#{element.to_s}".camelize.constantize
|
|
30
|
+
doc = request(api_method, parameters)
|
|
31
|
+
elements = []
|
|
32
|
+
doc.root.children.each do |child|
|
|
33
|
+
next unless child.name == parent.to_s
|
|
34
|
+
child.children.each do |child2|
|
|
35
|
+
next unless child2.name == element.to_s
|
|
36
|
+
elements << scrobbler_class.new_from_xml(child2)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
elements
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def Base.post_request(api_method, parameters = {}, request_method = 'get')
|
|
43
|
+
Base.request(api_method, parameters, 'post')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def Base.request(api_method, parameters = {}, request_method = 'get')
|
|
47
|
+
parameters = {:signed => false}.merge(parameters)
|
|
48
|
+
parameters['api_key'] = @@api_key
|
|
49
|
+
parameters['method'] = api_method.to_s
|
|
50
|
+
paramlist = []
|
|
51
|
+
# Check if we want a signed call and pop :signed
|
|
52
|
+
if parameters.delete :signed
|
|
53
|
+
#1: Sort alphabetically
|
|
54
|
+
params = parameters.sort{|a,b| a[0].to_s<=>b[0].to_s}
|
|
55
|
+
#2: concat them into one string
|
|
56
|
+
str = params.join('')
|
|
57
|
+
#3: Append secret
|
|
58
|
+
str = str + @@secret
|
|
59
|
+
#4: Make a md5 hash
|
|
60
|
+
md5 = Digest::MD5.hexdigest(str)
|
|
61
|
+
params << [:api_sig, md5]
|
|
62
|
+
params.each do |a|
|
|
63
|
+
paramlist << "#{sanitize(a[0])}=#{sanitize(a[1])}"
|
|
64
|
+
end
|
|
65
|
+
else
|
|
66
|
+
parameters.each do |key, value|
|
|
67
|
+
paramlist << "#{sanitize(key)}=#{sanitize(value)}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
url = '/2.0/?' + paramlist.join('&')
|
|
71
|
+
XML::Document.string(self.connection.send(request_method,url))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def Base.mixins(*args)
|
|
78
|
+
args.each do |arg|
|
|
79
|
+
if arg == :image
|
|
80
|
+
extend Scrobbler::ImageClassFuncs
|
|
81
|
+
include Scrobbler::ImageObjectFuncs
|
|
82
|
+
elsif arg == :streamable
|
|
83
|
+
attr_reader :streamable
|
|
84
|
+
extend StreamableClassFuncs
|
|
85
|
+
include StreamableObjectFuncs
|
|
86
|
+
else
|
|
87
|
+
raise ArgumentError, "#{arg} is not a known mixin"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def populate_data(data = {})
|
|
93
|
+
data.each do |key, value|
|
|
94
|
+
instance_variable_set("@#{key.to_s}", value)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def get_response(api_method, instance_name, parent, element, params, force=false)
|
|
99
|
+
if instance_variable_get("@#{instance_name}").nil? || force
|
|
100
|
+
instance_variable_set("@#{instance_name}", Base.get(api_method, parent, element, params))
|
|
101
|
+
end
|
|
102
|
+
instance_variable_get("@#{instance_name}")
|
|
103
|
+
end
|
|
104
|
+
end # class Base
|
|
105
|
+
end # module Scrobbler
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module Scrobbler
|
|
2
|
+
class Event < Base
|
|
3
|
+
# Load Helper modules
|
|
4
|
+
include ImageObjectFuncs
|
|
5
|
+
extend ImageClassFuncs
|
|
6
|
+
|
|
7
|
+
attr_accessor :id, :title, :start_date, :start_time, :description
|
|
8
|
+
attr_accessor :reviews, :tag, :url, :artists, :headliner, :image_small
|
|
9
|
+
attr_accessor :image_medium, :image_large, :attendance, :venue
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
|
|
13
|
+
def update_or_create_from_xml(xml, event=nil)
|
|
14
|
+
data = {}
|
|
15
|
+
artists = []
|
|
16
|
+
headliner = nil
|
|
17
|
+
venue = nil
|
|
18
|
+
|
|
19
|
+
xml.children.each do |child|
|
|
20
|
+
data[:id] = child.content.to_i if child.name == 'id'
|
|
21
|
+
data[:title] = child.content if child.name == 'title'
|
|
22
|
+
|
|
23
|
+
if child.name == 'artists'
|
|
24
|
+
child.children.each do |artist_element|
|
|
25
|
+
artists << Artist.new(artist_element.content) if artist_element.name == 'artist'
|
|
26
|
+
headliner = Artist.new(artist_element.content) if artist_element.name == 'headliner'
|
|
27
|
+
end
|
|
28
|
+
artists << headliner unless headliner.nil? || headliner_alrady_listed_in_artist_list?(artists,headliner)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
maybe_image_node(data, child)
|
|
32
|
+
data[:url] = child.content if child.name == 'url'
|
|
33
|
+
data[:description] = child.content if child.name == 'description'
|
|
34
|
+
data[:attendance] = child.content.to_i if child.name == 'attendance'
|
|
35
|
+
data[:reviews] = child.content.to_i if child.name == 'reviews'
|
|
36
|
+
data[:tag] = child.content if child.name == 'tag'
|
|
37
|
+
data[:start_date] = Time.parse(child.content) if child.name == 'startDate'
|
|
38
|
+
data[:start_time] = child.content if child.name == 'startTime'
|
|
39
|
+
venue = Venue.new_from_xml(child) if child.name == 'venue'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
if event.nil?
|
|
43
|
+
event = Event.new(data[:id],data)
|
|
44
|
+
else
|
|
45
|
+
event.send :populate_data, data
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
event.artists = artists.uniq
|
|
49
|
+
event.headliner = headliner
|
|
50
|
+
event.venue = venue
|
|
51
|
+
event
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def headliner_alrady_listed_in_artist_list?(artists,headliner)
|
|
55
|
+
artists.each do |artist|
|
|
56
|
+
return true if artist.name == headliner.name
|
|
57
|
+
end
|
|
58
|
+
false
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def new_from_libxml(xml)
|
|
62
|
+
update_or_create_from_xml(xml)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def initialize(id,input={})
|
|
67
|
+
raise ArgumentError if id.blank?
|
|
68
|
+
@id = id
|
|
69
|
+
populate_data(input)
|
|
70
|
+
load_info() if input[:include_info]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def shouts(force = false)
|
|
74
|
+
get_response('event.getshouts', :shouts, 'shouts', 'shout', {'event'=>@id}, force)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def attendees(force = false)
|
|
78
|
+
get_response('event.getattendees', :attendees, 'attendees', 'user', {'event'=>@id}, force)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def shout
|
|
82
|
+
# This function require authentication, but SimpleAuth is not yet 2.0
|
|
83
|
+
raise NotImplementedError
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def attend(session, attendance_status)
|
|
87
|
+
doc = Base.post_request('event.attend',{:event => @id, :signed => true, :status => attendance_status, :sk => session.key})
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def share
|
|
91
|
+
# This function require authentication, but SimpleAuth is not yet 2.0
|
|
92
|
+
raise NotImplementedError
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Load additional informatalbumion about this event
|
|
96
|
+
#
|
|
97
|
+
# Calls "event.getinfo" REST method
|
|
98
|
+
def load_info
|
|
99
|
+
doc = Base.request('event.getinfo', {'event' => @id})
|
|
100
|
+
doc.root.children.each do |child|
|
|
101
|
+
Event.update_or_create_from_xml(child, self) if child.name == 'event'
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Scrobbler
|
|
2
|
+
class Geo < Base
|
|
3
|
+
|
|
4
|
+
# Gets a list of events based on the location that
|
|
5
|
+
# the Geo object is set to
|
|
6
|
+
def events(options={})
|
|
7
|
+
options = set_default_options(options)
|
|
8
|
+
get_response('geo.getevents', :events, 'events', 'event', options, options[:force])
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def top_artists(options={})
|
|
12
|
+
options = set_default_options(options)
|
|
13
|
+
get_response('geo.gettopartists', :artists, 'topartists', 'artist', options, options[:force])
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def top_tracks(options={})
|
|
17
|
+
options = set_default_options(options)
|
|
18
|
+
get_response('geo.gettoptracks', :tracks, 'toptracks', 'track', options, options[:force])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def set_default_options(options={})
|
|
24
|
+
{:force => false, :page => 1}.merge options
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|