A privacy-first desktop downloader for YouTube and Instagram.
No accounts. No cloud. No data leaves your machine.
KineTube is a cross-platform desktop application that lets you download videos from YouTube and Instagram, transcribe them locally using Whisper AI, and manage your media -- entirely offline. It is built on Electron, React, and Express, and delegates all heavy lifting to battle-tested open-source tools (yt-dlp, FFmpeg, whisper.cpp, instaloader) that it downloads and manages automatically on first launch.
There is no server to sign up for, no API key to buy, and no usage limit. Everything runs on your computer.
| Category | Capability |
|---|---|
| YouTube | Videos, Shorts, channels, playlists -- up to 4K with FFmpeg merging |
| Reels, posts, stories, full profile bulk-download (up to 500 posts) | |
| Audio extraction | Rip MP3 from any video with one click |
| Transcription | Local Whisper AI transcription in 13 languages, five model sizes |
| Batch downloads | Mix YouTube and Instagram URLs in one queue |
| Resume interrupted downloads | If the app closes mid-download, the next launch offers to pick up where it left off |
| Dark mode | System-aware theme with manual override |
| Private content | Instagram login with 2FA support and multi-account management |
| Filename control | Prefix, suffix, numbering, and custom yt-dlp templates |
| Progress streaming | Real-time speed, ETA, and phase indicators via SSE |
| In-app updates | Current version and a manual "Check for Updates" button live in Settings |
graph TD
A[Electron Main Process] --> B[Vite + React Frontend]
A --> C[Express Backend :3001]
B -->|SSE streams| C
B -->|REST JSON| C
C --> D[yt-dlp]
C --> E[FFmpeg]
C --> F[whisper.cpp]
C --> G[instaloader Python]
D -->|video/audio| H[(Downloads Folder)]
E -->|merged .mp4| H
F -->|.txt transcript| H
G -->|Instagram media| H
sequenceDiagram
participant U as User
participant F as Frontend
participant B as Backend
participant Y as yt-dlp
U->>F: Paste URL + click Fetch
F->>B: POST /api/info
B->>Y: yt-dlp -J <url>
Y-->>B: JSON metadata
B-->>F: formats, title, thumbnail
F->>U: Show quality picker
U->>F: Select quality + Download
F->>B: GET /api/download (SSE)
B->>Y: yt-dlp --newline --progress
loop Real-time progress
Y-->>B: progress line
B-->>F: SSE progress event
F-->>U: Speed / ETA / percent
end
B-->>F: SSE done event + filePath
F->>U: Show success + Transcribe option
All other dependencies (yt-dlp, FFmpeg, whisper.cpp, instaloader) are downloaded automatically on first launch.
git clone https://github.com/spacesdrive/kinetube.git
cd kinetube
npm install
cd frontend && npm install && cd ..
npm run devThis starts the Express backend, the Vite dev server, and Electron simultaneously via concurrently.
# Build the React frontend first
npm run build:frontend
# Then package for your platform
npm run dist:win # Windows NSIS installer
npm run dist:mac # macOS DMG
npm run dist:linux # Linux AppImageKineTube calls yt-dlp under the hood. When you paste a URL and click Fetch, the backend runs yt-dlp -J to pull metadata and return available format streams to the frontend. On download, it constructs a format selector string such as bestvideo[height<=1080][ext=mp4]+bestaudio[ext=m4a] and streams progress back line-by-line over SSE. If FFmpeg is available, video and audio tracks are merged automatically.
If KineTube closes while a video is downloading, it remembers the request and offers to resume it on the next launch - yt-dlp resumes its own partial file rather than starting over.
Public content uses yt-dlp directly. Profile pages and private content route through instaloader, a Python library that handles Instagram's session-based authentication and pagination. KineTube wraps this in two helper scripts (instaloader_login.py, instaloader_profile.py) that communicate with the Express backend over stdin/stdout. Sessions are stored locally under backend/sessions/ as binary cookie files.
After a download completes, or for any existing audio/video file, KineTube extracts a 16 kHz mono WAV via FFmpeg and passes it to whisper-cli.exe (whisper.cpp). The transcript is saved as a .txt file next to the source media. Five model sizes are available from Tiny (75 MB) to Large (2.9 GB) and are downloaded on demand from Hugging Face.
| Layer | Technology |
|---|---|
| Desktop shell | Electron 33 |
| Frontend | React 19, Vite 8, Tailwind CSS 4, shadcn/ui |
| Backend | Express 5, Node.js |
| Downloader | yt-dlp (auto-managed) |
| Merger | FFmpeg (auto-managed) |
| Transcription | whisper.cpp v1.8.4 (auto-managed - prebuilt on Windows, built from source on macOS/Linux) |
| Instagram scraping | instaloader (Python, pip install instaloader) |
| Theme | next-themes |
| Icons | Lucide React |
kinetube/
electron/ # Electron main process and preload
backend/
routes/ # Express route handlers (download, info, instagram, transcribe, setup)
utils/ # yt-dlp/ffmpeg/whisper.cpp managers, shared download helper, pending-download registry
sessions/ # Instagram session files (gitignored)
downloads/ # Default download output (gitignored)
models/ # Whisper model files (gitignored)
frontend/
src/
components/ # React components (shadcn-based UI)
components/ui/ # shadcn/ui primitives
lib/ # Shared frontend helpers (fetch client, URL cleaning, cn())
All settings persist in localStorage and survive app restarts.
| Setting | Description |
|---|---|
| Output folder | Custom path or default to backend/downloads/ |
| Filename template | yt-dlp variables: %(title)s, %(uploader)s, %(upload_date)s, %(id)s |
| Numbering | Prepend a zero-padded sequence number to filenames |
| Prefix / suffix | Arbitrary text prepended or appended to every filename |
| Default Whisper model | Tiny / Base / Small / Medium / Large |
| Transcription language | Auto-detect or any of 13 preset languages |
Instagram support requires Python to be installed and accessible on your PATH.
pip install instaloaderOnce Python is detected, you can log in directly from the sidebar inside the app. Two-factor authentication is fully supported. Multiple accounts can be added and switched between without re-authenticating.
If you prefer to authenticate outside the app, copy the instaloader session file into backend/sessions/session-<username> and use the session import option in Settings.
| Action | Shortcut |
|---|---|
| Toggle DevTools | F12 |
| New search | Click logo or "New search" button |
| Submit URL | Enter |
Contributions are welcome. To get started:
- Read
CLAUDE.md- project identity, architecture map, and engineering standards. - Fork the repository and create a branch from
main. - Follow the Quick Start instructions above to run the project locally.
- Make your changes. Keep commits focused and the diff readable - see
docs/workflows/GIT.md. - Run
npm test(backend + frontend) before opening a pull request - seedocs/workflows/TESTING.md. - Open a pull request with a clear description of what changed and why.
For larger changes, open an issue first to discuss the approach before investing time in the implementation. If your change touches yt-dlp, FFmpeg, whisper.cpp, or instaloader, read docs/philosophy/CROSS_PLATFORM.md first - these are currently Windows-only.
MIT -- use it, modify it, ship it.