MFK

Full-Stack Engineer · Pakistan

Open to work · Available immediately

Ambaar

A download manager whose engine verifies itself

📅 2026👤 Solo build | design, engineering, packaging, release🏢 Open source | MIT👁 18 views
PythonPySide6Qtyt-dlpPyInstallerGitHub Actions
⚠️

Problem

A 42 GB download timed out on every online downloader I tried. The desktop tool I built to replace them broke two weeks later, silently | YouTube changed its player and the engine underneath went stale with no error to show for it.

🔧

Solution

Made the engine prove itself. Ambaar updates weekly, then resolves a real media URL and fetches the first two kilobytes before trusting the new version. A 403 there means signature deciphering is broken, and the previous working engine is restored automatically.

✦

Result

Shipped for Windows, macOS and Linux with a CI pipeline that launches every build before publishing it | a check that caught a Qt failure invisible to every build-time test.

Impact

  • ✦Self-verifying engine updater with regression-only rollback
  • ✦Packaged builds update without pip, by unpacking wheels onto sys.path
  • ✦CI launches every artifact before release | not just builds it
  • ✦48 regression tests covering version comparison, diagnosis and rollback logic
  • ✦One-click ffmpeg and JavaScript runtime install on first run

01The Problem

I was downloading a 42 GB video. Every online downloader I tried timed out | most of them capped at an hour regardless of file size. So I built a desktop one on top of yt-dlp, which solved the timeout immediately. Then it broke. Two weeks later YouTube changed something in its player and downloads started failing with "Requested format is not available". The engine had gone stale. Nothing in the app said so | the version number looked fine, the app looked fine, and the only symptom was downloads returning storyboard thumbnails instead of video. That is the real problem with every downloader I have used. They work the day you install them and quietly rot afterwards.

02The Insight

A version number tells you nothing about whether something still works. YouTube obfuscates its format URLs behind a JavaScript challenge called nsig. yt-dlp ships a JavaScript interpreter to solve it. When YouTube changes the challenge, the deciphering breaks | and the failure surfaces as a 403 on the media URL, long after the version check has reported everything as current. So the update itself is not the interesting part. The verification is. Anything can run pip on a timer; the question is how you know the result is any good.

03How Verification Works

Every update is treated as a change that must prove itself: 1. Probe the current install and record whether it works. 2. Check the release channel for something newer. 3. Install it. 4. Probe again | in a fresh subprocess. 5. If it worked before and fails now, restore the previous version. Step four is load-bearing and easy to get wrong. After a pip upgrade, the running interpreter still holds the old module in sys.modules. Verifying in-process tests the version you just replaced and reports a false pass | the bug that quietly ruins most self-updaters. The probe resolves a real media URL from a known video and issues a ranged GET against it. Two kilobytes is enough. A 403 there is the exact signature of broken signature deciphering.

04The Rollback Asymmetry

Rollback fires only on a genuine regression: it worked before, it fails now. That asymmetry is deliberate and it does two jobs. If the engine was already broken before the update, the newer build is kept | fixes come forward, not backward, and reverting would pin the user to an ever-older version. And because rollback requires the earlier probe to have passed, a network outage cannot trigger a spurious revert. An outage fails both probes, and both-fail means nothing moves. Without that condition, a flaky connection would walk users backwards through releases one week at a time.

05Packaging Broke the Whole Idea

A frozen app has no pip and no writable site-packages. So the moment Ambaar was packaged as an executable, the updater | the entire point of the project | stopped working. Every downloaded build would be pinned to whatever yt-dlp existed on build day. Precisely the failure the app was written to prevent, reintroduced by shipping it. yt-dlp is pure Python, which turned out to be the way through. A newer release does not need installing, it needs unpacking somewhere importable. The updater downloads the wheel, extracts it to the user data directory, and a bootstrap module puts that directory ahead of the bundled copy on sys.path before anything imports yt_dlp. The bundled engine stays as a fallback, so a corrupt download degrades to "older engine" rather than "app will not start".

06Two Bugs Worth Keeping

Python 3.8 does not fail loudly when you install yt-dlp on it. pip resolves around the requirement and installs a two-year-old release instead of refusing. The app looked fine, the version string looked plausible, and I spent a day debugging code that was correct. Ambaar now checks the interpreter first and says so explicitly, because no engine update can fix it. The second was mine. Trimming unused Qt modules to shrink the download produced a build that packaged cleanly, passed every check, and then died on launch with "DLL load failed while importing QtCore". One exclude had removed a library Qt still linked against. Qt now ships whole by default, and CI launches every artifact before publishing | because a build that compiles is not evidence that it runs.

07Design

Queue rows are painted by a QStyledItemDelegate rather than composed from widgets. A table of four columns cannot express the typographic hierarchy the rows needed, and every column would have needed styling to match. Painting directly is faster and gives full control over hierarchy. Every mark in the interface is a stroked path | status marks, dropdown chevrons, spin steppers, the empty state, the app icon. That is partly a design rule and partly practical: glyph icons assume the user has a font that ships them, which is exactly what breaks on a clean Windows install. The name is انبار, Urdu and Sindhi for a stockpile | which is what a downloader builds. Ambar also means amber, so the name and the accent colour are the same word twice.

08Outcome

Ambaar ships for Windows, macOS on both architectures, and Linux. Tagging a version builds all four on real runners, launches each one to confirm it starts, and publishes them to a release page. Users download and run | no Python required. The thing I would carry into the next project is smaller than the app. Verifying that something still works is a different question from checking what version it claims to be, and almost every tool I use answers the second question while pretending it answered the first.