reel_uk 1.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 +7 -0
- data/CHANGELOG.md +11 -0
- data/COMM-LICENSE +22 -0
- data/LICENSE +617 -0
- data/README.md +171 -0
- data/lib/reel_uk/cinema.rb +201 -0
- data/lib/reel_uk/internal/http.rb +49 -0
- data/lib/reel_uk/internal/listings.rb +44 -0
- data/lib/reel_uk/internal/parser/coming_soon.rb +30 -0
- data/lib/reel_uk/internal/parser/showtimes.rb +46 -0
- data/lib/reel_uk/internal/parser/whats_on.rb +62 -0
- data/lib/reel_uk/internal/title_sanitizer.rb +37 -0
- data/lib/reel_uk/internal/website.rb +51 -0
- data/lib/reel_uk/performance.rb +129 -0
- data/lib/reel_uk/version.rb +6 -0
- data/lib/reel_uk.rb +23 -0
- metadata +154 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ReelUk
|
|
4
|
+
# Internal utility classes: Do not use
|
|
5
|
+
# @api private
|
|
6
|
+
module Internal
|
|
7
|
+
# Reads pages from Reel's WordPress website, built on Jacro's cinema
|
|
8
|
+
# plugin. No token is needed.
|
|
9
|
+
class Website
|
|
10
|
+
include Http
|
|
11
|
+
|
|
12
|
+
HOME = 'https://reel-cinemas.co.uk/'
|
|
13
|
+
AJAX = 'https://reel-cinemas.co.uk/wp-admin/admin-ajax.php'
|
|
14
|
+
# The quick booking menu's request for every showtime of a film
|
|
15
|
+
SHOWTIMES_ACTION = 'display_showtime_byfilmid'
|
|
16
|
+
|
|
17
|
+
# @return [String] the home page, whose cinema menu lists every venue
|
|
18
|
+
def home
|
|
19
|
+
get(HOME)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @param [String] venue_url e.g. 'https://reel-cinemas.co.uk/chorley'
|
|
23
|
+
# @return [String] the venue's page, whose quick booking menu names
|
|
24
|
+
# the venue's Jacro location id
|
|
25
|
+
def venue(venue_url)
|
|
26
|
+
get("#{venue_url}/")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @param [String] venue_url e.g. 'https://reel-cinemas.co.uk/chorley'
|
|
30
|
+
# @return [String] the next three weeks of showtimes, with labels
|
|
31
|
+
def whats_on(venue_url)
|
|
32
|
+
get("#{venue_url}/whatson/")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @param [String] venue_url e.g. 'https://reel-cinemas.co.uk/chorley'
|
|
36
|
+
# @return [String] films not yet showing, with up to three showtimes each
|
|
37
|
+
def coming_soon(venue_url)
|
|
38
|
+
get("#{venue_url}/comingsoon/")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @param [String] film_id Jacro's film id, the same at every venue
|
|
42
|
+
# @param [String] location Jacro's location id for the venue
|
|
43
|
+
# @return [String] options naming every showtime of the film at the
|
|
44
|
+
# venue, however far ahead
|
|
45
|
+
def showtimes(film_id, location)
|
|
46
|
+
response = post(AJAX, 'action' => SHOWTIMES_ACTION, 'select_movie' => film_id, 'movie_loc' => location)
|
|
47
|
+
JSON.parse(response).fetch('html', '').to_s
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
module ReelUk
|
|
2
|
+
# A single screening of a film on the Reel Cinemas website
|
|
3
|
+
class Performance < Cinebase::Performance
|
|
4
|
+
# @!attribute [r] booking_url
|
|
5
|
+
# @return [String] the booking URL for the screening
|
|
6
|
+
# @!attribute [r] cinema_name
|
|
7
|
+
# @return [String] the cinema name
|
|
8
|
+
# @!attribute [r] cinema_id
|
|
9
|
+
# @return [String] the cinema id
|
|
10
|
+
# @!attribute [r] dimension
|
|
11
|
+
# @return [String] 2d or 3d
|
|
12
|
+
# @!attribute [r] film_name
|
|
13
|
+
# @return [String] the film name
|
|
14
|
+
|
|
15
|
+
# @!method initialize(options)
|
|
16
|
+
# @param [Hash] options options hash
|
|
17
|
+
# @option options [String] :booking_url (nil) buying url for the screening
|
|
18
|
+
# @option options [String] :cinema_name name of the cinema
|
|
19
|
+
# @option options [String] :cinema_id website id of the cinema
|
|
20
|
+
# @option options [String] :dimension ('2d') dimension of the screening
|
|
21
|
+
# @option options [Cinebase::Festival] :festival (nil) festival edition
|
|
22
|
+
# @option options [String] :film_name name of the film
|
|
23
|
+
# @option options [Integer] :film_year (nil) year from the film's title
|
|
24
|
+
# @option options [String] :language (nil) audio language, e.g. 'Hindi'
|
|
25
|
+
# @option options [Time] :starting_at listed start time of the performance
|
|
26
|
+
|
|
27
|
+
# Showtime labels and A1Web group headings, and the variants they mean.
|
|
28
|
+
# 'Movie Madness' marks cheap tickets, not a kind of screening.
|
|
29
|
+
VARIANTS = Cinebase::A1web::Performance::VARIANTS.merge(
|
|
30
|
+
'ParentBaby' => 'baby',
|
|
31
|
+
'Senior' => 'senior'
|
|
32
|
+
).freeze
|
|
33
|
+
|
|
34
|
+
# Event screenings on the WordPress website have no label
|
|
35
|
+
EVENT = /\A(?:RBO|NT Live|National Theatre Live|Met Opera|Exhibition on Screen)\b|\bLive On Stage\z|\s-\sThe Play\z/i
|
|
36
|
+
SUBTITLED = /\bSubtitled\b/i
|
|
37
|
+
THREE_D = Cinebase::A1web::Performance::THREE_D
|
|
38
|
+
IMAX = Cinebase::A1web::Performance::IMAX
|
|
39
|
+
LANGUAGE = Cinebase::A1web::Performance::LANGUAGE
|
|
40
|
+
TIME_ZONE = 'Europe/London'.freeze
|
|
41
|
+
|
|
42
|
+
# The old website's own booking links only work in a browser that has
|
|
43
|
+
# just visited the venue's pages, so link to the venue's Admit One
|
|
44
|
+
# ticketing site, which redirects to seat selection.
|
|
45
|
+
A1WEB_PERF_CODE = %r{/booking/(\d+)/}
|
|
46
|
+
|
|
47
|
+
# Performances within an inclusive range of showing dates, from all of
|
|
48
|
+
# the cinema's advertised dates. A venue on the WordPress website takes
|
|
49
|
+
# three requests and one more for each film; a venue on the old A1Web
|
|
50
|
+
# website takes one.
|
|
51
|
+
# @param [String] cinema_id the venue's path on the website, e.g. 'chorley'
|
|
52
|
+
# @param [Date] from first date (defaults to today in London)
|
|
53
|
+
# @param [Date] to last date (defaults to 13 days after from)
|
|
54
|
+
# @return [Array<ReelUk::Performance>]
|
|
55
|
+
def self.at(
|
|
56
|
+
cinema_id,
|
|
57
|
+
from: TZInfo::Timezone.get(TIME_ZONE).now.to_date,
|
|
58
|
+
to: from + 13
|
|
59
|
+
)
|
|
60
|
+
raise ArgumentError, 'to must not precede from' if to < from
|
|
61
|
+
|
|
62
|
+
cinema = Cinema.new(cinema_id)
|
|
63
|
+
performances = showings(cinema).select { |showing| (from..to).cover?(showing.date) }.map do |showing|
|
|
64
|
+
new(attributes(showing, cinema).merge(cinema_id: cinema.id, cinema_name: cinema.name))
|
|
65
|
+
end
|
|
66
|
+
performances.sort_by(&:starting_at)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @!method showing_on
|
|
70
|
+
# The date of the screening
|
|
71
|
+
# @return [Date]
|
|
72
|
+
|
|
73
|
+
# @!method starting_at
|
|
74
|
+
# UTC time of the screening
|
|
75
|
+
# @return [Time]
|
|
76
|
+
|
|
77
|
+
# @!method variant
|
|
78
|
+
# The kinds of screening (arts, baby, senior, subtitled ...)
|
|
79
|
+
# @return <Array[String]>
|
|
80
|
+
|
|
81
|
+
def self.showings(cinema)
|
|
82
|
+
if cinema.url.empty?
|
|
83
|
+
[]
|
|
84
|
+
elsif cinema.a1web?
|
|
85
|
+
today = TZInfo::Timezone.get(TIME_ZONE).now.to_date
|
|
86
|
+
html = Cinema.a1web_client.whats_on(cinema.url)
|
|
87
|
+
Cinebase::A1web::Listings.new(html, venue_url: cinema.url, today: today).showings
|
|
88
|
+
else
|
|
89
|
+
ReelUk::Internal::Listings.new(cinema.url).showings
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
private_class_method :showings
|
|
93
|
+
|
|
94
|
+
def self.attributes(showing, cinema)
|
|
95
|
+
title = showing.title
|
|
96
|
+
{
|
|
97
|
+
booking_url: booking_url(showing.booking_url, cinema),
|
|
98
|
+
dimension: [title, *showing.tags].any? { |text| text.match?(THREE_D) } ? '3d' : '2d',
|
|
99
|
+
festival: Cinebase::Festival.from_title(title, year: showing.date.year),
|
|
100
|
+
film_name: ReelUk::Internal::TitleSanitizer.new(title).sanitized,
|
|
101
|
+
film_year: Cinebase::TitleSanitizer.film_year(title),
|
|
102
|
+
language: title[LANGUAGE, 1],
|
|
103
|
+
starting_at: showing.starting_at,
|
|
104
|
+
variant: variant(showing)
|
|
105
|
+
}
|
|
106
|
+
end
|
|
107
|
+
private_class_method :attributes
|
|
108
|
+
|
|
109
|
+
def self.booking_url(url, cinema)
|
|
110
|
+
code = url[A1WEB_PERF_CODE, 1]
|
|
111
|
+
if cinema.a1web? && code
|
|
112
|
+
"https://reel#{cinema.id.delete('-')}.admit-one.co.uk/tickets/?perfCode=#{code}"
|
|
113
|
+
else
|
|
114
|
+
url
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
private_class_method :booking_url
|
|
118
|
+
|
|
119
|
+
def self.variant(showing)
|
|
120
|
+
title = showing.title
|
|
121
|
+
variant = showing.tags.filter_map { |tag| VARIANTS[tag] }
|
|
122
|
+
variant << 'subtitled' if title.match?(SUBTITLED)
|
|
123
|
+
variant << 'arts' if title.match?(EVENT)
|
|
124
|
+
variant << 'imax' if title.match?(IMAX)
|
|
125
|
+
variant.uniq
|
|
126
|
+
end
|
|
127
|
+
private_class_method :variant
|
|
128
|
+
end
|
|
129
|
+
end
|
data/lib/reel_uk.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'cgi/escape'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
require 'cinebase'
|
|
5
|
+
require 'cinebase/a1web'
|
|
6
|
+
|
|
7
|
+
require_relative './reel_uk/version'
|
|
8
|
+
|
|
9
|
+
require_relative './reel_uk/internal/http'
|
|
10
|
+
require_relative './reel_uk/internal/website'
|
|
11
|
+
require_relative './reel_uk/internal/title_sanitizer'
|
|
12
|
+
|
|
13
|
+
require_relative './reel_uk/internal/parser/coming_soon'
|
|
14
|
+
require_relative './reel_uk/internal/parser/showtimes'
|
|
15
|
+
require_relative './reel_uk/internal/parser/whats_on'
|
|
16
|
+
require_relative './reel_uk/internal/listings'
|
|
17
|
+
|
|
18
|
+
require_relative './reel_uk/cinema'
|
|
19
|
+
require_relative './reel_uk/performance'
|
|
20
|
+
|
|
21
|
+
# reel_uk gem
|
|
22
|
+
module ReelUk
|
|
23
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: reel_uk
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andy Croll
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: bundler
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '2.0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '2.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: minitest-mock
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: minitest-reporters
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rake
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: simplecov
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "<"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '2'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "<"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '2'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: webmock
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: cinebase
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '5.7'
|
|
103
|
+
type: :runtime
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '5.7'
|
|
110
|
+
description: Pull movie & cinema information from the Reel Cinemas website
|
|
111
|
+
email:
|
|
112
|
+
- andy@goodscary.com
|
|
113
|
+
executables: []
|
|
114
|
+
extensions: []
|
|
115
|
+
extra_rdoc_files: []
|
|
116
|
+
files:
|
|
117
|
+
- CHANGELOG.md
|
|
118
|
+
- COMM-LICENSE
|
|
119
|
+
- LICENSE
|
|
120
|
+
- README.md
|
|
121
|
+
- lib/reel_uk.rb
|
|
122
|
+
- lib/reel_uk/cinema.rb
|
|
123
|
+
- lib/reel_uk/internal/http.rb
|
|
124
|
+
- lib/reel_uk/internal/listings.rb
|
|
125
|
+
- lib/reel_uk/internal/parser/coming_soon.rb
|
|
126
|
+
- lib/reel_uk/internal/parser/showtimes.rb
|
|
127
|
+
- lib/reel_uk/internal/parser/whats_on.rb
|
|
128
|
+
- lib/reel_uk/internal/title_sanitizer.rb
|
|
129
|
+
- lib/reel_uk/internal/website.rb
|
|
130
|
+
- lib/reel_uk/performance.rb
|
|
131
|
+
- lib/reel_uk/version.rb
|
|
132
|
+
homepage: https://github.com/andycroll/reel_uk
|
|
133
|
+
licenses:
|
|
134
|
+
- AGPL
|
|
135
|
+
- MIT
|
|
136
|
+
metadata: {}
|
|
137
|
+
rdoc_options: []
|
|
138
|
+
require_paths:
|
|
139
|
+
- lib
|
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
141
|
+
requirements:
|
|
142
|
+
- - ">="
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: '3.4'
|
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
|
+
requirements:
|
|
147
|
+
- - ">="
|
|
148
|
+
- !ruby/object:Gem::Version
|
|
149
|
+
version: '0'
|
|
150
|
+
requirements: []
|
|
151
|
+
rubygems_version: 4.0.20
|
|
152
|
+
specification_version: 4
|
|
153
|
+
summary: It's a scraper, but a nice one
|
|
154
|
+
test_files: []
|