hornairs-scrobbler 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. data/.gitignore +13 -0
  2. data/.loadpath +5 -0
  3. data/History.txt +5 -0
  4. data/MIT-LICENSE +19 -0
  5. data/Manifest +75 -0
  6. data/README.rdoc +104 -0
  7. data/Rakefile +10 -0
  8. data/VERSION.yml +5 -0
  9. data/examples/album.rb +20 -0
  10. data/examples/artist.rb +13 -0
  11. data/examples/playlist.rb +7 -0
  12. data/examples/scrobble.rb +31 -0
  13. data/examples/tag.rb +11 -0
  14. data/examples/track.rb +12 -0
  15. data/examples/user.rb +15 -0
  16. data/lib/scrobbler.rb +33 -0
  17. data/lib/scrobbler/album.rb +181 -0
  18. data/lib/scrobbler/artist.rb +165 -0
  19. data/lib/scrobbler/auth.rb +47 -0
  20. data/lib/scrobbler/base.rb +105 -0
  21. data/lib/scrobbler/event.rb +105 -0
  22. data/lib/scrobbler/geo.rb +27 -0
  23. data/lib/scrobbler/helper/image.rb +52 -0
  24. data/lib/scrobbler/helper/streamable.rb +40 -0
  25. data/lib/scrobbler/library.rb +112 -0
  26. data/lib/scrobbler/playing.rb +49 -0
  27. data/lib/scrobbler/playlist.rb +87 -0
  28. data/lib/scrobbler/radio.rb +12 -0
  29. data/lib/scrobbler/rest.rb +47 -0
  30. data/lib/scrobbler/scrobble.rb +116 -0
  31. data/lib/scrobbler/session.rb +9 -0
  32. data/lib/scrobbler/shout.rb +21 -0
  33. data/lib/scrobbler/simpleauth.rb +60 -0
  34. data/lib/scrobbler/tag.rb +113 -0
  35. data/lib/scrobbler/track.rb +152 -0
  36. data/lib/scrobbler/user.rb +222 -0
  37. data/lib/scrobbler/venue.rb +67 -0
  38. data/setup.rb +1585 -0
  39. data/tasks/jeweler.rake +15 -0
  40. data/tasks/rdoc.rake +7 -0
  41. data/tasks/tests.rake +13 -0
  42. data/tasks/yardoc.rake +8 -0
  43. data/test/fixtures/xml/album/info.xml +43 -0
  44. data/test/fixtures/xml/artist/fans.xml +52 -0
  45. data/test/fixtures/xml/artist/info.xml +58 -0
  46. data/test/fixtures/xml/artist/similar.xml +1004 -0
  47. data/test/fixtures/xml/artist/topalbums.xml +61 -0
  48. data/test/fixtures/xml/artist/toptags.xml +19 -0
  49. data/test/fixtures/xml/artist/toptracks.xml +62 -0
  50. data/test/fixtures/xml/auth/session.xml +7 -0
  51. data/test/fixtures/xml/auth/token.xml +3 -0
  52. data/test/fixtures/xml/event/attend.xml +3 -0
  53. data/test/fixtures/xml/event/attendees.xml +53 -0
  54. data/test/fixtures/xml/event/event.xml +35 -0
  55. data/test/fixtures/xml/event/shouts.xml +35 -0
  56. data/test/fixtures/xml/geo/events-distance-p1.xml +151 -0
  57. data/test/fixtures/xml/geo/events-lat-long.xml +167 -0
  58. data/test/fixtures/xml/geo/events-p1.xml +152 -0
  59. data/test/fixtures/xml/geo/events-p2.xml +380 -0
  60. data/test/fixtures/xml/geo/events-p3.xml +427 -0
  61. data/test/fixtures/xml/geo/top_artists-p1.xml +76 -0
  62. data/test/fixtures/xml/geo/top_tracks-p1.xml +77 -0
  63. data/test/fixtures/xml/library/albums-f30.xml +454 -0
  64. data/test/fixtures/xml/library/albums-p1.xml +754 -0
  65. data/test/fixtures/xml/library/albums-p2.xml +754 -0
  66. data/test/fixtures/xml/library/albums-p3.xml +754 -0
  67. data/test/fixtures/xml/library/albums-p4.xml +739 -0
  68. data/test/fixtures/xml/library/albums-p5.xml +754 -0
  69. data/test/fixtures/xml/library/albums-p6.xml +754 -0
  70. data/test/fixtures/xml/library/albums-p7.xml +739 -0
  71. data/test/fixtures/xml/library/albums-p8.xml +724 -0
  72. data/test/fixtures/xml/library/artists-f30.xml +334 -0
  73. data/test/fixtures/xml/library/artists-p1.xml +554 -0
  74. data/test/fixtures/xml/library/artists-p2.xml +554 -0
  75. data/test/fixtures/xml/library/artists-p3.xml +554 -0
  76. data/test/fixtures/xml/library/artists-p4.xml +554 -0
  77. data/test/fixtures/xml/library/artists-p5.xml +554 -0
  78. data/test/fixtures/xml/library/artists-p6.xml +554 -0
  79. data/test/fixtures/xml/library/artists-p7.xml +444 -0
  80. data/test/fixtures/xml/library/tracks-f30.xml +472 -0
  81. data/test/fixtures/xml/library/tracks-p1.xml +789 -0
  82. data/test/fixtures/xml/library/tracks-p10.xml +771 -0
  83. data/test/fixtures/xml/library/tracks-p11.xml +792 -0
  84. data/test/fixtures/xml/library/tracks-p12.xml +777 -0
  85. data/test/fixtures/xml/library/tracks-p13.xml +762 -0
  86. data/test/fixtures/xml/library/tracks-p14.xml +759 -0
  87. data/test/fixtures/xml/library/tracks-p15.xml +762 -0
  88. data/test/fixtures/xml/library/tracks-p16.xml +756 -0
  89. data/test/fixtures/xml/library/tracks-p17.xml +780 -0
  90. data/test/fixtures/xml/library/tracks-p18.xml +756 -0
  91. data/test/fixtures/xml/library/tracks-p19.xml +774 -0
  92. data/test/fixtures/xml/library/tracks-p2.xml +765 -0
  93. data/test/fixtures/xml/library/tracks-p20.xml +777 -0
  94. data/test/fixtures/xml/library/tracks-p21.xml +777 -0
  95. data/test/fixtures/xml/library/tracks-p22.xml +771 -0
  96. data/test/fixtures/xml/library/tracks-p23.xml +765 -0
  97. data/test/fixtures/xml/library/tracks-p24.xml +783 -0
  98. data/test/fixtures/xml/library/tracks-p25.xml +777 -0
  99. data/test/fixtures/xml/library/tracks-p26.xml +777 -0
  100. data/test/fixtures/xml/library/tracks-p27.xml +756 -0
  101. data/test/fixtures/xml/library/tracks-p28.xml +771 -0
  102. data/test/fixtures/xml/library/tracks-p29.xml +753 -0
  103. data/test/fixtures/xml/library/tracks-p3.xml +771 -0
  104. data/test/fixtures/xml/library/tracks-p30.xml +780 -0
  105. data/test/fixtures/xml/library/tracks-p31.xml +753 -0
  106. data/test/fixtures/xml/library/tracks-p32.xml +771 -0
  107. data/test/fixtures/xml/library/tracks-p33.xml +762 -0
  108. data/test/fixtures/xml/library/tracks-p34.xml +538 -0
  109. data/test/fixtures/xml/library/tracks-p4.xml +792 -0
  110. data/test/fixtures/xml/library/tracks-p5.xml +780 -0
  111. data/test/fixtures/xml/library/tracks-p6.xml +789 -0
  112. data/test/fixtures/xml/library/tracks-p7.xml +789 -0
  113. data/test/fixtures/xml/library/tracks-p8.xml +780 -0
  114. data/test/fixtures/xml/library/tracks-p9.xml +774 -0
  115. data/test/fixtures/xml/tag/similar.xml +254 -0
  116. data/test/fixtures/xml/tag/topalbums.xml +805 -0
  117. data/test/fixtures/xml/tag/topartists.xml +605 -0
  118. data/test/fixtures/xml/tag/toptags.xml +1254 -0
  119. data/test/fixtures/xml/tag/toptracks.xml +852 -0
  120. data/test/fixtures/xml/track/fans.xml +34 -0
  121. data/test/fixtures/xml/track/info.xml +53 -0
  122. data/test/fixtures/xml/track/toptags.xml +504 -0
  123. data/test/fixtures/xml/user/events.xml +401 -0
  124. data/test/fixtures/xml/user/friends.xml +30 -0
  125. data/test/fixtures/xml/user/lovedtracks.xml +678 -0
  126. data/test/fixtures/xml/user/neighbours.xml +23 -0
  127. data/test/fixtures/xml/user/playlists.xml +61 -0
  128. data/test/fixtures/xml/user/profile.xml +12 -0
  129. data/test/fixtures/xml/user/recentbannedtracks.xml +24 -0
  130. data/test/fixtures/xml/user/recentlovedtracks.xml +24 -0
  131. data/test/fixtures/xml/user/recenttracks.xml +124 -0
  132. data/test/fixtures/xml/user/systemrecs.xml +18 -0
  133. data/test/fixtures/xml/user/topalbums.xml +61 -0
  134. data/test/fixtures/xml/user/topartists.xml +41 -0
  135. data/test/fixtures/xml/user/toptags.xml +44 -0
  136. data/test/fixtures/xml/user/toptracks.xml +65 -0
  137. data/test/fixtures/xml/user/weeklyalbumchart.xml +256 -0
  138. data/test/fixtures/xml/user/weeklyartistchart.xml +220 -0
  139. data/test/fixtures/xml/user/weeklytrackchart.xml +746 -0
  140. data/test/fixtures/xml/venue/events.xml +151 -0
  141. data/test/fixtures/xml/venue/venue.xml +16 -0
  142. data/test/mocks/rest.rb +212 -0
  143. data/test/spec_helper.rb +7 -0
  144. data/test/test_helper.rb +20 -0
  145. data/test/unit/album_spec.rb +52 -0
  146. data/test/unit/artist_spec.rb +130 -0
  147. data/test/unit/auth_spec.rb +36 -0
  148. data/test/unit/event_spec.rb +109 -0
  149. data/test/unit/geo_spec.rb +148 -0
  150. data/test/unit/library_spec.rb +133 -0
  151. data/test/unit/playing_test.rb +53 -0
  152. data/test/unit/playlist_spec.rb +25 -0
  153. data/test/unit/radio_spec.rb +22 -0
  154. data/test/unit/scrobble_spec.rb +55 -0
  155. data/test/unit/scrobble_test.rb +69 -0
  156. data/test/unit/simpleauth_test.rb +45 -0
  157. data/test/unit/tag_spec.rb +101 -0
  158. data/test/unit/track_spec.rb +95 -0
  159. data/test/unit/user_spec.rb +264 -0
  160. data/test/unit/venue_spec.rb +104 -0
  161. 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