Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions website/guide/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,32 @@ step 4:
}
```

Worth deciding now: **jack's copy of a download outlives the import.** Radarr
and Sonarr read the finished file out of this folder and write your library
copy, but nothing cleans up jack's — so the folder grows with every grab. Add
`unlinkImportedFiles` to have jack drop its copy once the import is confirmed:

```jsonc
{
"downloads": {
"completedPath": "/data/torrents/completed",
"unlinkImportedFiles": true
}
}
```

It's off by default because it deletes files, and it's a plain `unlink` of that
one file — if your *arr hardlinked into the library, the library keeps the data;
if it copied, you get the space back. You can also flip it later from the
management UI without a restart. See
[After the import](/guide/how-it-works#after-the-import) for the full picture,
and [`unlinkImportedFiles`](/reference/configuration#downloads-unlinkimportedfiles)
for the exact guarantees.

Every other key in this block is an optional tuning knob with a sensible
default — see [`downloads`](/reference/configuration#downloads). All of them are
editable later from the management UI, so you don't have to get them right here.

### `servers`

One entry per Radarr/Sonarr. Set each server's URL, and reference the API keys
Expand Down
43 changes: 42 additions & 1 deletion website/guide/how-it-works.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Learn how jack connects Radarr and Sonarr through Torznab and qBittorrent-compatible APIs to search and transfer media between trusted peers.
description: Learn how jack connects Radarr and Sonarr through Torznab and qBittorrent-compatible APIs to search, transfer, and import media between trusted peers, and what happens to downloaded files afterwards.
---

# How it works
Expand Down Expand Up @@ -64,6 +64,8 @@ sequenceDiagram
ARR->>JACK: GET /api/v2/torrents/info (poll progress)
JACK-->>ARR: completed → content_path = finished file
Note over ARR: scans completed folder, imports into library
JACK->>ARR: poll history — did the import land?
Note over JACK: confirmed → optionally unlink jack's copy
```

