lib/picturehouse_uk/internal/parser/screenings.rb
module PicturehouseUk
# @api private
module Internal
# @api private
module Parser
# Parses screenings page into an array of hashes for an individual cinema
class Screenings
# css for a day of films & screenings
LISTINGS = '.listings li:not(.dark)'.freeze
DATE = '.nav-collapse.collapse'.freeze
def initialize(cinema_id)
@cinema_id = cinema_id
end
# parse the cinema page into an array of screenings attributes
# @return [Array<Hash>]
def to_a
doc.css(LISTINGS).flat_map do |node|
FilmWithShowtimes.new(node,
date_from_html(node.css(DATE).to_s)).to_a
end
end
private
def date_from_html(html)
if html =~ /listings-further-ahead-today/
Date.now
else
html.match(/listings-further-ahead-(\d{4})(\d{2})(\d{2})/) do |m|
Date.new(m[1].to_i, m[2].to_i, m[3].to_i)
end
end
end
def doc
@doc ||= Nokogiri::HTML(page)
end
def page
@page ||= PicturehouseUk::Internal::Website.new.whats_on(@cinema_id)
end
end
end
# @api private
# collection of timings for a specific film
class FilmWithShowtimes
# film name css
NAME = '.top-mg-sm a'.freeze
# variants css
VARIANTS = '.film-times .col-xs-10'.freeze
def initialize(node, date)
@node = node
@date = date
end
# The film name
# @return [String]
def name
TitleSanitizer.new(raw_name).sanitized
end
# Showings hashes
# @return [Array<Hash>]
def to_a
Array(@node.css(VARIANTS)).flat_map do |variant|
Variant.new(variant, @date).to_a.map do |hash|
{
film_name: name,
dimension: dimension
}.merge(hash)
end
end
end
private
def dimension
raw_name =~ /3d/i ? '3d' : '2d'
end
def raw_name
@raw_name ||= @node.css(NAME).children.first.to_s
end
end
# @api private
# variants can have multiple screenings
class Variant
SHOWTIMES = '.btn'.freeze
VARIANT = '.film-type-desc'.freeze
TRANSLATOR = {
'Big Scream' => 'baby',
'IMAX' => 'imax',
"Kids' Club" => 'kids',
'NT Live' => 'arts',
'Screen Arts' => 'arts',
'Silver Screen' => 'senior'
}.freeze
def initialize(node, date)
@node = node
@date = date
end
# Variant arrays
# @return [Array<Hash>]
def to_a
@node.css(SHOWTIMES).map do |node|
{ variant: variant }.merge(Showtime.new(@node, @date).to_hash)
end
end
private
def variant
@variant ||= TRANSLATOR.select do |k, _|
variant_text.include?(k)
end.values.uniq
end
def variant_text
@variant_text ||= @node.css(VARIANT).to_s
end
end
# @api private
# parse an individual screening node
class Showtime
def initialize(node, date)
@node = node
@date = date
end
def to_hash
{
booking_url: booking_url,
starting_at: starting_at
}
end
private
def booking_url
return if href.nil? || href.empty?
"https://picturehouses.com#{href}"
end
def hour
split[0]
end
def href
@href ||= @node['href']
end
def min
split[1]
end
def split
@split ||= @node.text.split('.').map(&:to_i)
end
def starting_at
@starting_at ||= @date.to_time + (hour * 60 + min) * 60
end
end
end
end