nathlabs
Back to projects

DownMan

DownMan

A self-hosted download manager with a FastAPI backend, a Vue 3 web UI, and a Firefox extension that hands your browser downloads off to it. Files are fetched in parallel chunks, organised into category folders, and the whole queue survives a server restart.

Features

  • Parallel, chunked downloads — each file is split into byte ranges (CHUNK_THREADS, default 4) and downloaded concurrently using HTTP Range requests.
  • Concurrent queue — up to MAX_CONCURRENT (default 3) downloads run at once; the rest wait in an async queue.
  • Pause / resume / cancel — control individual downloads while they run.
  • Resumable across restarts — chunk progress is checkpointed to the OS temp dir, and the queue state is persisted in SQLite, so interrupted downloads are re-queued when the server starts again.
  • Automatic categorisation — files are sorted into Videos, Music, Apps, Documents, Compressed, or Other by extension, each saved to its own folder (folders are configurable per category).
  • Live updates — progress, speed, and status changes stream to the UI over Server-Sent Events (SSE); multiple browser tabs stay in sync.
  • Browser integration — the Firefox extension intercepts downloads and forwards them to the service, falling back to the browser's own downloader (with a notification) if DownMan isn't running.
  • Smart filenames — duplicate destinations get (1), (2), … appended rather than overwriting.

Architecture

                ┌──────────────────┐
  Firefox  ───► │ Firefox extension│ ──► POST /api/downloads
                └──────────────────┘            │
                                                ▼
        ┌──────────────────────────────────────────────────┐
        │  FastAPI server (server.py, port 6500)            │
        │  ├─ DownloadQueue  — async queue + worker pool    │
        │  ├─ DownloadManager — threaded chunked downloader │
        │  ├─ SQLite (~/.downman/downman.db) — persistence  │
        │  └─ SSE /api/events — live progress to the UI     │
        └──────────────────────────────────────────────────┘
                                                │ serves
                                                ▼
                                   Vue 3 SPA (backend/static)

Backend modules (backend/)

FileResponsibility
server.pyFastAPI app: REST API, SSE endpoint, serves the built UI
queue_manager.pyDownloadQueue + DownloadItem — async scheduling, pause/resume/cancel, progress broadcasting
downloader.pyDownloadManager — multi-threaded chunked download, retries, resume, merge
database.pySQLite persistence for downloads and per-category folder overrides
categories.pyExtension → category mapping and default folder resolution
config.pyPort, concurrency limits, download/data directories

Frontend (frontend/)

A Vue 3 + Pinia + Vite single-page app (icons via lucide-vue-next). The built output is committed under backend/static/, so the backend serves the UI without a build step. You only need the frontend/ toolchain to modify the UI.

Requirements

  • Python 3.10+ (uses str | None syntax and set[...] generics)
  • Backend dependencies in backend/requirements.txt: fastapi, uvicorn[standard], requests
  • (UI development only) Node.js 18+ for the Vue frontend

Getting started

1. Run the backend

cd backend
pip install -r requirements.txt
python server.py

The server listens on http://localhost:6500 — open it in your browser to use the web UI. Application data (the SQLite DB) lives in ~/.downman/, and downloads default to category subfolders under your system Downloads directory.

2. Install the Firefox extension (optional)

Load extensions/firefox in Firefox via about:debuggingThis FirefoxLoad Temporary Add-on, then select manifest.json. Once active, any download you start in Firefox is cancelled and forwarded to the DownMan service. If the service is down, the browser downloads the file normally and shows a notification.

3. Develop the UI (optional)

cd frontend
npm install
npm run dev      # Vite dev server with hot reload
npm run build    # outputs to backend/static/ for the server to serve

Configuration

Edit backend/config.py:

SettingDefaultDescription
PORT6500Port the server listens on
MAX_CONCURRENT3Max downloads running at once
CHUNK_THREADS4Parallel chunks per download

Per-category download folders can be overridden at runtime from the UI's settings dialog (stored in the database, not in config.py).

API reference

The backend exposes a REST API under /api plus an SSE stream:

MethodPathDescription
POST/api/downloadsAdd a download (url, optional dest/folder/filename/category)
GET/api/downloadsList all downloads
DELETE/api/downloads/{id}Cancel an active download or remove a finished one
DELETE/api/downloads?status=…Bulk-remove all downloads with a status
POST/api/downloads/{id}/pausePause a download
POST/api/downloads/{id}/resumeResume a download
GET/api/categoriesList categories with their current folders
POST/api/categories/{category}/folderSet a custom folder for a category
GET/api/detect-category?filename=…Detect a file's category
GET/api/eventsSSE stream of live download events

Interactive API docs are available at http://localhost:6500/docs while the server is running.

Notes & limitations

  • Servers must support Range requests. Chunked downloading relies on the server honouring byte ranges (responding 206 Partial Content). A 200 response is treated as a hard error rather than downloading the file single-threaded.
  • The server binds to 127.0.0.1 and CORS is open (*) so the browser extension's moz-extension:// origin can reach it. It is intended for local use, not exposure to a network.
  • Do not run the server with uvicorn --reload — a reload kills in-progress downloads.