npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fordi-org/gdown

v1.0.0

Published

Google Drive public file/folder downloader. Node port of https://github.com/wkentaro/gdown

Readme

@fordi-org/gdown

Google Drive public file/folder downloader when curl/wget fails. Node.js port of wkentaro/gdown.

  • Skips the virus-scan confirmation page so large downloads actually finish
  • Downloads folders recursively
  • Exports Google Docs/Sheets/Slides as PDF, DOCX, CSV, etc.
  • Resumes partial downloads with --continue
  • Also works with plain HTTP/HTTPS URLs as a curl/wget replacement

Install

Requires Node.js 20 or later.

npm install -g @fordi-org/gdown

Or run it without installing:

npx @fordi-org/gdown https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ

Quick start

# Just paste a Google Drive URL
npx @fordi-org/gdown https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ

# Or copy-paste a share link directly
npx @fordi-org/gdown 'https://drive.google.com/file/d/0B9P1L--7Wd2vU3VUVlFnbTgtS2c/view?usp=sharing'

Usage

CLI

Files

# Download by URL
gdown https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ

# Download by file ID
gdown 1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ

# Download from a share link
gdown 'https://drive.google.com/file/d/0B9P1L--7Wd2vU3VUVlFnbTgtS2c/view?usp=sharing'

# Save to a specific path
gdown https://drive.google.com/uc?id=0B9P1L--7Wd2vU3VUVlFnbTgtS2c -O /tmp/spam.txt

# Resolve the filename (with its real extension) without downloading
gdown https://drive.google.com/uc?id=0B9P1L--7Wd2vU3VUVlFnbTgtS2c --json

--json is in beta and its output format may change in a future release; pass --quiet to silence the beta warning in scripts. The output is an array of {url, path} entries, where path is the filename Google Drive reports. This lets you choose a name while keeping the original extension:

url="https://drive.google.com/uc?id=0B9P1L--7Wd2vU3VUVlFnbTgtS2c"
filename=$(gdown "$url" --json | jq -r '.[0].path')
gdown "$url" -O "my_name.${filename##*.}"

Pass -O/--output alongside --json to write the JSON to a file instead of stdout:

gdown https://drive.google.com/uc?id=0B9P1L--7Wd2vU3VUVlFnbTgtS2c --json -O listing.json

Folders

# Autodetect file vs. folder instead of passing --folder yourself
gdown https://drive.google.com/drive/folders/15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl --auto

# Download an entire folder
gdown https://drive.google.com/drive/folders/15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl -O /tmp/folder --folder

# List folder contents as a JSON array (each entry has url and path)
gdown https://drive.google.com/drive/folders/15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl --folder --json

# Only download entries matching a glob (also -g'*.txt'); '*' never crosses '/'
gdown https://drive.google.com/drive/folders/15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl --folder --glob '*.txt'

# '**' matches zero or more path segments, so this matches .txt files at any depth
gdown https://drive.google.com/drive/folders/15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl --folder --glob '**/*.txt'

# Advanced filter by path and download matches using JSON
gdown https://drive.google.com/drive/folders/15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl --folder --json \
  | jq -r '.[] | select(.path | test("shad")) | .url' \
  | xargs -n1 gdown

# Include the folder's own name by wrapping the listing: {name, files}
gdown https://drive.google.com/drive/folders/15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl --folder --json --parent

--auto treats a /drive/folders/ URL as a folder; anything else (a bare ID, a file URL) is tried as a file first and retried as a folder only if Drive reports it isn't a downloadable file.

Google Docs, Sheets, Slides

# Download a Google Slides file (default: pptx)
gdown "https://docs.google.com/presentation/d/15umvZKlsJ3094HNg5S4vJsIhxcFlyTeK/edit?usp=sharing"

# Export as PDF instead
gdown "https://docs.google.com/presentation/d/15umvZKlsJ3094HNg5S4vJsIhxcFlyTeK/edit" --format pdf

Default export formats: Docs → docx, Sheets → xlsx, Slides → pptx.

Resume, speed limit, proxy

# Resume a partially downloaded file
gdown https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ --continue

# Limit download speed
gdown https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ --speed 10MB

# Download via proxy
gdown https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ --proxy http://proxy:8080

Other options

# Skip TLS certificate verification
gdown https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ --no-check-certificate

# Don't use cookies in ~/.cache/gdown/cookies.txt
gdown https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ --no-cookies

# Use a different cookie jar file instead of ~/.cache/gdown/cookies.txt
gdown https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ --cookies-file ./my-cookies.txt

# Use a custom User-Agent
gdown https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ --user-agent "MyApp/1.0"

# Emit debug info (request URLs, status codes, redirect chains, parsed
# titles) to stderr -- useful for diagnosing --folder downloads
gdown https://drive.google.com/drive/folders/15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl --folder -v

If Drive serves a "Redirecting..." interstitial page instead of the real folder contents (seen under rate limiting or certain permissions/link states), --folder follows its redirect automatically. Pass --no-follow to disable that and get the pre-redirect-following behavior (an empty folder named "Redirecting...") instead.

