shortwave 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/.document +5 -0
  2. data/.gitignore +10 -0
  3. data/.gitmodules +3 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +74 -0
  6. data/Rakefile +133 -0
  7. data/VERSION +1 -0
  8. data/lib/shortwave.rb +12 -0
  9. data/lib/shortwave/authentication.rb +107 -0
  10. data/lib/shortwave/facade.rb +3 -0
  11. data/lib/shortwave/facade/build/facade_builder.rb +199 -0
  12. data/lib/shortwave/facade/build/facade_template.erb +17 -0
  13. data/lib/shortwave/facade/lastfm.rb +878 -0
  14. data/lib/shortwave/facade/remote.rb +86 -0
  15. data/lib/shortwave/model/album.rb +33 -0
  16. data/lib/shortwave/model/artist.rb +62 -0
  17. data/lib/shortwave/model/base_model.rb +112 -0
  18. data/lib/shortwave/model/chart_dates.rb +15 -0
  19. data/lib/shortwave/model/comparison.rb +15 -0
  20. data/lib/shortwave/model/event.rb +55 -0
  21. data/lib/shortwave/model/group.rb +26 -0
  22. data/lib/shortwave/model/location.rb +45 -0
  23. data/lib/shortwave/model/playlist.rb +36 -0
  24. data/lib/shortwave/model/shout.rb +21 -0
  25. data/lib/shortwave/model/tag.rb +47 -0
  26. data/lib/shortwave/model/track.rb +71 -0
  27. data/lib/shortwave/model/user.rb +70 -0
  28. data/lib/shortwave/model/venue.rb +37 -0
  29. data/lib/shortwave/model/weekly_charts.rb +31 -0
  30. data/lib/shortwave/providers.rb +161 -0
  31. data/shortwave.gemspec +178 -0
  32. data/test/authentication_test.rb +64 -0
  33. data/test/build/build_test.rb +25 -0
  34. data/test/build/data/intro.yml +2 -0
  35. data/test/build/data/screens/album_addTags.html +1238 -0
  36. data/test/build/data/screens/intro_truncated.html +426 -0
  37. data/test/build/data/screens/tasteometer_compare.html +1274 -0
  38. data/test/build/data/screens/user_getLovedTracks.html +1278 -0
  39. data/test/build/data/screens/venue_search.html +1261 -0
  40. data/test/build/facade_builder_test.rb +23 -0
  41. data/test/build/parameter_test.rb +43 -0
  42. data/test/build/remote_method_test.rb +47 -0
  43. data/test/build/ruby_class_test.rb +12 -0
  44. data/test/build/ruby_method_test.rb +137 -0
  45. data/test/helper.rb +35 -0
  46. data/test/model/album_test.rb +62 -0
  47. data/test/model/artist_test.rb +103 -0
  48. data/test/model/chart_dates_test.rb +11 -0
  49. data/test/model/comparison_test.rb +18 -0
  50. data/test/model/data/album_info.xml +38 -0
  51. data/test/model/data/album_search.xml +210 -0
  52. data/test/model/data/artist_info.xml +58 -0
  53. data/test/model/data/artist_search.xml +109 -0
  54. data/test/model/data/artist_shouts.xml +546 -0
  55. data/test/model/data/artist_top_fans.xml +405 -0
  56. data/test/model/data/event_info.xml +47 -0
  57. data/test/model/data/group_members.xml +242 -0
  58. data/test/model/data/group_weekly_album_chart.xml +1754 -0
  59. data/test/model/data/group_weekly_artist_chart.xml +604 -0
  60. data/test/model/data/group_weekly_track_chart.xml +1005 -0
  61. data/test/model/data/location_events.xml +383 -0
  62. data/test/model/data/ok.xml +2 -0
  63. data/test/model/data/playlist_fetch.xml +227 -0
  64. data/test/model/data/tag_search.xml +110 -0
  65. data/test/model/data/tag_similar.xml +254 -0
  66. data/test/model/data/tag_top_albums.xml +805 -0
  67. data/test/model/data/tag_top_artists.xml +605 -0
  68. data/test/model/data/tag_top_tags.xml +1254 -0
  69. data/test/model/data/tag_top_tracks.xml +843 -0
  70. data/test/model/data/tag_weekly_chart_list.xml +57 -0
  71. data/test/model/data/tasteometer_compare.xml +54 -0
  72. data/test/model/data/track_info.xml +53 -0
  73. data/test/model/data/track_search.xml +195 -0
  74. data/test/model/data/user_chartlist.xml +90 -0
  75. data/test/model/data/user_info.xml +16 -0
  76. data/test/model/data/user_neighbours.xml +484 -0
  77. data/test/model/data/user_playlists.xml +17 -0
  78. data/test/model/data/user_recent_tracks.xml +124 -0
  79. data/test/model/data/user_recommended_artists.xml +454 -0
  80. data/test/model/data/user_shouts.xml +9 -0
  81. data/test/model/data/user_weekly_artist_chart.xml +478 -0
  82. data/test/model/data/venue_events.xml +556 -0
  83. data/test/model/data/venue_past_events.xml +1778 -0
  84. data/test/model/data/venue_search.xml +355 -0
  85. data/test/model/event_test.rb +63 -0
  86. data/test/model/group_test.rb +45 -0
  87. data/test/model/location_test.rb +25 -0
  88. data/test/model/playlist_test.rb +51 -0
  89. data/test/model/shout_test.rb +23 -0
  90. data/test/model/tag_test.rb +39 -0
  91. data/test/model/track_test.rb +67 -0
  92. data/test/model/user_test.rb +125 -0
  93. data/test/model/venue_test.rb +60 -0
  94. data/test/provider/album_provider_test.rb +26 -0
  95. data/test/provider/artist_provider_test.rb +25 -0
  96. data/test/provider/group_provider_test.rb +9 -0
  97. data/test/provider/location_provider_test.rb +9 -0
  98. data/test/provider/playlist_provider_test.rb +12 -0
  99. data/test/provider/tag_provider_test.rb +24 -0
  100. data/test/provider/track_provider_test.rb +26 -0
  101. data/test/provider/user_provider_test.rb +11 -0
  102. data/test/provider/venue_provider_test.rb +15 -0
  103. data/test/provider_test_helper.rb +27 -0
  104. data/test/remote_test.rb +26 -0
  105. metadata +209 -0
