Go backend for the Buckty desktop application, built with Wails v2. The backend manages download orchestration, SQLite persistence, Google Drive integration, and application updates.
- Module:
buckty - Go version: 1.25.0
- Build framework: Wails v2 (
github.com/wailsapp/wails/v2)
buckty/
├── main.go # Wails application entry point; wires all services
├── app.go # Wails adapter; exposes methods to the Angular frontend
├── go.mod / go.sum # Go module definition and dependency checksums
├── wails.json # Wails build configuration
├── frontend/ # Angular frontend (separate project)
├── internal/
│ ├── platform/
│ │ └── paths.go # OS-specific directory resolution (Windows, macOS, Linux)
│ ├── database/
│ │ ├── database.go # SQLite connection, embedded migrations, schema management
│ │ └── migrations/
│ │ └── 001_initial.sql # Initial database schema
│ ├── downloads/
│ │ ├── types.go # Data models, request/response types, error codes, quality mapping
│ │ ├── store.go # SQLite persistence for download jobs (CRUD + queries)
│ │ ├── engine.go # Manual os/exec wrapper for yt-dlp and ffmpeg/ffprobe
│ │ └── service.go # Download orchestration (one-active-job workflow, events)
│ ├── drive/
│ │ └── service.go # Google OAuth2 flow, Drive API operations (upload, profile, quota)
│ └── update/
│ └── service.go # Update manifest fetching, checksum/signature verification, install
└── build/ # Compiled binaries and assets
| Dependency | Purpose |
|---|---|
github.com/wailsapp/wails/v2 |
Desktop app framework (Go + Webview) |
modernc.org/sqlite |
Pure-Go SQLite driver |
golang.org/x/oauth2 + google.golang.org/api/drive/v3 |
Google Drive OAuth and API |
github.com/google/uuid |
UUIDv7 job ID generation |
Note: yt-dlp and ffmpeg/ffprobe are not Go dependencies — they are external binaries that must be installed on the system PATH. The engine locates them via exec.LookPath.
main.go resolves platform paths, opens the SQLite database, instantiates all services, and launches the Wails application. The startup sequence is:
- Resolve platform-specific paths via
platform.ResolvePaths() - Ensure all directories exist
- Open SQLite database via
database.Open() - Create the download engine via
downloads.NewEngine(cookiesPath) - Create the download store and service via
downloads.NewStore(db)anddownloads.NewService(store, engine) - Create the Drive service and update service
- Construct the
Appand run viawails.Run()
app.go defines the App struct, which is bound to the Wails runtime. It serves as the bridge between the Angular frontend and the internal packages. Methods exposed to the frontend include:
- Downloads:
GetMetadata,StartDownload,CancelDownload,RetryDownload,GetDownload,GetDownloadHistory,DeleteDownload,OpenLocalFile - Google Drive:
ConnectGoogleDrive,DisconnectGoogleDrive,GetUserProfile,GetDriveStorage,UploadToDrive - Updates:
CheckForAppUpdate,InstallAppUpdate,GetEngineStatus,GetCurrentVersion - Utilities:
GetPlatformInfo,OpenExternalURL,SelectDirectory
Events are pushed to the frontend via wailsRuntime.EventsEmit for download progress, history updates, and engine status changes.
The engine uses manual os/exec calls to the yt-dlp and ffmpeg binaries instead of a Go wrapper library. This eliminates the dependency on go-ytdlp and gives full control over command construction and progress parsing.
Key design decisions:
- Binary discovery:
CheckStatus()usesexec.LookPath("yt-dlp"),exec.LookPath("ffmpeg"), andexec.LookPath("ffprobe")to locate binaries on the system PATH - No auto-installation: yt-dlp and ffmpeg must be installed manually by the user
- Progress parsing: Download progress is parsed from yt-dlp's stderr output using regex (
\[download\].*?(\d+\.?\d*)%) - Cookie support: Cookies are passed via
--cookiesflag if a cookies file exists at the configured path - Metadata extraction: Uses
yt-dlp --dump-single-json --skip-download --no-playlist URLand parses the JSON output - Download execution: Uses
yt-dlp -f FORMAT -o OUTPUT --no-playlist --newline URLand parses stderr for real-time progress
Paths holds OS-specific directory locations for data, config, cache, logs, and the database. ResolvePaths() detects the OS and returns the appropriate paths, creating all directories as needed.
| Platform | Data Dir | Config Dir | Cache Dir | Logs Dir |
|---|---|---|---|---|
| Windows | %LOCALAPPDATA%\Buckty\data\ |
%LOCALAPPDATA%\Buckty\config\ |
%LOCALAPPDATA%\Buckty\cache\ |
%LOCALAPPDATA%\Buckty\logs\ |
| macOS | ~/Library/Application Support/Buckty/data/ |
~/Library/Application Support/Buckty/config/ |
~/Library/Caches/Buckty/ |
~/Library/Logs/Buckty/ |
| Linux | $XDG_DATA_HOME/buckty/data/ |
$XDG_CONFIG_HOME/buckty/ |
$XDG_CACHE_HOME/buckty/ |
$XDG_STATE_HOME/buckty/logs/ |
Uses modernc.org/sqlite with a single connection. Embedded SQL migrations (from internal/database/migrations/) are applied automatically on open. Migrations are tracked in a schema_migrations table with version, timestamp, and SHA-256 checksum to prevent re-running or applying changed migrations.
Current schema (001_initial.sql):
schema_migrations— migration historydownload_jobs— full download tracking (job_id, source_url, metadata, progress, cloud fields)app_settings— key-value settings storedrive_accounts— Google Drive account metadatadrive_storage_snapshots— Drive quota snapshots
Orchestrates the download workflow:
- One-active-job enforcement (rejects new downloads while one is running)
- UUIDv7 job IDs
- Metadata extraction before download (non-fatal if it fails)
- Progress events emitted via callback to
app.go - Job lifecycle: starting → downloading → merging → complete / failed
Methods:
GetEngineStatus()— check yt-dlp/ffmpeg readinessRefreshEngine()— force engine re-checkGetMetadata(req)— extract video metadataStartDownload(req)— start a new downloadGetDownloadHistory(q)— query filtered historyGetJob(jobID)— get a single download recordOpenLocalFile(jobID)— get the local file pathCancelDownload(jobID)— cancel a running downloadRetryDownload(jobID)— retry a failed downloadDeleteDownload(jobID, deleteLocalFile)— remove a download record and optionally the local file
Implements OAuth2 with PKCE and state via a loopback HTTP server. Supports:
Connect— opens browser, handles OAuth callback, stores tokenDisconnect— removes stored tokenGetProfile— fetches user profile from Google Drive APIGetStorage— returns Drive quota informationUploadFile— uploads a local file to Drive and makes it publicly accessible
Tokens are stored as JSON files in the config directory. Client credentials are loaded from BUCKTY_GOOGLE_CLIENT_ID and BUCKTY_GOOGLE_CLIENT_SECRET environment variables.
Fetches a remote manifest (JSON) to check for new versions. Supports:
CheckForUpdate— fetches manifest, matches platform asset by OS/archInstallUpdate— downloads, verifies SHA-256 checksum, verifies signature, replaces executableGetCurrentVersion— returns the current application version
Signature verification is currently a placeholder (TODO). The update directory is platform-specific (under the cache or data dir).
The Angular frontend calls Go methods through Wails-generated bindings. Events are received via EventsOn:
import { StartDownload, GetMetadata, CancelDownload } from '../wailsjs/go/main/App';
import { EventsOn } from '../wailsjs/runtime/runtime';
// Method calls (request/response)
const jobId = await StartDownload({ url, quality, audioOnly, outputPath });
const metadata = await GetMetadata(url);
// Event listeners (push notifications from Go)
EventsOn("download_progress", (event) => { /* update progress bar */ });
EventsOn("history_updated", (jobId) => { /* refresh history list */ });
EventsOn("engine_status", (status) => { /* update engine readiness indicator */ });Stable error codes returned to the frontend for decision-making:
| Code | Meaning |
|---|---|
INVALID_URL |
URL is empty or malformed |
INVALID_DESTINATION |
Destination path is invalid |
DOWNLOAD_IN_PROGRESS |
A download is already running |
ENGINE_NOT_READY |
yt-dlp/ffmpeg not found in PATH |
ENGINE_INSTALL_FAILED |
yt-dlp/ffmpeg installation failed |
METADATA_FAILED |
Failed to extract video metadata |
URL_UNSUPPORTED |
URL not supported by yt-dlp |
DOWNLOAD_FAILED |
Download process failed |
OUTPUT_FILE_MISSING |
Downloaded file not found after completion |
DATABASE_ERROR |
SQLite operation failed |
DRIVE_NOT_CONNECTED |
No Google Drive token available |
DRIVE_AUTH_EXPIRED |
Google Drive token has expired |
DRIVE_REFRESH_FAILED |
Google Drive token refresh failed |
DRIVE_UPLOAD_FAILED |
Google Drive upload failed |
UPDATE_NOT_AVAILABLE |
No update available |
UPDATE_SIGNATURE_INVALID |
Update signature verification failed |
UPDATE_CHECKSUM_INVALID |
Update checksum mismatch |
UPDATE_INSTALL_FAILED |
Update installation failed |
- yt-dlp — must be on the system PATH (
yt-dlp --versionshould work) - ffmpeg — must be on the system PATH (
ffmpeg -versionshould work) - ffprobe — must be on the system PATH (
ffprobe -versionshould work)
- Go 1.25+
- Wails v2 (
go install github.com/wailsapp/wails/v2/cmd/wails@latest) - Node.js (for the Angular frontend)
# Install Go dependencies
go mod tidy
# Generate Wails bindings (from project root)
wails generate
# Build for the current platform
wails build
# Run in development mode (frontend dev server + Go backend)
wails dev# Google OAuth credentials (required for Drive integration)
export BUCKTY_GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
export BUCKTY_GOOGLE_CLIENT_SECRET="your-client-secret"- Never commit cookies.txt or real OAuth credentials to version control
- OAuth tokens are stored in the OS config directory, not in the SQLite database
- OAuth flow uses PKCE + state parameter for loopback redirect
- HTTPS for all external requests
- Signature + checksum verification for updates
- Removed
go-ytdlpdependency: The backend now uses manualos/execcalls to the yt-dlp and ffmpeg binaries instead of thego-ytdlpGo library. This eliminates the dependency on an unmaintained library and gives full control over command construction and progress parsing. - Manual binary management: yt-dlp, ffmpeg, and ffprobe must be installed manually on the system PATH. The engine discovers them via
exec.LookPath. - Progress parsing: Download progress is parsed from yt-dlp's stderr output using regex instead of relying on the library's progress callback.
- Fixed constructor signatures: All service constructors in
main.gonow match their actual Go signatures. - Added missing methods:
CancelDownload,RetryDownload,DeleteDownloadadded to the download service;GetCurrentVersionadded to the update service.