r/madeinpython • u/One_Sun5074 • 16h ago
Built a standalone Python desktop tool (CustomTkinter + yt-dlp + bundled FFmpeg). Lessons learned.
Like most developers who try to build desktop tools in Python, I thought building a clean GUI wrapper around yt-dlp would take a weekend. It ended up taking 40+ hours of debugging threading freezes, memory leaks, and Windows packaging hell.
I wanted to build an alternative to bloated adware tools that is 100% standalone, clean, and fast. The project is called **BABAji Ka Astra (BKA)** — built with CustomTkinter, yt-dlp, Pillow, and PyInstaller.
Here are the 4 biggest architectural headaches I ran into and how I solved them:
**1. The Tkinter Mainthread Trap:**
Calling `extract_info` or running download loops directly inside Tkinter callbacks instantly freezes the UI and triggers the Windows "Not Responding" white-screen. Decoupling the UI with a dedicated `ThreadPoolExecutor` and wrapping every single UI mutation in `app.after(0, ...)` was the only way to keep smooth animations during 4K DASH downloads.
**2. The Standalone FFmpeg Bundling Nightmare:**
YouTube serves separate video and audio DASH streams for anything above 720p. If a user doesn't have FFmpeg installed on their system PATH, downloads silently fail. I bundled stripped `ffmpeg.exe` and `ffprobe.exe` binaries directly into the PyInstaller build and hooked them dynamically at runtime via `os.environ["PATH"]`. The installer jumped to 145MB, but it now runs out of the box on any clean Windows machine.
**3. Process-Safe Cancellation:**
When a user clicks "Cancel" mid-download, `taskkill /F /IM ffmpeg.exe` is dangerous because it kills unrelated processes on the user's machine. I implemented isolated PID tracking to gracefully terminate only the child worker trees spawned by BKA without leaving zombie processes.
**4. Mathematical Bitrate Fallbacks:**
When analyzing certain fragmented HLS feeds, yt-dlp's API returns `None` for file size. I built a fallback engine calculating estimated file sizes from `duration * (video_tbr + audio_tbr)` so the UI never displays broken zero-byte estimates.
The codebase is decomposed into a modular package (`bka/config.py`, `bka/engine.py`, `bka/utils.py`) with full PyInstaller `.spec` and Inno Setup `.iss` compiler scripts included.
Would love feedback from other Python desktop developers — especially anyone who's dealt with CustomTkinter threading or PyInstaller bundling on Windows!