odeon_uk 3.0.6 → 4.0.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +5 -3
- data/CHANGELOG.md +14 -0
- data/{LICENSE.txt → COMM-LICENSE} +0 -0
- data/LICENSE +617 -0
- data/README.md +58 -29
- data/Rakefile +7 -21
- data/lib/odeon_uk.rb +5 -14
- data/lib/odeon_uk/cinema.rb +123 -75
- data/lib/odeon_uk/{api/response.rb → internal/api_response.rb} +3 -3
- data/lib/odeon_uk/internal/parser/api/film_lookup.rb +34 -0
- data/lib/odeon_uk/internal/parser/api/performance_day.rb +92 -0
- data/lib/odeon_uk/internal/title_sanitizer.rb +34 -39
- data/lib/odeon_uk/performance.rb +87 -0
- data/lib/odeon_uk/version.rb +2 -2
- data/odeon_uk.gemspec +19 -21
- data/rake/fixture_creator.rb +5 -57
- data/test/fixtures/api/all_cinemas.plist +0 -0
- data/test/fixtures/api/app_init.plist +0 -0
- data/test/fixtures/api/film_times/71-14876.plist +0 -0
- data/test/fixtures/api/film_times/71-15408.plist +0 -0
- data/test/fixtures/api/film_times/71-15684.plist +0 -0
- data/test/fixtures/api/film_times/71-15866.plist +0 -0
- data/test/fixtures/api/film_times/71-15868.plist +0 -0
- data/test/fixtures/api/film_times/71-15961.plist +0 -0
- data/test/fixtures/api/film_times/71-15963.plist +0 -0
- data/test/fixtures/api/film_times/71-15965.plist +0 -0
- data/test/fixtures/api/film_times/71-15967.plist +0 -0
- data/test/fixtures/api/film_times/71-15969.plist +0 -0
- data/test/fixtures/api/film_times/71-15977.plist +0 -0
- data/test/fixtures/api/film_times/71-15980.plist +0 -0
- data/test/fixtures/api/film_times/71-16037.plist +0 -0
- data/test/fixtures/api/film_times/71-16136.plist +0 -0
- data/test/fixtures/api/film_times/71-16142.plist +0 -0
- data/test/fixtures/api/film_times/71-16143.plist +0 -0
- data/test/fixtures/api/film_times/71-16187.plist +0 -0
- data/test/fixtures/api/film_times/71-16369.plist +0 -0
- data/test/fixtures/api/film_times/71-16370.plist +0 -0
- data/test/fixtures/api/film_times/71-16374.plist +0 -0
- data/test/fixtures/api/film_times/71-16386.plist +0 -0
- data/test/fixtures/api/film_times/71-16387.plist +0 -0
- data/test/fixtures/api/film_times/71-16388.plist +0 -0
- data/test/fixtures/api/film_times/71-16438.plist +0 -0
- data/test/fixtures/api/film_times/71-16454.plist +0 -0
- data/test/fixtures/api/film_times/71-16457.plist +0 -0
- data/test/fixtures/api/film_times/71-16477.plist +0 -0
- data/test/fixtures/api/film_times/71-16478.plist +0 -0
- data/test/fixtures/api/film_times/71-16480.plist +0 -0
- data/test/fixtures/api/film_times/71-16482.plist +0 -0
- data/test/fixtures/api/film_times/71-16489.plist +0 -0
- data/test/lib/odeon_uk/cinema_test.rb +154 -373
- data/test/lib/odeon_uk/{api/response_test.rb → internal/api_response_test.rb} +7 -4
- data/test/lib/odeon_uk/performance_test.rb +149 -0
- data/test/lib/odeon_uk/version_test.rb +3 -5
- data/test/support/api_fixtures_helper.rb +9 -3
- data/test/support/fake_api_response.rb +17 -0
- data/test/test_helper.rb +9 -3
- metadata +89 -145
- data/.rdoc_options +0 -16
- data/lib/odeon_uk/api/cinema.rb +0 -67
- data/lib/odeon_uk/api/screenings.rb +0 -103
- data/lib/odeon_uk/configuration.rb +0 -21
- data/lib/odeon_uk/html/cinema.rb +0 -101
- data/lib/odeon_uk/html/parser/film_with_screenings.rb +0 -160
- data/lib/odeon_uk/html/screenings.rb +0 -38
- data/lib/odeon_uk/html/website.rb +0 -38
- data/lib/odeon_uk/screening.rb +0 -71
- data/test/fixtures/api/film_times/71-100747.plist +0 -0
- data/test/fixtures/api/film_times/71-100750.plist +0 -0
- data/test/fixtures/api/film_times/71-100790.plist +0 -0
- data/test/fixtures/api/film_times/71-14646.plist +0 -0
- data/test/fixtures/api/film_times/71-14725.plist +0 -0
- data/test/fixtures/api/film_times/71-15086.plist +0 -0
- data/test/fixtures/api/film_times/71-15096.plist +0 -0
- data/test/fixtures/api/film_times/71-15122.plist +0 -0
- data/test/fixtures/api/film_times/71-15130.plist +0 -0
- data/test/fixtures/api/film_times/71-15141.plist +0 -0
- data/test/fixtures/api/film_times/71-15142.plist +0 -0
- data/test/fixtures/api/film_times/71-15143.plist +0 -0
- data/test/fixtures/api/film_times/71-15144.plist +0 -0
- data/test/fixtures/api/film_times/71-15145.plist +0 -0
- data/test/fixtures/api/film_times/71-15170.plist +0 -0
- data/test/fixtures/api/film_times/71-15172.plist +0 -0
- data/test/fixtures/api/film_times/71-15177.plist +0 -0
- data/test/fixtures/api/film_times/71-15179.plist +0 -0
- data/test/fixtures/api/film_times/71-15182.plist +0 -0
- data/test/fixtures/api/film_times/71-15286.plist +0 -0
- data/test/fixtures/api/film_times/71-15360.plist +0 -0
- data/test/fixtures/api/film_times/71-15586.plist +0 -0
- data/test/fixtures/api/film_times/71-15700.plist +0 -0
- data/test/fixtures/api/film_times/71-15718.plist +0 -0
- data/test/fixtures/api/film_times/71-15768.plist +0 -0
- data/test/fixtures/api/film_times/71-15788.plist +0 -0
- data/test/fixtures/api/film_times/71-15793.plist +0 -0
- data/test/fixtures/api/film_times/71-15794.plist +0 -0
- data/test/fixtures/api/film_times/71-15795.plist +0 -0
- data/test/fixtures/api/film_times/71-15796.plist +0 -0
- data/test/fixtures/api/film_times/71-15799.plist +0 -0
- data/test/fixtures/api/film_times/71-15802.plist +0 -0
- data/test/fixtures/api/film_times/71-15814.plist +0 -0
- data/test/fixtures/api/film_times/71-15817.plist +0 -0
- data/test/fixtures/api/film_times/71-15840.plist +0 -0
- data/test/fixtures/html/cinema/105.html +0 -2622
- data/test/fixtures/html/cinema/211.html +0 -3241
- data/test/fixtures/html/cinema/71.html +0 -3448
- data/test/fixtures/html/showtimes/11-imax.html +0 -170
- data/test/fixtures/html/showtimes/171-d-box.html +0 -203
- data/test/fixtures/html/showtimes/71-0.html +0 -59
- data/test/fixtures/html/showtimes/71.html +0 -2395
- data/test/fixtures/html/sitemap.html +0 -1303
- data/test/lib/odeon_uk/api/cinema_test.rb +0 -165
- data/test/lib/odeon_uk/api/screenings_test.rb +0 -58
- data/test/lib/odeon_uk/configuration_test.rb +0 -29
- data/test/lib/odeon_uk/html/cinema_test.rb +0 -149
- data/test/lib/odeon_uk/html/parser/film_with_screenings_test.rb +0 -97
- data/test/lib/odeon_uk/html/screenings_test.rb +0 -44
- data/test/lib/odeon_uk/html/website_test.rb +0 -67
- data/test/lib/odeon_uk/screening_test.rb +0 -92
- data/test/support/website_fixtures_helper.rb +0 -30
data/.rdoc_options
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
--- !ruby/object:RDoc::Options
|
2
|
-
encoding: UTF-8
|
3
|
-
static_path: []
|
4
|
-
rdoc_include:
|
5
|
-
- .
|
6
|
-
charset: UTF-8
|
7
|
-
exclude:
|
8
|
-
hyperlink_all: false
|
9
|
-
line_numbers: false
|
10
|
-
main_page:
|
11
|
-
markup: tomdoc
|
12
|
-
show_hash: false
|
13
|
-
tab_width: 8
|
14
|
-
title:
|
15
|
-
visibility: :protected
|
16
|
-
webcvs:
|
data/lib/odeon_uk/api/cinema.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
module OdeonUk
|
2
|
-
# Internal utility classes: Do not use
|
3
|
-
# @api private
|
4
|
-
module Api
|
5
|
-
# The object representing a cinema on the Odeon UK website
|
6
|
-
class Cinema
|
7
|
-
# @return [Integer] the numeric id of the cinema via the API
|
8
|
-
attr_reader :id
|
9
|
-
|
10
|
-
# @param [Integer, String] id cinema id
|
11
|
-
# @return [OdeonUk::Cinema]
|
12
|
-
def initialize(id)
|
13
|
-
@id = id.to_i
|
14
|
-
end
|
15
|
-
|
16
|
-
# Return basic cinema information for all cinemas
|
17
|
-
# @return [Array<OdeonUk::Cinema>]
|
18
|
-
def self.ids
|
19
|
-
cinemas_hash.keys.map(&:to_i)
|
20
|
-
end
|
21
|
-
|
22
|
-
# The locality (town) of the cinema
|
23
|
-
# @return [String]
|
24
|
-
def locality
|
25
|
-
cinema_hash['siteAddress2']
|
26
|
-
end
|
27
|
-
|
28
|
-
# The name of the cinema
|
29
|
-
# @return [String]
|
30
|
-
def name
|
31
|
-
cinema_hash['siteName']
|
32
|
-
end
|
33
|
-
|
34
|
-
# The url of the cinema
|
35
|
-
# @return [Nil]
|
36
|
-
def url
|
37
|
-
"http://www.odeon.co.uk/cinemas/#{urlized_name}/#{@id}/"
|
38
|
-
end
|
39
|
-
|
40
|
-
# Post code of the cinema
|
41
|
-
# @return [String]
|
42
|
-
def postal_code
|
43
|
-
cinema_hash['sitePostcode']
|
44
|
-
end
|
45
|
-
|
46
|
-
# The street adress of the cinema
|
47
|
-
# @return [String]
|
48
|
-
def street_address
|
49
|
-
cinema_hash['siteAddress1']
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def self.cinemas_hash
|
55
|
-
@@cinemas_hash ||= Api::Response.new.all_cinemas['sites']
|
56
|
-
end
|
57
|
-
|
58
|
-
def cinema_hash
|
59
|
-
@cinema_hash ||= self.class.cinemas_hash[id.to_s]
|
60
|
-
end
|
61
|
-
|
62
|
-
def urlized_name
|
63
|
-
name.downcase.gsub(/[^a-z0-9]/, '_')
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,103 +0,0 @@
|
|
1
|
-
module OdeonUk
|
2
|
-
# Internal utility classes: Do not use
|
3
|
-
# @api private
|
4
|
-
module Api
|
5
|
-
# The object representing a single screening of a film via the Odeon UK api
|
6
|
-
class Screenings
|
7
|
-
# All currently listed screenings at a cinema
|
8
|
-
# @param [Integer] cinema_id id of the cinema
|
9
|
-
# @return [Array<Hash>]
|
10
|
-
def self.at(cinema_id)
|
11
|
-
film_ids(cinema_id).flat_map do |film_id|
|
12
|
-
times_response = response.film_times(cinema_id, film_id)
|
13
|
-
|
14
|
-
times_response.flat_map do |day|
|
15
|
-
date = day['date']
|
16
|
-
screenings = day['attributes']
|
17
|
-
|
18
|
-
screenings.flat_map do |screening|
|
19
|
-
performances = screening['showtimes']
|
20
|
-
|
21
|
-
performances.flat_map do |p|
|
22
|
-
{
|
23
|
-
dimension: screening['attribute'].include?('3D') ? '3d' : '2d',
|
24
|
-
film_name: films_map(cinema_id)[film_id],
|
25
|
-
time: TimeParser.new(date, p[0]['performanceTime']).to_utc,
|
26
|
-
variant: VariantParser.new(screening['attribute']).to_a
|
27
|
-
}
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def self.app_init
|
37
|
-
@@app_init ||= Response.new.app_init
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.film_ids(cinema_id)
|
41
|
-
films_map(cinema_id).keys
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.films_map(cinema_id)
|
45
|
-
films_at(cinema_id).each_with_object({}) do |f, result|
|
46
|
-
result[f['filmMasterId']] = f['title']
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.films_at(cinema_id)
|
51
|
-
app_init['films'].select { |f| f['sites'].include?(cinema_id) }
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.response
|
55
|
-
@@response ||= Response.new
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
TimeParser = Struct.new(:date, :time) do
|
60
|
-
def to_utc
|
61
|
-
tz.local_to_utc(parsed_time)
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def early_morning_screening?
|
67
|
-
!!time.match(/\A0/)
|
68
|
-
end
|
69
|
-
|
70
|
-
def parsed_date
|
71
|
-
case date
|
72
|
-
when 'Today' then Time.now.strftime '%Y-%m-%d'
|
73
|
-
when 'Tomorrow' then (Time.now + 60 * 60 * 24).strftime '%Y-%m-%d'
|
74
|
-
else date.gsub('.', '').match(/\d+\s\w+\z/)[0]
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def parsed_time
|
79
|
-
parsed_time = Time.parse("#{parsed_date} #{time} UTC")
|
80
|
-
# Odeon deliberately mislabel their 00:01 screenings as the day before
|
81
|
-
early_morning_screening? ? parsed_time + 60 * 60 * 24 : parsed_time
|
82
|
-
end
|
83
|
-
|
84
|
-
def tz
|
85
|
-
@tz ||= TZInfo::Timezone.get('Europe/London')
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
VariantParser = Struct.new(:text) do
|
90
|
-
TRANSLATOR = {
|
91
|
-
'Culture' => 'arts',
|
92
|
-
'Kids' => 'kids',
|
93
|
-
'IMAX' => 'imax',
|
94
|
-
'Newbies' => 'baby',
|
95
|
-
'Silver Cinema' => 'senior'
|
96
|
-
}
|
97
|
-
|
98
|
-
def to_a
|
99
|
-
TRANSLATOR.select { |k, _| text.include?(k) }.values.uniq
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module OdeonUk
|
2
|
-
class << self
|
3
|
-
attr_accessor :configuration
|
4
|
-
end
|
5
|
-
|
6
|
-
def self.configuration
|
7
|
-
@configuration ||= Configuration.new
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.configure
|
11
|
-
yield(configuration)
|
12
|
-
end
|
13
|
-
|
14
|
-
class Configuration
|
15
|
-
attr_accessor :method
|
16
|
-
|
17
|
-
def initialize
|
18
|
-
@method = :html
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
data/lib/odeon_uk/html/cinema.rb
DELETED
@@ -1,101 +0,0 @@
|
|
1
|
-
module OdeonUk
|
2
|
-
# Internal utility classes: Do not use
|
3
|
-
# @api private
|
4
|
-
module Html
|
5
|
-
# The object representing a cinema on the Odeon UK website
|
6
|
-
class Cinema
|
7
|
-
ADDRESS_REGEX = '.gethere .span4 .description'
|
8
|
-
ALL_LINKS = '.sitemap a[href*=cinemas]'
|
9
|
-
|
10
|
-
# @return [Integer] the numeric id of the cinema on the Odeon website
|
11
|
-
attr_reader :id
|
12
|
-
|
13
|
-
# @param [Integer, String] id cinema id
|
14
|
-
# @return [OdeonUk::Cinema]
|
15
|
-
def initialize(id)
|
16
|
-
@id = id.to_i
|
17
|
-
end
|
18
|
-
|
19
|
-
# Return basic cinema information for all cinemas
|
20
|
-
# @return [Array<OdeonUk::Cinema>]
|
21
|
-
def self.ids
|
22
|
-
cinema_links.map { |link| id_from(link) }
|
23
|
-
end
|
24
|
-
|
25
|
-
# The locality (town) of the cinema
|
26
|
-
# @return [String]
|
27
|
-
def locality
|
28
|
-
return unless address_node
|
29
|
-
address_node.text.match(/\w+(\s\w+){0,}\s+(\w+(\s\w+){0,})/)[2]
|
30
|
-
end
|
31
|
-
|
32
|
-
# The name of the cinema
|
33
|
-
# @return [String]
|
34
|
-
def name
|
35
|
-
cinema_link_doc.children.first.to_s
|
36
|
-
end
|
37
|
-
|
38
|
-
# The web url of the cinema
|
39
|
-
# @return [String]
|
40
|
-
def url
|
41
|
-
@url ||= begin
|
42
|
-
link = cinema_link_doc.get_attribute('href')
|
43
|
-
(link[0] == '/') ? "http://www.odeon.co.uk#{link}" : link
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Post code of the cinema
|
48
|
-
# @return [String]
|
49
|
-
def postal_code
|
50
|
-
return unless address_node
|
51
|
-
address_node.text.match(/[A-Z]{1,2}\d{1,2}[A-Z]?\s\d{1,2}[A-Z]{1,2}/)[0]
|
52
|
-
end
|
53
|
-
|
54
|
-
# The street adress of the cinema
|
55
|
-
# @return [String]
|
56
|
-
def street_address
|
57
|
-
return unless address_node
|
58
|
-
address_node.text.match(/\A\s+(\w+(\s\w+){0,})/)[1]
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
def self.id_from(link)
|
64
|
-
link.get_attribute('href').match(/\/(\d+)\/$/)[1].to_i
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.cinema_links
|
68
|
-
@@cinema_links ||= begin
|
69
|
-
links = sitemap_doc.css(ALL_LINKS)
|
70
|
-
links.select { |link| link.get_attribute('href').match(/\/\d+\/$/) }
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.sitemap_doc
|
75
|
-
@@sitemap_doc ||= Nokogiri::HTML(sitemap_response)
|
76
|
-
end
|
77
|
-
|
78
|
-
def self.sitemap_response
|
79
|
-
@@sitemap_response ||= Html::Website.new.sitemap
|
80
|
-
end
|
81
|
-
|
82
|
-
def address_node
|
83
|
-
cinema_doc.css(ADDRESS_REGEX)[0]
|
84
|
-
end
|
85
|
-
|
86
|
-
def cinema_response
|
87
|
-
@cinema_response ||= Html::Website.new.cinema(id)
|
88
|
-
end
|
89
|
-
|
90
|
-
def cinema_doc
|
91
|
-
@cinema_doc ||= Nokogiri::HTML(cinema_response)
|
92
|
-
end
|
93
|
-
|
94
|
-
def cinema_link_doc
|
95
|
-
self.class.cinema_links.select do |link|
|
96
|
-
link.get_attribute('href').include?("/#{id}/")
|
97
|
-
end.first
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
@@ -1,160 +0,0 @@
|
|
1
|
-
module OdeonUk
|
2
|
-
# Internal utility classes: Do not use
|
3
|
-
# @api private
|
4
|
-
module Html
|
5
|
-
# Parses HTML with Nokogiri
|
6
|
-
module Parser
|
7
|
-
# Parses a chunk of HTML to derive movie showing data
|
8
|
-
class FilmWithScreenings
|
9
|
-
# CSS selector for a film title inside an individual film HTML
|
10
|
-
NAME_CSS = '.presentation-info h4 a'
|
11
|
-
# CSS selector for a group of showtimes inside an individual film HTML
|
12
|
-
SHOWTIMES_CSS = '.times-all.accordion-group'
|
13
|
-
|
14
|
-
# @param [String] html a chunk of html
|
15
|
-
def initialize(html)
|
16
|
-
@html = html
|
17
|
-
end
|
18
|
-
|
19
|
-
# The film name
|
20
|
-
# @return [String]
|
21
|
-
def film_name
|
22
|
-
@film_name ||= Internal::TitleSanitizer.new(raw_film_name).sanitized
|
23
|
-
end
|
24
|
-
|
25
|
-
# array containing hashes of screening attributes
|
26
|
-
# @return [Array<Hash>]
|
27
|
-
def to_a
|
28
|
-
doc.css(SHOWTIMES_CSS).map do |node|
|
29
|
-
dimension_parser(node).to_a.map do |hash|
|
30
|
-
hash.merge(film_name: film_name)
|
31
|
-
end
|
32
|
-
end.flatten
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def doc
|
38
|
-
@doc ||= Nokogiri::HTML(@html)
|
39
|
-
end
|
40
|
-
|
41
|
-
def raw_film_name
|
42
|
-
@raw_film_name ||= doc.css(NAME_CSS).children.first.to_s
|
43
|
-
end
|
44
|
-
|
45
|
-
def dimension_parser(node)
|
46
|
-
DimensionNodeParser.new(node)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# parses chunk of screenings for a particular screening dimension
|
51
|
-
class DimensionNodeParser
|
52
|
-
# CSS selector for a single screening inside a 'group of showtimes' HTML
|
53
|
-
SCREENING_CSS = '.show'
|
54
|
-
# CSS selector for showing technology for a 'group of showtimes' HTML
|
55
|
-
TECH_CSS = '.tech a'
|
56
|
-
|
57
|
-
# @param [Nokigiri::Node] node a Nokogiri node object
|
58
|
-
def initialize(node)
|
59
|
-
@node = node
|
60
|
-
end
|
61
|
-
|
62
|
-
# array containing hashes of screening attributes for dimension
|
63
|
-
# @return [Array<Hash>]
|
64
|
-
def to_a
|
65
|
-
screening_hashes.map do |hash|
|
66
|
-
hash.merge(dimension: dimension,
|
67
|
-
variant: add_imax(hash[:variant]))
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
private
|
72
|
-
|
73
|
-
def add_imax(original)
|
74
|
-
imax? ? "#{original} imax".strip : original
|
75
|
-
end
|
76
|
-
|
77
|
-
def dimension
|
78
|
-
dimension_from_tech || '2d'
|
79
|
-
end
|
80
|
-
|
81
|
-
def dimension_from_tech
|
82
|
-
tech.match(/[23]d/i) { |data| data[0] }
|
83
|
-
end
|
84
|
-
|
85
|
-
def imax?
|
86
|
-
!!tech.match(/imax/)
|
87
|
-
end
|
88
|
-
|
89
|
-
def screening_hashes
|
90
|
-
screening_nodes.map { |node| ScreeningNodeParser.new(node).to_hash }
|
91
|
-
end
|
92
|
-
|
93
|
-
def screening_nodes
|
94
|
-
@node.css(SCREENING_CSS)
|
95
|
-
end
|
96
|
-
|
97
|
-
def tech
|
98
|
-
@tech ||= @node.css(TECH_CSS).text.gsub('in ', '').downcase
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
# parses a single screening
|
103
|
-
class ScreeningNodeParser
|
104
|
-
# regex for time format
|
105
|
-
TIME_REGEX = %r(\d+/\d+/\d+ \d{2}\:\d{2})
|
106
|
-
# regex for D-Box screenings
|
107
|
-
DBOX_REGEX = /D-Box/
|
108
|
-
|
109
|
-
# @param [Nokigiri::Node] node a Nokogiri node object
|
110
|
-
def initialize(node)
|
111
|
-
@node = node
|
112
|
-
end
|
113
|
-
|
114
|
-
# hashes of screening attributes
|
115
|
-
# @return [Hash]
|
116
|
-
def to_hash
|
117
|
-
{
|
118
|
-
booking_url: booking_url,
|
119
|
-
time: utc_time,
|
120
|
-
variant: variant
|
121
|
-
}
|
122
|
-
end
|
123
|
-
|
124
|
-
private
|
125
|
-
|
126
|
-
def booking_url
|
127
|
-
link_attr('href').to_s
|
128
|
-
end
|
129
|
-
|
130
|
-
def link_attr(attribute)
|
131
|
-
@node.css('a').attribute(attribute)
|
132
|
-
end
|
133
|
-
|
134
|
-
def info
|
135
|
-
@node.css('i').to_s
|
136
|
-
end
|
137
|
-
|
138
|
-
def time
|
139
|
-
Time.parse(time_string)
|
140
|
-
end
|
141
|
-
|
142
|
-
def time_string
|
143
|
-
link_attr('title').to_s.match(TIME_REGEX).to_s + ' UTC'
|
144
|
-
end
|
145
|
-
|
146
|
-
def tz
|
147
|
-
@tz ||= TZInfo::Timezone.get('Europe/London')
|
148
|
-
end
|
149
|
-
|
150
|
-
def utc_time
|
151
|
-
tz.local_to_utc(time)
|
152
|
-
end
|
153
|
-
|
154
|
-
def variant
|
155
|
-
info.match(DBOX_REGEX) ? 'd-box' : ''
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|