@fordi-org/gdown
v1.0.0
Published
Google Drive public file/folder downloader. Node port of https://github.com/wkentaro/gdown
Maintainers
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/gdownOr run it without installing:
npx @fordi-org/gdown https://drive.google.com/uc?id=1l_5RK28JRL19wpT22B-DY9We3TVXnnQQQuick 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.jsonFolders
# 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 pdfDefault 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:8080Other 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 -vIf 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:
- Install a browser extension like Get cookies.txt LOCALLY
- Export
cookies.txtand move it to~/.cache/gdown/cookies.txt(or pass--cookies-file) - 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 testLicense
MIT (LICENSE)
