-
Notifications
You must be signed in to change notification settings - Fork 0
/
Show.py
162 lines (148 loc) · 7 KB
/
Show.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import requests
from helper import authenticate_session, confirm_seat_selection, get_seat_str, make_land_request, set_base_headers
from seating import SeatingPlan, Seat, GVSeatingPlan
import urllib.parse
requests.adapters.DEFAULT_RETRIES = 3
class Show:
EXCLUSION_LIST = ["*", "(Eng Sub) "]
def __init__(self, theatre_chain, show_date, start_time, hall, show_url, movie_name=None, theatre_name=None, has_subtitles=None, subtitles_language=None,
timezone=None, rating=None, seating=None):
self.movie_name = self.normalize(movie_name)
self.theatre_name = theatre_name
self.theatre_chain = theatre_chain
self.has_subtitles = has_subtitles
self.subtitles_language = subtitles_language
self.show_date = show_date
self.timezone = timezone
self.start_time = start_time
self.premium = self.is_premium()
self.rating = rating
self.hall = hall
self.show_url = show_url
self.seating = seating
if self.movie_name and "(D-Box)" in self.movie_name:
self.d_box = True
self.movie = self.movie.replace("(D-Box) ", "")
else:
self.d_box = False
def normalize(self, movie_name):
if not movie_name:
return None
for exclusion in self.EXCLUSION_LIST:
movie_name = movie_name.replace(exclusion, "")
return movie_name
def is_premium(self):
if self.theatre_name is None:
return False
if self.theatre_chain == "GV":
return "Gold Class" in self.theatre_name or "Deluxe" in self.theatre_name
class GVShow(Show):
# Seat Status:
# L - seat available
# B - seat booked
# T - seat blocked
# Seat Types:
# W - wheelchair bearth
# N - normal seat
def __init__(self, theatre_chain, cinema_id, film_code, show_date, start_time, hall, show_url, movie_name=None, theatre_name=None, has_subtitles=None, subtitles_language=None, timezone=None, rating=None):
self.cinema_id = cinema_id
self.film_code = film_code
Show.__init__(self, theatre_chain, show_date, start_time, hall, show_url, movie_name, theatre_name, has_subtitles, subtitles_language,
timezone, rating)
self.generate_seating_plan()
@staticmethod
def from_url(show_url):
# https://www.gv.com.sg/GVSeatSelection#/cinemaId/80/filmCode/6811/showDate/04-08-2022/showTime/2205/hallNumber/1
cinema_id = show_url.split("/cinemaId/")[1].split("/")[0]
film_code = show_url.split("/filmCode/")[1].split("/")[0]
show_date = show_url.split("/showDate/")[1].split("/")[0]
start_time = show_url.split("/showTime/")[1].split("/")[0]
hall = show_url.split("/hallNumber/")[1].split("/")[0]
new_gv_show = GVShow("GV", cinema_id, film_code,
show_date, start_time, hall, show_url)
return new_gv_show
def generate_seating_plan(self):
headers = {
'Host': 'www.gv.com.sg',
'Sec-Ch-Ua': '"Chromium";v="103", ".Not/A)Brand";v="99"',
'Accept': 'application/json, text/plain, */*',
'X_developer': 'ENOVAX',
'Content-Type': 'application/json; charset=UTF-8',
'Sec-Ch-Ua-Mobile': '?0',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36',
'Sec-Ch-Ua-Platform': '"Windows"',
'Origin': 'https://www.gv.com.sg',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Dest': 'empty',
'Referer': 'https://www.gv.com.sg/GVSeatSelection',
'Accept-Language': 'en-GB,en;q=0.9',
}
json_data = {
'cinemaId': self.cinema_id,
'filmCode': self.film_code,
'showDate': self.show_date,
'showTime': self.start_time,
'hallNumber': self.hall,
}
session = requests.Session()
session.headers = headers
authenticate_session(session)
seating_request = session.post(
GVSeatingPlan.GV_SEATING_PLAN_URL, json=json_data)
seating_data = seating_request.json()['data']
seating_plan = GVSeatingPlan([])
if not seating_data:
self.seating_plan = seating_plan
return
seating_plan.seat_matrix = [[]] * len(seating_data)
for row in range(len(seating_data)):
seating_plan.seat_matrix[row] = [None] * len(seating_data[row])
for row in range(len(seating_data)):
for col in range(len(seating_data[row])):
#print(seating_data[row][col])
seat_status = seating_plan.get_gv_seat_status(seating_data[row][col]['status'])
seat_type = seating_plan.get_gv_seat_type(seating_data[row][col]['type'])
if seating_data[row][col]['rowId'] is None:
continue
real_row = ord(seating_data[row][col]['rowId']) - ord('A') + 1
real_col = int(seating_data[row][col]['columnId'])
seating_plan.set_seat(real_row, real_col, Seat(real_row, real_col, seat_status, seat_type))
self.seating_plan = seating_plan
def block_seats(self, seats):
seat_str = get_seat_str(seats, self.seating_plan)
if not seat_str:
return None
session = requests.Session()
# authenticate and generate JSESSIONID
authenticate_session(session)
# obtain ticket ID
set_base_headers(session)
ticket_url = "https://www.gv.com.sg/.gv-api/getticketprice"
ticket_data = {"cinemaId": self.cinema_id, "filmCode": self.film_code, "showDate": self.show_date,
"showTime": self.start_time, "hallNumber": self.hall, "sectionId": "1", "seatType": "N", "sms": False}
ticket_request = session.post(ticket_url, json=ticket_data)
ticket_id = ticket_request.json()['data']['tickets'][0]['priceId']
# create payment session
payment_url = "https://www.gv.com.sg/.gv-api/getpaymentmodes"
payment_data = {"priceId": ticket_id}
payment_request = session.post(payment_url, json=payment_data)
# confirm seats
seats_data = confirm_seat_selection(session, seat_str)
# land request
land_response = make_land_request(session, seats_data)
if land_response.status_code == 200 and 'error' not in land_response.url:
return session.cookies
return None
def unblock_seats(self, seats, cookies):
session = requests.Session()
set_base_headers(session)
session.cookies = cookies
seat_str = get_seat_str(seats, self.seating_plan)
if not seat_str:
return None
seats_data = confirm_seat_selection(session, seat_str)
land_response = make_land_request(session, seats_data)
if land_response.status_code == 200 and 'error' in land_response.url:
return session.cookies
return None