Files
webshare-api/README.md
Michal Pemcak 97b9215917 Add Web UI queue screenshot to README.
Document light TUI UI and include docs/ui-queue.png (Iron Man multi-item queue).
2026-08-07 11:25:12 +02:00

5.9 KiB

webshare-api

Node.js/Express proxy that exposes Webshare.cz as protocols *arr apps understand, and as an MCP server for AI agents.

Official Webshare HTTP API documentation: https://webshare.cz/apidoc/

Role Endpoints Purpose
Torznab indexer GET /api?t=caps|search|tvsearch|movie Search → Torznab RSS/XML
Fake torrent GET /download/:ident Minimal .torrent whose webseed points at /stream/:ident
Stream GET /stream/:ident Fresh Webshare file_link + HTTP 302 to CDN
Fake qBittorrent /api/v2/* Download client API; streams the HTTPS file to disk
Debug GET /resolve/:ident JSON with the resolved CDN URL
Web UI GET / Two-tab UI: search files and add to queue; queue view with progress, speed, and cancel
MCP server POST /mcp (Streamable HTTP) Tools for AI agents: search, resolve links, login check

Webshare download links expire after roughly ten minutes, so the torrent never embeds a CDN URL—only a path on this service that resolves a fresh link at fetch time.

Web UI

Light monochrome TUI-style page at http://<host>:3001/Search and Queue tabs (keys 1 / 2, / focuses search). Queue shares the same download engine as the fake qBittorrent client.

Queue tab with multiple Iron Man downloads

Layout

src/             # source (CommonJS modules)
ui/              # Web UI source (index.html, styles.css, scripts.js)
scripts/build.mjs # esbuild: single server.js + minified single-file UI
dist/            # build output (gitignored; produced by npm run build / Docker)
  server.js      # one file: app + all npm dependencies
  mcp.js         # optional MCP-only entry
  ui/index.html  # CSS+JS inlined
__tests__/
compose.yaml
Dockerfile       # multi-stage: build with esbuild, runtime = Node + dist only

Build (smaller image / single JS)

npm install
npm run build    # → dist/server.js (~2 MB, all deps bundled) + dist/ui/index.html
npm start        # node dist/server.js
npm run start:dev # unbundled src/ for local hacking

esbuild bundles the server (and optional mcp entry) into a single .js file with dependencies inlined — no node_modules needed at runtime. The Web UI is minified into one dist/ui/index.html (CSS and JS inlined).

Docker uses a multi-stage build: final image copies only dist/, not source or node_modules, which keeps the image much smaller than npm ci --omit=dev.

Configuration

Environment variables (required unless noted):

Variable Default Description
WEBSHARE_USERNAME Webshare username or email
WEBSHARE_PASSWORD Webshare password (plain; hashed client-side)
PORT 3001 HTTP listen port
BASE_URL http://localhost:$PORT Public base URL Sonarr must reach (use the Compose service hostname when linking containers)
DOWNLOAD_PATH /downloads/webshare Where the fake qBittorrent writes files
MEDIA_ROOT /data Media root (used for path reporting)
MAX_CONCURRENT_DOWNLOADS 2 Parallel stream downloads
SONARR_URL http://sonarr:8989 Optional; Sonarr base URL
SONARR_API_KEY (empty) Optional; enables periodic missing-episode search
SONARR_SEARCH_INTERVAL_HOURS 2 Interval for that search
DOWNLOAD_HOST_PATH ./data/webshare Host path mounted at DOWNLOAD_PATH in Compose
MCP_ENABLED true Set to 0/false to disable the MCP HTTP endpoint
MCP_PATH /mcp HTTP path for the Streamable HTTP MCP endpoint

Copy .env.example and fill in credentials. Do not commit a filled .env.

Run with Compose

cp .env.example .env
# set WEBSHARE_USERNAME and WEBSHARE_PASSWORD
docker compose up -d --build

See compose.yaml. Override ports, BASE_URL, Sonarr settings, and volume mounts via .env as needed.

Run without Compose

npm install
npm run build
export WEBSHARE_USERNAME=...
export WEBSHARE_PASSWORD=...
npm start
# or: npm run start:dev  # no build step, uses src/

Sonarr / Radarr

  1. Indexer (Torznab): http://<host>:3001/api
  2. Download client (qBittorrent): host/port of this service; any username/password (login accepts all).

When both run on the same Compose network, use the service name, e.g. http://webshare-api:3001.

Sonarr hands .torrent files to the fake qBittorrent API. This service extracts the webseed, streams the file into DOWNLOAD_PATH, and reports progress via /api/v2/torrents/*.

MCP (AI agents)

Exposes Webshare to MCP-compatible clients over Streamable HTTP (not stdio).

With npm start (or Compose), MCP is available on the same process/port:

POST http://<host>:3001/mcp

Optional MCP-only process (no Torznab/qBittorrent):

export WEBSHARE_USERNAME=...
export WEBSHARE_PASSWORD=...
npm run mcp   # listens on PORT, serves POST /mcp

Tools

Tool Description
webshare_search Search files (query, optional limit / offset / sort / category)
webshare_get_link Resolve a temporary CDN URL for a file ident
webshare_login_check Verify credentials against the Webshare API

Client configuration example

HTTP / Streamable HTTP (preferred):

[mcp_servers.webshare]
url = "http://127.0.0.1:3001/mcp"
grok mcp add --transport http webshare http://127.0.0.1:3001/mcp

Credentials stay on the server process (WEBSHARE_* env); clients only need the URL.

The transport is stateless Streamable HTTP (POST only).

Tests

npm test

License

MIT

You need a valid Webshare account. This project only speaks their documented HTTP API (apidoc). Use at your own risk.