scrobbler2 0.0.4

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 (117) hide show
  1. data/.gitignore +1 -0
  2. data/README.rdoc +155 -0
  3. data/Rakefile +8 -0
  4. data/TODO +23 -0
  5. data/VERSION.yml +4 -0
  6. data/generators/acceptance_test/USAGE +9 -0
  7. data/generators/acceptance_test/acceptance_test_generator.rb +57 -0
  8. data/generators/acceptance_test/templates/acceptance_test.rb.erb +14 -0
  9. data/generators/resource/USAGE +8 -0
  10. data/generators/resource/resource_generator.rb +47 -0
  11. data/generators/resource/templates/resource.rb.erb +11 -0
  12. data/generators/resource/templates/spec.rb.erb +22 -0
  13. data/lib/scrobbler2.rb +23 -0
  14. data/lib/scrobbler2/album.rb +11 -0
  15. data/lib/scrobbler2/artist.rb +26 -0
  16. data/lib/scrobbler2/auth.rb +19 -0
  17. data/lib/scrobbler2/base.rb +100 -0
  18. data/lib/scrobbler2/event.rb +12 -0
  19. data/lib/scrobbler2/geo.rb +15 -0
  20. data/lib/scrobbler2/group.rb +14 -0
  21. data/lib/scrobbler2/library.rb +12 -0
  22. data/lib/scrobbler2/playlist.rb +10 -0
  23. data/lib/scrobbler2/tag.rb +18 -0
  24. data/lib/scrobbler2/track.rb +13 -0
  25. data/lib/scrobbler2/user.rb +29 -0
  26. data/lib/scrobbler2/venue.rb +12 -0
  27. data/script/console +10 -0
  28. data/script/destroy +14 -0
  29. data/script/generate +14 -0
  30. data/scrobbler2.gemspec +243 -0
  31. data/tasks/jeweler.rake +15 -0
  32. data/tasks/rcov.rake +9 -0
  33. data/tasks/rdoc.rake +7 -0
  34. data/tasks/tests.rake +10 -0
  35. data/test/acceptance/album/info_test.rb +56 -0
  36. data/test/acceptance/artist/add_tags_test.rb +14 -0
  37. data/test/acceptance/artist/events_test.rb +47 -0
  38. data/test/acceptance/artist/info_test.rb +53 -0
  39. data/test/acceptance/artist/shouts_test.rb +48 -0
  40. data/test/acceptance/artist/similar_artists_test.rb +20 -0
  41. data/test/acceptance/artist/tags_test.rb +24 -0
  42. data/test/acceptance/artist/top_albums_test.rb +34 -0
  43. data/test/acceptance/artist/top_fans.rb +19 -0
  44. data/test/acceptance/artist/top_tags.rb +18 -0
  45. data/test/acceptance/artist/top_tracks.rb +47 -0
  46. data/test/acceptance/auth/auth_test.rb +21 -0
  47. data/test/acceptance/event/info_test.rb +66 -0
  48. data/test/acceptance/event/shouts_test.rb +49 -0
  49. data/test/acceptance/geo/events_test.rb +14 -0
  50. data/test/acceptance/geo/top_artists_test.rb +16 -0
  51. data/test/acceptance/geo/top_tracks_test.rb +16 -0
  52. data/test/acceptance/group/members_test.rb +60 -0
  53. data/test/acceptance/group/weekly_album_chart_test.rb +61 -0
  54. data/test/acceptance/group/weekly_artist_chart_test.rb +54 -0
  55. data/test/acceptance/group/weekly_chart_list_test.rb +39 -0
  56. data/test/acceptance/group/weekly_track_chart_test.rb +61 -0
  57. data/test/acceptance/library/albums_test.rb +34 -0
  58. data/test/acceptance/library/artists_test.rb +33 -0
  59. data/test/acceptance/library/tracks_test.rb +33 -0
  60. data/test/acceptance/playlist/fetch_test.rb +68 -0
  61. data/test/acceptance/shared/album.rb +41 -0
  62. data/test/acceptance/shared/artist.rb +16 -0
  63. data/test/acceptance/shared/paged_result.rb +16 -0
  64. data/test/acceptance/shared/top_fans.rb +29 -0
  65. data/test/acceptance/shared/top_tags.rb +23 -0
  66. data/test/acceptance/shared/track.rb +23 -0
  67. data/test/acceptance/tag/similar_test.rb +15 -0
  68. data/test/acceptance/tag/top_albums_test.rb +37 -0
  69. data/test/acceptance/tag/top_artists_test.rb +31 -0
  70. data/test/acceptance/tag/top_tags_test.rb +32 -0
  71. data/test/acceptance/tag/top_tracks_test.rb +33 -0
  72. data/test/acceptance/tag/weekly_artist_chart.rb +54 -0
  73. data/test/acceptance/tag/weekly_chart_list.rb +39 -0
  74. data/test/acceptance/test_helper.rb +15 -0
  75. data/test/acceptance/track/info_test.rb +47 -0
  76. data/test/acceptance/track/similar_test.rb +22 -0
  77. data/test/acceptance/track/top_fans_test.rb +23 -0
  78. data/test/acceptance/track/top_tags_test.rb +24 -0
  79. data/test/acceptance/user/events_test.rb +27 -0
  80. data/test/acceptance/user/friends_test.rb +14 -0
  81. data/test/acceptance/user/info_test.rb +19 -0
  82. data/test/acceptance/user/loved_tracks_test.rb +14 -0
  83. data/test/acceptance/user/neighbours_test.rb +14 -0
  84. data/test/acceptance/user/past_events_test.rb +14 -0
  85. data/test/acceptance/user/playlists_test.rb +14 -0
  86. data/test/acceptance/user/recent_tracks_test.rb +14 -0
  87. data/test/acceptance/user/recommended_artists_test.rb +16 -0
  88. data/test/acceptance/user/recommended_events_test.rb +16 -0
  89. data/test/acceptance/user/shouts_test.rb +14 -0
  90. data/test/acceptance/user/top_albums_test.rb +14 -0
  91. data/test/acceptance/user/top_artists_test.rb +14 -0
  92. data/test/acceptance/user/top_tags_test.rb +14 -0
  93. data/test/acceptance/user/top_tracks_test.rb +14 -0
  94. data/test/acceptance/user/weekly_album_chart_test.rb +14 -0
  95. data/test/acceptance/user/weekly_artist_chart_test.rb +14 -0
  96. data/test/acceptance/user/weekly_chart_list_test.rb +14 -0
  97. data/test/acceptance/user/weekly_track_chart_test.rb +14 -0
  98. data/test/acceptance/venue/events_test.rb +14 -0
  99. data/test/acceptance/venue/past_events_test.rb +14 -0
  100. data/test/generators/test_acceptance_test_generator.rb +46 -0
  101. data/test/generators/test_generator_helper.rb +29 -0
  102. data/test/generators/test_resource_generator.rb +71 -0
  103. data/test/unit/album_spec.rb +17 -0
  104. data/test/unit/artist_spec.rb +62 -0
  105. data/test/unit/auth_spec.rb +22 -0
  106. data/test/unit/base_spec.rb +193 -0
  107. data/test/unit/event_spec.rb +23 -0
  108. data/test/unit/geo_spec.rb +36 -0
  109. data/test/unit/group_spec.rb +38 -0
  110. data/test/unit/library_spec.rb +27 -0
  111. data/test/unit/playlist_spec.rb +18 -0
  112. data/test/unit/spec_helper.rb +7 -0
  113. data/test/unit/tag_spec.rb +50 -0
  114. data/test/unit/track_spec.rb +33 -0
  115. data/test/unit/user_spec.rb +148 -0
  116. data/test/unit/venue_spec.rb +29 -0
  117. metadata +272 -0
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg
data/README.rdoc ADDED
@@ -0,0 +1,155 @@
1
+ = Scrobbler2
2
+
3
+ Scrobbler2 is a wrapper for the Last.fm web services (http://www.last.fm/api), inspired by Jnunemaker's Original Scrobbler Gem (http://github.com/jnunemaker/scrobbler).
4
+
5
+ == Installation
6
+
7
+ Install via ruby-gems
8
+ sudo gem install gingerhendrix-scrobbler2 --source http://gems.github.com
9
+
10
+ == Requirements
11
+
12
+ Scrobbler2 requires
13
+ * HTTParty (http://github.com/jnunemaker/httparty)
14
+ * ActiveSupport (http://rubyforge.org/projects/activesupport/).
15
+
16
+ = Usage
17
+
18
+ == API Key
19
+
20
+ All last.fm requests require an API Key. Register for an API key at http://www.last.fm/api
21
+
22
+ Scrobbler2::Base.api_key = "abcdefghijklmnopqrstuvwxyz123456"
23
+
24
+ == Authentication
25
+
26
+ Some requests (eg. write requests) require authentication. Authenticated request require an api secret (provided with your api key) and a session key.
27
+
28
+ Scrobbler2::Base.api_secret = "9876543210zyxwvutsrqponmlkjihgfe"
29
+ Scrobbler2::Base.session_key = "qwertyuioplkjhgfdsamnbvcxz"
30
+
31
+ === Obtaining a session key
32
+
33
+ scrobbler2 currently supports last.fm's desktop authentication protocol. In this process
34
+ 1. The app requests a authentication token
35
+ 2. The app sends the user to a last.fm authentication page
36
+ 3. The user agrees to allow the the app acess to their data.
37
+ 4. The app requests a session key.
38
+ 5. The app makes an authenticated request with the session key.
39
+
40
+ auth = Scrobbler2::Auth.new
41
+ token = auth.token
42
+ puts "Auth Token #{token} \n"
43
+ token.should_not be_nil
44
+ puts "Now go to #{auth.url} and authorise\n"
45
+
46
+ gets #Wait for enter
47
+
48
+ session = auth.session
49
+ puts "Session: #{session.inspect} \n"
50
+ session.should be_kind_of(Hash)
51
+ session['key'].should_not be_nil
52
+
53
+ Scrobbler2::Base.session_key = session['key']
54
+ user = Scrobbler2::User.new(username)
55
+ user.info
56
+
57
+ == Users
58
+
59
+ username = 'gingerhendrix'
60
+ user = Scrobbler2::User.new(username)
61
+
62
+ puts "#{username}'s Recent Tracks"
63
+ puts "=" * (username.length + 16)
64
+ user.recent_tracks["track"].each { |t| puts t["name"] }
65
+
66
+ puts
67
+ puts
68
+
69
+ puts "#{username}'s Top Tracks"
70
+ puts "=" * (username.length + 13)
71
+ user.top_tracks["track"].each { |t| puts "(#{t["playcount"]} plays) #{t["name"]}" }
72
+
73
+ == Albums
74
+
75
+ album = Scrobbler2::Album.new('Carrie Underwood', 'Some Hearts')
76
+
77
+ puts "Album: #{album.info["name"]}"
78
+ puts "Artist: #{album.info["artist"]}"
79
+ puts "Listeners: #{album.info["listeners"]}"
80
+ puts "URL: #{album.info["url"]}"
81
+ puts "Release Date: #{album.info["releasedate"]}"
82
+
83
+ puts
84
+ puts
85
+
86
+ puts "Album Tags"
87
+ longest_tag_name = album.info["toptags"]["tag"].collect {|t| t["name"] }.sort {|x, y| y.length <=> x.length }.first.length
88
+ puts "=" * longest_tag_name
89
+ album.info["toptags"]["tag"].each { |t| puts t["name"] }
90
+
91
+ == Artists
92
+
93
+ artist = Scrobbler2::Artist.new('Carrie Underwood')
94
+
95
+ puts 'Top Tracks'
96
+ puts "=" * 10
97
+ artist.top_tracks["track"].each { |t| puts "(#{t["playcount"]} plays) #{t["name"]}" }
98
+
99
+ puts
100
+
101
+ puts 'Similar Artists'
102
+ puts "=" * 15
103
+ artist.info["similar"]["artist"].each { |a| puts "#{a["name"]}" }
104
+
105
+ == Tags
106
+
107
+ tag = Scrobbler2::Tag.new('country')
108
+
109
+ puts 'Top Albums'
110
+ tag.top_albums["album"].each { |a| puts "(#{a["tagcount"]} tags) '#{a["name"]}' by #{a["artist"]["name"]}" }
111
+
112
+ puts
113
+
114
+ puts 'Top Tracks'
115
+ tag.top_tracks.each { |t| puts "(#{t["tagcount"]} tags) '#{t["name"]}' by #{t["artist"]["name"]}" }
116
+
117
+ == Tracks
118
+
119
+ track = Scrobbler2::Track.new('Carrie Underwood', 'Before He Cheats')
120
+ puts 'Fans'
121
+ puts "=" * 4
122
+ puts track.info["listeners"]
123
+
124
+ = Development
125
+
126
+ Scrobbler2 is still in development. If you want to help out please feel free to fork the project on github (http://github.com/gingerhendrix/scrobbler2).
127
+
128
+ == Build and install
129
+ The scrobbler2 gem can be built and installed via rake.
130
+
131
+ rake build # builds the gem (in pkg/)
132
+ rake install # builds and installs the gem (using sudo gem install)
133
+
134
+ == Tests
135
+
136
+ Scrobbler2 has unit and acceptance tests written using RSpec. The tests can be run using rake.
137
+
138
+ rake test:unit # runs the unit tests
139
+ rake test:acceptance # runs the acceptance tests
140
+
141
+ The acceptance tests run against the live last.fm api. You will need to set the api_key and authentication parameters in test/acceptance/test_helper.rb before
142
+ running these tests. You can obtain a session key by running the auth_test, this test is not invoked with the rest of the acceptance suite.
143
+
144
+ ruby test/acceptance/auth/auth_test.rb
145
+
146
+ == Internals
147
+
148
+ Scrobbler2 api methods use a simple set of macros to implement the api. All the hard work goes on in Scrobbler2::Base.
149
+
150
+ == TODO
151
+
152
+ * Write requests.
153
+ * Submissions
154
+ * Radio API
155
+
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'spec/rake/spectask'
5
+
6
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
7
+
8
+ task :default => 'test:unit'
data/TODO ADDED
@@ -0,0 +1,23 @@
1
+ 0.0.5 Release
2
+ Add README
3
+ Merge from VxJasonxV
4
+ Copy examples to /examples
5
+ Add a development section with info about rake tasks etc.
6
+ Look at api_key and secret_key
7
+ Simple website
8
+ Release
9
+ 0.0.6 Release
10
+ Fix auth (so user.getInfo works at least)
11
+ 0.1.0 Release
12
+ Finish API
13
+ Post and Auth Requests
14
+ user.{getInfo|getRemommendedArtists|getRecommendedEvents}
15
+ {artist|album|track}.{get|add|remove}Tag
16
+ {artist|track|event}.share
17
+ track.{love|ban}
18
+ library.add{Artist|Album|Track}
19
+ playlist.{create|addTrack}
20
+ event.attend
21
+ Search Requests
22
+ {album|artist|tag|track|venue}.search
23
+ Release
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 4
3
+ :major: 0
4
+ :minor: 0
@@ -0,0 +1,9 @@
1
+ Description:
2
+ Generate a scrobbler2 acceptance test
3
+
4
+ Usage:
5
+ ./script/generate acceptance_test resource func
6
+
7
+ * resource is a last.fm api resource (eg. user, track etc)
8
+ * func is a last.fm api method (eg. info, similar, top_tags etc)
9
+
@@ -0,0 +1,57 @@
1
+ class AcceptanceTestGenerator < RubiGen::Base
2
+
3
+ # default_options :author => nil
4
+
5
+ attr_reader :resource
6
+ attr_reader :func
7
+
8
+ def initialize(runtime_args, runtime_options = {})
9
+ super
10
+ usage if args.empty? || args.length < 2
11
+ @resource = args.shift
12
+ @func = args.shift
13
+ extract_options
14
+ end
15
+
16
+ def manifest
17
+ record do |m|
18
+ # Ensure appropriate folder(s) exists
19
+ m.directory "test/acceptance/#{@resource}"
20
+
21
+ # Create stubs
22
+ m.template "acceptance_test.rb.erb", "test/acceptance/#{@resource}/#{@func}_test.rb"
23
+ # m.template_copy_each ["template.rb", "template2.rb"]
24
+ # m.template_copy_each ["template.rb", "template2.rb"], "some/path"
25
+ # m.file "file", "some_file_copied"
26
+ # m.file_copy_each ["path/to/file", "path/to/file2"]
27
+ # m.file_copy_each ["path/to/file", "path/to/file2"], "some/path"
28
+ end
29
+ end
30
+
31
+ protected
32
+ def banner
33
+ <<-EOS
34
+ Creates a scrobbler2 acceptance test
35
+
36
+ USAGE: #{$0} #{spec.name} resource func
37
+ EOS
38
+ end
39
+
40
+ def add_options!(opts)
41
+ # opts.separator ''
42
+ # opts.separator 'Options:'
43
+ # For each option below, place the default
44
+ # at the top of the file next to "default_options"
45
+ # opts.on("-a", "--author=\"Your Name\"", String,
46
+ # "Some comment about this option",
47
+ # "Default: none") { |options[:author]| }
48
+ # opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
49
+ end
50
+
51
+ def extract_options
52
+ # for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
53
+ # Templates can access these value via the attr_reader-generated methods, but not the
54
+ # raw instance variable value.
55
+ # @author = options[:author]
56
+ end
57
+ end
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + '/../test_helper.rb'
2
+
3
+ describe "<%=func%> for <%=resource%> ..." do
4
+
5
+ before(:all) do #We only want to hit the webservice once.
6
+ @<%=resource%> = Scrobbler2::<%=resource.classify%>.new "..."
7
+ @<%=func%> = @<%=resource%>.<%=func%>
8
+ end
9
+
10
+ it "should be hash" do
11
+ @<%=func%>.should be_kind_of Hash
12
+ end
13
+
14
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generate a scrobbler2 resource
3
+
4
+ Usage:
5
+ ./script/generate resource resource [funcs]
6
+
7
+ * resource is a last.fm api resource (eg. user, track etc)
8
+ * funcs are a list of last.fm get api method (eg. info, similar, top_tags etc)
@@ -0,0 +1,47 @@
1
+ class ResourceGenerator < RubiGen::Base
2
+
3
+ default_options :author => nil
4
+
5
+ attr_reader :name
6
+ attr_reader :funcs
7
+
8
+ def initialize(runtime_args, runtime_options = {})
9
+ super
10
+ usage if args.empty?
11
+ @name = args.shift
12
+ @funcs = args
13
+ extract_options
14
+ end
15
+
16
+ def manifest
17
+ record do |m|
18
+ # Ensure appropriate folder(s) exists
19
+ m.directory 'lib/scrobbler2'
20
+ m.directory 'test/unit'
21
+
22
+ # Create stubs
23
+ m.template "resource.rb.erb", "lib/scrobbler2/#{name}.rb"
24
+ m.template "spec.rb.erb", "test/unit/#{name}_spec.rb"
25
+
26
+ # Create acceptance tests
27
+ funcs.each do |func|
28
+ m.dependency "acceptance_test", [name, func]
29
+ end
30
+ end
31
+ end
32
+
33
+ protected
34
+ def banner
35
+ <<-EOS
36
+ Creates a scrobbler2 resource
37
+
38
+ USAGE: #{$0} #{spec.name} name funcs
39
+ EOS
40
+ end
41
+
42
+ def add_options!(opts)
43
+ end
44
+
45
+ def extract_options
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ module Scrobbler2
2
+ class <%= name.classify %> < Base
3
+
4
+ def initialize()
5
+ @query = {}#TODO eg. {:artist => artist, :track => track}
6
+ end
7
+ <% funcs.each do |func| %>
8
+ has_resource :<%=func%>, :root => "<%=func.camelize.downcase%>"
9
+ <% end %>
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + "/spec_helper.rb"
2
+
3
+ describe "<%=name.classify%>" do
4
+ before(:each) do
5
+ @<%=name%> = Scrobbler2::<%=name.classify%>.new "..."
6
+ @<%=name%>.class.stub!(:get).and_return Hash.new
7
+ end
8
+
9
+ it "should have a default query {TODO}" do
10
+ @<%=name%>.instance_variable_get(:@query).should == {}
11
+ end
12
+
13
+ <% funcs.each do |func| %>
14
+
15
+ it "<%=func%> should call get with '<%=name%>.get<%=func%>'" do
16
+ @<%=name%>.class.should_receive(:get).with('<%=name%>.get<%=func%>', anything(), anything()).and_return Hash.new
17
+ @<%=name%>.<%=func%>
18
+ end
19
+
20
+ <% end %>
21
+
22
+ end
data/lib/scrobbler2.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'activesupport'
3
+ require 'httparty'
4
+ $: << File.dirname(__FILE__)
5
+
6
+ module Scrobbler2
7
+
8
+ end
9
+
10
+ require 'scrobbler2/base.rb'
11
+ require 'scrobbler2/auth.rb'
12
+ require 'scrobbler2/album.rb'
13
+ require 'scrobbler2/artist.rb'
14
+ require 'scrobbler2/event.rb'
15
+ require 'scrobbler2/geo.rb'
16
+ require 'scrobbler2/group.rb'
17
+ require 'scrobbler2/library.rb'
18
+ require 'scrobbler2/playlist.rb'
19
+ require 'scrobbler2/tag.rb'
20
+ require 'scrobbler2/track.rb'
21
+ require 'scrobbler2/user.rb'
22
+ require 'scrobbler2/venue.rb'
23
+
@@ -0,0 +1,11 @@
1
+ module Scrobbler2
2
+ class Album < Base
3
+
4
+ def initialize(artist, album)
5
+ @query = {:artist => artist, :album => album}
6
+ end
7
+
8
+ has_resource :info, :root => 'album'
9
+
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+
2
+ module Scrobbler2
3
+ class Artist < Base
4
+
5
+ def initialize(artist)
6
+ @query = {:artist => artist}
7
+ end
8
+
9
+ has_resource :events, :root => 'events'
10
+ has_resource :info, :root => 'artist'
11
+ has_resource :shouts, :root => 'shouts'
12
+ has_resource :similar, :root => 'similarartists'
13
+ has_resource :top_albums, :root => 'topalbums'
14
+ has_resource :top_fans, :root => 'topfans'
15
+ has_resource :top_tags, :root => 'toptags'
16
+ has_resource :top_tracks, :root => 'toptracks'
17
+
18
+ has_resource :tags, :root=> "tags", :auth => true
19
+
20
+ def add_tags(tags)
21
+ query = @query.merge :tags => tags.join(",")
22
+ self.class.post_with_auth("artist.addtags", query)
23
+ end
24
+
25
+ end
26
+ end