cineworld_uk 4.1.0 → 4.3.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/CHANGELOG.md +28 -0
- data/README.md +26 -1
- data/Rakefile +3 -24
- data/cineworld_uk.gemspec +2 -2
- data/lib/cineworld_uk/internal/api_response.rb +9 -31
- data/lib/cineworld_uk/internal/guest_token.rb +9 -52
- data/lib/cineworld_uk/internal/parser/api/film.rb +14 -1
- data/lib/cineworld_uk/internal/parser/api/performance.rb +5 -0
- data/lib/cineworld_uk/internal/title_sanitizer.rb +5 -10
- data/lib/cineworld_uk/performance.rb +5 -1
- data/lib/cineworld_uk/version.rb +2 -2
- data/lib/cineworld_uk.rb +2 -1
- data/test/fixtures/api/showtimes-014.json +76 -0
- data/test/fixtures/api/sites.json +52 -0
- data/test/lib/cineworld_uk/cinema_test.rb +63 -223
- data/test/lib/cineworld_uk/internal/api_response_test.rb +27 -182
- data/test/lib/cineworld_uk/internal/fixture_shape_test.rb +14 -0
- data/test/lib/cineworld_uk/internal/guest_token_test.rb +87 -0
- data/test/lib/cineworld_uk/internal/parser/api/cinema_address_test.rb +44 -85
- data/test/lib/cineworld_uk/internal/parser/api/film_test.rb +65 -127
- data/test/lib/cineworld_uk/internal/parser/api/performance_test.rb +27 -45
- data/test/lib/cineworld_uk/internal/title_sanitizer_test.rb +94 -120
- data/test/lib/cineworld_uk/performance_test.rb +165 -180
- data/test/lib/cineworld_uk/version_test.rb +3 -3
- data/test/live/api_shape_test.rb +22 -0
- data/test/live/integration_test.rb +13 -43
- data/test/live/live_helper.rb +11 -0
- data/test/package_test.rb +14 -7
- data/test/support/api_shapes.rb +48 -0
- data/test/support/vista_fixtures.rb +58 -0
- data/test/test_helper.rb +3 -0
- metadata +34 -29
- data/tasks/package.rake +0 -84
- data/test/fixtures/api/cinema-list.json +0 -1
- data/test/fixtures/api/dates-14.json +0 -1
- data/test/fixtures/api/performances-tomorrow-14.json +0 -1
- data/test/fixtures/api/vista-showtimes-brighton.json +0 -1
- data/test/support/fixture_reader.rb +0 -32
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b966798e50231ceceb95b749b8c3e9e962db5cc12edc7fb31e98ee40e110078d
|
|
4
|
+
data.tar.gz: f26069f75b3de854af94f90758b0d479faa8ef7f2923dfb3c6ed66d16a681432
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2d38f7b625fe0625160948172925120d2763ba1f9235acc683f58bf5c4b1fdeca4a6176734884e400dadfa34ed53c5d1a745af7b11ecbf52468884c1bc92d378
|
|
7
|
+
data.tar.gz: 71d23a661ac05b7eb340877e6c371ceae53cc4b757048a75d3ebfa4d713258ca7faae8cb74d7c360ecdf5da8655351c7c1167b920c10125a1dc43d6f434b2405
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
4
4
|
|
|
5
|
+
## 4.3.0 - 2026-10-22
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `Performance#film_year`, read from a trailing `(1996)` in the title, so a re-release gives the original year.
|
|
9
|
+
- `4dx` and `screenx` variants from Vista's `4DX`, `4DX 3D` and `ScreenX` attributes.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Require cinebase 5.4. Titles also lose `+ ... Q&A` and `+ Discussion` add-ons, `(35mm)`, `(70mm)` and `4K` markers, and `CFF:` festival prefixes.
|
|
13
|
+
- Film titles lose their year suffix and the `(4DX)`, `(ScreenX)`, `M4J:`, `£2 Family Films :`, `Horror Season 2026` and `(Re-release)` markers, and Lithuanian versions. For example `Horror Season 2026 From Dusk Till Dawn (1996)` is now `From Dusk Till Dawn` with `film_year` 1996 and the Horror Season 2026 festival. Consumers matching films by name will see these names change.
|
|
14
|
+
|
|
15
|
+
## 4.2.0 - 2026-10-22
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- `Performance#language` from Vista language attributes such as `Tamil`, `Performance#subtitled?`, and `Performance#festival`, a `Cinebase::Festival` with `name` and `year`.
|
|
19
|
+
- Live API shape tests that check real responses without storing them.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Require cinebase 5.2. The Vista client, guest token retrieval and platform packaging task now come from `cinebase/vista`; behaviour, errors and pinned curl-impersonate digests are unchanged.
|
|
23
|
+
- `CineworldUk::AuthenticationError` is now `Cinebase::Vista::AuthenticationError`, so existing `rescue` clauses keep working.
|
|
24
|
+
- Film titles also use cinebase's common rules: dub and subtitle versions, more language versions, anniversaries, Q&A add-ons and festival prefixes are removed.
|
|
25
|
+
- Tests use plain `Minitest::Test` classes, with hand-written fixtures in place of recorded API responses.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- `Sing-Along` inside a real title, such as `Bebefinn Sing-Along Movie`, is no longer removed.
|
|
29
|
+
|
|
30
|
+
### Removed
|
|
31
|
+
- The `fixtures` rake task, which saved API responses into the repository.
|
|
32
|
+
|
|
5
33
|
## 4.1.0 - 2026-10-15
|
|
6
34
|
|
|
7
35
|
### Added
|
data/README.md
CHANGED
|
@@ -177,6 +177,18 @@ performance.dimension
|
|
|
177
177
|
performance.variant
|
|
178
178
|
#=> ['audio_described']
|
|
179
179
|
|
|
180
|
+
performance.film_year
|
|
181
|
+
#=> 1996 # from the title, nil when it has no year
|
|
182
|
+
|
|
183
|
+
performance.language
|
|
184
|
+
#=> 'Tamil' # audio language, nil when the cinema does not tag one
|
|
185
|
+
|
|
186
|
+
performance.subtitled?
|
|
187
|
+
#=> true
|
|
188
|
+
|
|
189
|
+
performance.festival
|
|
190
|
+
#=> #<data Cinebase::Festival name="Cine-Excess", year=2026> # nil outside festivals
|
|
191
|
+
|
|
180
192
|
performance.starting_at
|
|
181
193
|
#=> 2026-10-14 14:40:00 UTC
|
|
182
194
|
|
|
@@ -193,6 +205,19 @@ performance.cinema_id
|
|
|
193
205
|
#=> 14
|
|
194
206
|
```
|
|
195
207
|
|
|
208
|
+
## Tests
|
|
209
|
+
|
|
210
|
+
```sh
|
|
211
|
+
bundle exec rake # unit tests against fixtures
|
|
212
|
+
bundle exec rake live # live API, needs curl-impersonate or CINEWORLD_TOKEN
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Fixtures in `test/fixtures/api` are hand-written: invented films and
|
|
216
|
+
addresses in the shape of Vista responses, never recorded API output.
|
|
217
|
+
`test/support/api_shapes.rb` describes the fields the gem reads. The unit suite
|
|
218
|
+
checks the fixtures against it and the live suite checks real responses, held
|
|
219
|
+
only in memory. When the API changes, update the shape first, then the fixtures.
|
|
220
|
+
|
|
196
221
|
## Building release packages
|
|
197
222
|
|
|
198
223
|
```sh
|
|
@@ -204,7 +229,7 @@ To build and check just one platform on a matching host:
|
|
|
204
229
|
|
|
205
230
|
```sh
|
|
206
231
|
bundle exec rake 'package:native[x86_64-linux-gnu]'
|
|
207
|
-
CINEWORLD_PACKAGE=pkg/cineworld_uk-4.
|
|
232
|
+
CINEWORLD_PACKAGE=pkg/cineworld_uk-4.3.0-x86_64-linux-gnu.gem bundle exec ruby test/package_test.rb
|
|
208
233
|
```
|
|
209
234
|
|
|
210
235
|
Native packaging downloads pinned upstream archives at **build time**, verifies
|
data/Rakefile
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
require "bundler/gem_tasks"
|
|
3
3
|
|
|
4
4
|
require 'rake/testtask'
|
|
5
|
-
|
|
5
|
+
require 'cinebase/vista/package_task'
|
|
6
|
+
|
|
7
|
+
Cinebase::Vista::PackageTask.new('cineworld_uk.gemspec', root: __dir__)
|
|
6
8
|
|
|
7
9
|
Rake::TestTask.new do |t|
|
|
8
10
|
t.libs << 'lib/cineworld_uk'
|
|
@@ -33,27 +35,4 @@ task :console do
|
|
|
33
35
|
IRB.start
|
|
34
36
|
end
|
|
35
37
|
|
|
36
|
-
desc 'Recreate test fixtures'
|
|
37
|
-
task :fixtures do
|
|
38
|
-
require 'cineworld_uk'
|
|
39
|
-
CineworldUk.token = ENV.fetch("CINEWORLD_TOKEN")
|
|
40
|
-
|
|
41
|
-
def js_fixture(name)
|
|
42
|
-
File.expand_path("../test/fixtures/#{name}.json", __FILE__)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
api = CineworldUk::Internal::ApiResponse.new
|
|
46
|
-
|
|
47
|
-
File.open(js_fixture('api/cinema-list'), 'w') do |file|
|
|
48
|
-
puts '* API Cinema List'
|
|
49
|
-
file.write api.cinema_list
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
File.open(js_fixture('api/performances-tomorrow-14'), 'w') do |file|
|
|
53
|
-
puts '* API Performances in Brighton Tomorrow'
|
|
54
|
-
file.write api.performances(14, Date.today + 1)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
end
|
|
58
|
-
|
|
59
38
|
task :default => :test
|
data/cineworld_uk.gemspec
CHANGED
|
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
18
18
|
spec.require_paths = ['lib']
|
|
19
19
|
|
|
20
|
+
spec.add_development_dependency 'base64'
|
|
20
21
|
spec.add_development_dependency 'bundler', '>= 2.0'
|
|
21
22
|
spec.add_development_dependency 'minitest-mock'
|
|
22
23
|
spec.add_development_dependency 'minitest-reporters'
|
|
@@ -24,7 +25,6 @@ Gem::Specification.new do |spec|
|
|
|
24
25
|
spec.add_development_dependency 'simplecov', '< 1'
|
|
25
26
|
spec.add_development_dependency 'webmock'
|
|
26
27
|
|
|
27
|
-
spec.add_runtime_dependency '
|
|
28
|
-
spec.add_runtime_dependency 'cinebase', '~> 5.0'
|
|
28
|
+
spec.add_runtime_dependency 'cinebase', '~> 5.4'
|
|
29
29
|
spec.add_runtime_dependency 'nokogiri', '>= 1.11'
|
|
30
30
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "net/http"
|
|
4
3
|
require "json"
|
|
5
4
|
require "date"
|
|
6
5
|
require "time"
|
|
@@ -15,8 +14,10 @@ module CineworldUk
|
|
|
15
14
|
"Subtitled" => "subbed", "Subtitles" => "subbed",
|
|
16
15
|
"Autism Friendly" => "autism-friendly",
|
|
17
16
|
"Movies for Juniors" => "junior",
|
|
18
|
-
"Unlimited Screening" => "unlimited-screening", "Q&A" => "qa"
|
|
17
|
+
"Unlimited Screening" => "unlimited-screening", "Q&A" => "qa",
|
|
18
|
+
"4DX" => "4dx", "4DX 3D" => "4dx", "ScreenX" => "screenx"
|
|
19
19
|
}.freeze
|
|
20
|
+
LANGUAGES = Cinebase::TitleSanitizer::LANGUAGES
|
|
20
21
|
|
|
21
22
|
def cinema_list
|
|
22
23
|
cinemas = fetch("sites").fetch("sites").map do |site|
|
|
@@ -53,6 +54,9 @@ module CineworldUk
|
|
|
53
54
|
ATTRIBUTES[attribute.dig("name", "text")]
|
|
54
55
|
end
|
|
55
56
|
attrs << "3d" if showtime["requires3dGlasses"]
|
|
57
|
+
language = showtime.fetch("attributeIds", []).filter_map do |id|
|
|
58
|
+
attributes.fetch(id).dig("shortName", "text")
|
|
59
|
+
end.find { |name| LANGUAGES.include?(name) }
|
|
56
60
|
# Formats belong to a session, not to the film as a whole.
|
|
57
61
|
id = showtime.fetch("id")
|
|
58
62
|
normalized_films << {
|
|
@@ -62,7 +66,7 @@ module CineworldUk
|
|
|
62
66
|
}
|
|
63
67
|
starts_at = showtime.fetch("schedule").fetch("startsAt")
|
|
64
68
|
{
|
|
65
|
-
"filmId" => id, "attributeIds" => attrs,
|
|
69
|
+
"filmId" => id, "attributeIds" => attrs, "language" => language,
|
|
66
70
|
"eventDateTime" => Time.iso8601(starts_at).utc.iso8601,
|
|
67
71
|
"bookingLink" =>
|
|
68
72
|
"https://web.cineworld.co.uk/order/showtimes/#{id}/seats"
|
|
@@ -82,34 +86,8 @@ module CineworldUk
|
|
|
82
86
|
private
|
|
83
87
|
|
|
84
88
|
def fetch(path, query = {})
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
raise AuthenticationError,
|
|
88
|
-
"Set CineworldUk.token to a current guest JWT " \
|
|
89
|
-
"before fetching data"
|
|
90
|
-
end
|
|
91
|
-
uri = URI(BASE_URL + path)
|
|
92
|
-
uri.query = URI.encode_www_form(query) unless query.empty?
|
|
93
|
-
request = Net::HTTP::Get.new(uri)
|
|
94
|
-
request["Authorization"] = "Bearer #{token}"
|
|
95
|
-
request["Connect-Region-Code"] = "GB"
|
|
96
|
-
request["Accept"] = "application/json"
|
|
97
|
-
response = Net::HTTP.start(
|
|
98
|
-
uri.host, uri.port, use_ssl: true, open_timeout: 10, read_timeout: 30
|
|
99
|
-
) do |http|
|
|
100
|
-
http.request(request)
|
|
101
|
-
end
|
|
102
|
-
case response
|
|
103
|
-
when Net::HTTPSuccess
|
|
104
|
-
JSON.parse(response.body)
|
|
105
|
-
when Net::HTTPUnauthorized
|
|
106
|
-
raise AuthenticationError,
|
|
107
|
-
"Vista rejected the guest token; " \
|
|
108
|
-
"supply a fresh token with CineworldUk.token="
|
|
109
|
-
else
|
|
110
|
-
# Omit response bodies and never redirect credentials to another host.
|
|
111
|
-
raise "Vista HTTP error #{response.code}"
|
|
112
|
-
end
|
|
89
|
+
Cinebase::Vista::Client.new(base_url: BASE_URL, region_code: "GB",
|
|
90
|
+
token: CineworldUk.token).get(path, query)
|
|
113
91
|
end
|
|
114
92
|
end
|
|
115
93
|
end
|
|
@@ -1,72 +1,29 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "base64"
|
|
4
3
|
require "json"
|
|
5
4
|
require "nokogiri"
|
|
6
|
-
require "open3"
|
|
7
5
|
|
|
8
6
|
module CineworldUk
|
|
9
7
|
module Internal
|
|
10
|
-
#
|
|
11
|
-
class GuestToken
|
|
12
|
-
|
|
13
|
-
@curl = curl || default_curl
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def fetch
|
|
17
|
-
token = extract_token(request_page)
|
|
18
|
-
validate_expiry!(token)
|
|
19
|
-
token
|
|
20
|
-
rescue JSON::ParserError, ArgumentError, IndexError, TypeError, NoMethodError
|
|
21
|
-
raise AuthenticationError, "Guest token page data is missing or invalid", cause: nil
|
|
22
|
-
end
|
|
8
|
+
# Reads the public guest token from the ticketing site's page data
|
|
9
|
+
class GuestToken < Cinebase::Vista::GuestToken
|
|
10
|
+
PAGE_URL = "https://web.cineworld.co.uk/"
|
|
23
11
|
|
|
24
12
|
private
|
|
25
13
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def curl_command
|
|
32
|
-
[@curl, "--disable", "--impersonate", "chrome150",
|
|
33
|
-
"--compressed", "--silent", "--show-error",
|
|
34
|
-
"--connect-timeout", "10", "--max-time", "30",
|
|
35
|
-
"--write-out", "\n%{http_code}", "https://web.cineworld.co.uk/"]
|
|
14
|
+
# The root page carries the token even when it displays a 404.
|
|
15
|
+
def accepted_statuses
|
|
16
|
+
%w[200 404]
|
|
36
17
|
end
|
|
37
18
|
|
|
38
|
-
def
|
|
39
|
-
|
|
40
|
-
unless result.success?
|
|
41
|
-
raise AuthenticationError,
|
|
42
|
-
"Guest token request failed (curl exit #{result.exitstatus})"
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
html, _, status = output.rpartition("\n")
|
|
46
|
-
unless %w[200 404].include?(status)
|
|
47
|
-
raise AuthenticationError, "Guest token page returned HTTP #{status}"
|
|
48
|
-
end
|
|
49
|
-
html
|
|
50
|
-
rescue Errno::ENOENT
|
|
51
|
-
raise AuthenticationError,
|
|
52
|
-
"Install curl-impersonate or pass its executable path with curl:"
|
|
19
|
+
def bundled_curl
|
|
20
|
+
File.expand_path("../../../vendor/curl-impersonate/bin/curl-impersonate", __dir__)
|
|
53
21
|
end
|
|
54
22
|
|
|
55
23
|
def extract_token(html)
|
|
56
24
|
script = Nokogiri::HTML(html).at_css("script#__NEXT_DATA__")
|
|
57
25
|
data = JSON.parse(script ? script.content : "")
|
|
58
|
-
|
|
59
|
-
unless token.is_a?(String) && !token.empty?
|
|
60
|
-
raise AuthenticationError, "Guest token is missing from the page"
|
|
61
|
-
end
|
|
62
|
-
token
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def validate_expiry!(token)
|
|
66
|
-
claims = JSON.parse(Base64.urlsafe_decode64(token.split(".").fetch(1)))
|
|
67
|
-
if Integer(claims.fetch("exp")) <= Time.now.to_i
|
|
68
|
-
raise AuthenticationError, "Guest token supplied by the page has expired"
|
|
69
|
-
end
|
|
26
|
+
data.dig("props", "pageProps", "environment", "gasToken")
|
|
70
27
|
end
|
|
71
28
|
end
|
|
72
29
|
end
|
|
@@ -21,6 +21,17 @@ module CineworldUk
|
|
|
21
21
|
@data['attributeIds']&.include?('3d') ? '3d' : '2d'
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
# @param [Integer] year edition when the title gives none
|
|
25
|
+
# @return [Cinebase::Festival, nil]
|
|
26
|
+
def festival(year)
|
|
27
|
+
Cinebase::Festival.from_title(@data['name'] || '', year: year)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [Integer, nil] the year at the end of the title
|
|
31
|
+
def film_year
|
|
32
|
+
Cinebase::TitleSanitizer.film_year(@data['name'] || '')
|
|
33
|
+
end
|
|
34
|
+
|
|
24
35
|
# Sanitized film name
|
|
25
36
|
# @return [String]
|
|
26
37
|
def name
|
|
@@ -34,11 +45,13 @@ module CineworldUk
|
|
|
34
45
|
def variant
|
|
35
46
|
attrs = @data['attributeIds'] || []
|
|
36
47
|
[
|
|
48
|
+
attrs.include?('4dx') ? '4dx' : nil,
|
|
37
49
|
attrs.include?('autism-friendly') ? 'autism_friendly' : nil,
|
|
38
50
|
attrs.include?('imax') ? 'imax' : nil,
|
|
39
51
|
attrs.include?('junior') ? 'kids' : nil,
|
|
40
52
|
attrs.include?('unlimited-screening') ? 'members' : nil,
|
|
41
|
-
attrs.include?('qa') ? 'q&a' : nil
|
|
53
|
+
attrs.include?('qa') ? 'q&a' : nil,
|
|
54
|
+
attrs.include?('screenx') ? 'screenx' : nil
|
|
42
55
|
].compact
|
|
43
56
|
end
|
|
44
57
|
end
|
|
@@ -18,13 +18,6 @@ module CineworldUk
|
|
|
18
18
|
# Strings and regex to be removed
|
|
19
19
|
def remove
|
|
20
20
|
[
|
|
21
|
-
/\s+[23]d/i, # dimension
|
|
22
|
-
/\(Hindi\)/i, # Indian Language
|
|
23
|
-
/\(Malayalam\)/i, # Indian Language
|
|
24
|
-
/\(Punjabi\)/i, # Indian Language
|
|
25
|
-
/\(Tamil\)/i, # Indian Language
|
|
26
|
-
/\(Cantonese\)/i, # Chinese
|
|
27
|
-
/\(Turkish\)/i, # Foreign Language
|
|
28
21
|
%r(-? \d{1,2}/\d{1,2}/\d{2,4}), # date
|
|
29
22
|
/\n/, # newlines
|
|
30
23
|
/\- Encore/, # encore
|
|
@@ -35,12 +28,14 @@ module CineworldUk
|
|
|
35
28
|
/\ATake 2 -/, # take 2
|
|
36
29
|
/ - (Subtitled) Movies for Juniors/i, # movies for juniors
|
|
37
30
|
'(IMAX)', # IMAX
|
|
31
|
+
/\A\((4DX|ScreenX)\)\s*/, # format, kept as a variant
|
|
32
|
+
/\AM4J: /, # movies for juniors
|
|
33
|
+
/\A£2 Family Films : /, # family pricing
|
|
38
34
|
'SciScreen: ', # SciScreen
|
|
39
35
|
/\s(-\s)*(With)*\sLive Q And A/i, # Live Q&A
|
|
40
36
|
/(\s+\-\s+)?MOVIES FOR JUNIORS/i, # movies for juniors
|
|
41
|
-
/\bsing\-?a\-?long\b/i, # singalong
|
|
42
37
|
%r{\s20\d{2}[\/-]20\d{2} Season\b}
|
|
43
|
-
]
|
|
38
|
+
] + COMMON_REMOVE
|
|
44
39
|
end
|
|
45
40
|
|
|
46
41
|
# Regexes and their replacements
|
|
@@ -61,7 +56,7 @@ module CineworldUk
|
|
|
61
56
|
/ROH The Royal Ballet\s*[:-] (.*)/ => 'The Royal Ballet: ',
|
|
62
57
|
/Royal Ballet Live\s*[:-] (.*)/ => 'The Royal Ballet: ',
|
|
63
58
|
/San Francisco Ballets (.*)/ => 'San Francisco Ballet: '
|
|
64
|
-
}
|
|
59
|
+
}.merge(COMMON_REPLACE)
|
|
65
60
|
end
|
|
66
61
|
end
|
|
67
62
|
end
|
|
@@ -71,14 +71,18 @@ module CineworldUk
|
|
|
71
71
|
events.map do |event_data|
|
|
72
72
|
performance = Internal::Parser::Api::Performance.new(event_data)
|
|
73
73
|
film = films_hash[performance.film_id]
|
|
74
|
+
starting_at = utc(performance.starting_at)
|
|
74
75
|
|
|
75
76
|
{
|
|
76
77
|
cinema_name: response["body"]["cinemaName"] ||
|
|
77
78
|
CineworldUk::Cinema.new(cinema_id).name,
|
|
78
79
|
booking_url: performance.booking_url,
|
|
79
80
|
dimension: film.dimension,
|
|
81
|
+
festival: film.festival(starting_at.year),
|
|
80
82
|
film_name: film.name,
|
|
81
|
-
|
|
83
|
+
film_year: film.film_year,
|
|
84
|
+
language: performance.language,
|
|
85
|
+
starting_at: starting_at,
|
|
82
86
|
variant: (performance.variant + film.variant).sort
|
|
83
87
|
}
|
|
84
88
|
end
|
data/lib/cineworld_uk/version.rb
CHANGED
data/lib/cineworld_uk.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require 'json'
|
|
2
2
|
|
|
3
3
|
require 'cinebase'
|
|
4
|
+
require 'cinebase/vista'
|
|
4
5
|
|
|
5
6
|
require_relative './cineworld_uk/version'
|
|
6
7
|
|
|
@@ -17,7 +18,7 @@ require_relative './cineworld_uk/performance'
|
|
|
17
18
|
|
|
18
19
|
# cineworld_uk gem
|
|
19
20
|
module CineworldUk
|
|
20
|
-
|
|
21
|
+
AuthenticationError = Cinebase::Vista::AuthenticationError
|
|
21
22
|
|
|
22
23
|
# A raw guest JWT, without the "Bearer " prefix. Never persisted by the gem.
|
|
23
24
|
class << self
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"businessDate": "2026-10-24",
|
|
3
|
+
"showtimes": [
|
|
4
|
+
{
|
|
5
|
+
"id": "014-1001",
|
|
6
|
+
"filmId": "FILM-1",
|
|
7
|
+
"schedule": { "startsAt": "2026-10-24T09:00:00+01:00" },
|
|
8
|
+
"attributeIds": ["A-2D", "A-AD"],
|
|
9
|
+
"requires3dGlasses": false
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": "014-1002",
|
|
13
|
+
"filmId": "FILM-1",
|
|
14
|
+
"schedule": { "startsAt": "2026-10-24T14:30:00+01:00" },
|
|
15
|
+
"attributeIds": ["A-IMAX"],
|
|
16
|
+
"requires3dGlasses": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "014-1003",
|
|
20
|
+
"filmId": "FILM-2",
|
|
21
|
+
"schedule": { "startsAt": "2026-10-24T18:00:00+01:00" },
|
|
22
|
+
"attributeIds": ["A-TAMIL", "A-ST"],
|
|
23
|
+
"requires3dGlasses": false
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "014-1004",
|
|
27
|
+
"filmId": "FILM-3",
|
|
28
|
+
"schedule": { "startsAt": "2026-10-24T10:00:00+01:00" },
|
|
29
|
+
"attributeIds": ["A-M4J"],
|
|
30
|
+
"requires3dGlasses": false
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "014-1005",
|
|
34
|
+
"filmId": "FILM-4",
|
|
35
|
+
"schedule": { "startsAt": "2026-10-24T20:15:00+01:00" },
|
|
36
|
+
"attributeIds": ["A-AC"],
|
|
37
|
+
"requires3dGlasses": false
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": "014-1007",
|
|
41
|
+
"filmId": "FILM-5",
|
|
42
|
+
"schedule": { "startsAt": "2026-10-24T21:00:00+01:00" },
|
|
43
|
+
"attributeIds": ["A-4DX"],
|
|
44
|
+
"requires3dGlasses": false
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "014-1006",
|
|
48
|
+
"filmId": "FILM-1",
|
|
49
|
+
"schedule": { "startsAt": "2026-10-25T00:15:00+01:00" },
|
|
50
|
+
"attributeIds": [],
|
|
51
|
+
"requires3dGlasses": false
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"relatedData": {
|
|
55
|
+
"films": [
|
|
56
|
+
{ "id": "FILM-1", "title": { "text": "The Example Film" } },
|
|
57
|
+
{ "id": "FILM-2", "title": { "text": "Imaginary Picture (Tamil)" } },
|
|
58
|
+
{ "id": "FILM-3", "title": { "text": "Pretend Pups - Movies For Juniors" } },
|
|
59
|
+
{ "id": "FILM-4", "title": { "text": "Cine-Excess 2026: Scum Of The Earth" } },
|
|
60
|
+
{ "id": "FILM-5", "title": { "text": "(4DX) Wildwood (2026)" } }
|
|
61
|
+
],
|
|
62
|
+
"attributes": [
|
|
63
|
+
{ "id": "A-2D", "shortName": { "text": "2D" }, "name": { "text": "2D Film" } },
|
|
64
|
+
{ "id": "A-AD", "shortName": { "text": "AD" }, "name": { "text": "Audio Described" } },
|
|
65
|
+
{ "id": "A-IMAX", "shortName": { "text": "IMAX" }, "name": { "text": "IMAX Film" } },
|
|
66
|
+
{ "id": "A-TAMIL", "shortName": { "text": "Tamil" }, "name": { "text": "Tamil" } },
|
|
67
|
+
{ "id": "A-ST", "shortName": { "text": "ST" }, "name": { "text": "Subtitled" } },
|
|
68
|
+
{ "id": "A-M4J", "shortName": { "text": "M4J" }, "name": { "text": "Movies for Juniors" } },
|
|
69
|
+
{ "id": "A-AC", "shortName": { "text": "AC" }, "name": { "text": "Event Cinema" } },
|
|
70
|
+
{ "id": "A-4DX", "shortName": { "text": "4DX" }, "name": { "text": "4DX" } }
|
|
71
|
+
],
|
|
72
|
+
"sites": [
|
|
73
|
+
{ "id": "014", "name": { "text": "Brighton" } }
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sites": [
|
|
3
|
+
{
|
|
4
|
+
"id": "014",
|
|
5
|
+
"name": { "text": "Brighton" },
|
|
6
|
+
"contactDetails": {
|
|
7
|
+
"addressV2": {
|
|
8
|
+
"line1": { "text": "1 Example Marina" },
|
|
9
|
+
"line2": { "text": "Brighton" },
|
|
10
|
+
"line3": { "text": "East Sussex" },
|
|
11
|
+
"line4": { "text": "BN2 0ZZ" }
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "088",
|
|
17
|
+
"name": { "text": "Glasgow Silverburn" },
|
|
18
|
+
"contactDetails": {
|
|
19
|
+
"addressV2": {
|
|
20
|
+
"line1": { "text": "2 Example Centre" },
|
|
21
|
+
"line2": { "text": "Glasgow" },
|
|
22
|
+
"line3": { "text": "Lanarkshire" },
|
|
23
|
+
"line4": { "text": "G53 0ZZ" }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "103",
|
|
29
|
+
"name": { "text": "Leicester Square" },
|
|
30
|
+
"contactDetails": {
|
|
31
|
+
"addressV2": {
|
|
32
|
+
"line1": { "text": "3 Example Square" },
|
|
33
|
+
"line2": { "text": "London" },
|
|
34
|
+
"line3": null,
|
|
35
|
+
"line4": { "text": "WC2H 0ZZ" }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": "999",
|
|
41
|
+
"name": { "text": "Example - Riverside" },
|
|
42
|
+
"contactDetails": {
|
|
43
|
+
"addressV2": {
|
|
44
|
+
"line1": { "text": "4 Example Quay" },
|
|
45
|
+
"line2": { "text": "Exampleton" },
|
|
46
|
+
"line3": null,
|
|
47
|
+
"line4": { "text": "EX1 0ZZ" }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|