billboard 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History ADDED
@@ -0,0 +1 @@
1
+ 0.1.0 - initial release
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Wynn Netherland
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,37 @@
1
+ # billboard
2
+
3
+ Ruby wrapper for the Billboard charts API. Great for cheating at trivia games.
4
+
5
+ ## Installation
6
+
7
+ sudo gem install billboard
8
+
9
+ ## Usage
10
+
11
+ api_key = 'OU812' # get yours at http://developer.billboard.com/apps/register
12
+ client = Billboard::Client.new(api_key)
13
+
14
+ ### Find a chart by type
15
+
16
+ charts = client.chart_specs(:type => 'Videos').charts
17
+
18
+ ### Find items on a chart
19
+
20
+ items = client.search(:id => charts.last.id).chart_items
21
+ items.last.song = "Lost: The Complete Third Season"
22
+ items.last.weeks_on = 21
23
+
24
+ ## Note on Patches/Pull Requests
25
+
26
+ * Fork the project.
27
+ * Make your feature addition or bug fix.
28
+ * Add tests for it. This is important so I don't break it in a
29
+ future version unintentionally.
30
+ * Commit, do not mess with rakefile, version, or history.
31
+ (if you want to have your own version, that is fine but
32
+ bump version in a commit by itself I can ignore when I pull)
33
+ * Send me a pull request. Bonus points for topic branches.
34
+
35
+ ## Copyright
36
+
37
+ Copyright (c) 2009 Wynn Netherland. See LICENSE for details.
@@ -0,0 +1,91 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "billboard"
8
+ gem.summary = %Q{Ruby wrapper for the Billboard charts API}
9
+ gem.description = %Q{Great for cheating at trivia games}
10
+ gem.email = "wynn@squeejee.com"
11
+ gem.homepage = "http://github.com/pengwynn/billboard"
12
+ gem.authors = ["Wynn Netherland"]
13
+ gem.rubyforge_project = "billboard"
14
+ gem.files = FileList["[A-Z]*", "{examples,lib,test}/**/*"]
15
+
16
+ gem.add_dependency('mash', '0.0.3')
17
+ gem.add_dependency('httparty', '0.4.3')
18
+
19
+ gem.add_development_dependency('thoughtbot-shoulda')
20
+ gem.add_development_dependency('jeremymcanally-matchy')
21
+ gem.add_development_dependency('mocha')
22
+ gem.add_development_dependency('fakeweb')
23
+ gem.add_development_dependency('mash')
24
+ end
25
+
26
+ rescue LoadError
27
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
28
+ end
29
+
30
+ require 'rake/testtask'
31
+ Rake::TestTask.new(:test) do |test|
32
+ test.libs << 'lib' << 'test'
33
+ test.pattern = 'test/**/*_test.rb'
34
+ test.verbose = true
35
+ end
36
+
37
+ begin
38
+ require 'rcov/rcovtask'
39
+ Rcov::RcovTask.new do |test|
40
+ test.libs << 'test'
41
+ test.pattern = 'test/**/*_test.rb'
42
+ test.verbose = true
43
+ end
44
+ rescue LoadError
45
+ task :rcov do
46
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
47
+ end
48
+ end
49
+
50
+ task :default => :test
51
+
52
+ require 'rake/rdoctask'
53
+ Rake::RDocTask.new do |rdoc|
54
+ if File.exist?('VERSION.yml')
55
+ config = YAML.load(File.read('VERSION.yml'))
56
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
57
+ else
58
+ version = ""
59
+ end
60
+
61
+ rdoc.rdoc_dir = 'rdoc'
62
+ rdoc.title = "billboard #{version}"
63
+ rdoc.rdoc_files.include('README*')
64
+ rdoc.rdoc_files.include('lib/**/*.rb')
65
+ end
66
+
67
+ begin
68
+ require 'rake/contrib/sshpublisher'
69
+ namespace :rubyforge do
70
+
71
+ desc "Release gem and RDoc documentation to RubyForge"
72
+ task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
73
+
74
+ namespace :release do
75
+ desc "Publish RDoc to RubyForge."
76
+ task :docs => [:rdoc] do
77
+ config = YAML.load(
78
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
79
+ )
80
+
81
+ host = "#{config['username']}@rubyforge.org"
82
+ remote_dir = "/var/www/gforge-projects/remixr/rdoc"
83
+ local_dir = 'rdoc'
84
+
85
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
86
+ end
87
+ end
88
+ end
89
+ rescue LoadError
90
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
91
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :minor: 1
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+
3
+ gem 'mash', '0.0.3'
4
+ require 'mash'
5
+
6
+ gem 'httparty', '0.4.3'
7
+ require 'httparty'
8
+
9
+ gem 'activesupport', '~> 2.3.2'
10
+ require 'activesupport'
11
+
12
+ class APIKeyNotSet < StandardError; end
13
+
14
+ module Billboard
15
+
16
+ # Get your API key from http://developer.billboard.com/apps/register
17
+ def self.api_key
18
+ raise APIKeyNotSet if @api_key.nil?
19
+
20
+ @api_key
21
+ end
22
+
23
+ def self.api_key=(api_key)
24
+ @api_key = api_key
25
+ end
26
+
27
+ end
28
+
29
+ class Hash
30
+
31
+ # Converts all of the keys to strings, optionally formatting key name
32
+ def rubyify_keys!
33
+ keys.each{|k|
34
+ v = delete(k)
35
+ new_key = k.to_s.underscore
36
+ self[new_key] = v
37
+ v.rubyify_keys! if v.is_a?(Hash)
38
+ v.each{|p| p.rubyify_keys! if p.is_a?(Hash)} if v.is_a?(Array)
39
+ }
40
+ self
41
+ end
42
+
43
+ end
44
+
45
+ directory = File.expand_path(File.dirname(__FILE__))
46
+
47
+ require File.join(directory, 'billboard', 'client')
@@ -0,0 +1,85 @@
1
+ module Billboard
2
+ class Client
3
+ include HTTParty
4
+ base_uri 'api.billboard.com/apisvc/chart/v1'
5
+ format :json
6
+
7
+ attr_reader :api_key
8
+
9
+ # Get your api_key found here http://developer.billboard.com/apps/register
10
+ def initialize(api_key=nil)
11
+ @api_key = api_key
12
+ @api_key ||= Billboard.api_key
13
+
14
+ @api_path = ''
15
+
16
+ end
17
+
18
+ # Use this resource to search Billboard data for chart items by
19
+ # id, by date, by artist, or by song.
20
+ #
21
+ # Parameters:
22
+ #
23
+ # id string(optional) Chart spec(format) id - this can be retrieved by spec service
24
+ # start_date string(optional) Chart issue date range start
25
+ # end_date string(optional) Chart issue date range end
26
+ # artist string(optional) Artist name to search
27
+ # song string(optional) Song name to search
28
+ #
29
+ # start default: 1 Start position of raw ResultSet
30
+ # count default: 50 number of data might be returned. Maximum 50
31
+ # sort default: date-, name+ Sort order desired, with "+" or "-" suffix to indicate ascending or descending. For example, date+
32
+ #
33
+ def search(query={})
34
+ results = Mash.new(self.class.get('/list', :query => scrub_query(query))['searchResults']).rubyify_keys!
35
+ results.chart_items = results.delete('chart_item')
36
+ results.chart_items = [] if results.chart_items.nil?
37
+ results
38
+ end
39
+
40
+
41
+ # Get chart data based on chart ID
42
+ #
43
+ # Parameters
44
+ #
45
+ # id String
46
+ #
47
+ def chart(id, query={})
48
+ chart = Mash.new(self.class.get('/item', :query => {:id => id}.merge(query).merge(self.default_options))).chart
49
+ chart.rubyify_keys!
50
+ chart.chart_items.items = chart.chart_items.delete('chart_item')
51
+ chart
52
+ end
53
+
54
+ # This resource returns data on the different chart names
55
+ # and chart types.
56
+ #
57
+ # The API orders the results ascending by ChartSpecId.
58
+ #
59
+ # Parameters
60
+ #
61
+ # name string(optional) chart name, for example: The Billboard Hot 100
62
+ # type string(optional) chart type, for example: Singles
63
+ #
64
+ def chart_specs(query={})
65
+ results = Mash.new(self.class.get('/list/spec', :query => query.merge(self.default_options))['chartSpecs'])
66
+ results.rubyify_keys!
67
+ results.charts = results.delete('chart_spec')
68
+ results
69
+ end
70
+
71
+ protected
72
+
73
+ def default_options
74
+ {:api_key => @api_key, :format => 'json'}
75
+ end
76
+
77
+ def scrub_query(query)
78
+ query[:sdate] = query[:start_date] unless query[:start_date].blank?
79
+ query[:edate] = query[:end_date] unless query[:end_date].blank?
80
+ query[:sort] = query[:sort].gsub('+', ' ') unless query[:sort].blank?
81
+ query.merge(self.default_options)
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class ClientTest < Test::Unit::TestCase
4
+ include Billboard
5
+
6
+ context "Hitting the Billboard API" do
7
+ setup { @client = Billboard::Client.new('OU812') }
8
+
9
+ should "find chart data based on chart id" do
10
+ stub_get 'http://api.billboard.com/apisvc/chart/v1/item?id=3064446&format=json&api_key=OU812', 'chart.json'
11
+ chart = @client.chart(3064446)
12
+ chart.description.should == 'Chart'
13
+ chart.chart_items.items.size.should == 10
14
+ chart.chart_items.items.last.artist_name.should == 'Sade'
15
+ end
16
+
17
+ should "find chart data based on artist name and date range" do
18
+ stub_get 'http://api.billboard.com/apisvc/chart/v1/list?end_date=1975-12-31&format=json&sdate=1975-01-01&artist=Waylon%20Jennings&sort=date%20&edate=1975-12-31&start_date=1975-01-01&api_key=OU812', 'artist_search_with_date_range.json'
19
+ results = @client.search(:artist => 'Waylon Jennings', :start_date => '1975-01-01', :end_date => '1975-12-31', :sort => 'date+')
20
+ results.total_records.should == 927
21
+ results.chart_items.size.should == 50
22
+ results.chart_items.last.song.should == "Sweet Dream Woman"
23
+ results.chart_items.last.weeks_on.should == 13
24
+ end
25
+
26
+ should "find album charts" do
27
+ stub_get 'http://api.billboard.com/apisvc/chart/v1/list/spec?type=album&api_key=OU812&format=json', 'album_charts.json'
28
+ results = @client.chart_specs(:type => 'album')
29
+ results.total_records.should == 589
30
+ results.total_returned.should == 50
31
+ results.charts.last.name.should == 'Latin Rhythm Albums'
32
+
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,257 @@
1
+ {
2
+ "chartSpecs": {
3
+ "firstPosition": 1,
4
+ "totalReturned": 50,
5
+ "chartSpec": [{
6
+ "type": "Albums",
7
+ "name": "Billboard Comprehensive Albums",
8
+ "id": 292
9
+ },
10
+ {
11
+ "type": "Albums",
12
+ "name": "European Top 100 Albums",
13
+ "id": 293
14
+ },
15
+ {
16
+ "type": "Albums",
17
+ "name": "Heatseekers",
18
+ "id": 294
19
+ },
20
+ {
21
+ "type": "Albums",
22
+ "name": "Latin Pop Albums",
23
+ "id": 295
24
+ },
25
+ {
26
+ "type": "Albums",
27
+ "name": "Top Heatseekers (East North Central)",
28
+ "id": 296
29
+ },
30
+ {
31
+ "type": "Albums",
32
+ "name": "Top Heatseekers (Middle Atlantic)",
33
+ "id": 297
34
+ },
35
+ {
36
+ "type": "Albums",
37
+ "name": "Top Heatseekers (Mountain)",
38
+ "id": 298
39
+ },
40
+ {
41
+ "type": "Albums",
42
+ "name": "Top Heatseekers (Northeast)",
43
+ "id": 299
44
+ },
45
+ {
46
+ "type": "Albums",
47
+ "name": "Top Heatseekers (Pacific)",
48
+ "id": 300
49
+ },
50
+ {
51
+ "type": "Albums",
52
+ "name": "Top Heatseekers (South Atlantic)",
53
+ "id": 301
54
+ },
55
+ {
56
+ "type": "Albums",
57
+ "name": "Top Heatseekers (South Central)",
58
+ "id": 302
59
+ },
60
+ {
61
+ "type": "Albums",
62
+ "name": "Top Heatseekers (West North Central)",
63
+ "id": 303
64
+ },
65
+ {
66
+ "type": "Albums",
67
+ "name": "Regional Mexican Albums",
68
+ "id": 304
69
+ },
70
+ {
71
+ "type": "Albums",
72
+ "name": "The Billboard 200",
73
+ "id": 305
74
+ },
75
+ {
76
+ "type": "Albums",
77
+ "name": "The Billboard Classical 50",
78
+ "id": 306
79
+ },
80
+ {
81
+ "type": "Albums",
82
+ "name": "Top Bluegrass Albums",
83
+ "id": 307
84
+ },
85
+ {
86
+ "type": "Albums",
87
+ "name": "Top Blues Albums",
88
+ "id": 308
89
+ },
90
+ {
91
+ "type": "Albums",
92
+ "name": "Top Canadian Albums",
93
+ "id": 309
94
+ },
95
+ {
96
+ "type": "Albums",
97
+ "name": "Top Christian Albums",
98
+ "id": 310
99
+ },
100
+ {
101
+ "type": "Albums",
102
+ "name": "Top Classical Albums",
103
+ "id": 311
104
+ },
105
+ {
106
+ "type": "Albums",
107
+ "name": "Top Classical Budget Albums",
108
+ "id": 312
109
+ },
110
+ {
111
+ "type": "Albums",
112
+ "name": "Top Classical Crossover Albums",
113
+ "id": 313
114
+ },
115
+ {
116
+ "type": "Albums",
117
+ "name": "Top Classical Midline Albums",
118
+ "id": 314
119
+ },
120
+ {
121
+ "type": "Albums",
122
+ "name": "Top Comedy Albums",
123
+ "id": 315
124
+ },
125
+ {
126
+ "type": "Albums",
127
+ "name": "Top Compilation Albums",
128
+ "id": 316
129
+ },
130
+ {
131
+ "type": "Albums",
132
+ "name": "Top Contemporary Christian",
133
+ "id": 317
134
+ },
135
+ {
136
+ "type": "Albums",
137
+ "name": "Top Contemporary Jazz",
138
+ "id": 318
139
+ },
140
+ {
141
+ "type": "Albums",
142
+ "name": "Top Contemporary Jazz Albums",
143
+ "id": 319
144
+ },
145
+ {
146
+ "type": "Albums",
147
+ "name": "Top Country Albums",
148
+ "id": 320
149
+ },
150
+ {
151
+ "type": "Albums",
152
+ "name": "Top Country Catalog Albums",
153
+ "id": 321
154
+ },
155
+ {
156
+ "type": "Albums",
157
+ "name": "Top Electronic Albums",
158
+ "id": 322
159
+ },
160
+ {
161
+ "type": "Albums",
162
+ "name": "Top Gospel Albums",
163
+ "id": 323
164
+ },
165
+ {
166
+ "type": "Albums",
167
+ "name": "Top Heatseekers",
168
+ "id": 324
169
+ },
170
+ {
171
+ "type": "Albums",
172
+ "name": "Top Holiday Albums",
173
+ "id": 325
174
+ },
175
+ {
176
+ "type": "Albums",
177
+ "name": "Top Independent Albums",
178
+ "id": 326
179
+ },
180
+ {
181
+ "type": "Albums",
182
+ "name": "Top Internet Albums",
183
+ "id": 327
184
+ },
185
+ {
186
+ "type": "Albums",
187
+ "name": "Top Jazz Albums",
188
+ "id": 328
189
+ },
190
+ {
191
+ "type": "Albums",
192
+ "name": "Top Kid Audio",
193
+ "id": 329
194
+ },
195
+ {
196
+ "type": "Albums",
197
+ "name": "Top Latin Albums",
198
+ "id": 330
199
+ },
200
+ {
201
+ "type": "Albums",
202
+ "name": "Top New Age Albums",
203
+ "id": 331
204
+ },
205
+ {
206
+ "type": "Albums",
207
+ "name": "Top Pop Catalog",
208
+ "id": 332
209
+ },
210
+ {
211
+ "type": "Albums",
212
+ "name": "Top R&B\/Hip-Hop Albums",
213
+ "id": 333
214
+ },
215
+ {
216
+ "type": "Albums",
217
+ "name": "Top R&B\/Hip-Hop Catalog Albums",
218
+ "id": 334
219
+ },
220
+ {
221
+ "type": "Albums",
222
+ "name": "Top Rap Albums",
223
+ "id": 335
224
+ },
225
+ {
226
+ "type": "Albums",
227
+ "name": "Top Reggae Albums",
228
+ "id": 336
229
+ },
230
+ {
231
+ "type": "Albums",
232
+ "name": "Top Soundtracks",
233
+ "id": 337
234
+ },
235
+ {
236
+ "type": "Albums",
237
+ "name": "Latin Tropical Albums",
238
+ "id": 338
239
+ },
240
+ {
241
+ "type": "Albums",
242
+ "name": "Top World Albums",
243
+ "id": 339
244
+ },
245
+ {
246
+ "type": "Albums",
247
+ "name": "Tropical\/Salsa",
248
+ "id": 340
249
+ },
250
+ {
251
+ "type": "Albums",
252
+ "name": "Latin Rhythm Albums",
253
+ "id": 399
254
+ }],
255
+ "totalRecords": 589
256
+ }
257
+ }