docs: add OKF knowledge base
This commit is contained in:
69
doc/structure/overview.md
Normal file
69
doc/structure/overview.md
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
type: Project
|
||||
title: webshare-api Project Overview
|
||||
description: Purpose, stack, repo layout, and the verified build/test/run commands for the Webshare.cz HTTP API service.
|
||||
tags: [project, node, express, torznab, qbittorrent, mcp]
|
||||
timestamp: 2026-10-19T00:00:00Z
|
||||
---
|
||||
|
||||
# webshare-api Project Overview
|
||||
|
||||
## Purpose
|
||||
|
||||
`webshare-api` re-exposes [Webshare.cz](https://webshare.cz) as the protocols *arr apps understand, plus an [MCP](https://modelcontextprotocol.io) 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](https://esbuild.github.io) (`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](https://github.com/evilmartians/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`.
|
||||
|
||||
## Related
|
||||
|
||||
- Full configuration table, *arr integration steps, and MCP client config: root [`README.md`](../../README.md).
|
||||
Reference in New Issue
Block a user