# telegram-exporter — ⚠️ churned
**Status: churned as of 2026-08-25. No further development, no maintenance, no
issue support.** This repo now contains only these instructions; the retired
Python implementation lives in git history (see the last section).
## Why
[iyear/tdl](https://github.com/iyear/tdl) — an actively maintained Telegram
toolkit in Go, built on [gotd/td](https://github.com/gotd/td) — already covers
this project's purpose: export chat history and download media from DMs, groups
and channels over MTProto with a user account (so neither Bot API limit applies:
it can read history, and there is no 20 MB download cap). Maintaining a parallel
tool is not justified.
In short: a gotd-based rewrite was researched and judged feasible but not
worth it, since tdl already exists and is proven; the original project's
research and build reports are in git history at commit `3286ee2`.
## Use tdl instead
Install: see .
```bash
tdl login # user-account login (phone + code + 2FA)
# 1) export message metadata to JSON
tdl chat export -c @mygroup --all --with-content -o export.json
# 2) download the media it references
tdl dl -f export.json -d ./exports --takeout --group --skip-same --continue
```
Flag notes, mapped to what this project used to do:
- `--takeout` — takeout session with lower flood-wait limits for bulk export
(an improvement this project never had).
- `--group` — detect albums (`grouped_id`) and download grouped messages together.
- `--skip-same` + `--continue` — resume: skip files matching existing name+size,
continue interrupted downloads without prompting.
- `--all --with-content` — include text-only messages with their content
(equivalent of `--include-text`).
- Filters: time range / message-id range via `-i`, plus expression filters, e.g.
`-f "Media.Size > 5*1024*1024"`. Extension filters via `-i jpg,png` / `-e mp4`.
- tdl defaults to aggressive parallelism (`-t 8 -l 4`). If you hit flood waits
on a large export, lower it (`-t 4 -l 1`).
What tdl does **not** replicate from this project's contract: per-post album
folders keyed on message id, the `messages.jsonl` append-only sidecar, the
cursor with filter-mismatch refusal, and the dry-run disk estimate. If you need
those guarantees, the old implementation is in this repo's history and `src/`.
## Special case: exporting to WebDAV
tdl can only write to a local directory — it has no WebDAV (or any remote)
destination. When the group's media is larger than local disk, use a **rolling
pipeline**: tdl downloads into a small staging directory while
[rclone](https://rclone.org/) concurrently moves (upload + delete local)
finished files to WebDAV. Local disk then only needs to hold the files
currently in flight plus one sync interval of throughput — Telegram caps a
single file at 2 GB (4 GB from premium uploaders), so a few dozen GB of staging
covers the worst case regardless of the group's total size.
One-time rclone remote setup:
```bash
rclone config create tg-webdav webdav \
url=https://dav.example.com/remote.php/dav/files/you \
vendor=other user=YOU pass=SECRET
```
Pipeline (bash):
```bash
tdl dl -f export.json -d ./staging --takeout --group --skip-same --continue &
TDL_PID=$!
while kill -0 "$TDL_PID" 2>/dev/null; do
rclone move ./staging tg-webdav:tg-export --min-age 2m --delete-empty-src-dirs
sleep 60
done
rclone move ./staging tg-webdav:tg-export --delete-empty-src-dirs # final sweep
```
Pipeline (PowerShell):
```powershell
$tdl = Start-Process tdl -ArgumentList 'dl','-f','export.json','-d','./staging','--takeout','--group','--skip-same','--continue' -PassThru -NoNewWindow
while (-not $tdl.HasExited) {
rclone move ./staging tg-webdav:tg-export --min-age 2m --delete-empty-src-dirs
Start-Sleep -Seconds 60
}
rclone move ./staging tg-webdav:tg-export --delete-empty-src-dirs
```
Why it works:
- `--min-age 2m` keeps rclone away from files tdl is still writing; the final
sweep after tdl exits catches everything else.
- Both legs are independently resumable: re-run tdl (`--skip-same --continue`)
and re-run the rclone loop; nothing is downloaded or uploaded twice.
- Caveat: `--skip-same` compares name+size against the **staging** dir, which
is empty after files move to WebDAV. Cross-run dedupe therefore rests on
`--continue` (tdl's own completion tracking) — keep the same `export.json`
between runs. If you restart with a fresh export, narrow it to the missing
message-id range (`-T id -i ,`) instead of re-downloading
everything.
**Zero-staging streaming (no local disk at all) is not possible with tdl.** It
requires custom code that pipes download chunks straight into a WebDAV `PUT` —
both Telethon (`iter_download`) and gotd (`Stream(ctx, w)`) support that; see
the reports in `plans/reports/` if you ever need to build it.
## The retired implementation
A complete, tested (214 offline tests) Python/Telethon exporter with per-post
album folders, a `messages.jsonl` sidecar, resumable cursor semantics and a
dry-run size estimator lives at commit `3286ee2`:
```bash
git show 3286ee2:README.md # its documentation
git checkout 3286ee2 -- src tests pyproject.toml requirements.txt # resurrect it
```
It is unmaintained and pins Telethon `<2`; expect bit-rot.