fandango 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +0 -1
- data/.irbrc +2 -3
- data/.ruby-version +1 -0
- data/.travis.yml +2 -2
- data/Gemfile +2 -0
- data/Gemfile.lock +37 -0
- data/README.md +45 -22
- data/Rakefile +2 -2
- data/fandango.gemspec +3 -3
- data/lib/fandango.rb +13 -35
- data/lib/fandango/api.rb +14 -0
- data/lib/fandango/api/movies_near.rb +36 -0
- data/lib/fandango/api/theater_showtimes.rb +47 -0
- data/lib/fandango/movie.rb +34 -18
- data/lib/fandango/showtime.rb +18 -0
- data/lib/fandango/theater.rb +44 -35
- data/lib/fandango/version.rb +1 -1
- data/spec/api/movies_near.spec.rb +30 -0
- data/spec/api/theater_showtimes.spec.rb +36 -0
- data/spec/movie.spec.rb +17 -18
- data/spec/showtime.spec.rb +21 -0
- data/spec/spec_helper.rb +5 -10
- data/spec/support/fixture_helpers.rb +14 -0
- data/spec/support/fixtures/movies_near_me_73142.rss +185 -1
- data/spec/support/fixtures/{movies_near_me_73142.yaml → movies_near_me_73142.yml} +70 -70
- data/spec/support/fixtures/showtimes_amcquailspringsmall24_aaktw_2016_08_01.html +7264 -0
- data/spec/support/fixtures/theater_showtimes_amcquailspringsmall24.yml +203 -0
- data/spec/support/fixtures/theater_showtimes_amcquailspringsmall24_tomorrow.yml +190 -0
- data/spec/support/minitest.rb +9 -0
- data/spec/support/vcr.rb +6 -0
- data/spec/support/vcr_cassettes/theater_showtimes_amcquailspringsmall24.yml +10974 -0
- data/spec/support/vcr_cassettes/theater_showtimes_amcquailspringsmall24_tomorrow.yml +10759 -0
- data/spec/theater.spec.rb +58 -12
- metadata +79 -48
- data/.rvmrc +0 -1
- data/lib/fandango/parser.rb +0 -39
- data/spec/fandango.spec.rb +0 -41
- data/spec/parser.spec.rb +0 -12
- data/spec/support/fixtures/item.html +0 -1
- data/spec/support/helpers.rb +0 -25
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 852bc1a00a4783ec4b36469fe7db37179dd6201c
|
4
|
+
data.tar.gz: 3c9bd3977acc1d8e629bfbf84c6bc258d138b214
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a3ae6deafd0527b381e036167ff321277d8f86d4eed21fbe719ae30d2334819934e396ad0f8a2fb212a66a61457ed883a6a675d22e2b0b6c8e5db34a76d652e3
|
7
|
+
data.tar.gz: 9d6d73995bec4a0221385b667c65115e0e5cf99716f9894ea02428eb7c157d8156230bdfdda86ceca268aa9315ce2272e449d4afb6840ebc734b29058269ff20
|
data/.gitignore
CHANGED
data/.irbrc
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.3.1
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
fandango (2.0.0)
|
5
|
+
nokogiri (~> 1.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
addressable (2.4.0)
|
11
|
+
awesome_print (1.7.0)
|
12
|
+
crack (0.4.3)
|
13
|
+
safe_yaml (~> 1.0.0)
|
14
|
+
mini_portile2 (2.1.0)
|
15
|
+
minitest (5.9.0)
|
16
|
+
nokogiri (1.6.8.1)
|
17
|
+
mini_portile2 (~> 2.1.0)
|
18
|
+
rake (11.2.2)
|
19
|
+
safe_yaml (1.0.4)
|
20
|
+
vcr (3.0.3)
|
21
|
+
webmock (1.9.3)
|
22
|
+
addressable (>= 2.2.7)
|
23
|
+
crack (>= 0.3.2)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
awesome_print
|
30
|
+
fandango!
|
31
|
+
minitest
|
32
|
+
rake
|
33
|
+
vcr
|
34
|
+
webmock
|
35
|
+
|
36
|
+
BUNDLED WITH
|
37
|
+
1.13.1
|
data/README.md
CHANGED
@@ -6,34 +6,57 @@ Uses Fandango's RSS moviesnearme feed. E.g. http://www.fandango.com/rss/moviesne
|
|
6
6
|
|
7
7
|
## Usage
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
The movies are an array of hashes. Each hash contains title and Fandango's id.
|
13
|
-
|
14
|
-
### Example output format
|
15
|
-
|
16
|
-
```
|
9
|
+
```ruby
|
10
|
+
theaters_and_movies = Fandango.movies_near(73142)
|
11
|
+
=begin
|
17
12
|
[
|
18
13
|
[ 0] {
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
:id => "123456"
|
14
|
+
:name => "AMC Quail Springs Mall 24",
|
15
|
+
:id => "aaktw",
|
16
|
+
:address => "2501 West Memorial Oklahoma City, OK 73134",
|
17
|
+
:postal_code => "73134",
|
18
|
+
:showtimes_link => "http://www.fandango.com/amcquailspringsmall24_aaktw/theaterpage?wssaffid=11836&wssac=123",
|
19
|
+
:movies => [
|
20
|
+
[ 0] {
|
21
|
+
:title => "Abraham Lincoln: Vampire Hunter",
|
22
|
+
:id => "141897"
|
29
23
|
},
|
30
|
-
#
|
24
|
+
# ...
|
31
25
|
]
|
32
26
|
},
|
33
|
-
#
|
27
|
+
# ...
|
34
28
|
]
|
29
|
+
=end
|
30
|
+
|
31
|
+
movies_and_showtimes = Fandango.theater_showtimes(theaters_and_movies.first.fetch(:showtimes_link))
|
32
|
+
=begin
|
33
|
+
[
|
34
|
+
{
|
35
|
+
:title => "Bad Moms",
|
36
|
+
:id => "191125",
|
37
|
+
:runtime => 101,
|
38
|
+
:showtimes => [
|
39
|
+
[0] {
|
40
|
+
:datetime => #<DateTime: 2016-08-02T11:30:00-05:00 ((2457603j,59400s,0n),-18000s,2299161j)>
|
41
|
+
},
|
42
|
+
# ...
|
43
|
+
]
|
44
|
+
},
|
45
|
+
# ...
|
46
|
+
=end
|
47
|
+
```
|
48
|
+
|
49
|
+
### `theaters_and_movies` with id and different date
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
Fandango.theater_showtimes(
|
53
|
+
:theater_id => theaters_and_movies.first.fetch(:id),
|
54
|
+
:date => Date.tomorrow, # optional, defaults to `Date.today`
|
55
|
+
)
|
35
56
|
```
|
36
57
|
|
37
|
-
##
|
58
|
+
## Compatibility
|
38
59
|
|
39
|
-
|
60
|
+
Development of this gem will only officially support Ruby versions 2.3.0. (see `.travis.yml`)
|
61
|
+
It used to support 1.9.2. and 1.9.3, and it still may work, but it's not tested as of now.
|
62
|
+
Contributions are very welcome, and I will do what I can to help.
|
data/Rakefile
CHANGED
data/fandango.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_runtime_dependency 'nokogiri', '~> 1.0'
|
22
22
|
|
23
23
|
s.add_development_dependency 'awesome_print'
|
24
|
-
s.add_development_dependency '
|
25
|
-
s.add_development_dependency 'minitest'
|
26
|
-
s.add_development_dependency 'vcr'
|
24
|
+
s.add_development_dependency 'webmock'
|
25
|
+
s.add_development_dependency 'minitest'
|
26
|
+
s.add_development_dependency 'vcr'
|
27
27
|
end
|
data/lib/fandango.rb
CHANGED
@@ -3,47 +3,25 @@ require "fandango/version"
|
|
3
3
|
require 'open-uri'
|
4
4
|
require 'nokogiri'
|
5
5
|
|
6
|
-
require 'fandango/
|
6
|
+
require 'fandango/api'
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def movies_near(postal_code)
|
13
|
-
raise ArgumentError, "postal code cannot be blank" if postal_code.nil? || postal_code == ''
|
14
|
-
response = request(postal_code)
|
15
|
-
raise BadResponse.new(response) unless response.status.first == '200'
|
16
|
-
source = response.read
|
17
|
-
parse source
|
18
|
-
end
|
19
|
-
|
20
|
-
def request(postal_code)
|
21
|
-
open(url_for_postal_code(postal_code))
|
22
|
-
end
|
8
|
+
require 'fandango/theater'
|
9
|
+
require 'fandango/movie'
|
10
|
+
require 'fandango/showtime'
|
23
11
|
|
24
|
-
|
25
|
-
# Return hash of theaters and movies playing at each..
|
26
|
-
def parse(source)
|
27
|
-
Parser.parse(source)
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def url_for_postal_code(postal_code)
|
33
|
-
cleaned_postal_code = clean_postal_code(postal_code)
|
34
|
-
"http://www.fandango.com/rss/moviesnearme_#{cleaned_postal_code}.rss"
|
35
|
-
end
|
12
|
+
module Fandango
|
36
13
|
|
37
|
-
|
38
|
-
def clean_postal_code(postal_code)
|
39
|
-
postal_code.to_s.gsub(' ', '')
|
40
|
-
end
|
14
|
+
module_function
|
41
15
|
|
16
|
+
def movies_near(postal_code)
|
17
|
+
MoviesNear.(postal_code)
|
42
18
|
end
|
43
19
|
|
44
|
-
|
45
|
-
|
46
|
-
|
20
|
+
def theater_showtimes(showtimes_link_or_options)
|
21
|
+
if showtimes_link_or_options.is_a?(Hash)
|
22
|
+
TheaterShowtimes.by_id_and_date(showtimes_link_or_options)
|
23
|
+
else
|
24
|
+
TheaterShowtimes.(showtimes_link_or_options)
|
47
25
|
end
|
48
26
|
end
|
49
27
|
|
data/lib/fandango/api.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Fandango
|
2
|
+
autoload :MoviesNear, 'fandango/api/movies_near'
|
3
|
+
autoload :TheaterShowtimes, 'fandango/api/theater_showtimes'
|
4
|
+
|
5
|
+
module API
|
6
|
+
|
7
|
+
class BadResponse < StandardError
|
8
|
+
def initialize(response)
|
9
|
+
super "Bad response:\n#{response.inspect}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Fandango
|
2
|
+
module MoviesNear
|
3
|
+
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def call(postal_code)
|
7
|
+
response = request(postal_code)
|
8
|
+
raise BadResponse.new(response) unless response.status.first == '200'
|
9
|
+
|
10
|
+
xml = response.read
|
11
|
+
Parser.(xml)
|
12
|
+
end
|
13
|
+
|
14
|
+
def request(postal_code)
|
15
|
+
cleaned_postal_code = postal_code.to_s.gsub(' ', '')
|
16
|
+
url_for_postal_code = "http://www.fandango.com/rss/moviesnearme_#{cleaned_postal_code}.rss"
|
17
|
+
open(url_for_postal_code)
|
18
|
+
end
|
19
|
+
|
20
|
+
module Parser
|
21
|
+
|
22
|
+
module_function
|
23
|
+
|
24
|
+
def call(xml)
|
25
|
+
doc = Nokogiri.XML(xml)
|
26
|
+
doc.css('item').map do |item_node|
|
27
|
+
Theater.parse(item_node)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class BadResponse < API::BadResponse; end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Fandango
|
2
|
+
module TheaterShowtimes
|
3
|
+
|
4
|
+
BASE_URL = 'http://www.fandango.com/theater_%{theater_id}/theaterpage?date=%{date}'
|
5
|
+
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def call(showtimes_link)
|
9
|
+
response = request(showtimes_link)
|
10
|
+
raise BadResponse.new(response) unless response.status.first == '200'
|
11
|
+
|
12
|
+
html = response.read
|
13
|
+
Parser.(html)
|
14
|
+
end
|
15
|
+
|
16
|
+
def by_id_and_date(theater_id:, date: Date.today)
|
17
|
+
url = BASE_URL % {:theater_id => theater_id, :date => date}
|
18
|
+
call url
|
19
|
+
end
|
20
|
+
|
21
|
+
def request(showtimes_link)
|
22
|
+
open(showtimes_link)
|
23
|
+
end
|
24
|
+
|
25
|
+
module Parser
|
26
|
+
|
27
|
+
module_function
|
28
|
+
|
29
|
+
def call(html)
|
30
|
+
doc = Nokogiri.HTML(html)
|
31
|
+
doc.css('.showtimes-movie-container').map do |movie_node|
|
32
|
+
movie = Movie.parse(movie_node)
|
33
|
+
movie[:showtimes] =
|
34
|
+
movie_node.at_css('.showtimes-times').css('a').map do |showtime_node|
|
35
|
+
Showtime.parse(showtime_node)
|
36
|
+
end
|
37
|
+
movie
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
class BadResponse < API::BadResponse; end
|
46
|
+
|
47
|
+
end
|
data/lib/fandango/movie.rb
CHANGED
@@ -1,29 +1,45 @@
|
|
1
1
|
module Fandango
|
2
2
|
module Movie
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
# Return array of movie attributes.
|
7
|
-
def parse(description_node)
|
8
|
-
description_node.css('li').map do |li|
|
9
|
-
{
|
10
|
-
title: parse_title(li),
|
11
|
-
id: parse_id(li),
|
12
|
-
}
|
13
|
-
end
|
14
|
-
end
|
4
|
+
module_function
|
15
5
|
|
16
|
-
|
6
|
+
def parse(node)
|
7
|
+
a_tag = node.at_css('a.showtimes-movie-title') || node.at_css('a')
|
8
|
+
hash = {
|
9
|
+
title: parse_title(a_tag),
|
10
|
+
id: parse_id(a_tag),
|
11
|
+
}
|
17
12
|
|
18
|
-
|
19
|
-
|
13
|
+
if a_tag.attr(:class)&.include?('showtimes-movie-title')
|
14
|
+
hash[:runtime] = parse_runtime(node)
|
20
15
|
end
|
21
16
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
17
|
+
hash
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse_title(a_tag)
|
21
|
+
a_tag.content
|
22
|
+
end
|
23
|
+
|
24
|
+
# E.g. '141081' in fandango.com/the+adventures+of+tintin+3d_141081/movietimes
|
25
|
+
def parse_id(a_tag)
|
26
|
+
a_tag['href'].match(%r{fandango\.com/.*_(?<id>\d+)/})[:id]
|
27
|
+
end
|
26
28
|
|
29
|
+
# <div class="showtimes-movie-rating-runtime">
|
30
|
+
# <!-- Display rating -->
|
31
|
+
# R ,
|
32
|
+
# <!-- Display runtime -->
|
33
|
+
# 1 hr 41 min
|
34
|
+
# </div>
|
35
|
+
def parse_runtime(node)
|
36
|
+
rating_runtime = node.at_css('.showtimes-movie-rating-runtime')
|
37
|
+
%r{(?<hour>\d+)\s+hr\s+(?<min>\d+)} =~ rating_runtime.content
|
38
|
+
begin
|
39
|
+
Integer(hour) * 60 + Integer(min)
|
40
|
+
rescue TypeError
|
41
|
+
#puts rating_runtime
|
42
|
+
end
|
27
43
|
end
|
28
44
|
|
29
45
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Fandango
|
2
|
+
module Showtime
|
3
|
+
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def parse(node)
|
7
|
+
{
|
8
|
+
datetime: parse_datetime(node),
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse_datetime(node)
|
13
|
+
datetime_str = node.at_css('time').attr('datetime')
|
14
|
+
DateTime.parse(datetime_str)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
data/lib/fandango/theater.rb
CHANGED
@@ -1,49 +1,58 @@
|
|
1
1
|
module Fandango
|
2
2
|
module Theater
|
3
3
|
|
4
|
-
|
4
|
+
module_function
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
end
|
6
|
+
def parse(item_node)
|
7
|
+
hash = {}
|
9
8
|
|
10
|
-
|
11
|
-
description_node ||= Fandango::Parser.parse_description(item_node)
|
12
|
-
name = parse_name(item_node)
|
13
|
-
id = parse_id(item_node)
|
14
|
-
address = parse_address(description_node)
|
15
|
-
postal_code = parse_postal_code(address)
|
16
|
-
|
17
|
-
{
|
18
|
-
name: name,
|
19
|
-
id: id,
|
20
|
-
address: address,
|
21
|
-
postal_code: postal_code,
|
22
|
-
}
|
23
|
-
end
|
9
|
+
description_node = parse_description_node(item_node)
|
24
10
|
|
25
|
-
|
11
|
+
hash[:name] = parse_name(item_node)
|
12
|
+
hash[:id] = parse_id(item_node)
|
13
|
+
hash[:address] = parse_address(description_node)
|
14
|
+
hash[:postal_code] = parse_postal_code(hash[:address])
|
15
|
+
hash[:showtimes_link] = parse_showtimes_link(item_node)
|
16
|
+
hash[:movies] = parse_movies(description_node)
|
26
17
|
|
27
|
-
|
28
|
-
|
29
|
-
end
|
18
|
+
hash
|
19
|
+
end
|
30
20
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
21
|
+
# Description content is in the form of HTML wrapped in CDATA.
|
22
|
+
# Parse it and return a parsed Nokogiri node.
|
23
|
+
def parse_description_node(item_node)
|
24
|
+
cdata = item_node.at_css('description')
|
25
|
+
Nokogiri::HTML(cdata.content)
|
26
|
+
end
|
38
27
|
|
39
|
-
|
40
|
-
|
41
|
-
|
28
|
+
def parse_name(item_node)
|
29
|
+
item_node.at_css('title').content.strip
|
30
|
+
end
|
42
31
|
|
43
|
-
|
44
|
-
|
45
|
-
|
32
|
+
# E.g. 'aaicu' in http://www.fandango.com/northpark7_aaicu/theaterpage
|
33
|
+
def parse_id(item_node)
|
34
|
+
item_node.
|
35
|
+
at_css('link').
|
36
|
+
content.
|
37
|
+
match(%r{fandango\.com/.*_(?<id>.*)/theaterpage})[:id]
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_address(description_node)
|
41
|
+
description_node.at_css('p').content
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse_postal_code(address)
|
45
|
+
address.match(/(?<postal_code>\d+)$/)[:postal_code]
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_showtimes_link(item_node)
|
49
|
+
item_node.at_css('link').content.strip
|
50
|
+
end
|
46
51
|
|
52
|
+
def parse_movies(description_node)
|
53
|
+
description_node.css('li').map do |li|
|
54
|
+
Movie.parse(li)
|
55
|
+
end
|
47
56
|
end
|
48
57
|
|
49
58
|
end
|