Telegram frontend for the VienDesu! backend
  • Python 94.9%
  • Nix 5.1%
Find a file
Aleksandr 8d50982f0e config: add NODE_AUTH_ENABLED to hide sign-in/registration
When off, sign-in and registration are hidden everywhere: main-menu
buttons, the /signin bot command, and the signin/signup handlers.
Existing sessions keep working. Exposed as services.node.authEnabled
in the NixOS module.

Co-Authored-By: Eva
2026-07-13 22:48:50 +03:00
node config: add NODE_AUTH_ENABLED to hide sign-in/registration 2026-07-13 22:48:50 +03:00
.gitignore Node: VienDesu Telegram bot (Python prototype) 2026-07-12 18:30:54 +03:00
flake.lock Node: VienDesu Telegram bot (Python prototype) 2026-07-12 18:30:54 +03:00
flake.nix config: add NODE_AUTH_ENABLED to hide sign-in/registration 2026-07-13 22:48:50 +03:00
pyproject.toml Telegram proxy support and self-provisioned bot identity 2026-07-12 18:54:27 +03:00
README.md config: add NODE_AUTH_ENABLED to hide sign-in/registration 2026-07-13 22:48:50 +03:00

Node

VienDesu Telegram bot, named after the rabbit librarian from BLACK SOULS II.

Feature parity with the web frontend: game/author search with filters and cursor pagination, entity cards, profile management, author/game creation and editing — built around inline (callback) keyboards, plus inline mode for sharing games in any chat.

Status: this Python implementation is a working prototype. The bot will be rewritten in Rust (on top of the viendesu workspace crates) once the feature set settles; treat the Python code as the executable spec.

Run

export NODE_BOT_TOKEN="123456:ABC..."   # or NODE_BOT_TOKEN_FILE=/path/to/secret
# optional overrides:
export NODE_API_URL="https://api.desu.church/"
export NODE_CDN_URL="https://cdn.viende.su/"
export NODE_SITE_URL="https://viende.su/"
export NODE_DB="node.db"

python -m node        # or: node (after pip install -e .; mind the name clash
                      # with node.js if both end up on one PATH)

Dependencies: aiogram>=3.13, httpx, aiosqlite, mistune>=3.0 (see pyproject.toml). On Nix: nix develop for a shell, nix build for the package.

For inline mode, enable it for the bot in @BotFather (/setinline).

NixOS module

# flake inputs: node-bot.url = "git+ssh://forgejo@git.viende.su:61488/VienDesu/Node.git";
{
  imports = [ node-bot.nixosModules.default ];

  services.node = {
    enable = true;
    # Secret file with the bot token; loaded via systemd LoadCredential,
    # so root-owned agenix/sops-nix paths work as-is:
    tokenFile = config.age.secrets.node-bot-token.path;
    # apiUrl (staging) / cdnUrl / siteUrl (viende.su) — optional;
    # authEnabled = false hides sign-in/registration everywhere — optional;
    # environmentFile — optional extra NODE_* overrides (also for secrets).
  };
}

The service runs as a DynamicUser with StateDirectory=node (sqlite lives in /var/lib/node/node.db) and a hardened sandbox. The token never enters the Nix store or the process environment — the bot reads it from the credential file via NODE_BOT_TOKEN_FILE.

Layout

  • node/api.py — typed client for the core API; mirrors the frontend's api layer: {ok}/{error} envelope, {change: v} patches, cursor pagination.
  • node/handlers/ — one router per area: auth, profile, game search, game/author/user cards, content management (create/edit wizards), inline mode.
  • node/keyboards.py, node/cb.py — inline keyboards and callback-data factories (callback_data is capped at 64 bytes; entity ids are ~39 digits).
  • node/db.py — sqlite: per-user session tokens and search state.
  • node/md.py — markdown → Telegram-HTML (mistune with a Telegram renderer).
  • node/genres.py — genre slugs + Russian labels, mirrored from the frontend.

Feature parity notes

Deliberately mirrors frontend behaviour, including its stubs: registration and password change show "unavailable", rating submission shows "soon".