spektrix_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.
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SpektrixUk
4
+ # Internal utility classes: Do not use
5
+ # @api private
6
+ module Internal
7
+ Venue = Data.define(
8
+ :id, :name, :client, :url, :booking_url, :adr, :latitude, :longitude,
9
+ :film, :three_d, :year, :event_variants, :instance_variants
10
+ )
11
+
12
+ # A cinema selling through Spektrix. Each Spektrix account names its
13
+ # attributes differently, so each venue says how to read them.
14
+ #
15
+ # @!attribute [r] id
16
+ # @return [String] the gem's own stable id, e.g. 'tyneside'
17
+ # @!attribute [r] client
18
+ # @return [String] the Spektrix account, e.g. 'tynesidecinema'
19
+ # @!attribute [r] booking_url
20
+ # @return [String] format string taking the instance number
21
+ # @!attribute [r] film
22
+ # @return [Proc] whether an event is a film
23
+ # @!attribute [r] three_d
24
+ # @return [String, nil] instance attribute marking 3D
25
+ # @!attribute [r] year
26
+ # @return [String, nil] event attribute holding the film's year
27
+ # @!attribute [r] event_variants
28
+ # @return [Hash] event attribute => { value => variant }
29
+ # @!attribute [r] instance_variants
30
+ # @return [Hash] instance attribute => { value => variant }
31
+ class Venue
32
+ # Tickets, passes and courses that some venues file alongside films
33
+ NOT_FILMS = /\bPass\z|\bBundle\b|\bLecture\b|Gift Voucher|Membership/i
34
+
35
+ COUNTRY = "United Kingdom"
36
+
37
+ ALL = [
38
+ new(
39
+ id: "broadway",
40
+ name: "Broadway",
41
+ client: "broadwaynottingham",
42
+ url: "https://www.broadway.org.uk",
43
+ booking_url: "https://www.broadway.org.uk/book/%<instance>s",
44
+ adr: { street_address: "14-18 Broad Street", locality: "Nottingham", postal_code: "NG1 3AL" },
45
+ latitude: 52.954306,
46
+ longitude: -1.143663,
47
+ film: ->(event) { event["attribute_Film"] == true || event["attribute_EventCinema"] == true },
48
+ three_d: nil,
49
+ year: "attribute_Year",
50
+ event_variants: { "attribute_EventCinema" => { true => "arts" } },
51
+ instance_variants: {
52
+ "attribute_AD" => { true => "audio_described" },
53
+ "attribute_Captioned" => { true => "subtitled" },
54
+ "attribute_DementiaFriendly" => { true => "relaxed" },
55
+ "attribute_FamilyMatinee" => { true => "kids" },
56
+ "attribute_ParentAndBaby" => { true => "baby" },
57
+ "attribute_SilverScreen" => { true => "senior" }
58
+ }
59
+ ),
60
+ new(
61
+ id: "home",
62
+ name: "HOME",
63
+ client: "home",
64
+ url: "https://homemcr.org",
65
+ booking_url: "https://tickets.homemcr.org/home/website/ChooseSeats.aspx?EventInstanceId=%<instance>s",
66
+ adr: { street_address: "2 Tony Wilson Place", locality: "Manchester", postal_code: "M15 4FN" },
67
+ latitude: 53.473626,
68
+ longitude: -2.246606,
69
+ film: ->(event) { event["attribute_ShowType"] == "Film" },
70
+ three_d: nil,
71
+ year: nil,
72
+ event_variants: { "attribute_EventCategory" => { "Stage on Screen" => "arts" } },
73
+ instance_variants: {
74
+ "attribute_AdditionalEvent" => { "+ Q&A" => "q&a" },
75
+ "attribute_AudioDescription" => { "AD" => "audio_described" },
76
+ "attribute_CaptionSubtitled" => { "CAP" => "subtitled" },
77
+ "attribute_ParentAndBaby" => { "Baby Friendly" => "baby" },
78
+ "attribute_Relaxed" => { "Relaxed" => "relaxed" }
79
+ }
80
+ ),
81
+ # The Leeds Heritage Theatres account also sells Leeds Grand Theatre
82
+ # and City Varieties, which host some of the cinema's own screenings
83
+ new(
84
+ id: "hpph",
85
+ name: "Hyde Park Picture House",
86
+ client: "leedsheritagetheatres",
87
+ url: "https://hpph.co.uk",
88
+ booking_url: "https://tickets.hpph.co.uk/leedsheritagetheatres/website/ChooseSeats.aspx?EventInstanceId=%<instance>s",
89
+ adr: { street_address: "73 Brudenell Road", locality: "Leeds", postal_code: "LS6 1JD" },
90
+ latitude: 53.812058,
91
+ longitude: -1.569421,
92
+ film: lambda { |event|
93
+ event["attribute_LiveOrFilm"] == "Film" && event["attribute_Website"] == "HPPH" &&
94
+ ["Hyde Park Picture House", ""].include?(event["attribute_Venue"])
95
+ },
96
+ three_d: nil,
97
+ year: "attribute_YearOfProduction",
98
+ event_variants: {
99
+ "attribute_AlternativeContent" => { true => "arts" },
100
+ "attribute_AudioDescription" => { true => "audio_described" }
101
+ },
102
+ instance_variants: {
103
+ "attribute_Analogue" => { "35mm" => "35mm" },
104
+ "attribute_AudioDescribed" => { true => "audio_described" },
105
+ "attribute_AutismFriendlyScreening" => { true => "relaxed" },
106
+ "attribute_Captioned" => { true => "subtitled" },
107
+ "attribute_CinemaSpecialEvent" => { "Q&A" => "q&a" },
108
+ "attribute_DementiaFriendly" => { true => "relaxed" },
109
+ "attribute_RelaxedPerformance" => { true => "relaxed" },
110
+ "attribute_Strand" => { "Bring Your Own Baby" => "baby" },
111
+ "attribute_ToddlerFriendlyScreening" => { true => "kids" }
112
+ }
113
+ ),
114
+ new(
115
+ id: "showroom",
116
+ name: "Showroom Cinema",
117
+ client: "showroomworkstation",
118
+ url: "https://showroomcinema.org.uk",
119
+ booking_url: "https://tickets.showroomcinema.org.uk/showroomworkstation/website/ChooseSeats.aspx?EventInstanceId=%<instance>s",
120
+ adr: { street_address: "15 Paternoster Row", locality: "Sheffield", postal_code: "S1 2BX" },
121
+ latitude: 53.377263,
122
+ longitude: -1.46532,
123
+ film: ->(event) { event["attribute_ShowroomNonFilmEvent"] != true },
124
+ three_d: nil,
125
+ year: nil,
126
+ event_variants: {
127
+ "attribute_Genre1Dropdown" => { "Alternative Content" => "arts", "Theatre" => "arts" },
128
+ "attribute_Genre2Dropdown" => { "Alternative Content" => "arts" },
129
+ "attribute_Genre3Dropdown" => { "Alternative Content" => "arts" }
130
+ },
131
+ instance_variants: {
132
+ "attribute_AccessAudioDescribed" => { true => "audio_described" },
133
+ "attribute_AccessDementiaFriendly" => { true => "relaxed" },
134
+ "attribute_AccessRelaxed" => { true => "relaxed" },
135
+ "attribute_AccessSubtitled" => { true => "subtitled" },
136
+ "attribute_Strand" => { "Baby Kino" => "baby", "Family Time" => "kids", "Relaxed Screenings" => "relaxed" }
137
+ }
138
+ ),
139
+ new(
140
+ id: "tyneside",
141
+ name: "Tyneside Cinema",
142
+ client: "tynesidecinema",
143
+ url: "https://tynesidecinema.co.uk",
144
+ booking_url: "https://tynesidecinema.co.uk/book-online/%<instance>s",
145
+ adr: { street_address: "10 Pilgrim Street", locality: "Newcastle upon Tyne", postal_code: "NE1 6QG" },
146
+ latitude: 54.973903,
147
+ longitude: -1.612254,
148
+ film: ->(event) { event["attribute_Medium"] != "Non-Film" },
149
+ three_d: "attribute_3DScreening",
150
+ year: nil,
151
+ event_variants: {
152
+ "attribute_AudioDescription" => { true => "audio_described" },
153
+ "attribute_Genre1" => { "Concert Film/Event Cinema" => "arts" }
154
+ },
155
+ instance_variants: {
156
+ "attribute_35mmScreening" => { true => "35mm" },
157
+ "attribute_DementiaFriendly" => { true => "relaxed" },
158
+ "attribute_FamilyFilmClub" => { true => "kids" },
159
+ "attribute_LiveSatelliteScreening" => { true => "arts" },
160
+ "attribute_QAndAScreening" => { true => "q&a" },
161
+ "attribute_RelaxedScreening" => { true => "relaxed" },
162
+ "attribute_SilverScreen" => { true => "senior" },
163
+ "attribute_SubtitledForHardOfHearing" => { true => "subtitled" },
164
+ "attribute_TynesideBabyClub" => { true => "baby" }
165
+ }
166
+ )
167
+ ].to_h { |venue| [venue.id, venue] }.freeze
168
+
169
+ # @param [String] id e.g. 'tyneside'
170
+ # @return [SpektrixUk::Internal::Venue]
171
+ # @raise [KeyError] for an unknown id
172
+ def self.find(id)
173
+ ALL.fetch(id.to_s)
174
+ end
175
+
176
+ # @param [Hash] event a Spektrix event
177
+ # @return [Boolean]
178
+ def film?(event)
179
+ film.call(event) && !event["name"].to_s.match?(NOT_FILMS)
180
+ end
181
+
182
+ # @return [Hash] address in microformats adr naming
183
+ def address
184
+ {
185
+ street_address: adr[:street_address],
186
+ extended_address: nil,
187
+ locality: adr[:locality],
188
+ region: nil,
189
+ postal_code: adr[:postal_code],
190
+ country_name: COUNTRY
191
+ }
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,82 @@
1
+ module SpektrixUk
2
+ # A single screening of a film at a Spektrix cinema
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 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 the film was made
24
+ # @option options [Time] :starting_at listed start time of the performance
25
+
26
+ # Spektrix lists some films a month ahead at midnight, before the times
27
+ # are set
28
+ PLACEHOLDER_TIME = 'T00:00:00'.freeze
29
+
30
+ # Films within an inclusive range of showing dates, from two requests for
31
+ # any range: the venue's events and their instances.
32
+ # @param [String] cinema_id id of the cinema, e.g. 'tyneside'
33
+ # @param [Date] from first date (defaults to today in London)
34
+ # @param [Date] to last date (defaults to 13 days after from)
35
+ # @return [Array<SpektrixUk::Performance>]
36
+ # @raise [KeyError] for an unknown cinema
37
+ def self.at(
38
+ cinema_id,
39
+ from: TZInfo::Timezone.get('Europe/London').now.to_date,
40
+ to: from + 13
41
+ )
42
+ raise ArgumentError, 'to must not precede from' if to < from
43
+
44
+ cinema = Cinema.new(cinema_id)
45
+ venue = SpektrixUk::Internal::Venue.find(cinema.id)
46
+ api = SpektrixUk::Internal::Api.new(venue.client)
47
+ films = api.events(from, to + 1).select { |event| venue.film?(event) }.to_h { |event| [event.fetch('id'), event] }
48
+ performances = screenings(api.instances(from, to + 1), films, from..to).map do |instance|
49
+ parsed = SpektrixUk::Internal::Parser::Instance.new(instance, event: films.fetch(instance.dig('event', 'id')), venue: venue)
50
+ new(parsed.to_hash.merge(cinema_id: cinema.id, cinema_name: cinema.name))
51
+ end
52
+ performances.sort_by(&:starting_at)
53
+ end
54
+
55
+ # @!method showing_on
56
+ # The date of the screening
57
+ # @return [Date]
58
+
59
+ # @!method starting_at
60
+ # UTC time of the screening
61
+ # @return [Time]
62
+
63
+ # @!method variant
64
+ # The kinds of screening (arts, audio_described, kids, subtitled ...)
65
+ # @return <Array[String]>
66
+
67
+ # private
68
+
69
+ # Instances that go ahead, of films, at a set time, on a London date in
70
+ # the range
71
+ def self.screenings(instances, films, dates)
72
+ instances.select do |instance|
73
+ start = instance.fetch('start')
74
+ !instance['cancelled'] &&
75
+ films.key?(instance.dig('event', 'id')) &&
76
+ !start.end_with?(PLACEHOLDER_TIME) &&
77
+ dates.cover?(Date.iso8601(start[0, 10]))
78
+ end
79
+ end
80
+ private_class_method :screenings
81
+ end
82
+ end
@@ -0,0 +1,6 @@
1
+ # Ruby interface for UK independent cinemas that sell tickets through Spektrix
2
+ # @version 1.0.0
3
+ module SpektrixUk
4
+ # Gem version
5
+ VERSION = '1.0.0'.freeze
6
+ end
@@ -0,0 +1,19 @@
1
+ require 'json'
2
+
3
+ require 'cinebase'
4
+
5
+ require_relative './spektrix_uk/version'
6
+
7
+ require_relative './spektrix_uk/internal/http'
8
+ require_relative './spektrix_uk/internal/api'
9
+ require_relative './spektrix_uk/internal/venue'
10
+ require_relative './spektrix_uk/internal/title_sanitizer'
11
+
12
+ require_relative './spektrix_uk/internal/parser/instance'
13
+
14
+ require_relative './spektrix_uk/cinema'
15
+ require_relative './spektrix_uk/performance'
16
+
17
+ # spektrix_uk gem
18
+ module SpektrixUk
19
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spektrix_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.6'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '5.6'
110
+ description: Pull movie & cinema information from UK independent cinemas that use
111
+ Spektrix
112
+ email:
113
+ - andy@goodscary.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - CHANGELOG.md
119
+ - COMM-LICENSE
120
+ - LICENSE
121
+ - README.md
122
+ - lib/spektrix_uk.rb
123
+ - lib/spektrix_uk/cinema.rb
124
+ - lib/spektrix_uk/internal/api.rb
125
+ - lib/spektrix_uk/internal/http.rb
126
+ - lib/spektrix_uk/internal/parser/instance.rb
127
+ - lib/spektrix_uk/internal/title_sanitizer.rb
128
+ - lib/spektrix_uk/internal/venue.rb
129
+ - lib/spektrix_uk/performance.rb
130
+ - lib/spektrix_uk/version.rb
131
+ homepage: https://github.com/andycroll/spektrix_uk
132
+ licenses:
133
+ - AGPL
134
+ - MIT
135
+ metadata: {}
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '3.4'
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ requirements: []
150
+ rubygems_version: 4.0.20
151
+ specification_version: 4
152
+ summary: It's an API client, but a nice one
153
+ test_files: []