mirror of
https://github.com/aculix/ticket-monitoring.git
synced 2026-10-27 07:15:51 +00:00
feat: watch BookMyShow alongside District in one process
BookMyShow sits behind Cloudflare bot management that rejects curl and Node fetch with 403 on the TLS fingerprint alone, so no header or cookie copying helps and a proxy makes no difference. impit performs the request with a real Chrome fingerprint; it ships musl and arm64 binaries, so the Alpine multi-arch image is unaffected. BMS has no 204 either: a date that is not on sale returns 200 with no showtimeWidgets key, so 'closed' is read from the payload. Sites now live in src/providers/, each exposing check() and extract() and returning one normalized session shape. State is namespaced per site, so each keeps its own dedupe and failure tracking and neither can silence the other. Alert titles name the site. Sessions without exact seat counts render without them, which BMS needs. Old flat District variable names still work. CI now starts the built image and runs a real check through both providers before publishing, since a broken native binary only fails at runtime.
This commit is contained in:
1 parent
00e6852863
commit
608221fe18
17 files changed
+1188
-539
No files matched your search
+42
-28
@@ -1,31 +1,13 @@
|
||||
# Copy to .env and fill in. Every value below is read from the environment,
|
||||
# so you can also set them directly (Docker, systemd, CI) instead of using a file.
|
||||
# The example values watch IMAX shows of one film at one Ahmedabad cinema.
|
||||
# Copy to .env and fill in. Every value is read from the environment, so you can set
|
||||
# these directly (Docker, systemd, CI) instead of using a file.
|
||||
#
|
||||
# Configure District, BookMyShow, or both. Both are watched in one process, each with
|
||||
# its own dedupe and failure tracking, so one site breaking never silences the other.
|
||||
|
||||
# ── What to watch ─────────────────────────────────────────────────────────────
|
||||
# Open the film's page on district.in, then read these off the network request to
|
||||
# /gw/consumer/movies/v5/movie (see "Finding your IDs" in the README).
|
||||
MOVIE_CODE=y7EZNLXN5Y # ?frmtid= in the page URL — identifies movie + language
|
||||
CONTENT_ID=187151 # MV<number> in the page URL
|
||||
CITY_KEY=ahmedabad # city slug as it appears in the page URL
|
||||
LAT=23.033938956712916 # city coordinates; the API rejects requests without them
|
||||
LNG=72.57696301365426
|
||||
TARGET_DATE=2026-08-10 # the date you are waiting for (YYYY-MM-DD)
|
||||
|
||||
# Restrict to one cinema. Leave empty to watch every cinema in the city.
|
||||
CINEMA_ID=1032362
|
||||
|
||||
# Which shows count as a match. A session matches if it carries FORMAT_TAG *or* if its
|
||||
# screen format contains FORMAT_MATCH (case-insensitive), so "IMAX" also catches
|
||||
# "IMAX 3D". Set BOTH to empty to match every show regardless of format.
|
||||
FORMAT_TAG=imax_2d
|
||||
FORMAT_MATCH=IMAX
|
||||
# ── Shared ────────────────────────────────────────────────────────────────────
|
||||
TARGET_DATE=2026-09-25 # the date you are waiting for (YYYY-MM-DD)
|
||||
FORMAT_LABEL=IMAX # cosmetic: how the format is named in alerts
|
||||
|
||||
# Opened when you tap the notification.
|
||||
BOOKING_URL=https://www.district.in/movies/the-odyssey-movie-tickets-in-ahmedabad-MV187151?frmtid=y7EZNLXN5Y&fromdate=2026-08-10
|
||||
|
||||
# ── Notifications (ntfy) ──────────────────────────────────────────────────────
|
||||
# Subscribe to this topic in the ntfy app. Treat it as a password: anyone who knows
|
||||
# it can read your alerts and publish to you. Use a long random string.
|
||||
NTFY_TOPIC=change-me-to-something-random
|
||||
@@ -35,10 +17,41 @@ NTFY_TOPIC=change-me-to-something-random
|
||||
NTFY_URL=https://ntfy.sh
|
||||
# NTFY_TOKEN=tk_... # only if your server (or topic) requires auth
|
||||
|
||||
# ── District (district.in) ────────────────────────────────────────────────────
|
||||
# Leave DISTRICT_MOVIE_CODE unset to skip District entirely.
|
||||
# Read these off the movie's page URL, e.g.
|
||||
# district.in/movies/the-odyssey-movie-tickets-in-ahmedabad-MV187151?frmtid=y7EZNLXN5Y
|
||||
DISTRICT_MOVIE_CODE=y7EZNLXN5Y # ?frmtid= — identifies movie + language
|
||||
DISTRICT_CONTENT_ID=187151 # digits after MV
|
||||
DISTRICT_CITY_KEY=ahmedabad # city slug in the path
|
||||
DISTRICT_LAT=23.033938956712916 # any coordinates in that city; the API needs them
|
||||
DISTRICT_LNG=72.57696301365426
|
||||
DISTRICT_CINEMA_ID=1032362 # empty = watch every cinema in the city
|
||||
DISTRICT_FORMAT_TAG=imax_2d # session tag that counts as a match
|
||||
DISTRICT_FORMAT_MATCH=IMAX # or a screen-format substring; both empty = any show
|
||||
DISTRICT_BOOKING_URL=https://www.district.in/movies/the-odyssey-movie-tickets-in-ahmedabad-MV187151?frmtid=y7EZNLXN5Y&fromdate=2026-09-25
|
||||
|
||||
# ── BookMyShow (in.bookmyshow.com) ────────────────────────────────────────────
|
||||
# Leave BMS_EVENT_CODE unset to skip BookMyShow entirely.
|
||||
# From the movie URL, e.g. in.bookmyshow.com/movies/ahmedabad/avengers-endgame-encore/ET00514163
|
||||
BMS_EVENT_CODE=ET00514163 # the ET... code
|
||||
# BMS_REF_EVENT_CODE= # only if the URL's refEventCode differs from above
|
||||
BMS_REGION_CODE=AHD # BMS region code (AHD, BANG, MUMBAI, NCR ...)
|
||||
BMS_REGION_SLUG=ahmedabad # city slug in the path
|
||||
BMS_LAT=23.0395677
|
||||
BMS_LNG=72.5660045
|
||||
BMS_VENUE_CODE=PPAM # empty = watch every cinema in the region
|
||||
# BMS_LANGUAGE=hindi # only if you want one language's shows
|
||||
BMS_FORMAT_MATCH=IMAX # matched against the screen format; empty = any show
|
||||
BMS_BOOKING_URL=https://in.bookmyshow.com/movies/ahmedabad/avengers-endgame-encore/ET00514163
|
||||
|
||||
# Watch only some of the configured providers. Unset = every provider you configured.
|
||||
# PROVIDERS=district,bookmyshow
|
||||
|
||||
# ── Behaviour ─────────────────────────────────────────────────────────────────
|
||||
CHECK_INTERVAL_SECONDS=60 # how often to poll; don't go lower without good reason
|
||||
FAILURE_THRESHOLD=6 # consecutive failures before the "monitor broken" alert
|
||||
TZ_OFFSET_MINUTES=330 # showtimes are rendered in this offset (330 = IST)
|
||||
TZ_OFFSET_MINUTES=330 # timezone used for showtimes and dates (330 = IST)
|
||||
HEARTBEAT_HOUR=9 # daily "still alive" push at this local hour; -1 disables
|
||||
CURRENCY=₹
|
||||
# EXPIRY_UTC= # auto: local midnight after TARGET_DATE. Override to extend.
|
||||
@@ -47,6 +60,7 @@ CURRENCY=₹
|
||||
STATE_PATH=./state.json # Docker image defaults this to /data/state.json
|
||||
PORT=4733 # status endpoint (--loop mode only)
|
||||
|
||||
# Routes only the site checks through a SOCKS5 proxy; notifications stay direct.
|
||||
# Needed on datacenter hosts, whose IPs the site's WAF is likely to block.
|
||||
# Routes District checks through a SOCKS5 proxy; notifications stay direct.
|
||||
# Needed on datacenter hosts, whose IPs District's WAF blocks. It does nothing for
|
||||
# BookMyShow, which blocks on TLS fingerprint rather than IP (impit handles that).
|
||||
# PROXY_URL=socks5://user:pass@proxy.example.net:1080
|
||||
Reference in new issue
Block a user