UBB FMI Timetable Service is the open-source data pipeline that powers the UBB FMI app.
It retrieves public timetable pages from the Faculty of Mathematics and Computer Science (UBB), normalizes them into stable JSON contracts, and publishes static artifacts that the mobile client can fetch and cache.
- Provide a reliable, low-cost backend for timetable delivery.
- Keep runtime complexity out of the mobile app.
- Publish versioned, schema-backed JSON with predictable paths.
- Run unattended through scheduled automation.
The pipeline generates static JSON files under dist/:
catalog.json: available academic years, programs, years, and groups.announcements.json: manual and auto-generated operational announcements.discounts.json: app discount cards and color metadata.rooms.json: room code to address mapping from the published legend page./{academicYear}/{programId}/y{year}/g{group}.json: per-group timetable payloads..scrape-status.json: pipeline status, warnings, and failures for operational use.
scripts/scrape.pydownloads and parses timetable sources, then writes per-group files.scripts/build_catalog.pybuilds the catalog fromconfig/sources.jsonand optional scrape status overrides.scripts/build_announcements.pybuilds announcements and injects a warning notice when scraping fails.scripts/build_discounts.pyvalidates and publishes discounts content.- GitHub Actions publishes
dist/to thegh-pagesbranch.
scripts/: scraping, parsing, generation, and build utilities.config/: source definitions and content configuration.schemas/: JSON schemas for all public payloads.tests/: parser and builder unit tests..github/workflows/update-timetables.yml: scheduled pipeline + publication workflow.apitesting.paw: API testing collection.
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtpython scripts/scrape.py --config config/sources.json --out dist --soft-fail-empty
python scripts/build_catalog.py --config config/sources.json --out dist --status dist/.scrape-status.json
python scripts/build_announcements.py --out dist --announcements config/announcements.json --status dist/.scrape-status.json
python scripts/build_discounts.py --out dist --discounts config/discounts.jsonpytestPrimary input: config/sources.json.
Supported shapes:
- Root
academicYear+programs. - Root
sourceswhere each source can define its ownacademicYear. academicYearsbuckets containing nestedprogramsorsources.
Each source entry supports:
academicYear(optional when inherited from parent)programIdtitleyearurlgroups(array of ints or comma-separated string)
You can generate config/sources.json from the official timetable index:
python scripts/generate_sources.py \
--index-url https://www.cs.ubbcluj.ro/files/orar/2025-2/tabelar/index.html \
--academic-year 2025-2026 \
--program-map config/program-map.example.json \
--out config/sources.jsonThe default workflow runs in GitHub Actions and publishes static files via GitHub Pages.
Workflow: .github/workflows/update-timetables.yml
Behavior:
- Runs daily at
06:00 UTC. - During July and August, only Monday runs are executed.
- Publishes
dist/togh-pagesusingpeaceiris/actions-gh-pages.
Expected public URLs:
https://<user>.github.io/<repo>/catalog.jsonhttps://<user>.github.io/<repo>/announcements.jsonhttps://<user>.github.io/<repo>/discounts.jsonhttps://<user>.github.io/<repo>/rooms.jsonhttps://<user>.github.io/<repo>/<academicYear>/<programId>/y<year>/g<group>.json
Public schemas are versioned in schemas/:
schemas/catalog.schema.jsonschemas/timetable.schema.jsonschemas/announcements.schema.jsonschemas/discounts.schema.jsonschemas/rooms.schema.json
- Source-level failures do not stop other sources from processing.
- Existing timetable files remain valid if a source fails.
- With
--soft-fail-empty, missing new files are created as empty payloads. dist/.scrape-status.jsonrecords failures and warnings for downstream steps.build_announcements.pycan automatically publish a warning notice if failures occurred.
This repository is intended to serve as the public backend for the UBB FMI app.
For external contributions, prefer focused changes with tests and schema compatibility preserved.