@@ -0,0 +1,36 @@
1
+ module Shortwave
2
+ module Model
3
+ # A playlist
4
+ #
5
+ # === Attributes
6
+ #
7
+ # +id+:: id
8
+ # +title+:: title
9
+ # +description+:: description
10
+ # +created_at+:: Creation time
11
+ # +size+:: Number of tracks in the playlist
12
+ # +duration+:: length in milliseconds of the playlist
13
+ # +creator_url+:: Last.fm url of creator
14
+ # +url+:: Last.fm url of playlist
15
+ class Playlist < BaseModel
16
+ element :id, Integer
17
+ element :title, String
18
+ element :description, String
19
+ element :created_at, Time, :tag => "date"
20
+ element :size, Integer
21
+ element :duration, Integer
22
+ element :streamable, Boolean
23
+ element :creator_url, String, :tag => "creator"
24
+ element :url, String
25
+
26
+ def streamable?
27
+ @streamable
28
+ end
29
+
30
+ # This can only be called on a user's own playlist
31
+ def add_track(track)
32
+ @session.playlist_facade.add_track(id, track.name, track.artist_name)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,21 @@
1
+ module Shortwave
2
+ module Model
3
+ # A shout message on Last.fm
4
+ #
5
+ # === Attributes
6
+ #
7
+ # +message+:: The message text
8
+ # +time+:: The time the message was written
9
+ class Shout < BaseModel
10
+ tag "shout"
11
+ element :message, String, :tag => "body"
12
+ element :time, Time, :tag => "date"
13
+ element :author, String
14
+
15
+ # The user who left the shout message
16
+ def user
17
+ @user ||= @session.user.build(:name => author)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ module Shortwave
2
+ module Model
3
+ # A Last.fm tag
4
+ #
5
+ # ===Attributes
6
+ #
7
+ # +name+:: Tag text
8
+ # +count+:: Number of times this tag has been applied
9
+ # +url+:: URL on Last.fm site
10
+ class Tag < BaseModel
11
+ element :name, String
12
+ element :count, Integer
13
+ element :url, String
14
+ element :streamable, Boolean
15
+
16
+ # Can music be streamed from this tag?
17
+ def streamable?
18
+ streamable
19
+ end
20
+
21
+ # Returns similar tags to this one.
22
+ def similar
23
+ link :similar, :Tag, name
24
+ end
25
+
26
+ # Returns the most popular albums tagged with this tag.
27
+ def albums
28
+ link :top_albums, :Album, name
29
+ end
30
+
31
+ # Returns the most popular artists tagged with this tag.
32
+ def artists
33
+ link :top_artists, :Artist, name
34
+ end
35
+
36
+ # Returns the most popular tracks tagged with this tag.
37
+ def tracks
38
+ link :top_tracks, :Track, name
39
+ end
40
+
41
+ # Returns the tag text
42
+ def to_s
43
+ name
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,71 @@
1
+ module Shortwave
2
+ module Model
3
+ # A track. Tracks are taggable and sharable.
4
+ #
5
+ # === Attributes
6
+ #
7
+ # +name+:: Track name
8
+ # +id+:: Last.fm id
9
+ # +mbid+:: Musicbrainz ID
10
+ # +listeners+:: number of listeners
11
+ # +play_count+:: number of times played
12
+ # +duration+:: Track duration in milliseconds
13
+ # +url+:: Track url on Last.fm
14
+ # +artist+:: Track's artist
15
+ # +album+:: Album track appears on.
16
+ class Track < BaseModel
17
+ element :name, String
18
+ element :id, Integer
19
+ element :listeners, Integer
20
+ element :play_count, Integer, :tag => "playcount"
21
+ element :mbid, String
22
+ element :duration, Integer
23
+ element :url, String
24
+ element :streamable, Boolean
25
+ has_one :artist, Artist
26
+ has_one :album, Album
27
+
28
+ identified_by "artist.name", :name
29
+ taggable
30
+ sharable
31
+
32
+ # The most popular tags applied to this track
33
+ def tags
34
+ link :top_tags, :Tag, identifiers
35
+ end
36
+
37
+ # This track's fans
38
+ def fans
39
+ link :top_fans, :User, identifiers
40
+ end
41
+
42
+ # Similar tracks to this one.
43
+ def similar
44
+ link :similar, :Track, identifiers
45
+ end
46
+
47
+ # Love this track
48
+ def love
49
+ @session.track_facade.ban(name, artist.name)
50
+ # TODO include scrobble api call
51
+ end
52
+
53
+ # Don't play this track again.
54
+ def ban
55
+ @session.track_facade.love(name, artist.name)
56
+ # TODO include scrobble api call
57
+ end
58
+
59
+ # Can this track be streamed
60
+ def streamable?
61
+ @streamable
62
+ end
63
+
64
+ private
65
+
66
+ def identifiers
67
+ mbid && ! mbid.empty?() ? {:mbid => mbid} : {:artist => artist.name, :track => name}
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,70 @@
1
+ module Shortwave
2
+ module Model
3
+ class User < BaseModel
4
+ element :name, String
5
+ element :id, Integer
6
+ element :real_name, String, :tag => "realname"
7
+ element :url, String
8
+ element :image, String
9
+ element :language, String, :tag => "lang"
10
+ element :country, String
11
+ element :age, Integer
12
+ element :gender, String
13
+ element :subscriber, Boolean
14
+ element :play_count, Integer, :tag => "playcount"
15
+
16
+ identified_by :name
17
+ shoutable
18
+ include WeeklyCharts
19
+
20
+ # Returns the events that this user is attending.
21
+ def events
22
+ link :events, :Event, name
23
+ end
24
+
25
+ # Returns the events a user has attended.
26
+ def past_events
27
+ link :past_events, :Event, name
28
+ end
29
+
30
+ # Returns the recent tracks played by this user.
31
+ def recent_tracks
32
+ link :recent_tracks, :Track, name
33
+ end
34
+
35
+ # Returns tracks a user has "loved".
36
+ def loved_tracks
37
+ link :loved_tracks, :Track, name
38
+ end
39
+
40
+ # Returns other Last.fm users with similar taste to this user.
41
+ def neighbours
42
+ link :neighbours, :User, name
43
+ end
44
+
45
+ # Returns the first 50 of a user's friends on Last.fm
46
+ def friends
47
+ link :friends, :User, name
48
+ end
49
+
50
+ # Returns a user's playlists
51
+ def playlists
52
+ link :playlists, :Playlist, name
53
+ end
54
+
55
+ # Returns events this user may be interested in.
56
+ def recommended_events
57
+ link :recommended_events, :Event
58
+ end
59
+
60
+ # Returns the first 50 artists this user may be interested in.
61
+ def recommended_artists
62
+ link :recommended_artists, :Artist
63
+ end
64
+
65
+ def compare_with(other_user)
66
+ Comparison.parse(@session.tasteometer_facacde.compare("user", "user", name, other_user.name), :single => true)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,37 @@
1
+ require 'forwardable'
2
+
3
+ module Shortwave
4
+ module Model
5
+ # A venue that hosts events.
6
+ #
7
+ # === Attributes
8
+ #
9
+ # +id+:: Last.fm id
10
+ # +name+:: Venue name
11
+ # +url+:: Venue url on Last.fm
12
+ # +location+:: Venue's location
13
+ # +city+:: Venue city
14
+ # +street_address+:: Venue street address
15
+ # +country+:: Venue country
16
+ # +postcode+:: Venue post code
17
+ class Venue < BaseModel
18
+ extend Forwardable
19
+ def_delegators(:location, :city, :street_address, :country, :postcode)
20
+
21
+ element :id, Integer
22
+ element :name, String
23
+ element :url, String
24
+ has_one :location, "Shortwave::Model::Location"
25
+
26
+ # Returns events showing at this venue.
27
+ def events
28
+ link :events, :Event, id
29
+ end
30
+
31
+ # Returns past events from this venue.
32
+ def past_events
33
+ link :past_events, :Event, id
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,31 @@
1
+ module Shortwave
2
+ module Model
3
+ module WeeklyCharts
4
+ # Returns the most popular albums from this group for the last week
5
+ def album_chart
6
+ link :weekly_album_chart, "Album", name
7
+ end
8
+
9
+ # Returns the most popular artists from this group for the last week
10
+ def artist_chart
11
+ link :weekly_artist_chart, "Artist", name
12
+ end
13
+
14
+ # Returns the most popular tracks from this group for the last week
15
+ def track_chart
16
+ link :weekly_track_chart, "Track", name
17
+ end
18
+
19
+ # Returns an array of Time ranges, repesenting the weeks charts are available
20
+ def chart_dates
21
+ @chart_dates ||= charts.map {|cd| cd.from..cd.to }.reverse
22
+ end
23
+
24
+ private
25
+
26
+ def charts
27
+ @charts ||= link :weekly_chart_list, "ChartDates", name
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,161 @@
1
+ module Shortwave
2
+ module Provider
3
+ # Intended to be mixed in to authentication classes
4
+ module ProviderMethods
5
+ [:album, :artist, :group, :location, :playlist, :track, :tag, :user, :venue].each do |name|
6
+ klass_name = name.to_s.capitalize
7
+ module_eval <<-EOV
8
+ def #{name}
9
+ @#{name}_provider ||= Provider::#{klass_name}Provider.new(#{name}_facade)
10
+ end
11
+
12
+ def #{name}_facade
13
+ @#{name}_facade ||= Facade::#{klass_name}.new(self)
14
+ end
15
+ EOV
16
+ end
17
+
18
+ def event_facade
19
+ @event_facade ||= Facade::Event.new(self)
20
+ end
21
+
22
+ def location_facade
23
+ @location_facade ||= Facade::Geo.new(self)
24
+ end
25
+
26
+ def tasteometer_facacde
27
+ @tasteometer_facade ||= Facade::Tasteometer.new(self)
28
+ end
29
+ end
30
+
31
+
32
+ # You should generally use an instance of this class provided by a session:
33
+ # session.album
34
+ class BaseProvider
35
+ # Creates a provider with a facade
36
+ def initialize(facade)
37
+ @klass = Model.const_get(self.class.name.split("::").last.sub("Provider",''))
38
+ @facade = facade
39
+ end
40
+
41
+ # Builds a model object.
42
+ def build(attributes)
43
+ model = @klass.new
44
+ attributes.each {|attr, value| model.send("#{attr}=".to_sym, value) }
45
+ model.session = @facade.session
46
+ model
47
+ end
48
+
49
+ protected
50
+
51
+ # Defines a search method on this provider
52
+ def self.searchable
53
+ define_method :search do |name|
54
+ parse_collection @facade.search(name)
55
+ end
56
+ end
57
+
58
+ def self.identifiable_by_mbid
59
+ define_method :get_by_id do |mbid|
60
+ mbid = mbid.uuid if mbid.respond_to? :uuid
61
+ parse_model @facade.info(:mbid => mbid)
62
+ end
63
+ end
64
+
65
+ # Parses an xml response into a Shortwave::Model::* object
66
+ def parse_model(response)
67
+ model = @klass.parse(response, :single => true)
68
+ model.session = @facade.session
69
+ model
70
+ end
71
+
72
+ # Parses an xml response into an array of Shortwave::Model::* objects
73
+ def parse_collection(response)
74
+ @klass.parse(response).each {|model| model.session = @facade.session }
75
+ end
76
+ end
77
+
78
+ class PlaylistProvider < BaseProvider
79
+ def create(title, description=nil)
80
+ hsh = description ? {:description => description} : {}
81
+ parse_model @facade.create(hsh.merge(:title => title))
82
+ end
83
+ end
84
+
85
+ # Produces album objects.
86
+ class AlbumProvider < BaseProvider
87
+ searchable
88
+ identifiable_by_mbid
89
+
90
+ # Gets an album, given an artist name and an album name
91
+ def get(artist, name)
92
+ parse_model @facade.info(:artist => artist, :album => name)
93
+ end
94
+ end
95
+
96
+
97
+ # Produces artist objects.
98
+ class ArtistProvider < BaseProvider
99
+ searchable
100
+ identifiable_by_mbid
101
+
102
+ def get(artist)
103
+ parse_model @facade.info(:artist => artist)
104
+ end
105
+ end
106
+
107
+
108
+ class GroupProvider < BaseProvider
109
+ end
110
+
111
+
112
+ # Locations can only be built
113
+ class LocationProvider < BaseProvider
114
+ end
115
+
116
+
117
+ # Produces Tag objects
118
+ class TagProvider < BaseProvider
119
+ searchable
120
+
121
+ # Returns a tag named "name"
122
+ def get(name)
123
+ parse_model @facade.search(name)
124
+ end
125
+
126
+ # Returns the most popular tags from Last.fm
127
+ def popular
128
+ parse_collection @facade.top_tags
129
+ end
130
+ end
131
+
132
+
133
+ # Produces track objects.
134
+ class TrackProvider < BaseProvider
135
+ searchable
136
+ identifiable_by_mbid
137
+
138
+ # Gets a track, given an artist name and a track name
139
+ def get(artist, name)
140
+ parse_model @facade.info(:artist => artist, :track => name)
141
+ end
142
+ end
143
+
144
+
145
+ # Produces Venue objects
146
+ class VenueProvider < BaseProvider
147
+ def search(name, country=nil)
148
+ hsh = {}
149
+ hsh[:country] = country if country
150
+ parse_collection @facade.search(name, hsh)
151
+ end
152
+ end
153
+
154
+
155
+ class UserProvider < BaseProvider
156
+ def logged_in_user
157
+ parse_model @facade.info
158
+ end
159
+ end
160
+ end
161
+ end