A Telegram bot that downloads media from URLs and sends files back to the chat.
Built in Go with Postgres-backed job queue and yt-dlp as the download backend.
cmd/downly/ entrypoint
internal/
config/ YAML config loader
db/ Postgres queries and schema
downloader/ yt-dlp wrapper
telegram/ Telegram bot handlers
worker/ job processing loop
cleanup/ old job cleanup loop
updater/ yt-dlp auto-updater
migrate/ embedded SQL migrations
logging/ structured logger setup
- User sends a URL to the Telegram bot
- Job is inserted into Postgres with queue position
- Worker claims jobs using
FOR UPDATE SKIP LOCKED - Progress updates are edited into the original Telegram message
- Completed file is sent back to the user
User commands:
/start,/help- show usage/queue- show your active jobs and queue positions/history- show your past downloads/cancel <job_id>- cancel a pending or running job
Admin commands:
/stats- bot analytics/promote <job_id>- raise job priority/demote <job_id>- reset job priority/broadcast <message>- message all users/ban <user_id> [reason]- block a user/unban <user_id>- unblock a user
Copy sample-config.yaml to config.yaml and fill in your values.
Key fields:
downly.telegram.bot_token- Telegram bot tokendownly.database.postgres_url- Postgres connection stringdownly.worker.numbers_of_workers- concurrent download workersdownly.worker.max_file_size_mb- max file size for Telegram uploaddownly.limits.rate_limit_seconds- cooldown between URL submissions per userdownly.limits.max_retries- auto-retry count for failed downloadsdownly.services.ytdl.auto_update_hours- yt-dlp self-update intervaldownly.admin.user_ids- Telegram user IDs with admin access
go build -o .build/downly ./cmd/downlydocker compose up --buildDevelopment:
docker compose -f compose.development.yaml up --buildExport cookies to cookies/instagram.txt and set in config:
downly:
services:
ytdl:
cookies_file: "/app/cookies/instagram.txt"A template is at cookies/instagram.txt.sample.