Skip to content

LinuxCTRL/grabr

Repository files navigation

grabr

Grabr Logo

A modern, elegant file downloader — CLI tool, Node.js/Bun library, and web UI.

CLI Dashboard npm version docs

Interface Gallery

TUI Dashboard Web UI Dashboard
TUI Dashboard Web UI Dashboard

grabr is a local-first download manager featuring chunked parallel downloading, resumable transfers, and automatic database synchronization across all platforms. No cloud, no tracking.

Key Features:

  • Unified Database Sync: The CLI, Bun/Hono daemon, and web UI all read/write to the same SQLite database file (~/.grabr/grabr.db), keeping downloads instantly synced.
  • YouTube Format Selector: Intercepts YouTube links in browser extensions, Web UI, and the CLI to present a format selector for combined video resolutions (4K, 1080p, 720p, etc.) or audio-only downloads.
  • Interactive CLI Dashboard: Responsive split-pane TUI dashboard with live chunk visualizer, inline job addition form, delete confirmation prompts, and shortcuts to open target save directories.
  • Browser Integration: Route browser downloads directly to the Grabr daemon using official extensions for Chrome, Edge, and Firefox. Firefox add-on now available on Mozilla Add-ons.
  • Version Checking: Automatically alerts you in both the CLI dashboard and Web UI when a newer release of Grabr is available on NPM.

Works with: Node.js ≥18, Bun ≥1.0


Install

CLI & TS Library (NPM)

npm install -g @linuxctrl/grabr          # CLI globally
npm install @linuxctrl/grabr             # or as a library

YouTube Support (yt-dlp)

yt-dlp is required for downloading YouTube videos and fetching format metadata. Install it with your package manager:

OS Command
macOS brew install yt-dlp
Linux sudo apt install yt-dlp (Debian/Ubuntu) or sudo pacman -S yt-dlp (Arch) or pip install yt-dlp
Windows winget install yt-dlp or pip install yt-dlp

Make sure yt-dlp is available on your PATH. Verify with yt-dlp --version.


CLI Usage

grabr --help

grabr add <url>                    # Start a download
grabr add <url> --output ./videos  # Custom output directory
grabr add <url> --chunks 8         # 8 parallel chunks
grabr add <url> --name file.zip    # Custom filename

grabr list                         # List all jobs
grabr pause <id|all>               # Pause active downloads
grabr resume <id|all>              # Resume paused/failed downloads
grabr remove <id>                  # Remove a job
grabr clear --completed            # Clear completed jobs

grabr ui                           # Open Web UI in browser
grabr daemon start                 # Run server in background
grabr daemon stop                  # Stop background server
grabr daemon status                # Check daemon status

Run grabr without arguments to open the interactive full-screen TUI dashboard.


Browser Integration (Chrome, Edge & Firefox Extensions)

Grabr comes with browser extensions to capture downloads and route them directly to the Grabr daemon.

Browser Store Status
Firefox Available on Mozilla Add-ons
Google Chrome 🔜 Coming soon — install manually for now
Microsoft Edge 🔜 Coming soon — install manually for now

Features:

  • Automatic Interception: Captures browser clicks on files matching specific extensions (like .zip, .tar.gz, .dmg, .iso, .exe) or files exceeding custom size thresholds.
  • Context Menus: Right-click any hyperlink and select "Send link to Grabr" to prompt download.
  • Batch Downloader: Highlight text containing multiple URLs, right-click, and select "Download links in selection with Grabr" to queue them in parallel.
  • Real-time Toolbar Popup: Includes a live WebSocket progress dashboard, dynamic active badge count, and action controls (Pause/Resume/Delete) right from your toolbar.

Setup (Manual / Development):

For Google Chrome:

  1. Open Google Chrome and navigate to chrome://extensions.
  2. Toggle on Developer mode in the top-right corner.
  3. Click Load unpacked in the top-left and select the /extension/google directory inside this repository.

For Microsoft Edge:

  1. Open Microsoft Edge and navigate to edge://extensions.
  2. Toggle on Developer mode in the bottom-left corner.
  3. Click Load unpacked and select the /extension/edge directory inside this repository.

For Mozilla Firefox:

  1. Install directly from Mozilla Add-ons.
  2. Or for development: open about:debugging#/runtime/this-firefox, click Load Temporary Add-on..., and select manifest.json from /extension/firefox.

Library API

import { Downloader, SpeedMeter, loadConfig, saveConfig } from '@linuxctrl/grabr'
import type { DownloadJob, DownloadOptions, JobStatus, ChunkInfo, GrabrConfig } from '@linuxctrl/grabr'

const downloader = new Downloader()
await downloader.start()

// Add a download
const job = await downloader.addJob('https://example.com/file.zip', {
  outputDir: './downloads',
  chunks: 4,
  filename: 'myfile.zip',
})

