2026-11-08 19:28:03 +01:00
2026-11-08 19:28:03 +01:00
2026-11-08 19:28:03 +01:00
2026-11-08 19:28:03 +01:00
2026-11-08 19:28:03 +01:00
2026-11-08 19:28:03 +01:00

librus-tui

A terminal-looking web frontend for Librus Synergia, built on the async Synergia client from dani3l0/librusik (lib/api/librus.py, stable branch).

The whole UI is a single-page phosphor-green "TUI" in the browser: keyboard navigation, command bar, box-drawn panels, live clock, scanlines and an OAuth boot log. The Python backend talks to Synergia and keeps your Librus cookies server-side; the browser only gets an opaque session cookie.

 _     ___ ____  ____  _   _ ____
| |   |_ _| __ )|  _ \| | | / ___|
| |    | ||  _ \| |_) | | | \___ \
| |___ | || |_) |  _ <| |_| |___) |
|_____|___|____/|_| \_\\___/|____/   // TUI

Quick start

./run.sh            # real Librus account, http://127.0.0.1:8765
./run.sh --demo     # offline sample data, no Librus account needed

run.sh creates .venv, installs the two dependencies, and starts the server. To run it manually:

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python app.py --demo

Then open http://127.0.0.1:8765. In demo mode use the [ enter demo mode ] button; in real mode log in with your Synergia credentials.

CLI options:

option default description
--host 127.0.0.1 bind address
--port 8765 HTTP port
--demo off use the offline dataset
--debug off verbose logs / access log

Environment equivalents: LIBRUS_HOST, LIBRUS_PORT, LIBRUS_DEMO=1.

Views

key view contents
1 dashboard profile, lucky number, behaviour, counters, today's lessons, upcoming breaks
2 grades weighted subject averages, colour-coded grade chips, comments, teacher, date
3 timetable week grid, substitutions, cancellations, extra activities
4 homework tests and homework sorted by date, full descriptions
5 attendance register with absences, lateness and excused lessons
6 messages inbox + reader + attachment downloads
7 free days school/teacher free days and parent-teacher conferences

Keyboard

  • 1–7 — switch view
  • j / k, arrows — scroll; in messages move through the inbox
  • g / G — top / bottom
  • r — refresh
  • : — command line (:grades, :week 1, :reload, :logout, …)
  • ? — help
  • / — filter grades (grades view)
  • [ / ] — previous / next week (timetable view)
  • q — log out
  • Esc — close modal / leave command line

How it works

browser ── fetch /api/* ──> aiohttp app ── HTTPS ──> synergia.librus.pl
   │                          │
   │ session cookie only      ├─ librus.py  (OAuth + gateway API + message scraping)
   └──────────────────────────┘
  1. POST /api/login performs the same flow as librusik: Synergia portal session, api.librus.pl/OAuth/Authorization?client_id=46, the 2FA redirect, then Auth/TokenInfo / Auth/UserInfo to verify the resulting cookies.
  2. Cookies (DZIENNIKSID, SDZIENNIKSID, …) stay in an in-memory Librus object on the server. The browser gets a random librustui_session cookie.
  3. /api/* endpoints wrap the client methods from librusik and return JSON. Message HTML is sanitised with BeautifulSoup before it reaches the browser.
  4. Sessions expire after 12 h idle / 24 h absolute; restarting the server invalidates all of them.

Files

app.py                  aiohttp server, sessions, API endpoints, sanitizer
librus.py               async Synergia client (adapted from librusik, MIT)
demo.py                 offline dataset behind --demo
static/index.html       TUI shell
static/style.css        phosphor terminal theme
static/js/00-core.js    state, helpers, API wrapper, chrome
static/js/10-auth.js    login, session chrome, clock
static/js/20-dashboard.js
static/js/22-grades.js
static/js/24-timetable.js
static/js/26-more-views.js
static/js/30-app.js     navigation, commands, keyboard, bootstrap

Security notes

  • Bind address defaults to 127.0.0.1, not 0.0.0.0.
  • Credentials are sent from the browser to this server, then to Librus; they are not logged or written to disk.
  • Session cookies are HttpOnly, SameSite=Lax. Responses set a strict CSP, X-Frame-Options: DENY, nosniff and no-referrer.
  • Cross-origin POSTs are rejected by an Origin check.
  • Message content is treated as untrusted and sanitised server-side (scripts, event handlers, iframes and unsafe URL schemes are removed).
  • If you expose this on the internet, put it behind HTTPS (e.g. Caddy/nginx), set --host 127.0.0.1, and consider adding authentication in front of it.

Limitations

  • Librus has no public API contract. If Synergia changes its markup or gateway responses, parts can break; the UI shows a "signal lost" panel with the upstream error instead of crashing.
  • The messages reader scrapes the HTML portal, exactly like librusik, so it is the most fragile view.
  • Attachments are proxied through the server and require the original session cookies to still be valid.
  • One process keeps sessions in memory; there is no multi-user persistence. Restart = everyone logs in again.

Credits

Client flow, endpoints and scraping logic are adapted from dani3l0/librusik, MIT licensed, copyright © 2022 dani3l0.

This project is unofficial and not affiliated with Librus. Use it with your own account at your own risk.

S
Description
An alternative vibe coded front end for the Polish Librus Synergia.
Readme
112 KiB
0 Stars 1 Watchers 0 Forks
Languages
JavaScript 42.7%
Python 33.9%
CSS 18.8%
HTML 4.4%
Shell 0.2%