A simple Python GUI application for downloading YouTube videos and audio using yt_dlp.
- Fetch video metadata (title, available video-only formats).
- Display video thumbnail and title.
- Choose output format:
mp4,mkv, ormp3. - Select resolution and video codec for
mp4/mkvdownloads. - Download audio only (MP3) with automatic conversion via
ffmpeg. - Shows download progress with percentage, speed, ETA, and transferred size.
- Configurable save directory stored in
config.json. - Background download thread to keep the UI responsive.
main/
├── backend.py # Business logic connecting UI and VideoHandler
├── handler.py # Wraps yt_dlp for metadata and downloading
├── path.py # Utilities for storing/retrieving save and ffmpeg directory
├── window.py # Tkinter/ttkbootstrap GUI implementation
├── config.json # Stores the last used download directory, and ffmpeg directory
└── README.md # This file
- Python 3.8+
yt_dlpfor video handlingttkbootstrapfor styled Tkinter widgetsPillowfor thumbnail image displayffmpegexecutable located in project root or provide the directory path in config.json.
- Clone or download the repository.
- Install dependencies:
pip install yt-dlp ttkbootstrap Pillow
- Ensure
ffmpeg.exeis available in the project directory or or provide the directory path in config.json.
- Run the application:
python -m main.window
- Enter a YouTube URL and click Check Video.
- Choose desired format, resolution, and codec (if applicable).
- Click Download and select a save directory if prompted.
- During downloading a Cancel button will appear – click it to abort the transfer.
The download will stop and a partial file may remain; delete or restart as needed. - Monitor progress in the UI; open folder after completion if prompted.
FFmpeg is required for merging video/audio streams and MP3 conversion. Follow these steps:
- Go to ffmpeg.org/download.
- Under Get packages & executable files, click the Windows icon.
- On the next page, under Windows EXE Files, you'll see precompiled builds from gyan.dev:
- Click ffmpeg-git-essentials.7z (minimal, ~50 MB) or ffmpeg-git-full.7z (complete, ~150 MB).
- Extract the
.7zfile to a folder likeC:\ffmpeg.
- Add the extracted folder to your system PATH, or update
config.json:{ "ffmpeg_path": "C:/ffmpeg/bin" } - Verify installation by opening PowerShell and running:
Both should print version info. If not, check your PATH or
ffmpeg -version ffprobe -version
config.jsonsetting.
- Using Homebrew (easiest):
brew install ffmpeg
- Or download from ffmpeg.org and build from source.
- Update
config.jsonif needed:{ "ffmpeg_path": "/usr/local/bin" }
- Using package manager (Debian/Ubuntu):
sudo apt update sudo apt install ffmpeg
- Or use your distribution's package manager (yum, pacman, etc.).
- Update
config.jsonif the binary is in a non-standard location.
The application stores settings in config.json located in the main/ directory. By default it contains:
{
"save_path": "",
"ffmpeg_path": "ffmpeg.exe"
}- save_path: Directory where downloaded videos are saved. Leave empty to prompt on each download.
- ffmpeg_path: Full path to the
ffmpegbinary or directory containingffmpeg.exeandffprobe.exe. Examples:- Windows:
"C:/ffmpeg/bin"(folder containing executables) or"ffmpeg.exe"(if in PATH) - macOS/Linux:
"/usr/local/bin"(folder) or"ffmpeg"(if in PATH)
- Windows:
You can edit this file directly or delete it to reset settings to defaults.
This project is provided as-is under the MIT License.
- Built with
yt_dlpfor downloading and metadata. - GUI styled using
ttkbootstrap.
Enjoy downloading your favorite videos!
-
GUI: Run
python -m main.window, enter a YouTube URL, click Check Video, choose format/resolution/codec, then Download. -
CLI (headless, basic): you can create a small wrapper that calls the handler directly if you need automation. Example (pseudo):
from main.handler import VideoHandler
vh = VideoHandler()
vh.fetch_metadata('https://youtu.be/VIDEO_ID')
vh.start_download(format_id, 'C:/Downloads', 'mp4', lambda d: print(d))- FFmpeg not found: If you see an FFmpeg error, ensure
ffmpeg/ffprobeare installed and theffmpeg_pathinmain/config.jsonpoints to the directory containing the executables (not the executable itself). Example config:
{
"save_path": "C:/Users/you/Downloads",
"ffmpeg_path": "C:/ffmpeg/bin"
}-
HTTP 416 (Requested range not satisfiable) after cancelling and restarting:
- This usually means a partial
.partfile remains from the interrupted download and the server rejected the resume range. Fixes:- Delete the
.partfile for the video in your download folder and retry. - Or enable the "Force restart" behavior (disable resume) so a fresh download starts. The code supports
continuedlinyt_dlpoptions — set toFalseto avoid range requests.
- Delete the
- This usually means a partial
-
Rate limiting (HTTP 429): Try again later or use a proxy/VPN. You can add a proxy in
yt_dlpoptions via theproxysetting. -
Geo-restricted content: Enable
geo_bypassinyt_dlpoptions or use a VPN/proxy to access the content. -
Permissions issues when opening folders:
- On Windows, the app uses
os.startfileto open folders; ensure your user has access rights. - On macOS/Linux the repository provides a small test script
scripts/test_platform.pythat attempts to open a file using the platform default opener — run it to verify your system opener is available.
- On Windows, the app uses
Run the full suite from the project root with pytest so Python can find the package:
python -m pytest testsAvoid invoking individual test files directly with python as that bypasses package resolution and leads to ModuleNotFoundError: No module named 'main'. Using -m pytest ensures the root directory is on PYTHONPATH
Contributions welcome — open issues or PRs on the GitHub repo linked at the top of this README.
I’ve packaged the optimized Windows build on Gumroad. It's completely free (just enter $0, though PWYW is enabled if you want to buy a student a coffee).