odeon_uk 3.0.6 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|