cineworld_uk 4.2.0-aarch64-linux-gnu → 4.3.2-aarch64-linux-gnu

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a53e950d494fc1001a5468c753534f9cc5668358049ac76e11f3e99fc75994a9
4
- data.tar.gz: 3edce17e65610aa1aeceb35e9705a3679239a350d09d85f545033d8d4d59bf5c
3
+ metadata.gz: 14cb5242f05eeed5d33d552343b6e8776c0c503dcf5ffc160da8c27a12f64f7e
4
+ data.tar.gz: 15f50f8493be63748390c5511bc8d9def8ce730a67c79e07f53df602f89f64cc
5
5
  SHA512:
6
- metadata.gz: 11dc64e0eebf618fcc5e3cf5a7c6e6f302f5705cba98d73b6f040d450b1957d6c01dab6ffe85c1d7c3cb25b51f537654f4af5b505229b3c57e424a0f93bcd991
7
- data.tar.gz: ce879b7ffd4b058ef2a3a0568aefa8e5b6c0ae6b1c87e5727fd852567d1aae7e5981f3debf3d6d8cf25d739ff81d0693342fa54d6ee084797b2aca7d7d6f0552
6
+ metadata.gz: 700a1af26d3110e3b2b920144280a53d2892390ba7e08d87e268b8ca54e8e79e327e0dfd7a2b02c136a554f2d0225966e9ffb4a18d3bb843f6b9e7815d5eec24
7
+ data.tar.gz: b6a2b40e8b5f0df0a12f3c357245ef150d87042b0131ed350b754e7d227b9141d3e794318cef2e6804b5052c9b7c48e80b10d094424c4ea2e007f2465b0cfbcb
@@ -0,0 +1,73 @@
1
+ name: Release Gem
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ jobs:
7
+ package:
8
+ strategy:
9
+ matrix:
10
+ include:
11
+ - runner: ubuntu-latest
12
+ platform: x86_64-linux-gnu
13
+ - runner: ubuntu-24.04-arm
14
+ platform: aarch64-linux-gnu
15
+ - runner: macos-15
16
+ platform: arm64-darwin
17
+ - runner: macos-15-intel
18
+ platform: x86_64-darwin
19
+ runs-on: ${{ matrix.runner }}
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: '4.0'
25
+ bundler-cache: true
26
+ - run: bundle exec rake 'package:native[${{ matrix.platform }}]'
27
+ - run: CINEWORLD_PACKAGE="$(echo pkg/*.gem)" bundle exec ruby test/package_test.rb
28
+ - uses: actions/upload-artifact@v4
29
+ with:
30
+ name: gem-${{ matrix.platform }}
31
+ path: pkg/*.gem
32
+
33
+ release:
34
+ needs: package
35
+ runs-on: ubuntu-latest
36
+ permissions:
37
+ id-token: write
38
+ contents: write
39
+ steps:
40
+ - uses: actions/checkout@v4
41
+ - uses: ruby/setup-ruby@v1
42
+ with:
43
+ ruby-version: '4.0'
44
+ bundler-cache: true
45
+ - run: bundle exec rake test
46
+ - run: bundle exec rake build
47
+ - uses: actions/download-artifact@v4
48
+ with:
49
+ path: pkg
50
+ pattern: gem-*
51
+ merge-multiple: true
52
+ - uses: rubygems/configure-rubygems-credentials@v1.0.0
53
+ - name: Push the source and platform gems
54
+ run: |
55
+ for gem in pkg/*.gem; do
56
+ if output=$(gem push "$gem" 2>&1); then
57
+ echo "$output"
58
+ elif echo "$output" | grep -q "Repushing of gem versions is not allowed"; then
59
+ echo "Already published: $gem"
60
+ else
61
+ echo "$output"
62
+ exit 1
63
+ fi
64
+ done
65
+ - name: Tag the release
66
+ run: |
67
+ tag="v$(ruby -e 'print Gem::Specification.load(Dir["*.gemspec"].first).version')"
68
+ if git ls-remote --exit-code --tags origin "$tag" >/dev/null; then
69
+ echo "$tag already exists"
70
+ else
71
+ git tag "$tag"
72
+ git push origin "$tag"
73
+ fi
data/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
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.2 - 2026-10-22
6
+
7
+ ### Changed
8
+ - Reuse one Vista client, and so one kept-alive connection, per thread instead of opening a TLS connection for every request. Requires cinebase 5.5. A cinema day now takes about 0.19s rather than 0.37s.
9
+
10
+ ## 4.3.1 - 2026-10-22
11
+
12
+ ### Fixed
13
+ - Publish the platform gems that bundle curl-impersonate. 4.3.0 shipped only the source gem. No code changes.
14
+
15
+ ## 4.3.0 - 2026-10-22
16
+
17
+ ### Added
18
+ - `Performance#film_year`, read from a trailing `(1996)` in the title, so a re-release gives the original year.
19
+ - `4dx` and `screenx` variants from Vista's `4DX`, `4DX 3D` and `ScreenX` attributes.
20
+
21
+ ### Changed
22
+ - Require cinebase 5.4. Titles also lose `+ ... Q&A` and `+ Discussion` add-ons, `(35mm)`, `(70mm)` and `4K` markers, and `CFF:` festival prefixes.
23
+ - 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.
24
+
5
25
  ## 4.2.0 - 2026-10-22
6
26
 
7
27
  ### Added
data/README.md CHANGED
@@ -177,6 +177,9 @@ 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
+
180
183
  performance.language
181
184
  #=> 'Tamil' # audio language, nil when the cinema does not tag one
182
185
 
@@ -226,7 +229,7 @@ To build and check just one platform on a matching host:
226
229
 
227
230
  ```sh
228
231
  bundle exec rake 'package:native[x86_64-linux-gnu]'
229
- CINEWORLD_PACKAGE=pkg/cineworld_uk-4.2.0-x86_64-linux-gnu.gem bundle exec ruby test/package_test.rb
232
+ CINEWORLD_PACKAGE=pkg/cineworld_uk-4.3.2-x86_64-linux-gnu.gem bundle exec ruby test/package_test.rb
230
233
  ```
231
234
 
232
235
  Native packaging downloads pinned upstream archives at **build time**, verifies
@@ -236,6 +239,11 @@ and installation-tests each platform on its corresponding runner and saves the
236
239
  gems as workflow artifacts; it does not publish them. Publish the source and
237
240
  platform gems together for automatic platform selection to work for users.
238
241
 
242
+ To release, bump the version, merge, then run the **Release Gem** workflow in
243
+ GitHub Actions. It builds the source and four platform gems, publishes them
244
+ through RubyGems trusted publishing (no MFA code needed) and tags the release.
245
+ Versions already on RubyGems are skipped, so a failed run can be rerun.
246
+
239
247
  ## Contributing
240
248
 
241
249
  1. Fork it
data/cineworld_uk.gemspec CHANGED
@@ -25,6 +25,6 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency 'simplecov', '< 1'
26
26
  spec.add_development_dependency 'webmock'
27
27
 
28
- spec.add_runtime_dependency 'cinebase', '~> 5.2'
28
+ spec.add_runtime_dependency 'cinebase', '~> 5.5'
29
29
  spec.add_runtime_dependency 'nokogiri', '>= 1.11'
30
30
  end
@@ -14,7 +14,8 @@ module CineworldUk
14
14
  "Subtitled" => "subbed", "Subtitles" => "subbed",
15
15
  "Autism Friendly" => "autism-friendly",
16
16
  "Movies for Juniors" => "junior",
17
- "Unlimited Screening" => "unlimited-screening", "Q&A" => "qa"
17
+ "Unlimited Screening" => "unlimited-screening", "Q&A" => "qa",
18
+ "4DX" => "4dx", "4DX 3D" => "4dx", "ScreenX" => "screenx"
18
19
  }.freeze
19
20
  LANGUAGES = Cinebase::TitleSanitizer::LANGUAGES
20
21
 
@@ -85,8 +86,17 @@ module CineworldUk
85
86
  private
86
87
 
87
88
  def fetch(path, query = {})
88
- Cinebase::Vista::Client.new(base_url: BASE_URL, region_code: "GB",
89
- token: CineworldUk.token).get(path, query)
89
+ client.get(path, query)
90
+ end
91
+
92
+ # One client keeps one connection open, so reuse it until the token changes.
93
+ def client
94
+ token = CineworldUk.token
95
+ if @client.nil? || @client_token != token
96
+ @client_token = token
97
+ @client = Cinebase::Vista::Client.new(base_url: BASE_URL, region_code: "GB", token: token)
98
+ end
99
+ @client
90
100
  end
91
101
  end
92
102
  end
@@ -27,6 +27,11 @@ module CineworldUk
27
27
  Cinebase::Festival.from_title(@data['name'] || '', year: year)
28
28
  end
29
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
+
30
35
  # Sanitized film name
31
36
  # @return [String]
32
37
  def name
@@ -40,11 +45,13 @@ module CineworldUk
40
45
  def variant
41
46
  attrs = @data['attributeIds'] || []
42
47
  [
48
+ attrs.include?('4dx') ? '4dx' : nil,
43
49
  attrs.include?('autism-friendly') ? 'autism_friendly' : nil,
44
50
  attrs.include?('imax') ? 'imax' : nil,
45
51
  attrs.include?('junior') ? 'kids' : nil,
46
52
  attrs.include?('unlimited-screening') ? 'members' : nil,
47
- attrs.include?('qa') ? 'q&a' : nil
53
+ attrs.include?('qa') ? 'q&a' : nil,
54
+ attrs.include?('screenx') ? 'screenx' : nil
48
55
  ].compact
49
56
  end
50
57
  end
@@ -28,6 +28,9 @@ module CineworldUk
28
28
  /\ATake 2 -/, # take 2
29
29
  / - (Subtitled) Movies for Juniors/i, # movies for juniors
30
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
31
34
  'SciScreen: ', # SciScreen
32
35
  /\s(-\s)*(With)*\sLive Q And A/i, # Live Q&A
33
36
  /(\s+\-\s+)?MOVIES FOR JUNIORS/i, # movies for juniors
@@ -56,9 +56,13 @@ module CineworldUk
56
56
 
57
57
  # private
58
58
 
59
+ API = :cineworld_uk_performance_api
60
+
59
61
  # @api private
62
+ # One API, and so one kept-alive connection, per thread: job runners
63
+ # import several cinemas at once.
60
64
  def self.api
61
- @api ||= Internal::ApiResponse.new
65
+ Thread.current[API] ||= Internal::ApiResponse.new
62
66
  end
63
67
  private_class_method :api
64
68
 
@@ -80,6 +84,7 @@ module CineworldUk
80
84
  dimension: film.dimension,
81
85
  festival: film.festival(starting_at.year),
82
86
  film_name: film.name,
87
+ film_year: film.film_year,
83
88
  language: performance.language,
84
89
  starting_at: starting_at,
85
90
  variant: (performance.variant + film.variant).sort
@@ -1,6 +1,6 @@
1
1
  # Ruby interface for http://www.cineworld.co.uk
2
- # @version 4.2.0
2
+ # @version 4.3.2
3
3
  module CineworldUk
4
4
  # Gem version
5
- VERSION = "4.2.0".freeze
5
+ VERSION = "4.3.2".freeze
6
6
  end
@@ -36,6 +36,13 @@
36
36
  "attributeIds": ["A-AC"],
37
37
  "requires3dGlasses": false
38
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
+ },
39
46
  {
40
47
  "id": "014-1006",
41
48
  "filmId": "FILM-1",
@@ -49,7 +56,8 @@
49
56
  { "id": "FILM-1", "title": { "text": "The Example Film" } },
50
57
  { "id": "FILM-2", "title": { "text": "Imaginary Picture (Tamil)" } },
51
58
  { "id": "FILM-3", "title": { "text": "Pretend Pups - Movies For Juniors" } },
52
- { "id": "FILM-4", "title": { "text": "Cine-Excess 2026: Scum Of The Earth" } }
59
+ { "id": "FILM-4", "title": { "text": "Cine-Excess 2026: Scum Of The Earth" } },
60
+ { "id": "FILM-5", "title": { "text": "(4DX) Wildwood (2026)" } }
53
61
  ],
54
62
  "attributes": [
55
63
  { "id": "A-2D", "shortName": { "text": "2D" }, "name": { "text": "2D Film" } },
@@ -58,7 +66,8 @@
58
66
  { "id": "A-TAMIL", "shortName": { "text": "Tamil" }, "name": { "text": "Tamil" } },
59
67
  { "id": "A-ST", "shortName": { "text": "ST" }, "name": { "text": "Subtitled" } },
60
68
  { "id": "A-M4J", "shortName": { "text": "M4J" }, "name": { "text": "Movies for Juniors" } },
61
- { "id": "A-AC", "shortName": { "text": "AC" }, "name": { "text": "Event Cinema" } }
69
+ { "id": "A-AC", "shortName": { "text": "AC" }, "name": { "text": "Event Cinema" } },
70
+ { "id": "A-4DX", "shortName": { "text": "4DX" }, "name": { "text": "4DX" } }
62
71
  ],
63
72
  "sites": [
64
73
  { "id": "014", "name": { "text": "Brighton" } }
@@ -14,6 +14,45 @@ class CineworldUk::Internal::ApiResponseTest < Minitest::Test
14
14
  super
15
15
  end
16
16
 
17
+ def test_reuses_one_client_while_the_token_holds
18
+ stub_request(:get, "#{BASE_URL}sites").to_return(body: '{"sites":[]}')
19
+ api = CineworldUk::Internal::ApiResponse.new
20
+
21
+ clients = count_clients { 3.times { api.cinema_list } }
22
+
23
+ assert_equal 1, clients
24
+ end
25
+
26
+ def test_builds_a_new_client_for_a_new_token
27
+ stub_request(:get, "#{BASE_URL}sites").to_return(body: '{"sites":[]}')
28
+ api = CineworldUk::Internal::ApiResponse.new
29
+
30
+ clients = count_clients do
31
+ api.cinema_list
32
+ CineworldUk.token = "renewed-token"
33
+ api.cinema_list
34
+ end
35
+
36
+ assert_equal 2, clients
37
+ end
38
+
39
+ def test_each_thread_has_its_own_performance_api
40
+ main = CineworldUk::Performance.send(:api)
41
+
42
+ other = Thread.new { CineworldUk::Performance.send(:api) }.value
43
+
44
+ assert_same main, CineworldUk::Performance.send(:api)
45
+ refute_same main, other
46
+ end
47
+
48
+ def count_clients
49
+ clients = 0
50
+ original = Cinebase::Vista::Client.method(:new)
51
+ counting = ->(**options) { clients += 1; original.call(**options) }
52
+ Cinebase::Vista::Client.stub(:new, counting) { yield }
53
+ clients
54
+ end
55
+
17
56
  def test_rejects_missing_token
18
57
  CineworldUk.token = nil
19
58
 
@@ -47,6 +47,22 @@ class CineworldUk::Internal::Parser::Api::FilmTest < Minitest::Test
47
47
  assert_nil film.festival(2026)
48
48
  end
49
49
 
50
+ def test_film_year
51
+ assert_equal 1996, film('name' => 'Horror Season 2026 From Dusk Till Dawn (1996)').film_year
52
+ end
53
+
54
+ def test_film_year_without_year
55
+ assert_nil film.film_year
56
+ end
57
+
58
+ def test_variant_4dx
59
+ assert_includes film('attributeIds' => ['4dx']).variant, '4dx'
60
+ end
61
+
62
+ def test_variant_screenx
63
+ assert_includes film('attributeIds' => ['screenx']).variant, 'screenx'
64
+ end
65
+
50
66
  def test_variant_is_sorted
51
67
  variant = film('attributeIds' => %w(qa junior imax)).variant
52
68
 
@@ -90,6 +90,31 @@ class CineworldUk::Internal::TitleSanitizerTest < Minitest::Test
90
90
  assert_sanitized 'Bebefinn Sing-Along Movie', 'Bebefinn Sing-Along Movie'
91
91
  end
92
92
 
93
+ def test_removes_format_prefix
94
+ assert_sanitized 'Wildwood', '(4DX) Wildwood'
95
+ assert_sanitized 'Wildwood', '(ScreenX) Wildwood'
96
+ end
97
+
98
+ def test_removes_movies_for_juniors_prefix
99
+ assert_sanitized 'Paw Patrol: The Mighty Movie', 'M4J: Paw Patrol: The Mighty Movie'
100
+ end
101
+
102
+ def test_removes_family_films_prefix
103
+ assert_sanitized 'Paw Patrol: The Dino Movie', '£2 Family Films : Paw Patrol: The Dino Movie'
104
+ end
105
+
106
+ def test_removes_film_year
107
+ assert_sanitized 'Street Fighter', 'Street Fighter (2026)'
108
+ end
109
+
110
+ def test_removes_season_prefix_and_year
111
+ assert_sanitized 'From Dusk Till Dawn', 'Horror Season 2026 From Dusk Till Dawn (1996)'
112
+ end
113
+
114
+ def test_removes_re_release
115
+ assert_sanitized 'Zindagi Na Milegi Dobara', 'Zindagi Na Milegi Dobara (Re-release) (Hindi)'
116
+ end
117
+
93
118
  def test_removes_festival_prefix
94
119
  assert_sanitized 'Scum Of The Earth', 'Cine-Excess 2026: Scum Of The Earth'
95
120
  end
@@ -18,13 +18,13 @@ class CineworldUk::PerformanceTest < Minitest::Test
18
18
  performances = performances_on_date
19
19
 
20
20
  assert(performances.all? { |p| p.instance_of?(CineworldUk::Performance) })
21
- assert_equal 6, performances.count
21
+ assert_equal 7, performances.count
22
22
  end
23
23
 
24
24
  def test_at_accepts_string_id
25
25
  stub_showtimes(DATE)
26
26
 
27
- assert_equal 6, CineworldUk::Performance.at('014', from: DATE, to: DATE).count
27
+ assert_equal 7, CineworldUk::Performance.at('014', from: DATE, to: DATE).count
28
28
  end
29
29
 
30
30
  def test_at_parses_first_performance
@@ -70,6 +70,18 @@ class CineworldUk::PerformanceTest < Minitest::Test
70
70
  assert_equal Cinebase::Festival.new(name: 'Cine-Excess', year: 2026), performance.festival
71
71
  end
72
72
 
73
+ def test_at_parses_format_and_film_year
74
+ performance = performances_on_date[5]
75
+
76
+ assert_equal 'Wildwood', performance.film_name
77
+ assert_equal 2026, performance.film_year
78
+ assert_equal %w(4dx), performance.variant
79
+ end
80
+
81
+ def test_new_sets_film_year
82
+ assert_equal 1996, CineworldUk::Performance.new(options(film_year: 1996)).film_year
83
+ end
84
+
73
85
  def test_at_keeps_after_midnight_on_next_utc_day
74
86
  assert_equal Time.utc(2026, 10, 24, 23, 15), performances_on_date.last.starting_at
75
87
  end
@@ -80,7 +92,7 @@ class CineworldUk::PerformanceTest < Minitest::Test
80
92
 
81
93
  performances = CineworldUk::Performance.at(14, from: DATE, to: DATE + 1)
82
94
 
83
- assert_equal 6, performances.count
95
+ assert_equal 7, performances.count
84
96
  assert_not_requested :get, "#{BASE_URL}sites"
85
97
  end
86
98
 
@@ -53,6 +53,7 @@ module Support
53
53
  [CineworldUk::Cinema, CineworldUk::Performance].each do |klass|
54
54
  klass.instance_variables.each { |name| klass.remove_instance_variable(name) }
55
55
  end
56
+ Thread.current[CineworldUk::Performance::API] = nil if defined?(CineworldUk::Performance::API)
56
57
  end
57
58
  end
58
59
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cineworld_uk
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.0
4
+ version: 4.3.2
5
5
  platform: aarch64-linux-gnu
6
6
  authors:
7
7
  - Andy Croll
@@ -113,14 +113,14 @@ dependencies:
113
113
  requirements:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
- version: '5.2'
116
+ version: '5.5'
117
117
  type: :runtime
118
118
  prerelease: false
119
119
  version_requirements: !ruby/object:Gem::Requirement
120
120
  requirements:
121
121
  - - "~>"
122
122
  - !ruby/object:Gem::Version
123
- version: '5.2'
123
+ version: '5.5'
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: nokogiri
126
126
  requirement: !ruby/object:Gem::Requirement
@@ -143,6 +143,7 @@ extensions: []
143
143
  extra_rdoc_files: []
144
144
  files:
145
145
  - ".agents/setup"
146
+ - ".github/workflows/release.yml"
146
147
  - ".github/workflows/test.yml"
147
148
  - ".gitignore"
148
149
  - ".ruby-version"
@@ -217,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
218
  - !ruby/object:Gem::Version
218
219
  version: '0'
219
220
  requirements: []
220
- rubygems_version: 3.6.9
221
+ rubygems_version: 4.0.20
221
222
  specification_version: 4
222
223
  summary: It's a scraper, but a nice one
223
224
  test_files: