Native desktop video downloader built with Go, MyGo, yt-dlp, and FFmpeg. The application analyzes videos and playlists, lets users choose quality, audio, subtitles, and containers, manages downloads in a queue, converts local media, and stores download history.
Current release: v3.2.0
Native desktop video downloader built with Go, MyGo, yt-dlp, and FFmpeg. The application analyzes videos and playlists, lets users choose quality, audio, subtitles, and containers, manages downloads in a queue, converts local media, and stores download history.
This project is the native Go/MyGo rewrite of Video-Downloader, the original Flet/Python application by Fazi Gondal.
| Light Mode | Dark Mode |
|---|---|
![]() |
![]() |
| History | Multi-Audio & Subtitle Picker |
|---|---|
![]() |
![]() |
| Format Explorer | Settings & Dependency Inspector |
|---|---|
![]() |
![]() |
~; container overhead, metadata, thumbnails, subtitles, and remuxing can change the final file size.The size shown on the configuration page sums the selected physical stream
payloads once. If an automatic fallback is already a combined video+audio
stream, its embedded audio is not counted a second time. Custom multi-audio
selection adds only the checked tracks. If yt-dlp does not report an exact
stream size, the app estimates it from bitrate and duration and displays ~.
go.mod.go.mod.CGO_ENABLED=0.yt-dlp, ffmpeg, and ffprobe for extraction,PATH.The application first looks for bundled tools and then falls back to PATH. See Bundled tools.
Release artifacts are published from version tags by .github/workflows/release.yml.
The Windows release includes the application executable and bundled yt-dlp/FFmpeg tools when the release workflow completes successfully.
Preferred options:
.deb package on Debian/Ubuntu-based systems..tar.gz archive and run the included install.sh.The Linux archive may require GTK/WebKit runtime packages on minimal distributions. The package manager version is preferred because it can declare system dependencies.
The current release workflow targets macOS arm64. Local builds can also target macOS amd64 when run on a compatible environment. The workflow bundles yt-dlp and an architecture-matched FFmpeg/FFprobe Homebrew bottle. Unsigned/ad-hoc builds may be blocked by Gatekeeper; configure Developer ID signing and notarization for public distribution.
Clone the repository and enter the project directory:
git clone https://github.com/fazi-gondal/video-downloader-mygo.git
cd video-downloader-mygo
Use the pinned dependency graph. Do not run go get github.com/egoist/mygo@latest as part of normal setup because it changes the tested version:
go mod download
go run .
For MyGo development mode with live rebuilding:
go tool mygo dev
On Windows, these commands work from PowerShell. The bundled-tool helper is a Bash script; use Git Bash, WSL, or another Bash environment when running it locally.
The complete build instructions are in BUILD.md. Common commands are:
# Native application build for the current/default target.
go tool mygo build
# Explicit targets. MyGo can cross-compile native UI targets without cgo.
go tool mygo build -platform windows/amd64
go tool mygo build -platform linux/amd64
go tool mygo build -platform linux/arm64
Artifacts are written below build/, as configured by mygo.json:
install.sh.Before packaging a release, download the matching helper tools:
bash scripts/fetch-tools.sh windows-amd64
bash scripts/fetch-tools.sh linux-amd64
# Or fetch every supported helper directory:
bash scripts/fetch-tools.sh all
Do not commit downloaded binaries from resources/*/bin/; they are ignored intentionally because FFmpeg archives are large.
resources/README.md describes the resource layout and resolution order. The expected development layout is:
resources/
icon.png
windows-amd64/bin/
yt-dlp.exe
ffmpeg.exe
ffprobe.exe
linux-amd64/bin/
yt-dlp
ffmpeg
ffprobe
linux-arm64/bin/ # same three Unix executables
darwin-amd64/bin/ # yt-dlp plus Homebrew FFmpeg/FFprobe in releases
darwin-arm64/bin/ # yt-dlp plus Homebrew FFmpeg/FFprobe in releases
The helper script supports these environment variables:
| Variable | Default | Purpose |
|---|---|---|
YTDLP_TAG |
2026.08.19 |
yt-dlp release tag used for the download URL |
FFMPEG_RELEASE |
latest |
FFmpeg-Builds release tag used for the archive URL |
Example:
YTDLP_TAG=2026.08.19 FFMPEG_RELEASE=latest bash scripts/fetch-tools.sh linux-amd64
The script requires curl, unzip, and tar/xz as appropriate for the
target archive. It verifies SHA-256 checksums before extracting only yt-dlp,ffmpeg, and ffprobe into the platform resource directory, and marks Unix
executables as executable. Update the recorded checksum when intentionally
upgrading a helper release. macOS FFmpeg/FFprobe are installed from a
architecture-matched Homebrew bottle; the release workflow runs those jobs on
matching macOS runners.
The release currently does not bundle a JavaScript runtime. yt-dlp may use a
runtime such as Deno for some modern YouTube challenge flows; install a
supported runtime on PATH when yt-dlp reports that one is required, or use a
source build with the runtime available. This behavior should be verified
against the target sites before promising complete extractor parity.
Runtime lookup order is:
resources/bin/<tool>.resources/<tool>.resources/<os>-<arch>/bin/<tool>.PATH.The bundled ARY Plus extractor supports aryplus.tv episode URLs and series
playlists, multi-quality HLS streams up to 4K, thumbnails, and DRM checks.
ARY Plus API access uses the built-in public client key; you may override it
with ARYPLUS_API_KEY and set ARYPLUS_API_BASE to use a compatible API
endpoint.
The app accepts HTTP and HTTPS URLs with a host for yt-dlp analysis and
downloads. ARY Plus episode and series URLs remain supported through the
application's dedicated resolver.
For a single video, the result card shows its thumbnail, title, uploader, duration, extractor, available audio tracks, and available subtitles. For a playlist, use Select all, Select none, or click individual checkboxes. Individual checkbox changes are committed immediately, so the tick remains visible when the list redraws.
For a TikTok, Instagram, X/Twitter, or YouTube Shorts video, the result card is
also the download screen: review the metadata and click Download HD. The
app skips the normal quality picker, uses the best available video/audio
source, writes an MP4, and does not use configured browser cookies.
Downloaded filenames use the media title and extension. The app does not append
yt-dlp video IDs to final filenames; playlist entries retain their playlist
index to keep entries distinguishable.
Select Continue to download options for a single video or Download selected for a playlist.
The configuration page is scrollable. It contains:
The custom audio and subtitle pickers use three columns and a bounded internal scroll area. Long labels are truncated inside their cells so the grid remains inside the window.
Selecting multiple audio tracks or any subtitle tracks changes the container to MKV and locks the container selector. MKV is used because it can carry multiple audio and text-subtitle streams reliably. When the selections return to default/none, the previous container choice is restored.
Select Start download. The application opens the Downloads page, where each task displays:
At the beginning of a download, size or ETA can be unavailable while yt-dlp
initializes. The card displays size unknown, speed calculating, orETA calculating until a value is available. The progress bar becomes
determinate when yt-dlp reports a total or the configuration estimate can be
used as a fallback.
Subtitle HTTP 429 responses are treated as partial subtitle warnings when the media download succeeds. The video/audio file still completes, but the blocked language may be missing until a later retry.
Open Converter, drop a media file onto the drop zone or select Browse, choose Audio or Video, select an output format, and select Convert. Lossy audio supports bitrates up to 320 kbps, including MP3 conversion. FLAC and WAV are lossless and ignore bitrate. Video uses a lossless remux only when FFprobe confirms that the source codecs fit the target container; other conversions use container-appropriate FFmpeg re-encoding.
downloads.json alongside app data; choose Pause and close to safely stop active transfers for later resumption.Settings are stored in settings.json under the platform application directory:
| Platform | Location |
|---|---|
| Windows | %LOCALAPPDATA%\\VideoDownloader\\settings.json |
| macOS | ~/Library/Application Support/VideoDownloader/settings.json |
| Linux | ~/.config/VideoDownloader/settings.json |
Current settings fields are:
| JSON field | Type | Description |
|---|---|---|
download_dir |
string | Default output directory. |
max_concurrent |
integer | Download workers, from 1 through 16. |
concurrent_fragments |
integer | yt-dlp fragment concurrency. |
proxy |
string | HTTP, HTTPS, SOCKS4, SOCKS4A, SOCKS5, or SOCKS5H proxy URL. |
cookies_browser |
string | Browser/profile value passed to yt-dlp. |
custom_headers |
object | Header name/value pairs used by extraction/download configuration. |
rate_limit_kbps |
integer | Per-download rate limit; zero means unlimited. |
keep_originals |
boolean | Keep source files after conversion. |
write_subtitles |
boolean | Enable subtitles by default. |
subtitle_langs |
string array | Default language codes or all. |
multi_audio |
boolean | Enable all available audio tracks by default. |
embed_thumbnail |
boolean | Embed thumbnail metadata where supported. |
embed_metadata |
boolean | Embed metadata and chapters. |
prefer_vp9_video |
boolean | Prefer VP9 video when available; yt-dlp falls back automatically when it is unavailable. |
theme_mode |
string | system, dark, or light. |
The Settings page is the preferred way to edit this file. It validates numeric ranges, proxy schemes, headers, cookies-browser input, subtitle languages, and theme values before writing.
.
├── main.go Application entry point and native window.
├── mygo.json MyGo package metadata and output directory.
├── go.mod Go module and pinned MyGo CLI tool.
├── internal/
│ ├── app/
│ │ ├── app.go Root shell, pages, state, and UI behavior.
│ │ ├── components.go Shared cards, pills, and icon helpers.
│ │ ├── preferences_view.go Refined Settings and About screens.
│ │ └── thumbnail_loader.go Bounded thumbnail HTTP/image loader.
│ ├── config/ Settings model and persistence.
│ ├── models/ Media, download, and conversion models.
│ ├── services/
│ │ ├── ytdlp.go Analysis, format parsing, and downloads.
│ │ ├── ytdlp_errors.go User-facing yt-dlp error classification.
│ │ ├── download_manager.go Concurrent download queue and events.
│ │ ├── ffmpeg.go FFmpeg conversion and probing.
│ │ ├── conversion.go Conversion worker queue.
│ │ └── history.go JSON-backed download history.
│ ├── tools/ Bundled/PATH executable resolution.
│ └── ui/ Theme and embedded SVG icons.
├── resources/ Shared and platform-specific resources.
├── scripts/fetch-tools.sh Helper binary downloader.
├── .github/workflows/ci.yml Test, vet, and Linux packaging smoke build.
├── .github/workflows/release.yml Tagged Windows/Linux/macOS release build.
└── BUILD.md Detailed development and packaging guide.
The application keeps worker processes away from UI widgets. yt-dlp and FFmpeg run in background services, publish task events, and the app invalidates/redraws from state on the UI side.
.github/workflows/ci.yml runs on pushes to main/master and pull requests.
It verifies the module graph, runs the race-enabled test suite, runs go vet,
and performs a Linux native packaging smoke build. The packaging matrix also
checks Windows amd64/arm64, Linux amd64/arm64, and macOS arm64 artifacts.
go test -race ./... -count=1
go vet ./...
CGO_ENABLED=0 go tool mygo build -platform linux/amd64 -skip-build-command
The CI job uses the Go version from go.mod, does not modify dependencies, and sets CGO_ENABLED=0 for the native packaging smoke build.
.github/workflows/release.yml runs for tags matching v*. Before tagging:
version in mygo.json.CHANGELOG.md and review the release checklist in BUILD.md.git tag v3.2.0
git push origin v3.2.0
The workflow checks that the tag matches mygo.json, downloads platform tools, uses the pinned MyGo CLI, builds Windows and Linux from Ubuntu, builds macOS from macOS, and uploads the generated artifacts to a draft GitHub release.
The workflow requires contents: write through the repository-provided GITHUB_TOKEN. Optional update/signing features require the secrets documented in the MyGo GitHub Actions guide.
Run the same checks used by the project locally:
go mod download
go run .
go test ./... -count=1
go vet ./...
go build ./...
git diff --check
Run the package smoke build:
CGO_ENABLED=0 go tool mygo build -platform linux/amd64 -skip-build-command
CGO_ENABLED=0 go tool mygo build -platform windows/amd64 -skip-build-command
On systems with Bash, check the helper script syntax:
bash -n scripts/fetch-tools.sh
Race tests may require a working C compiler on the host even though production MyGo builds use CGO_ENABLED=0:
CGO_ENABLED=1 go test -race ./... -count=1
yt-dlp or FFmpeg is not foundPATH.bash scripts/fetch-tools.sh <platform> and rebuild.resources/<platform>/bin.Subtitle servers can rate-limit individual language requests. The app spaces subtitle requests, retries with backoff, ignores subtitle-only failures, and displays a warning. Retry later, select fewer languages, or choose None for subtitles.
This is intentional. MKV is the reliable container for several audio streams and embedded text subtitle streams. The UI locks the container selector while those options are selected.
Initial analysis is intentionally lightweight. Open the format section and choose Load available formats. This runs the full yt-dlp format extraction only when needed.
Unsigned releases can trigger SmartScreen. Verify the release source and checksum/signature policy before running it. Configure Windows code signing in mygo.json for trusted distribution.
Install the runtime dependencies required by MyGo for your distribution. Prefer the generated .deb package where available because it can integrate package dependencies more reliably than extracting the tarball manually.
Check these first:
mygo.json.curl, unzip, and xz-utils are installed on the build runner.go tool mygo; do not replace it with an unpinned go install ...@latest command.Before opening a pull request:
gofmt, go test ./..., go vet ./..., and go build ./....Use focused commits with conventional prefixes such as feat:, fix:, docs:, test:, and chore:.
This project is distributed under the MIT License.
Copyright © 2026 Fazi Gondal.