Pipe to stdout

gdown https://github.com/wkentaro/gdown/archive/refs/tags/v4.0.0.tar.gz -O - --quiet | tar zxvf -

Any URL

gdown also works with regular URLs, not just Google Drive:

gdown https://httpbin.org/ip -O ip.json

[!NOTE] For Google Drive URLs, gdown automatically extracts the file ID and downloads the actual file. Use curl or wget to download the raw HTML page instead.

Node API

import {
  download,
  downloadFolder,
  cachedDownload,
  extractall,
  stat,
  readdir,
  copyFile,
} from "@fordi-org/gdown";

// Download a file
const url = "https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ";
await download({ url, output: "fcn8s_from_caffe.npz" });

// Download by file ID
await download({ id: "0B9P1L--7Wd2vNm9zMTJWOGxobkU", output: "output.npz" });

// Download from a share link
const shareUrl = "https://drive.google.com/file/d/0B9P1L--7Wd2vNm9zMTJWOGxobkU/view?usp=sharing";
await download({ url: shareUrl, output: "output.npz" });

// Download with hash verification and caching
await cachedDownload({
  url,
  path: "output.npz",
  hash: "md5:fa837a88f0c40c513d975104edf3da17",
  postprocess: extractall,
});

// Track download progress
await download({
  url,
  output: "output.npz",
  quiet: true,
  progress: (bytesSoFar, bytesTotal) => {
    if (bytesTotal !== null) {
      process.stdout.write(`\r${((bytesSoFar / bytesTotal) * 100).toFixed(1)}%`);
    }
  },
});

// Download a folder
await downloadFolder({ url: "https://drive.google.com/drive/folders/15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl" });

// Download a folder by ID
await downloadFolder({ id: "15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl" });

// fs.promises-like helpers. stat() and readdir() resolve without
// downloading anything; copyFile() is download()'s underlying
// implementation -- download() is now just copyFile() with `output`
// renamed to `dest`.

// Look up size/name/mtime without downloading the file
const info = await stat({ id: "1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ" });
// { id, name, size, mtime, isDirectory(), isFile() }
// Drive doesn't expose a creation time or POSIX ctime/atime through this
// flow, so only size/mtime are populated -- there's no field to fake them with.

// List one level of a folder's contents without downloading anything
const names = await readdir({ id: "15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl" });
// ["file_00.txt", "file_01.txt", "subfolder", ...]
const entries = await readdir({ id: "15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl", withFileTypes: true });
// [{ id, name, isDirectory(), isFile() }, ...]

// Copy (download) a file -- dest is nullable just like download()'s
// output (defaults to the detected filename in cwd; a trailing-slash/
// existing-directory path gets the detected filename appended)
await copyFile({ id: "1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ", dest: "output.npz" });

All functions are async and return Promises (there are no synchronous variants). See the JSDoc comments in src/download.js and src/downloadFolder.js for the full option list — it mirrors the Python API's keyword arguments (useCookies, verify, resume, format, userAgent, pathGlob, followRedirects, etc.), in camelCase.

GDriveClient

For repeated calls against the same session/config (cookies, proxy, TLS, user agent, speed limit), GDriveClient holds that configuration once and exposes the functions above as methods taking a Drive URL or file/folder id as a plain first argument, instead of an {url, id} options bag on every call:

import { GDriveClient } from "@fordi-org/gdown";

const client = new GDriveClient({
  cookiesFile: "/tmp/my-cookies.txt",
  quiet: true,
  resume: true,
});

const info = await client.stat("1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ");
const names = await client.readdir("15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl");
await client.copyFile("1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ", "output.npz");
await client.download("1l_5RK28JRL19wpT22B-DY9We3TVXnnQQ", "output.npz");
await client.downloadFolder("15uNXeRBIhVvZJIhL4yTw4IsStMhUaaxl", "out/");

urlOrId accepts either a full URL or a bare file/folder id (same detection the CLI itself uses). Per-call options that aren't part of the shared session config (withFileTypes, progress, outputStream, pathGlob, etc.) are passed as an options object after the positional arguments -- see the JSDoc comments in src/client.js.

FAQ

"Permission Denied" error

Make sure the file sharing is set to "Anyone with the link".

Download still fails even with "Anyone with the link"

Google throttles downloads when too many people access the same file. If you can still open the file in your browser, try exporting cookies:

  1. Install a browser extension like Get cookies.txt LOCALLY
  2. Export cookies.txt and move it to ~/.cache/gdown/cookies.txt (or pass --cookies-file)
  3. Run the download again

Once the file is in place, gdown loads it automatically (no extra flags needed).

Download stops after ~1 hour

Google Drive terminates connections after approximately 1 hour for large files. Use --continue to resume, and retry until the download completes:

gdown --continue https://drive.google.com/uc?id=<file_id>

Can I use gdown for non-Google-Drive URLs?

Yes. It works with any public HTTP/HTTPS URL.

Development

git clone https://github.com/fordi-org/gdown.git
cd gdown
npm install
npm test

License

MIT (LICENSE)