Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
# IISER Tirupati Course Timetable Builder
Parses the institute's "Advanced Course Schedule" PDF into structured course
data and generates a standalone, interactive HTML timetable-building app
(search courses, add them to a personal weekly grid, detect nothing extra —
just view/print your schedule) with no server or dependencies needed to use
the output.
## Pipeline
```
PDF → parser.py → extractor.py → lookup.py (optional CLI)
↓
html_generator.py → timetable.html
```
1. **`parser.py`** — Reads the raw PDF with `pdfplumber` and turns each page
into a list of `Slot` objects (one per table cell: day, time, group/column
label, room, and the raw text lines in that cell).
2. **`extractor.py`** — Converts `Slot`s into `Course` objects: splits/normalizes
multi-code cells (e.g. `BIO413/713/MLS414`) into individual course codes,
pulls out the title and credit value, and filters out non-course cells
(empty slots, "Seminar"/"Colloquium" announcement rows).
3. **`lookup.py`** — Builds a `{code: [Course, ...]}` dictionary for quick
lookups by course code, and a small CLI for checking a code's sessions
without generating the full HTML.
4. **`html_generator.py`** — Serializes the extracted `Course` list to JSON
and embeds it into a single self-contained `timetable.html` file (HTML +
CSS + JS, light/dark themes, search, print support).
5. **`main.py`** — Wires the whole pipeline together for a single input PDF.
6. **`models.py`** — Shared `Slot` and `Course` dataclasses used across all
modules.
## Requirements
- Python 3.10+ (uses `from __future__ import annotations` and `X | None` syntax)
- [`pdfplumber`](https://github.com/jsvine/pdfplumber)
```bash
pip install pdfplumber
```
## Usage
### Generate the full timetable app
Edit the `PDF` path at the top of `main.py` to point at your schedule file,
then run:
```bash
python main.py
```
This produces `timetable.html` in the current directory — open it directly
in a browser. It's fully self-contained (fonts are loaded from Google Fonts
CDN; everything else is inline).
### Look up a specific course code
```bash
python lookup.py "path/to/schedule.pdf" BIO413 PHY201
```
Prints every scheduled session (day, time, room, credits) for each code
given. Missing codes print `not found` instead of raising.
### Inspect raw extracted courses (debugging)
```bash
python extractor.py "path/to/schedule.pdf"
```
Prints every extracted `Course` before it's handed to the HTML generator.
### Debug the PDF parsing itself
If a page isn't parsing correctly, `parser.py` has two debug modes:
```bash
# Show every column band on a page: its header, whether it's a Room
# band, and a preview of its content lines
python parser.py --debug "path/to/schedule.pdf" <page-index>
# Show raw (top, bottom, text) for every word in one specific band,
# for diagnosing block-boundary issues by hand
python parser.py --debug-band "path/to/schedule.pdf" <page-index> <band-index>
```
## Notable design decisions
- **Column boundaries come from the PDF's real vertical gridlines**
(`page.edges`), not from guessing gaps between word positions — this is
what makes the parser robust to centered headers over left-aligned body
text and other layout quirks.
- **The header ("Group") row is found by scoring**, not by grabbing the
first matching text, since Group/Room tokens can appear more than once
on a page in non-top-to-bottom order.
- **Friday uses a different layout** (lab blocks, some columns have no
paired Room column) and falls back to gap-based block splitting instead
of Room-anchored splitting.
- **A course code can have multiple sessions per week** (cross-listed /
multi-section courses like `BIO413/713/MLS414` meeting on different days).
`lookup.py` deliberately maps `code -> list[Course]`, not `code -> Course`,
so clash detection doesn't silently lose sessions.
- **Announcement rows** ("Seminar", "Colloquium") occupy course-shaped table
cells but aren't real scheduled courses, so `extractor.py` filters them out.
## File overview
| File | Purpose |
|---|---|
| `models.py` | `Slot` and `Course` dataclasses |
| `parser.py` | PDF → `list[Slot]` |
| `extractor.py` | `list[Slot]` → `list[Course]` |
| `lookup.py` | `list[Course]` → `{code: [Course]}` lookup dict + CLI |
| `html_generator.py` | `list[Course]` → standalone `timetable.html` |
| `main.py` | Runs the full pipeline for one PDF |
## Known limitations
- The parser is tuned specifically to IISER Tirupati's "Advanced Course
Schedule" PDF layout (drawn gridlines, `Group`/`Room` header tokens,
Monday–Friday with Friday as a distinct lab-block layout). Other
timetable formats will likely need adjustments to `parser.py`.
- `main.py` currently hardcodes the input PDF path — pass it as a CLI arg
if you need to process multiple files.