A native PySide6 desktop app (with a battle-tested CLI engine underneath) for downloading all media from a Telegram channel to a local SSD and re-uploading a folder back to a channel — with deduplication, best-quality resolution, resumable state, and a multi-worker download dashboard.
🇷🇺 Русская версия README — README.ru.md. The app ships in English and Russian, switchable live from the header.
Download dashboard (dark theme). Settings screen in light theme:
- Native GUI — a 6-screen wizard: Login → Settings → Duplicate Review → Download Dashboard → Upload Pipeline → Reports.
- Dark & light themes — a Discord-style design system, switchable at runtime (dark by default).
- English / Russian — full localisation, switchable live from the header bar; the choice is remembered between sessions.
- Streaming, zero-in-memory I/O — network chunks are written straight to the external SSD, so a 50 GB file never tries to fit in RAM and the Mac's internal disk is spared.
- Smart downloading
- Deduplication — the same file posted multiple times is downloaded once (matched by name + size, and duration for video).
- Best-quality resolution — when a video exists in several qualities, only the highest resolution/bitrate is kept; worse copies are dropped before they hit disk.
- "Download everything" + review — preview the plan and bring individual skipped duplicates/worse versions back before the run starts.
- Multi-worker, multi-connection downloads (FastTelethon) with per-worker progress bars and a live operations log.
- Resumable & immortal state — a
download_state.dbthat a--rescannever touches, plus a disk-recovery scanner; the filesystem is the source of truth. - Automatic FloodWait handling and reconnection after dropped connections.
- faststart remux so macOS spacebar preview and instant seeking work out of the box (toggleable).
- Comics & files by link — besides media attached to a message (photos, videos,
documents — incl.
.pdf/.cbzsent as files), the app can also fetch content from external links in messages (web-page previews and URLs in text):- Direct file links (
.pdf,.cbz,.zip, images, …) are downloaded as-is. - Gallery web pages are scraped and their images bundled into a single comic.
- Pick the format — save assembled comics as CBZ (a ZIP of images, any format,
no extra libraries) or PDF (Pillow for any image format; a built-in JPEG writer is
the fallback). Everything lands in a
comics_and_links/subfolder and is skipped if already downloaded. (JavaScript-heavy reader sites may not expose images; direct file links always work.)
- Direct file links (
- Upload Pipeline — send a folder back to a channel as native media (video with
preview) with idempotent "skip already-uploaded" tracking (
upload_state.db). - Reports — per-run summary cards plus one-click access to the text reports the
engine leaves in the destination folder. An
--verifyaudit mode checks integrity without downloading.
- Python 3.12
- macOS (primary target; the engine is cross-platform, the GUI is tuned for macOS)
- A Telegram API ID and API hash from https://my.telegram.org
- See
requirements.txt— Pyrogram, TgCrypto, PySide6, etc.
git clone https://github.com/KyLaEga/telegram-export.git
cd telegram-export
python3.12 -m venv venv
venv/bin/python3.12 -m pip install -r requirements.txtThe app reads its credentials from config.json (the same file the CLI uses).
This file is git-ignored and must never be committed — it contains your API ID,
API hash, phone number, channel and destination path.
Copy the template and fill it in (or just enter the values on the Login screen, which
writes config.json for you):
cp config.example.json config.json🔒 Security note.
config.json,*.session(a live login token),*.dband*.logare all listed in.gitignore. Never share your.sessionfile — it grants access to your Telegram account.
venv/bin/python3.12 run_gui.pyOn first launch, sign in on the Login screen (you'll be prompted for the Telegram code and, if enabled, your 2FA cloud password). Then choose options and start the export.
The GUI is a thin layer over export_media.py. The engine still works standalone:
# Download (uses config.json; see --help for all flags)
venv/bin/python3.12 export_media.py
# Clean re-index without re-downloading
venv/bin/python3.12 export_media.py --rescan
# Audit on-disk files against the plan
venv/bin/python3.12 export_media.py --verify
# Also download comics & files from links in messages (assemble pages as CBZ or PDF)
venv/bin/python3.12 export_media.py --links --links-format pdf
# Upload a folder back to a channel
venv/bin/python3.12 uploader.py --target @your_channel /path/to/folderRun export_media.py --help for the full set of flags (connections, workers, dedup,
quality, faststart, reset, etc.).
A dependency-free regression suite (no pytest needed):
QT_QPA_PLATFORM=offscreen venv/bin/python3.12 tests/run_tests.pyIt covers the Reporter contract, the options/checkbox logic, the Reports screen, the localisation engine (EN/RU key parity + live switching), and the dark/light theme toggle.
Packaged with BeeWare Briefcase (config in
pyproject.toml; app icon in gui/resources/appicon.icns):
venv/bin/python3.12 -m pip install briefcase
venv/bin/python3.12 -m briefcase create macOS # bundle deps into the .app
venv/bin/python3.12 -m briefcase build macOS # ad-hoc sign the .app
venv/bin/python3.12 -m briefcase run macOS # launch the built app
venv/bin/python3.12 -m briefcase package macOS --adhoc-sign # → dist/*.dmgThe bundle pins PySide6==6.7.3 and ships a local wheelhouse/pyaes wheel (the
Briefcase Python installs with --only-binary, and those have no upstream wheel for
the target). The resulting .dmg is ad-hoc signed — fine for local use; for
distribution you'd sign with a Developer ID and notarize.
export_media.py # download engine (Pyrogram/asyncio) + CLI
uploader.py # upload pipeline (folder → channel) + upload_state.db
fast_download.py # FastTelethon multi-connection helper
run_gui.py # GUI launcher
gui/
app.py # MainWindow: header + screen stack + wiring
theme.py # TensorMedia design system (dark/light palettes, widgets)
i18n.py # translation engine (EN default + RU)
topbar.py # header: theme + language switchers
controller.py # Qt <-> asyncio bridge (background engine thread)
reporter.py # thread-safe event queue -> Qt signals
screens/ # login, options, review, dashboard, upload, reports
tests/run_tests.py # regression suite
config.example.json # template (copy to config.json)
MIT © 2026 KyLaEga


{ "api_id": 0, // number from my.telegram.org "api_hash": "your_32_char_api_hash", // string from my.telegram.org "phone": "+10000000000", // your phone, intl format "channel": "@your_channel_or_t.me_link_or_id", // source channel "dest": "/Volumes/SSD/telegram_export" // download destination }