1. You grab a release. Your *arr's download client is the **qBittorrent**
Expand All @@ -78,6 +80,45 @@ sequenceDiagram
5. *arr polls jack's `/api/v2/torrents/info` for progress; once jack reports
the torrent complete, *arr scans the completed folder and imports the file
into your library, renamed and tracked.
6. jack watches that *arr's history until the import is confirmed, then — if
you've turned it on — removes its own copy from the completed folder. See
[After the import](#after-the-import) below.

### After the import

Importing doesn't consume the file in `completedPath`. Radarr and Sonarr read
it and write your library copy; jack's copy stays where it was, and jack has no
further use for it — a finished download is never re-served to peers or
re-imported.

That leaves you with two on-disk outcomes, and which one you get is decided by
your *arr, not by jack:

- **Your *arr hardlinked** (its default when the completed folder and the
library live on the same filesystem) — the library entry and jack's copy are
two names for the same bytes. Nothing is duplicated, but the completed folder
keeps filling with entries you'll never look at.
- **Your *arr copied or moved** (different filesystems, or hardlinks disabled) —
the library now holds its own bytes, and jack's copy is a genuine second copy
of every file you've ever grabbed. Left alone, `completedPath` grows without
bound.

[`downloads.unlinkImportedFiles`](/reference/configuration#downloads-unlinkimportedfiles)
is the switch for this. Turn it on and jack unlinks its copy as soon as the
import is confirmed: in the hardlink case that just drops the redundant
directory entry and your library is untouched, and in the copy case it frees the
space. It's **off by default**, so an instance you set up and forget will
accumulate.

The unlink is deliberately narrow. It runs only on an import jack has confirmed
— the destination *arr reports the download in its history, or the manual import
jack pushed reports `completed` — so a queued, in-progress, or failed import
keeps its file, and so does a file another download still needs. jack removes
that one file and nothing else; it never touches your library.

Flip it from **Settings → Downloads** in the [management
UI](/guide/management-ui) or set it in `config.jsonc`. It's the one key in the
`downloads` block that applies without a restart.

## 3. Serving — being a peer to others

Expand Down
61 changes: 58 additions & 3 deletions website/guide/management-ui.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Manage jack servers, peers, API keys, downloads, catalog requests, and logs from the self-hosted web management console.
description: Manage jack servers, peers, API keys, downloads, catalog requests, and logs from the self-hosted web management console, with live updates over Server-Sent Events.
---

# Management UI
Expand All @@ -11,11 +11,11 @@ instance without hand-editing `config.jsonc`. With the
operate jack day to day:

- **Overview** — your configured servers and peers, and whether each one
initialized cleanly.
initialized cleanly, with transfer activity updating live.
- **Catalog** — browse everything your peers share, and request titles into
your library.
- **Downloads** — inspect, cancel, retry, and delete in-flight or finished
grabs.
grabs, updating live as they progress.
- **Peers** and **Servers** — add, edit, and remove your friends and your
Radarr/Sonarr connectors.
- **Settings → Downloads** — the whole
Expand All @@ -28,6 +28,28 @@ operate jack day to day:
Don't want it? Delete the `jack-ui` service and the backend's
`JACK_MANAGEMENT_KEY` line to run jack headless.

## Settings → Downloads

The whole [`downloads`](/reference/configuration#downloads) block is editable
here, so there's no reason to hand-edit `config.jsonc` for it:

- **Completed folder**, **simultaneous transfers**, and the
**[drop imported files](/reference/configuration#downloads-unlinkimportedfiles)**
switch — the settings you actually choose — sit at the top.
- **Transfer retries** and **import watcher** tuning are collapsed below, each
labelled with how many of its values you've moved off jack's defaults.

Every field's placeholder is jack's default, and **clearing a field means "use
the default"** — jack drops the key from the config file rather than storing a
blank. `completedPath` is the exception: it has no default, so it can't be
cleared. If your config has no `downloads` block at all, the page offers to set
one up.

One **Save** covers the form and only lights up once something changed;
**Revert** discards your edits. `unlinkImportedFiles` takes effect the moment
you save — **every other key here is read at startup, so restart jack** to apply
it.

## Access control

The UI supports two auth modes, depending on where the management key comes
Expand Down Expand Up @@ -60,6 +82,39 @@ separate listener the UI never touches.
See [`apps/ui/README.md`](https://github.com/roziscoding/jack/blob/main/apps/ui/README.md)
for the full UI configuration reference.

## Live updates

The UI doesn't poll. Overview, Downloads, and Settings each hold a
[Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
stream open through the BFF, and jack pushes a fresh snapshot the moment
something changes — a transfer's progress, a connector's state, a peer or server
you just edited. There is no refresh interval to tune and no manual refresh
button.

The streams are plain `GET` endpoints on the management API:

| Stream | What it pushes |
| --- | --- |
| `/overview/stream` | Connector overview + download state |
| `/downloads/stream` | Every persisted download change |
| `/config/stream` | Peer and server config changes |

Each sends its current snapshot immediately on connect, then a full snapshot per
change — no deltas to reassemble — plus a `ping` event every 15 seconds so idle
proxies don't drop the connection. The Logs page tails `/logs/stream`, which
works the same way except each event is a single log line rather than a
snapshot.

The browser reconnects on its own if a stream drops; Overview and Downloads show
a **Live** badge that flips to **Reconnecting…** while it's down.

**Behind a reverse proxy:** SSE needs response buffering **off** and an idle
timeout **longer than 15 seconds** on whatever sits in front of the UI. jack
sends `X-Accel-Buffering: no` (nginx and compatible proxies honour it) and the
BFF forwards that header, but proxies that buffer regardless — or cut idle
connections early — will leave the UI stuck on **Reconnecting…**. See
[Troubleshooting](/guide/troubleshooting#management-ui-stuck-on-reconnecting).

## Management API

The UI's backing API — the **management API** — is a separate listener on its
Expand Down
46 changes: 45 additions & 1 deletion website/guide/troubleshooting.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Diagnose jack connectivity, Radarr or Sonarr registration, qBittorrent client checks, downloads, imports, permissions, and peer errors.
description: Diagnose jack connectivity, Radarr or Sonarr registration, qBittorrent client checks, downloads, imports, permissions, management UI live updates, and peer errors.
---

# Troubleshooting
Expand Down Expand Up @@ -126,6 +126,50 @@ depends_on:
(This needs `healthcheck` blocks on those services — the linuxserver.io images
ship with them.)

## The completed folder keeps growing

Everything imports fine, but `downloads.completedPath` never shrinks — every
title you've ever grabbed is still sitting there.

That's the default behaviour, not a bug. Importing doesn't consume the file:
Radarr/Sonarr read it and write your library copy, and jack's copy stays put.
Whether that costs you real space depends on your *arr — a hardlinked import
shares bytes with the library, a copied one doesn't — but either way the folder
fills up.

**Fix:** turn on
[`downloads.unlinkImportedFiles`](/reference/configuration#downloads-unlinkimportedfiles),
in `config.jsonc` or from **Settings → Downloads** in the management UI. It
applies immediately, with no restart. jack then unlinks its copy as each import
is confirmed — safely: only on a confirmed import, only that one file, never
your library. Details in [After the import](/guide/how-it-works#after-the-import).

This only affects downloads imported **after** you enable it. Files already in
the folder are yours to clear out — deleting the download rows from the
management UI's Downloads page removes their files too.

## Management UI stuck on "Reconnecting…"

The Overview and Downloads pages show a **Live** badge while their
[event stream](/guide/management-ui#live-updates) is connected. If it sits on
**Reconnecting…** — or flips to it every few seconds — the stream is being
closed or buffered before it reaches the browser. The pages still load; they
just stop updating on their own.

Three usual causes:

- **A reverse proxy is buffering the response.** SSE only works if the proxy
streams bytes through. jack sends `X-Accel-Buffering: no` and the UI's BFF
forwards it, which nginx honours; for others turn buffering off explicitly
(`proxy_buffering off;` on nginx, `flush_interval = -1` on Traefik, Caddy's
`reverse_proxy` streams by default).
- **The proxy's idle timeout is too short.** Streams are idle between changes,
with only a `ping` every 15 seconds. Give the UI route a read/idle timeout
well above that — 60 seconds or more.
- **The management API is down or unreachable.** The BFF answers `503` when it
can't reach jack. Check `docker compose ps` and the backend logs for
`Management API listening`.

## Seeing what jack is doing

Set `LOG_LEVEL=trace` to log every HTTP request (method, path, status,
Expand Down
2 changes: 1 addition & 1 deletion website/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ features:
details: No trackers, no swarm — files transfer over plain, authenticated HTTP.
- icon: 🖥️
title: Web management console
details: Manage servers, peers, API keys, and downloads without hand-editing config files.
details: Manage servers, peers, API keys, and downloads without hand-editing config files — transfers and connector state update live.
---