Turn any YouTube playlist into a daily email course with spaced repetition. Submit a playlist URL and your email — get one lesson a day until the course is done.
Live at: mindos.fly.dev
- Submit a YouTube playlist URL + email
- App fetches all video transcripts (3-tier pipeline)
- LLM (OpenRouter) breaks each transcript into lessons with key takeaways
- Lessons stored in SQLite with a spaced repetition schedule
- APScheduler emails one lesson per day via Resend until the course is complete
- Track progress live via SSE stream or poll the job status endpoint
| Layer | Tech |
|---|---|
| Backend | FastAPI + APScheduler |
| Transcript | youtube-transcript-api → yt-dlp → Groq Whisper (3-tier fallback) |
| LLM | OpenRouter (configurable model) |
| Database | SQLite (WAL mode) |
| Resend | |
| Admin reporting | gspread + Google Auth |
| Monitoring | Sentry |
| Deployment | DigitalOcean (Docker) |
| Frontend | Single-page HTML/JS (index.html, admin.html) |
POST /api/enroll — submit playlist URL + email, starts job
GET /api/job/{id} — poll job progress
GET /api/job/{id}/stream — SSE stream for live progress
GET /api/courses — list enrolled courses (by email)
DELETE /api/courses/{id} — cancel a course
GET /api/courses/{id}/schedule — full lesson schedule
GET /api/videos/{id}/emails — emails generated for a video
POST /api/emails/{id}/send-now — manually trigger a specific email
POST /api/courses/{id}/send-first — trigger first email for a course
GET /api/cron — manual cron trigger (CRON_SECRET required)
/admin — password-protected dashboard for monitoring enrollments, viewing job status, and manually triggering emails.
youtube-transcript-api— fast, usesYOUTUBE_PROXYif setyt-dlp— auto-generated captions fallbackGroq Whisper— audio transcription; ffmpeg auto-chunks files >24MB
- JIT: enrollment processes 1 video immediately
advance_processingruns at 2am IST nightly to queue the next video per coursesend_emailsjob runs every 5 minutesgenerate_reviewsruns hourly
pip install -r requirements.txt
cp .env.example .env
uvicorn main:app --reloadRequired env vars:
OPENROUTER_API_KEY
GROQ_API_KEY
RESEND_API_KEY
CRON_SECRET
ADMIN_USER
ADMIN_PASSWORD
YOUTUBE_PROXY # optional, WebShare format
LLM_BUDGET_CAP # optional, hard USD cap (default 1.0)
SENTRY_DSN # optional