shortwave 0.0.1

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.
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