| name | odyssey-imax-grab |
| description | Use this when a user wants to monitor movie tickets, watch for seats, track IMAX 70mm seats, use Fandango, get notified when tickets or seats open, render a seat map PNG, or create a cron seat watch for a theater/movie/date window. |
Odyssey IMAX Grab
Monitor a Fandango movie at a specific theater, rank live available seats, render a PNG seat map, and deliver alerts from a Hermes cron.
Linked references:
references/fandango-napi.md - endpoints, schemas, headers, and quirks.
references/seat-ranking.md - row-tier policy and tuning for each auditorium.
references/browseruse-fallback.md - browser/network fallback when theater discovery changes.
Quick Start
- Install the skill:
hermes skills install alt-glitch/odyssey-imax-grab/odyssey-imax-grab
- Set the skill path explicitly. Commands below assume the installed skill path; if you are running from this repository instead, set
SKILL_DIR to the local odyssey-imax-grab/ directory.
SKILL_DIR="$HOME/.hermes/skills/alt-glitch/odyssey-imax-grab"
cd "$SKILL_DIR"
-
Ask the user for their theater/location, movie, preferred format, date range, and alert destination. Reuse an existing Telegram/Discord/etc chat id from the user's prior Hermes crons when available.
Prefer a direct Fandango theater URL slug or network showtimes request over guessed IDs. Ask the user to open the theater page on fandango.com and read the slug: .../amc-metreon-16-aanem/... means chain AMC, TMS AANEM. The matching network request looks like /napi/theaterMovieShowtimes/AANEM?chainCode=AMC...; see references/browseruse-fallback.md.
-
Resolve the Fandango theater id directly:
python scripts/find_theater.py AMC:AANEM --sample-date 2026-07-25
If Fandango returns a different chainCode than the hinted chain, find_theater.py prints a warning. Verify the theater URL slug or network request before continuing.
- Generate config. By default it writes
~/.hermes/odyssey-imax-grab/config.json, which is also the cron script's default config path:
python scripts/setup.py \
--theater AMC:AANEM \
--movie "The Odyssey" \
--format-match "IMAX,70MM" \
--format-label "IMAX 70mm" \
--start-date 2026-07-25 \
--end-date 2026-08-02
- Smoke test from the skill directory:
python scripts/monitor_cron.py --dry-run --force
- Install the cron scripts under
~/.hermes/scripts/. Hermes cron create --no-agent --script only runs scripts from this directory and cannot pass --config, so monitor_cron.py uses ~/.hermes/odyssey-imax-grab/config.json by default.
mkdir -p ~/.hermes/scripts
cp scripts/monitor_cron.py scripts/fandango_lib.py scripts/seatmap_render.py ~/.hermes/scripts/
- Install Pillow in the copied script venv for PNG rendering.
monitor_cron.py re-execs once into the sibling odyssey-venv when PIL is missing from the launching Python.
uv venv ~/.hermes/scripts/odyssey-venv
VIRTUAL_ENV="$HOME/.hermes/scripts/odyssey-venv" uv pip install Pillow
python ~/.hermes/scripts/monitor_cron.py --dry-run --force
- Create a Hermes
no_agent cron. Empty stdout means no alert; non-empty stdout is delivered. PNGs are attached by printing MEDIA:/path/to/seatmap.png.
hermes cron create '*/10 * * * *' --no-agent --script monitor_cron.py --deliver telegram:<chat_id> --name odyssey-seatwatch
Workflow
- Run
setup.py --questions and ask the user the missing inputs.
- Run
find_theater.py with a direct CHAIN:TMS_ID from a real Fandango theater URL or showtimes request if possible. Generic city/name search is best effort because Fandango's search schema changes more often than showtimes/seat maps.
- Run
setup.py with the selected theater/movie/format/dates. It resolves the movie id, samples a seat map, detects row letters from seat IDs, proposes row tiers, and writes ~/.hermes/odyssey-imax-grab/config.json.
- Review row tiers in the config. For true large-format IMAX 70mm rooms, the sweet spot is usually slightly behind the geometric row center.
- Run
monitor_cron.py --dry-run --force.
- Copy the three runtime scripts to
~/.hermes/scripts/, create ~/.hermes/scripts/odyssey-venv, and create the Hermes cron with --no-agent, --script monitor_cron.py, and the user's messaging delivery target.
Pitfalls
- Always fetch showtimes first and use the current
showtimeHashCode before fetching /napi/seatMap/...; do not cache hashes across runs.
- Seat numbers are reversed versus x position in some houses. Example: in a 34-wide row,
G34 can be far left and G1 far right. Rank by x + width / 2 distance from the house center.
- Rows can skip
I. Detect row letters by regex on actual seat IDs, not by A..Z assumptions.
- Wheelchair and companion seats appear in the map. The ranking filters to
type == "standard".
- Fandango has older
smp__seats-container and newer dark seat-map__ front ends, but both consume the same napi/seatMap JSON. Render from JSON.
- System Python may be PEP-668 managed, and
uv venv may not include pip. Use uv venv <dir> && VIRTUAL_ENV=<abs> uv pip install Pillow. monitor_cron.py re-execs once into a sibling odyssey-venv/bin/python if PIL is missing.
- For Hermes cron, the script path is
~/.hermes/scripts/monitor_cron.py, so the Pillow venv must be ~/.hermes/scripts/odyssey-venv.
- PNG rendering is best effort. Scan and state persistence still run if Pillow or rendering fails.
Advanced
- Use
references/fandango-napi.md when modifying endpoint calls or schema parsing.
- Use
references/seat-ranking.md before changing row tiers or center-band logic.
- Use
references/browseruse-fallback.md if Fandango theater discovery fails or a chain needs a captured adapter.