bandsintown 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ == 0.1.1 2009-09-08
2
+ * fixed escaping issue with / and ? in artist urls
3
+
4
+ == 0.1.0 2009-09-05
5
+ * Full Bandsintown API support
6
+ * Added Artists - Events API method
7
+ * Added Events - Recommended API method
8
+ * Updated Bandsintown::Connection class
9
+ * Added attributes for on_sale_datetime and ticket_status to Bandsintown::Event class
10
+ * Lots of documentation
11
+
12
+ == 0.0.2 2009-06-03
13
+ * Added the daily events API method
14
+
15
+ == 0.0.1 2009-02-20
16
+
17
+ * 1 major enhancement:
18
+ * Initial release
@@ -0,0 +1,27 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ lib/bandsintown.rb
6
+ lib/bandsintown/artist.rb
7
+ lib/bandsintown/base.rb
8
+ lib/bandsintown/connection.rb
9
+ lib/bandsintown/event.rb
10
+ lib/bandsintown/venue.rb
11
+ script/console
12
+ script/destroy
13
+ script/generate
14
+ script/txt2html
15
+ spec/bandsintown/artist_spec.rb
16
+ spec/bandsintown/base_spec.rb
17
+ spec/bandsintown/connection_spec.rb
18
+ spec/bandsintown/event_spec.rb
19
+ spec/bandsintown/venue_spec.rb
20
+ spec/bandsintown_spec.rb
21
+ spec/spec.opts
22
+ spec/spec_helper.rb
23
+ website/index.html
24
+ website/index.txt
25
+ website/javascripts/rounded_corners_lite.inc.js
26
+ website/stylesheets/screen.css
27
+ website/template.html.erb
@@ -0,0 +1,88 @@
1
+ = bandsintown
2
+
3
+ == Description
4
+
5
+ Bandsintown.com API gem
6
+
7
+ A Ruby library for accessing the Bandsintown API.
8
+
9
+ The Bandsintown API lets any developer access the largest database of upcoming concert listings and concert tickets in the world.
10
+
11
+ For more information visit http://www.bandsintown.com/api/requests.
12
+
13
+ == Installing
14
+
15
+ sudo gem install bandsintown
16
+
17
+ == Usage
18
+
19
+ === Requiring
20
+
21
+ require 'bandsintown'
22
+
23
+ === Setting the bandsintown app_id parameter
24
+
25
+ Bandsintown.app_id = 'YOUR_APP_ID'
26
+
27
+ === Find all upcoming events for a given artist
28
+
29
+ artist = Bandsintown::Artist.new("The Killers")
30
+ events = artist.events
31
+
32
+ === Find events this week around Boston, MA
33
+
34
+ events = Bandsintown::Event.search({
35
+ :location => 'Boston, MA',
36
+ :start_date => Time.now,
37
+ :end_date => 1.week.from_now
38
+ })
39
+
40
+ === Find events this week for Mos Def and Talib Kweli
41
+
42
+ events = Bandsintown::Event.search({
43
+ :artists => ['Mos Def', 'Talib Kweli'],
44
+ :start_date => Time.now,
45
+ :end_date => 1.week.from_now
46
+ })
47
+
48
+ === Find recommended events around Boston, MA for fans of Led Zeppelin
49
+
50
+ events = Bandsintown::Event.recommended({
51
+ :artists => ['Led Zeppelin'],
52
+ :location => 'Boston, MA'
53
+ })
54
+
55
+ === find events added/updated/deleted within the last day
56
+
57
+ events = Bandsintown::Event.daily
58
+
59
+ == Links
60
+
61
+ * RDoc[http://bandsintown.rubyforge.org/rdoc]
62
+ * {Bandsintown.com API Documentation}[http://www.bandsintown.com/api/requests]
63
+ * Github[http://github.com/bandsintown/bandsintown]
64
+
65
+ == LICENSE:
66
+
67
+ (The MIT License)
68
+
69
+ Copyright (c) 2009 Mike Costanza
70
+
71
+ Permission is hereby granted, free of charge, to any person obtaining
72
+ a copy of this software and associated documentation files (the
73
+ 'Software'), to deal in the Software without restriction, including
74
+ without limitation the rights to use, copy, modify, merge, publish,
75
+ distribute, sublicense, and/or sell copies of the Software, and to
76
+ permit persons to whom the Software is furnished to do so, subject to
77
+ the following conditions:
78
+
79
+ The above copyright notice and this permission notice shall be
80
+ included in all copies or substantial portions of the Software.
81
+
82
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
83
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
84
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
85
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
86
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
87
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
88
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/bandsintown'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('bandsintown', Bandsintown::VERSION) do |p|
7
+ p.developer('Mike Costanza', 'mike@bandsintown.com')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ p.rubyforge_name = p.name # TODO this is default value
10
+ p.extra_deps = [
11
+ ['activesupport','>= 2.0.2'],
12
+ ['json', '>= 1.1.3']
13
+ ]
14
+ p.extra_dev_deps = [
15
+ ['newgem', ">= #{::Newgem::VERSION}"]
16
+ ]
17
+
18
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
19
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
20
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
21
+ p.rsync_args = '-av --delete --ignore-errors'
22
+ end
23
+
24
+ require 'newgem/tasks' # load /tasks/*.rake
25
+ Dir['tasks/**/*.rake'].each { |t| load t }
26
+
27
+ # TODO - want other tests/tasks run by default? Add them to the list
28
+ # task :default => [:spec, :features]
@@ -0,0 +1,27 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'rubygems'
5
+ require 'open-uri'
6
+ require 'cgi'
7
+ require 'activesupport'
8
+ require 'json'
9
+
10
+ require 'bandsintown/base'
11
+ require 'bandsintown/connection'
12
+ require 'bandsintown/artist'
13
+ require 'bandsintown/event'
14
+ require 'bandsintown/venue'
15
+
16
+ module Bandsintown
17
+ VERSION = '0.1.1'
18
+ class APIError < StandardError; end
19
+ class << self
20
+ # All Bandsintown API requests require an app_id parameter for identification.
21
+ # See http://www.bandsintown.com/api/authentication for more information.
22
+ #
23
+ attr_accessor :app_id
24
+ end
25
+ end
26
+
27
+
@@ -0,0 +1,49 @@
1
+ module Bandsintown
2
+ class Artist < Base
3
+
4
+ attr_accessor :name, :events
5
+
6
+ def initialize(name, url = nil)
7
+ @name = name
8
+ @bandsintown_url = url || build_bandsintown_url
9
+ end
10
+
11
+ #Returns an array of Bandsintown::Event objects for each of the artist's upcoming events available through bandsintown.com.
12
+ #See http://www.bandsintown.com/api/requests#artists-events for more information.
13
+ #
14
+ #====example:
15
+ # artist = Bandsintown::Artist.new("Little Brother")
16
+ # upcoming_little_brother_events = artist.events
17
+ #
18
+ def events
19
+ return @events unless @events.blank?
20
+ @events = self.class.request_and_parse("#{api_name}/events").map { |event| Bandsintown::Event.build_from_json(event) }
21
+ end
22
+
23
+ # name used in api requests. / and ? must be double escaped.
24
+ #
25
+ def api_name
26
+ name = @name.dup
27
+ name.gsub!('/', CGI.escape('/'))
28
+ name.gsub!('?', CGI.escape('?'))
29
+ URI.escape(name)
30
+ end
31
+
32
+ def self.resource_path
33
+ "artists"
34
+ end
35
+
36
+ private
37
+
38
+ def build_bandsintown_url
39
+ name = @name.dup
40
+ name.gsub!('&', 'And')
41
+ name.gsub!('+', 'Plus')
42
+ name = name.split.map { |w| w.capitalize }.join if name =~ /\s/
43
+ name.gsub!('/', CGI.escape('/'))
44
+ name.gsub!('?', CGI.escape('?'))
45
+ "http://www.bandsintown.com/#{URI.escape(name)}"
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,31 @@
1
+ module Bandsintown
2
+ class Base
3
+
4
+ attr_accessor :bandsintown_url
5
+
6
+ def self.request(api_method, args={})
7
+ self.connection.request(self.resource_path, api_method, args)
8
+ end
9
+
10
+ def self.connection
11
+ @connection ||= Bandsintown::Connection.new("http://api.bandsintown.com")
12
+ end
13
+
14
+ def self.parse(response)
15
+ json = JSON.parse(response)
16
+ check_for_errors(json)
17
+ json
18
+ end
19
+
20
+ def self.check_for_errors(json)
21
+ if json.is_a?(Hash) && json.has_key?("errors")
22
+ raise Bandsintown::APIError.new(json["errors"].join(", "))
23
+ end
24
+ end
25
+
26
+ def self.request_and_parse(api_method, args={})
27
+ parse(request(api_method, args))
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,36 @@
1
+ module Bandsintown
2
+ class Connection
3
+ attr_accessor :base_url
4
+
5
+ def initialize(base_url)
6
+ @base_url = base_url
7
+ end
8
+
9
+ def request(resource_path, method_path, args = {})
10
+ request_url = "#{@base_url}/#{resource_path}/#{method_path}?#{encode(args.symbolize_keys)}"
11
+ begin
12
+ open(request_url).read
13
+ rescue OpenURI::HTTPError => error_response
14
+ error_response.io.read
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def encode(args = {})
21
+ start_date = args.delete(:start_date)
22
+ end_date = args.delete(:end_date)
23
+ if start_date && end_date
24
+ start_date = start_date.strftime("%Y-%m-%d") unless start_date.is_a?(String)
25
+ end_date = end_date.strftime("%Y-%m-%d") unless end_date.is_a?(String)
26
+ args[:date] = "#{start_date},#{end_date}"
27
+ elsif args.has_key?(:date)
28
+ args[:date] = args[:date].strftime("%Y-%m-%d") unless args[:date].is_a?(String)
29
+ end
30
+ args[:format] = "json"
31
+ args[:app_id] = Bandsintown.app_id
32
+ args.to_param
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,102 @@
1
+ module Bandsintown
2
+ class Event < Base
3
+
4
+ attr_accessor :bandsintown_id, :datetime, :ticket_url, :artists, :venue, :status, :ticket_status, :on_sale_datetime
5
+
6
+ def tickets_available?
7
+ ticket_status == "available"
8
+ end
9
+
10
+ #Returns an array of Bandsintown::Event objects matching the options passed.
11
+ #See http://www.bandsintown.com/api/requests#events-search for more information.
12
+ #====options:
13
+ # :artists - an array of artist names or music brainz id's (formatted as 'mbid_<id>').
14
+ # :location - a string with one of the following formats:
15
+ # * 'city, state' for United States and Canada
16
+ # * 'city, country' for other countries
17
+ # * 'latitude,longitude'
18
+ # * ip address - will use the location of the passed ip address
19
+ # * 'use_geoip' - will use the location of the ip address that made the request
20
+ # :radius - a number in miles. API default is 25, maximum is 150.
21
+ # :date - use one of the following formats:
22
+ # * 'upcoming' - all upcoming dates, this is the API default.
23
+ # * single date
24
+ # * String formatted 'yyyy-mm-dd'
25
+ # * Time/Date/DateTime object (anything that responds to strftime)
26
+ # * date range
27
+ # * String formatted 'yyyy-mm-dd,yyyy-mm-dd'
28
+ # * alternatively use :start_date and :end_date with 'yyyy-mm-dd' Strings or Time/Date/DateTime objects.
29
+ # :per_page - number of results per response. API default is 50, maximum is 100.
30
+ # :page - offset for paginated results. API default is 1.
31
+ #
32
+ #====notes:
33
+ #:location or :artists is required for this request, all other arguments are optional.
34
+ #
35
+ #====examples:
36
+ #All concerts (first page w/ 50 results) in New York City for The Roots or Slum Village within the next 30 days (using Date objects):
37
+ # Bandsintown::Event.search(:location => "New York, NY", :artists => ["The Roots", "Slum Village"], :start_date => Date.today, :end_date => Date.today + 30)
38
+ #
39
+ #All concerts (first page w/ 50 results) on Dec 31 2009 (using formatted date string) within 100 miles of London:
40
+ # Bandsintown::Event.search(:location => "London, UK", :radius => 100, :date => "2009-12-31")
41
+ #
42
+ #Second page of all concerts near the request's ip address within in the next month, using Time objects and 100 results per page:
43
+ # Bandsintown::Event.search(:start_date => Time.now, :end_date => 1.month.from_now, :per_page => 100, :page => 2, :location => "use_geoip")
44
+ #
45
+ def self.search(options = {})
46
+ events = []
47
+ self.request_and_parse("search", options).each { |event| events << Bandsintown::Event.build_from_json(event) }
48
+ events
49
+ end
50
+
51
+ #Returns an array of Bandsintown::Event objects for all events added to Bandsintown within the last day (updated at 12:00 PM EST daily).
52
+ #See http://www.bandsintown.com/api/requests#events-daily for more information.
53
+ #
54
+ def self.daily
55
+ events = []
56
+ self.request_and_parse("daily").each { |event| events << Bandsintown::Event.build_from_json(event) }
57
+ events
58
+ end
59
+
60
+ #Returns an array of Bandsintown::Event objects matching the options passed.
61
+ #See http://www.bandsintown.com/api/requests#events-recommended for more information.
62
+ #====options:
63
+ #All options are the same as Bandsintown::Event.search with the following extra option:
64
+ # :only_recs - boolean for whether to include events with the artists from the :artists option. default is false.
65
+ #
66
+ #====notes:
67
+ #:location and :artists are required for this request, all other arguments are optional.
68
+ #
69
+ #====examples:
70
+ #All concerts (first page w/ 50 results) in Boston, MA recommended for fans of Metallica, including Metallica concerts
71
+ # Bandsintown::Event.recommended(:location => "Boston, MA", :artists => ["Metallica"])
72
+ #
73
+ #All concerts (first page w/ 50 results) on Dec 31 2009 within 100 miles of London recommended for fans of Usher and Lil Wayne, excluding Usher and Lil Wayne concerts
74
+ # Bandsintown::Event.recommended(:location => "London, UK", :radius => 100, :date => "2009-12-31", :artists => ["Usher", "Lil Wayne"], :only_recs => true)
75
+ #
76
+ def self.recommended(options = {})
77
+ events = []
78
+ self.request_and_parse("recommended", options).each { |event| events << Bandsintown::Event.build_from_json(event) }
79
+ events
80
+ end
81
+
82
+ def self.resource_path
83
+ "events"
84
+ end
85
+
86
+ def self.build_from_json(json_hash)
87
+ event = Bandsintown::Event.new()
88
+ event.bandsintown_id = json_hash["id"]
89
+ event.bandsintown_url = json_hash["url"]
90
+ event.datetime = Time.parse(json_hash["datetime"])
91
+ event.ticket_url = json_hash["ticket_url"]
92
+ event.status = json_hash["status"]
93
+ event.ticket_status = json_hash["ticket_status"]
94
+ event.on_sale_datetime = Time.parse(json_hash["on_sale_datetime"]) rescue nil
95
+ event.venue = Bandsintown::Venue.new(json_hash["venue"])
96
+ event.artists = []
97
+ json_hash["artists"].each { |artist| event.artists << Bandsintown::Artist.new(artist["name"], artist["url"]) }
98
+ event
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,18 @@
1
+ module Bandsintown
2
+ class Venue < Base
3
+
4
+ attr_accessor :name, :bandsintown_id, :region, :city, :country, :latitude, :longitude
5
+
6
+ def initialize(args={})
7
+ @name = args["name"]
8
+ @bandsintown_url = args["url"]
9
+ @bandsintown_id = args["id"]
10
+ @region = args["region"]
11
+ @city = args["city"]
12
+ @country = args["country"]
13
+ @latitude = args["latitude"]
14
+ @longitude = args["longitude"]
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/bandsintown.rb'}"
9
+ puts "Loading bandsintown gem"
10
+ exec "#{irb} #{libs} --simple-prompt"