Skip to content

Repository files navigation

🎬 Video Grabber

See a video worth keeping? Click once. It's on your disk.

A Chrome extension that finds the video on whatever page you're on and downloads it. No pasting links into sketchy websites, no "premium to unlock 1080p", no waiting rooms.

Русская версия

Video Grabber popup


Why this one

Most "video downloaders" fall into two camps: browser extensions that only handle plain MP4 files and give up on YouTube, or websites where you paste a link, dodge three popups, and get a watermarked 480p file. This one does both halves properly:

  • One click, no link juggling. Open the popup, hit the button. That's the whole workflow. The thing you wanted to save is saved before you've forgotten why you wanted it.
  • Actually gets max quality on YouTube. Modern YouTube ships video and audio as separate encrypted streams. Extensions that pretend otherwise hand you a silent file or a 360p one. Video Grabber delegates to yt-dlp + ffmpeg, which fetch both streams and mux them: 4K with sound if that's what's on offer.
  • Works on logged-in videos. Age-restricted, private, unlisted, subscriber-only. The extension hands your existing session cookies to yt-dlp through the browser's own API, so you don't have to close Chrome or export anything. (More on this below. It's the part every other tool gets wrong.)
  • Sees what the page is actually loading. It watches network traffic and the DOM, so it catches videos that never appear as a visible download link, including HLS streams.
  • Downloads can't be knocked off course. The popup doesn't do the downloading: a separate local service does. Close the popup, switch tabs, minimise the browser, click somewhere by accident, and the file still lands. Reopen the popup and the same progress is waiting for you.
  • Whole playlists in one click. On a playlist page a second button shows up. Every video is queued into its own folder named after the playlist, numbered in order, so nothing gets muddled.
  • A queue you can see. Progress, speed and time left for each item. Cancel any of them, retry a failed one with a single button.
  • You pick the folder. Not just Downloads: hit "change" and choose anywhere. The path is remembered.
  • Everything stays local. No accounts, no servers, no telemetry. The extension talks to a Python script on your own machine and nothing else.
  • Not just YouTube. The yt-dlp backend covers ~1800 sites. The direct-file grabber covers most of the rest.

Bonus: pick "Audio only" and you get an MP3. Handy for talks, interviews, and podcasts you'd rather listen to than watch.


Requirements

Tool Why Install
Python 3.8+ runs the native host python.org
yt-dlp downloads from YouTube & co. pip install -U yt-dlp
ffmpeg muxes video + audio winget install Gyan.FFmpeg (Win) · brew install ffmpeg (Mac) · apt install ffmpeg (Linux)
Node.js or Deno required since 2026: YouTube needs a JS runtime to decipher stream URLs winget install OpenJS.NodeJS

The installer checks all four and tells you what's missing.

Only downloading plain MP4/WebM files? You can skip every one of these and just do Step 1.


Install

Step 1. Load the extension

  1. Download or clone this repo.
  2. Open chrome://extensions
  3. Turn on Developer mode (top right)
  4. Click Load unpacked → select the repo folder
  5. The 🎬 icon appears. Pin it for one-click access.

Direct file downloads work right now. For YouTube, continue.

Step 2. Install the yt-dlp bridge

From the repo folder:

python install_native_host.py

That's it, no arguments. The script finds your extension ID by itself, writes the native messaging manifest, and registers it for Chrome, Edge, Brave and Chromium. No admin rights needed.

Step 3. Restart your browser

Fully quit and reopen it. Open the popup: the footer should read yt-dlp: ready ✓ in green.

Still red? Jump to Troubleshooting.


How to use it

Click the 🎬 icon:

The "Save to" bar Shows where files land. change opens a folder picker, lets you type a path, 📂 opens the folder. The choice sticks until you change it.

Top section: "Download this page in best quality" The YouTube path, and the one you'll use most. Press the red button and yt-dlp downloads the page's video, muxes audio in, and drops it in your chosen folder. The dropdown picks quality: Max, ≤1080p, ≤720p, ≤480p, or Audio only (mp3).

On a playlist page, "Whole playlist (own folder)" appears below it. The extension reads the list, creates a folder named after the playlist, and queues every video in order: 01 - Title.mp4, 02 - ..., and so on.

"Downloads" section The queue: what's downloading, what's waiting, what's finished. cancels, retries a failed item into the same folder with the same number. cancel all and clear finished tidy the list.

Bottom section: "Found on page" Direct media files spotted on the page. saves instantly. Items tagged HLS/DASH are streams, so their button routes through yt-dlp instead.

The 🗗 button in the header opens the same panel as a standalone window. A Chrome popup closes the moment you click elsewhere; this window stays put, which helps when you're downloading a batch. It follows whatever tab is active, so the buttons always apply to what you're looking at.

The badge number on the icon = media found on this tab. Empty list? Hit ▶ Play on the video, then ⟳ in the popup. Some players don't request the video until you start it.


Cookies: what to click, and why it matters

Short version: there is nothing to click. It's automatic. But it's worth knowing why, because this is where other downloaders fail.

Age-restricted, private, unlisted and subscriber-only videos need your login to download. yt-dlp's usual answer is --cookies-from-browser chrome, which reads Chrome's cookie database directly. That fails the moment Chrome is running:

ERROR: Could not copy Chrome cookie database

The file is locked by the running browser. So the "official" workaround is to close Chrome entirely, which is absurd given you found the video in Chrome.

Video Grabber sidesteps this. The extension already has legitimate access to your cookies through the browser's chrome.cookies API, so it reads them directly, hands them to the local host, which writes a temporary Netscape-format cookie file, passes it to yt-dlp, and deletes it as soon as the download finishes. Chrome stays open. Nothing is exported to disk permanently, and nothing leaves your machine.

Practical upshot: stay logged in to the site in the same Chrome profile, and restricted videos just work. If a video downloads fine in a private window on the site, it'll download fine here.

The cookies permission exists solely for this. Cookies go to one place: the local yt-dlp process on your own computer.


What it can't do

Being straight with you:

  • DRM-protected content (Netflix, Disney+, paid platforms) is encrypted by design. Not supported, and not something this project will try to work around.
  • Blob-only videos with no source URL. Some players stream via MediaSource with no fetchable URL. The yt-dlp button still handles these if the site is supported.
  • YouTube breaks downloaders regularly. The service pulls a fresh yt-dlp every three days while the queue is idle, so this usually sorts itself out. If it doesn't, update by hand: pip install -U yt-dlp.

Troubleshooting

Footer says Specified native messaging host not found The bridge isn't installed, or the extension ID changed (moving the folder changes it, since the ID is derived from the path). Re-run python install_native_host.py and restart the browser.

Download dies partway through with HTTP Error 403: Forbidden Stale yt-dlp: it picks a YouTube player client whose URLs only serve the first few megabytes. Usually fixes itself (the service updates every three days); by hand it's pip install -U yt-dlp. daemon.log records how the last check went.

Video unavailable, but the video plays fine in the browser Almost always a stale yt-dlp or a missing JS runtime:

pip install -U yt-dlp
node --version   # must print something

If both check out, the video likely needs a login. Make sure you're signed in on that site in this Chrome profile.

Only low quality available, 1080p+ formats missing The JS challenge solver didn't run. Confirm node or deno is on your PATH, and that you have internet access: the solver is fetched from GitHub on first use.

Downloaded file has no sound ffmpeg is missing, so the audio stream never got muxed in. Install it and re-download.

The download service isn't responding Logs live in %LOCALAPPDATA%\VideoGrabber\: daemon.log (what the service did) and host.log (how the browser reached it). settings.json there holds your chosen folder. The service starts on the first download and shuts itself down after half an hour of idling.


How it works

┌──────────────┐   video URLs   ┌────────────────┐
│  content.js  │ ─────────────► │  background.js │  watches webRequest + DOM
└──────────────┘                └───────┬────────┘
                                        │ media list, cookies
                                        ▼
                                ┌────────────────┐
                                │    popup.js    │  UI and queue
                                └───────┬────────┘
                                        │ native messaging (stdio + JSON)
                                        ▼
                             ┌─────────────────────┐
                             │ native/yt_dlp_host  │  thin client, lives only
                             │        .py          │  while the popup is open
                             └──────────┬──────────┘
                                        │ TCP on 127.0.0.1 + token
                                        ▼
                             ┌─────────────────────┐
                             │  native/vg_daemon   │  queue, yt-dlp, progress,
                             │        .py          │  folder picker
                             └─────────────────────┘

The key detail: the browser launches native hosts inside its own job object and kills the whole process tree the moment the popup's port goes away. yt-dlp used to die with it, which is why downloads broke halfway through with Native host has exited. Now a separate service does the work, started through WMI so it never inherits the browser's job and keeps going no matter what happens to the window.

File Role
manifest.json MV3 extension manifest
background.js sniffs media URLs from network traffic; builds the cookie file
content.js scrapes <video>/<source> elements, watches for SPA changes
popup.html / .css / .js the interface
native/yt_dlp_host.py native host: bridge between the extension and the download service
native/vg_daemon.py download service: queue, yt-dlp, playlists, save folder
install_native_host.py installer: auto-detects extension ID, registers the host
_locales/ UI translations (English, Russian)
tools/make_screenshot.py renders the README screenshot from the real popup code
tools/requeue_failed.py puts failed downloads back in the queue from a dump file

The UI follows your browser language: Russian if that's your locale, English otherwise. PRs adding locales are welcome: copy _locales/en/messages.json and translate the values.


License

MIT, see LICENSE.

Downloading is your responsibility: respect copyright and each site's terms of service. This tool is meant for saving things you're allowed to save.

About

One-click video downloader for Chrome. Direct MP4/WebM plus YouTube in max quality via yt-dlp, with cookie support for logged-in videos.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages