Files
webshare-api/doc/structure/overview.md

4.9 KiB

type, title, description, tags, timestamp
type title description tags timestamp
Project webshare-api Project Overview Purpose, stack, repo layout, and the verified build/test/run commands for the Webshare.cz HTTP API service.
project
node
express
torznab
qbittorrent
mcp
2026-10-19T00:00:00Z

webshare-api Project Overview

Purpose

webshare-api re-exposes Webshare.cz as the protocols *arr apps understand, plus an MCP server for AI agents. The roles:

  • Torznab indexer — GET /api?t=caps|search|tvsearch|movie turns Webshare search into Torznab RSS/XML, so Sonarr/Radarr can use it as an indexer.
  • Fake torrent — GET /download/:ident returns a minimal .torrent whose webseed points at this service's /stream/:ident, never at a CDN URL (Webshare links expire in ~10 minutes).
  • Stream — GET /stream/:ident fetches a fresh Webshare file_link and issues an HTTP 302 to the CDN.
  • Fake qBittorrent client — /api/v2/* is a qBittorrent-compatible download API that streams the HTTPS file to disk and reports progress; this is what *arr apps hand the torrent to.
  • Web UI — GET /, a two-tab TUI-style page (Search, Queue) sharing the same download engine as the fake qBittorrent client.
  • MCP server — POST /mcp (Streamable HTTP, stateless POST-only) exposes webshare_search, webshare_get_link, and webshare_login_check to AI agents.

Webshare credentials are optional: with empty WEBSHARE_USERNAME/WEBSHARE_PASSWORD the app runs in guest mode using unauthenticated file_link (no wst). Guest downloads work but use the free-tier CDN, which is typically much slower than an authenticated account.

Stack

  • Runtime: Node.js >=18, CommonJS modules.
  • Framework: Express 4 (CORS wide open for LAN UI access; 4 MB JSON body limit).
  • Build: esbuild (scripts/build.mjs) bundles the server and the optional MCP entry each into a single .js file with dependencies inlined (no node_modules at runtime), and inlines the Web UI into one dist/ui/index.html (CSS + JS inlined).
  • Tests: Jest 30 + supertest. npm test runs jest --coverage --runInBand. Coverage thresholds are enforced globally: 90% lines, 80% branches, 90% functions, 90% statements over src/**/*.js (excluding src/index.js, which is the entrypoint that starts listening). Test timeout is 15 s and Jest is configured with forceExit: true.
  • Docker: multi-stage build (Dockerfile); the final image copies only dist/ (no source or node_modules), so the image is far smaller than npm ci --omit=dev.
  • Commit hooks: lefthook (lefthook.yml) runs gitleaks (secret scan), a large-file guard, and a conventional-commit subject check. No repo-wide formatter is enforced.

Repo layout

src/             # source (CommonJS)
  index.js       # express app + app.listen at module load (server entry)
  qbt.js         # fake qBittorrent client / download queue; cancelDownload returns a boolean
  mcp.js         # MCP server entry (Streamable HTTP)
  webshare.js    # Webshare API client
  torznab.js     # Torznab caps/feed builders
  torrent.js     # minimal .torrent generation
ui/              # Web UI source (index.html, styles.css, scripts.js)
scripts/build.mjs # esbuild: server.js + mcp.js + single-file UI
dist/            # build output (gitignored; produced by npm run build or Docker)
__tests__/       # Jest + supertest tests
compose.yaml     # Docker Compose
data/            # host download data dir (Compose mount target)

The src/ modules: qbt.js is the shared download engine used by both the Web UI queue and the fake qBittorrent API; cancelDownload(hash) returns a boolean indicating whether a matching download was cancelled.

Build / test / run (verified)

Command What it does
npm install Install dependencies.
npm run build node scripts/build.mjs → dist/server.js (~1.9 MB, all deps bundled), dist/mcp.js (~1.8 MB), dist/ui/index.html (CSS+JS inlined).
npm start node dist/server.js — run the built server (also serves MCP on PORT).
npm run start:dev node src/index.js — run unbundled src/ for local hacking (no build step).
npm run mcp / npm run mcp:dev Run the MCP-only process (no Torznab/qBittorrent), serving POST /mcp.
npm test jest --coverage --runInBand (enforces the coverage thresholds above).
docker compose up -d --build Run via Compose (see compose.yaml; copy .env.example to .env first).

Default listen port is 3001 (PORT). Webshare credentials are read from WEBSHARE_USERNAME / WEBSHARE_PASSWORD; full configuration reference lives in the root README.md. Do not commit a filled .env.

  • Full configuration table, *arr integration steps, and MCP client config: root README.md.