Dmitry c6e2a43e4b
All checks were successful
Release App / release-app (push) Successful in 46s
Add saved GIF picker and docs
2026-04-26 12:50:18 +03:00
2026-04-26 12:50:18 +03:00
2026-04-23 17:00:41 +03:00
2026-04-24 15:18:10 +03:00
2026-04-24 15:18:10 +03:00
2026-04-26 12:50:18 +03:00

telegram-tui

A minimal Telegram terminal client built with ncurses and TDLib.

Features

  • interactive login flow inside the TUI
  • chat list in the left pane
  • message view in the right pane
  • keyboard-first text compose, reply, edit, forward, and delete flows
  • attachment browser and inline media preview
  • clipboard image sending with >paste / >clip
  • saved GIF picker backed by Telegram saved animations
  • scroll chats and message history with the keyboard

Requirements

  • CMake 3.21+
  • a C++17 compiler
  • ncurses
  • TDLib build dependencies (gperf, openssl, zlib, git)

The project vendors TDLib automatically by default. If you already have TDLib installed with CMake package metadata, configure with -DTELEGRAM_TUI_USE_SYSTEM_TDLIB=ON. If you have a prebuilt TDLib bundle with include/ and lib/, configure with -DTELEGRAM_TUI_TDLIB_ROOT=/path/to/tdlib.

Build

cmake -S . -B build
cmake --build build -j

During configure, CMake also checks the app config at $XDG_DATA_HOME/telegram-tui/config.json or ~/.local/share/telegram-tui/config.json. If that file contains api_id and api_hash, they are embedded into the build. For CI or release builds, prefer setting TELEGRAM_TUI_BUILD_API_ID and TELEGRAM_TUI_BUILD_API_HASH in the environment so credentials come from secrets instead of local config.

Run

Create a Telegram application at https://my.telegram.org/apps, then either rely on the embedded credentials from the app config above, or export credentials:

export TELEGRAM_API_ID=123456
export TELEGRAM_API_HASH=0123456789abcdef0123456789abcdef
./build/telegram-tui

Or start the app without env vars and enter them interactively when prompted. When entered in the TUI, the app now stores api_id and api_hash in ~/.local/share/telegram-tui/config.json and reuses them on later launches.

Clipboard image sending via >paste or >clip supports:

  • raw clipboard images via wl-clipboard on Wayland or KDE Plasma Wayland
  • raw clipboard images via xclip on X11
  • KDE Klipper clipboard entries that point to a local image file via qdbus/qdbus6

Klipper by itself is still not a raw image backend for this feature.

To use Telegram test servers instead of production:

export TELEGRAM_USE_TEST_DC=1
./build/telegram-tui

The client stores TDLib state in ~/.local/share/telegram-tui/tdlib for production and ~/.local/share/telegram-tui/test/tdlib for test mode.

Gitea Actions

The repository includes .gitea/workflows/build-tdlib.yaml, which builds the latest upstream TDLib tag on Gitea Actions and publishes a bundled TDLib archive plus checksum to the Gitea Generic Package Registry under the tdlib package. It also refreshes a latest/tdlib-latest.json manifest with the newest published version.

The repository also includes .gitea/workflows/release-app.yaml, which downloads a prebuilt TDLib bundle from the shinoa-tdlib repository using a pinned version tag such as v1.8.63, builds a versioned app release tag such as v0.1.1, and publishes an archive containing usr/bin/shinoa plus the bundled usr/lib/libtdjson.so*. The root PKGBUILD installs that prebuilt release as shinoa-bin. The package disables debug splitting with options=(!debug). That workflow expects Gitea secrets named TELEGRAM_API_ID and TELEGRAM_API_HASH. Release builds are configured to fail if those secrets are missing.

To prepare the TDLib bundle on your own machine:

cmake -S td -B td-build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$PWD/td-install"
cmake --build td-build -j"$(nproc)"
cmake --install td-build
./scripts/package-tdlib.sh td-install tdlib-linux-x86_64.tar.gz

Publish tdlib-linux-x86_64.tar.gz to the shinoa-tdlib repository under a versioned tag such as v1.8.63. Then update TDLIB_RELEASE_TAG in .gitea/workflows/release-app.yaml and run the Release App workflow.

Keys

  • Up / Down: move selection
  • Tab: switch focus between chats and messages
  • Enter: open the selected chat
  • i: start composing a message
  • a: prepare a reply to the latest message
  • g: open the saved GIF picker for the current account
  • m: open the attachments browser for the current chat
  • o: open the selected attachment from the message pane
  • PgUp / PgDn: scroll the current message view
  • r: reload chats or history
  • Esc: cancel current input
  • q: quit

Compose Commands

While composing, these commands are available:

  • >r <msg> [text]: prepare a reply to a message reference
  • >e <msg> <text>: edit one of your messages
  • >f <msg...>: forward one or more messages
  • >d <msg...>: delete one or more of your messages
  • >paste [caption] or >clip [caption]: send an image from the clipboard

Message references can be a visible message number such as 12, a raw Telegram message id, or a range/list such as 3,5,8-10 where supported.

Saved GIF Picker

Press g in an open chat to fetch saved animations from the account and open the picker. Use Up / Down to move, r to refresh, and Enter to send the selected GIF.

If the GIF file is already cached locally, the picker renders a static preview frame using the same preview backend as other media. For image previews, install one of chafa, kitten, or img2sixel; for video/GIF thumbnail extraction, install ffmpegthumbnailer or ffmpeg.

Description
No description provided
Readme 396 KiB
v0.1.2 Latest
2026-04-26 10:01:54 +00:00
Languages
C++ 96.8%
CMake 2.9%
Shell 0.3%