Architecture

Six layers, one direction of trust.

Every request crosses each boundary in order, and each layer checks it again. Nothing on your Mac listens on a network port.

System map

Every component, every connection.

Pick a flow to see how data moves through VidGrab, or hover a component to see what it talks to.

Browser · untrustedYour Mac · your account onlyInternethovermessagestdioJSONIPCtokenargvwriteHTTPSHTTPSupdateWeb pagethe video you watchContent scriptbutton in shadow DOMService workerstreams · cookiesNative hostvalidates · re-encodesPrivate socketUnix · 0600 · peer uidDownloadsfiles · private queueKeychainGoogle tokens, localVidGrab appSwift 6 · re-validatesBridge serviceDownload queueUploader & libraryEngineyt-dlp · ffmpeg · DenoGitHub releasesyt-dlp · SHA-256 sumsGoogle Driveuploads · streamingVideo siteswhat you download from
  1. You click Download on the video; the content script passes the request to the service worker.
  2. The service worker adds that video's cookies and sends it to the native host over stdio.
  3. The host validates the message, re-encodes it, and relays it through the private socket.
  4. The app validates it again, queues the job, and starts the engine with a fixed argument list.
  5. yt-dlp fetches the video over HTTPS in parallel fragments; ffmpeg writes the MP4 to your folder.
Protocol

Small, versioned, validated.

The extension and the app talk in length-prefixed JSON frames, the format Chrome uses for native messaging. Pick a message to see it on the wire and the checks it passes.

  1. Size1 MB at most, checked before parsingpassed
  2. Versionmust be 1passed
  3. Request id1–64 letters, digits or dashespassed
  4. Typeping, probe, enqueue or jobspassed
  5. Linkshttp or https only, 8 KB at mostpassed
  6. Headerscookie, referer, user-agent, originpassed
  7. Formats and idsstrict character sets, UUID job idspassed
length · LEC7 00 00 00JSON payload199 bytes
→ Extension sends
{
  "v": 1,
  "id": "a3",
  "type": "enqueue",
  "format": "137+bestaudio[ext=m4a]/137+bestaudio",
  "destination": "googleDrive",
  "media": {
    "url": "https://example.com/watch",
    "headers": {
      "referer": "https://example.com/"
    }
  }
}
← App replies
{
  "v": 1,
  "id": "a3",
  "ok": true,
  "jobId": "6F1C2E3A-1B2C-4D5E-8F90-123456789ABC"
}
Engine

Proven tools, pinned and kept current.

VidGrab ships its engine inside the app, pinned to exact versions and checked against SHA-256 checksums when it's built.

ComponentVersionLicenceRole
yt-dlp2026.10.21UnlicenseFinds and downloads videos. Kept up to date automatically.
ffmpeg9.0.2GPL v3Combines video and audio into MP4 without re-encoding.
Deno2.9.8MITSolves the JavaScript challenges some sites, including YouTube, require.
Request path

From button to file.

  1. Chrome extensionManifest V3 · TypeScriptSpots streams on the page and puts the Download button on the video.
  2. Native messaging hoststdio · framed JSONStarted by Chrome for VidGrab's extension ID only. Validates and re-encodes each message.
  3. Private socketUnix socket · 0600Relays to the app over a socket only your user account can open.
  4. VidGrab appSwift 6 · SwiftUIValidates again, queues the job, and runs the engine with a fixed argument list.
  5. Engineyt-dlp · ffmpeg · Denoyt-dlp downloads, ffmpeg merges streams, Deno solves site challenges.
  6. DestinationYour Mac · Google DriveYour download folder, or Google Drive through resumable uploads.
Built with

Native where it matters.

A Swift 6 app with strict concurrency checking, a TypeScript extension with no runtime dependencies, and open-source engines underneath.

Swift 6 strict concurrencySwiftUI app and menu barAVKit player and streamingKeychain access tokensTypeScript extensionManifest V3 Chromeesbuild bundlingyt-dlp extractionffmpeg stream mergingDeno challenge solvingGoogle Drive API v3 resumable uploadsSwift Testing 90 testsVitest 60 testsGitHub Actions CI
Under the hood

Every stream, split eight ways.

HLS \ DASH \ MP4 \ 4K \ M4A

Each video downloads as parallel fragments. If the connection drops, VidGrab asks what already arrived and carries on from there.