Fast • Clean • Reliable
Download Stories, public posts, and restricted media from Telegram — in seconds.
Telegram Downloader is a production-ready bot that fetches media from Telegram links and delivers it to the user in private chat.
| Source | Method | Speed |
|---|---|---|
| Public channel / group posts | copy_message (no re-upload) |
Instant |
| Restricted content | User account → download → bot re-upload | Depends on file size |
| Stories (photo / video) | Telethon Stories API | Depends on file size |
Built with a clean modular architecture, structured logging, typed models, and Docker support.
- Stories — photo & video via Telethon
GetStoriesByID - Public posts — instant copy, no bandwidth waste
- Restricted media — when the logged-in account has access
- Media types — photos, videos, documents, voice, audio, animations, stickers
- Message ranges —
https://t.me/channel/100-110(up to 50) - Colored inline buttons —
primary/success/danger(Bot API style) - Parallel downloads — up to 5 concurrent for ranges
- High upload timeouts — large files won’t fail mid-transfer
.envconfiguration — no secrets in code- Structured logging — clear, filterable output
- Exception hierarchy — predictable error handling
- Type hints + async throughout
- Docker-ready
- No database — stateless by design
| Layer | Technology |
|---|---|
| Bot framework | python-telegram-bot ≥ 22.7 |
| User / Stories API | Telethon |
| Config | python-dotenv |
| Runtime | Python 3.11+ |
TelegramDownLoader/
├── app.py # Entry point
├── config.py # Env-based settings
├── requirements.txt
├── .env.example
├── Dockerfile
├── README.md
│
├── core/
│ ├── manager.py # Application lifecycle
│ ├── telethon_client.py # User client (Stories + restricted)
│ ├── logger.py
│ └── exceptions.py
│
├── handlers/
│ ├── start.py # /start + styled button
│ ├── story.py # Story links
│ └── restricted.py # Public / restricted posts
│
├── services/
│ ├── parser.py # Link detection
│ ├── story.py
│ ├── restricted.py # Parallel download pipeline
│ └── sender.py # Media delivery + keyboards
│
├── tg/
│ ├── story.py # Telethon GetStoriesByID
│ └── messages.py # Restricted message fetch
│
├── models/
│ ├── media.py # MediaType, MediaItem, DownloadResult
│ └── result.py
│
└── utils/
├── regex.py
├── files.py
└── helpers.py
git clone https://github.com/DevZ44d/TelegramDownLoader.git
cd TelegramDownLoaderpython -m venv venv
# Windows
venv\Scripts\activate
# Linux / macOS
source venv/bin/activatepip install -r requirements.txtcp .env.example .envEdit .env:
API_ID=12345678
API_HASH=your_api_hash
BOT_TOKEN=123456:ABC-DEF...
SESSION_STRING= # optional but required for Stories & restricted
DEVELOPER_URL=https://t.me/YourUsername
DOWNLOAD_DIR=downloads
LOG_LEVEL=INFO| Variable | Required | Description |
|---|---|---|
API_ID |
Yes | From my.telegram.org |
API_HASH |
Yes | From my.telegram.org |
BOT_TOKEN |
Yes | From @BotFather |
SESSION_STRING |
Recommended | Telethon string session (Stories + restricted) |
DEVELOPER_URL |
No | Shown on the start button |
DOWNLOAD_DIR |
No | Temp files (default: downloads) |
LOG_LEVEL |
No | DEBUG / INFO / WARNING / ERROR |
from telethon.sync import TelegramClient
from telethon.sessions import StringSession
api_id = 12345
api_hash = "your_hash"
with TelegramClient(StringSession(), api_id, api_hash) as client:
print(client.session.save())Paste the output into SESSION_STRING.
Without a session string, public posts still work. Stories and restricted content will not.
python app.pydocker build -t telegram-downloader .
docker run --env-file .env \
-v "$(pwd)/downloads:/app/downloads" \
telegram-downloader| Type | Example |
|---|---|
| Story | https://t.me/username/s/123 |
| Public post | https://t.me/channel/456 |
| Message range | https://t.me/channel/100-105 |
| Restricted post* | Same as public (account must be a member) |
* Requires a valid SESSION_STRING.
Requires Telegram clients released after 9 February 2026. Older clients ignore style.
from telegram import InlineKeyboardButton
from telegram.constants import KeyboardButtonStyle
InlineKeyboardButton(
"Developer",
url="https://t.me/...",
style=KeyboardButtonStyle.PRIMARY, # blue
# style=KeyboardButtonStyle.SUCCESS, # green
# style=KeyboardButtonStyle.DANGER, # red
)User sends link
│
▼
┌──────────────┐
│ Link parser │ → Story / Public / Invite / Unknown
└──────┬───────┘
│
├─ Story ──────────► Telethon GetStoriesByID → download → bot send
│
├─ Public post ────► bot.copy_message (fast path)
│ │ fail
│ ▼
│ Telethon download → bot re-upload
│
└─ Restricted ─────► Telethon only → download → bot re-upload
- Public: zero download when the bot can see the chat.
- Restricted / Stories: user client fetches media; bot delivers it to the user.
- Never commit
.envor session files. SESSION_STRINGgrants full account access — treat it like a password.- The bot only answers in private chats.
- Temp files are deleted after send.
- Fork the repo
- Create a branch:
git checkout -b feature/my-feature - Commit:
git commit -m "Add my feature" - Push and open a Pull Request
Keep code typed, async, and consistent with the existing layout.
Built for speed and clarity. Drop a link. Get the media.