// Listen for events
downloader.on('job:progress', ({ jobId, downloadedBytes, speed, eta }) => {
  console.log(`${jobId}: ${downloadedBytes} bytes at ${speed} B/s`)
})

downloader.on('job:status', ({ jobId, status }) => {
  console.log(`${jobId}: ${status}`)
})

// Control downloads
await downloader.pauseJob(job.id)
await downloader.resumeJob(job.id)
await downloader.removeJob(job.id)

await downloader.stop()

Types

interface DownloadJob {
  id: string
  url: string
  filename: string
  destination: string
  totalBytes: number
  downloadedBytes: number
  chunks: ChunkInfo[]
  status: 'queued' | 'downloading' | 'paused' | 'completed' | 'failed'
  speed: number        // bytes/sec (EMA smoothed)
  eta: number          // seconds remaining
  createdAt: number
  updatedAt: number
  error?: string
}

interface ChunkInfo {
  index: number
  start: number
  end: number
  downloaded: number
  status: 'pending' | 'downloading' | 'done' | 'failed'
}

Project Structure

grabr/
├── dist/                        # Built output (published to npm)
│   ├── index.js                 #   ESM library
│   ├── index.cjs                #   CJS library
│   ├── index.d.ts               #   TypeScript declarations
│   └── cli.js                   #   CLI executable
├── extension/                   # Browser extensions
│   ├── google/                  #   Chrome extension folder
│   ├── edge/                    #   Edge extension folder
│   └── firefox/                 #   Firefox extension folder (GECKO compatible)
├── src/
│   ├── index.ts                 # Public library entry point
│   ├── core/                    # Download engine (UI-agnostic)
│   │   ├── downloader.ts        #   Orchestrator (EventEmitter)
│   │   ├── chunker.ts           #   HEAD request → split into ranges
│   │   ├── worker.ts            #   Single chunk fetch
│   │   ├── merger.ts            #   Assembles chunks into final file
│   │   ├── resume.ts            #   Resume state files
│   │   ├── config.ts            #   ~/.grabr/config.json
│   │   └── types.ts             #   Shared types
│   ├── store/
│   │   ├── db.ts                #   sql.js SQLite setup
│   │   └── jobs.ts              #   CRUD for download jobs
│   ├── cli/
│   │   ├── index.tsx            # CLI entry (Ink/React)
│   │   ├── commands/            #   add, list, pause, resume, remove, clear, ui, daemon
│   │   └── ui/                  #   Ink components (Dashboard, JobRow, ProgressBar)
│   ├── server/
│   │   ├── index.ts             # Hono HTTP + WebSocket server
│   │   └── static/              # Built Web UI assets
│   └── web/                     # Web UI source (vanilla TS)
│       ├── index.html
│       ├── main.ts
│       ├── components/
│       └── styles/
├── downloads/                   # Default output directory
├── .grabr/                      # State directory (db + resume files)
├── package.json
├── tsconfig.json
└── bun.lock

Architecture

URL → chunker → [chunk workers] → merger → final file
                      ↓
               EventEmitter
                      ↓
        CLI Dashboard  |  WebSocket → Browser UI

Download Engine

  • Checks Accept-Ranges header → parallel chunk download or single stream
  • Speed calculated with EMA (exponential moving average, α=0.2)
  • Retry logic: 3 attempts with exponential backoff
  • Filename collision: file(1).zip, file(2).zip ...

Storage

Uses sql.js — SQLite compiled to WebAssembly. Works on both Node.js and Bun without native compilation.

Resume state is also saved as JSON files in .grabr/<jobId>.json for crash recovery.

Server + Web UI

The daemon server uses Hono with Bun's native WebSocket support. The Web UI is vanilla TypeScript with SVG progress rings and CSS custom properties.


Development

# Install
bun install

# Run CLI in dev mode
bun run cli --help
bun run src/cli/index.tsx add https://example.com/file.zip

# Run server
bun run src/server/index.ts

# TypeScript check
bun run typecheck

# Build for production
bun run build

# Build outputs:
#   dist/index.js   — ESM library
#   dist/index.cjs  — CJS library
#   dist/cli.js     — CLI executable
#   dist/*.d.ts     — TypeScript declarations

Prerequisites

  • Bun (recommended for development) — curl -fsSL https://bun.sh/install | bash
  • Node.js 18+ (for production use)

Config

Config file: ~/.grabr/config.json

{
  "outputDir": "~/Downloads",
  "maxConcurrent": 3,
  "defaultChunks": 4,
  "serverPort": 7474,
  "theme": "dark"
}

Publishing

bun run build
npm publish

The dist/ directory is published, containing the compiled CLI and library.


License

MIT

About

A modern, elegant file downloader — CLI tool & Node.js/Bun library.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors