Telegram bot for downloading media from YouTube, TikTok, Instagram, X/Twitter, Pinterest, Spotify, and SoundCloud.
Production runs as a single Go binary (webhook/polling + asynq worker + Prometheus metrics). See go/README.md for development details.
- Video/photo downloads via yt-dlp (YouTube, TikTok, Instagram, X)
- Pinterest pins and boards
- Spotify metadata (Web API) and optional audio via yt-dlp YouTube search
- SoundCloud metadata and optional audio via yt-dlp
POST /download/pinterestHTTP API- EN/RU localization, admin panel, broadcasts,
/clearqueue command - Grafana dashboards at saveinator.xdshka.party
cp .env.example .env
# Edit BOT_TOKEN, DB_PASSWORD, Spotify creds, etc.
docker compose up -d --build
docker compose --profile tools run --rm migrate # first deploy / schema updatesServices:
| Service | Description |
|---|---|
saveinator |
Go app: Telegram webhook, asynq worker, metrics :9101 + :9102 |
db |
PostgreSQL 16 (existing pgdata volume preserved on upgrade) |
redis |
Queue, locks, rate limits |
docker compose -f docker-compose.dev.yml up -d # Postgres + Redis
cd go && go run ./cmd/saveinator # or scripts/run-go-dev.shSet USE_POLLING=true in .env.go.dev for local polling without webhook.
USE_POLLING=false
WEBHOOK_HOST=https://saveinator-hooks.xdshka.party
WEBHOOK_PATH=/webhook
WEBHOOK_SECRET_TOKEN=long-random-value
DATABASE_URL=postgresql+asyncpg://saveinator:${DB_PASSWORD}@db:5432/saveinatorPublic routes (via Caddy/Cloudflare): /, /health, /webhook*. Metrics stay on 127.0.0.1:9101 and :9102.
./scripts/deploy.sh # sync + build + up saveinator
./scripts/cutover-to-go.sh # one-time migration from legacy Python stack
./scripts/cleanup-python-vps.shMonitoring: see MONITORING.md.
cd go && go test ./...Schema is managed with Alembic (db/migrations/). Run via migrate container:
docker compose --profile tools run --rm migrateSee .env.example. Key values:
| Variable | Description |
|---|---|
BOT_TOKEN |
Telegram bot token |
DATABASE_URL |
PostgreSQL URL (postgresql+asyncpg://... in Docker) |
DB_PASSWORD |
Postgres password for Compose |
REDIS_URL |
Redis for asynq and rate limits |
SAVEINATOR_MODE |
all (default), bot, or worker |
METRICS_PORT / WORKER_METRICS_PORT |
Prometheus scrape ports (default 9101 / 9102) |
Telegram → Caddy :8093 → saveinator :8000 (webhook)
saveinator → PostgreSQL (users, downloads, broadcasts)
saveinator → Redis (asynq queue, locks, runtime settings)
saveinator → yt-dlp / ffmpeg (downloads in-process worker)
Prometheus → :9101 + :9102 → Grafana (saveinator.xdshka.party)
Code layout:
go/— application sourcelocales/— EN/RU stringsdb/migrations/— Alembic schema historymonitoring/— Prometheus, Grafana, alerts