This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
tt-bot is a Telegram bot for downloading TikTok and Instagram videos, slideshows, and audio without watermarks. Production-grade with proxy rotation, queue management, 3-part retry strategy, and multilingual support.
Stack: Python 3.13, aiogram 3.24, yt-dlp, curl_cffi, aiohttp, SQLAlchemy 2.0, asyncpg
Structure:
main.py- Main bot entry pointtiktok_api/- TikTok extraction (client.py is the core with 3-part retry)instagram_api/- Instagram extraction via RapidAPIhandlers/- Telegram message handlers (link_dispatcher.pyroutes Instagram vs TikTok)media_types/- Media sending/processing package (shared across sources)data/- Configuration, database, localizationmisc/- Queue management, utilitiesstats/- Statistics bot and graphs
For detailed architecture, see docs/CODEBASE_MAP.md.
# Run the main bot
uv run main.py
# Run the stats bot
uv run stats.py
# Run with Docker
docker-compose up -d
# Install dependencies
uv sync- 3-part retry strategy: URL resolution → Video info → Download, each with independent proxy rotation
- Chrome 120 impersonation: Fixed browser fingerprint to bypass TikTok WAF blocking
- Singleton resources: Shared ThreadPoolExecutor (500), curl session pool (1000/proxy), aiohttp connector
- Context managers: VideoInfo implements RAII for yt-dlp resource cleanup
- Repository pattern: db_service.py abstracts database operations
- Queue management: Per-user concurrency limits via QueueManager
- VideoInfo cleanup: Slideshows MUST call
.close()or usewithstatement to release yt-dlp resources - Chrome 120 only: Newer versions (136+) blocked with proxies due to fingerprint mismatch
- Database initialization: Call
initialize_database_components()before any DB operations - yt-dlp private API: Uses
_extract_web_data_and_status()which may break on yt-dlp updates - ProxySession sticky: Same proxy used across all 3 parts unless retry triggers rotation
- New command: Add handler in
handlers/, register router inmain.py - New language: Create
data/locale/XX.json(auto-detected) - New error type: Add to
*_api/exceptions.py, register viaregister_error_mapping()in package__init__.py - New video source: Create
source_api/module → add URL filter inhandlers/link_dispatcher.py→ create handler - New unsupported content handler: Add to
handlers/get_video.py