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
11 changes: 11 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copilot instructions

Read [`AGENTS.md`](../AGENTS.md) at the repo root before making any change. It
holds the repo layout, the writing style, and the hard rules for opening a docs
drift PR.

Those drift rules are not optional: work from local clones, read files and
commit diffs end to end, confirm every claim against the upstream commit, skip
what is already documented, keep the edits minimal and restricted to `docs/` and
`static/openapi-spec/`, and structure the PR description as "What was added"
plus "Already covered by prior PRs".
54 changes: 54 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Agent instructions

This repo is the Docusaurus site for Maintainerr. The code it documents lives in
[Maintainerr/Maintainerr](https://github.com/Maintainerr/Maintainerr).

## Repo layout

| Path | What it holds |
| ---------------------- | ------------------------------------------------------------------ |
| `docs/` | The Next (unreleased) docs. Edits for an unreleased change go here |
| `versioned_docs/` | Frozen snapshots of released versions. Do not edit by hand |
| `static/openapi-spec/` | The bundled OpenAPI YAML |
| `blog/`, `src/` | Blog posts and site theme |

Run `npm run format` before committing, and `npm run build` to check the site
still builds and no link broke.

## Docs drift PRs

A bot opens a "Docs drift report" issue that compares the last release to
Maintainerr's `HEAD`. These rules are hard rules when you open the PR for one.

- **Work from local clones, never from github.com web views.** Web views can be
cached or truncated. Clone `Maintainerr/Maintainerr` and
`Maintainerr/Maintainerr_docs` before anything else.
- **Read complete files, not excerpts.** Coverage you would otherwise miss often
sits past the first screenful. Read each doc file and each commit diff end to
end.
- **The upstream commits and diffs are the source of truth.** Use the issue's
prose summary as guidance, but confirm every claim against the local clone
with `git show <sha>` before editing.
- **Skip what is already documented.** Read the current `main` of this repo and
the most recent merged docs PRs first. If something is already covered, do not
document it again.
- **Minimal edits only.** Make only the doc updates still missing for the Next
release. No speculative additions and no broad rewrites.
- **Doc-only changes.** Restrict edits to `docs/` and `static/openapi-spec/`. Do
not touch sidebars, config, or unrelated assets unless a doc edit strictly
requires it.
- **Keep the PR tied to the code diff**, not to the issue summary alone.
- **Structure the PR description** in two parts:
1. **What was added**, one short bullet per doc edit, citing the upstream
commit or PR.
2. **Already covered by prior PRs**, listing anything in this drift that an
earlier merged docs PR already documented, so reviewers can confirm it was
skipped on purpose.

## Writing style

- Plain English, kept short. Describe how things work today, not what changed
since some version.
- Plain hyphens only. No em dashes or en dashes.
- Always "Seerr", never Overseerr or Jellyseerr.
- No real media titles in examples.
8 changes: 6 additions & 2 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ The 250 limits one request, not how much a user can select. The web UI sends 25

If some items fail, the rest still go through. Both endpoints answer `{ results: [{ mediaId, code, message? }] }`, where `code` is `1` for success and `0` for failure, with `message` explaining a failure. A request is rejected outright with `400` only when it is empty, holds more than 250 ids, or asks to add without naming a collection.

Adding an exclusion takes the collection and rule execution lock, on both `POST /api/rules/exclusions/bulk` and `POST /api/rules/exclusion`, so it cannot land while a run is acting on the same item. Both wait up to 30 seconds for a running job and answer `409` if it is still going. Removing an exclusion takes no lock.

### Metadata

| Endpoint | Purpose |
Expand Down Expand Up @@ -144,12 +146,14 @@ If some items fail, the rest still go through. Both endpoints answer `{ results:

| Endpoint | Purpose |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `GET /api/settings/tracearr` | Read the saved Tracearr base URL, API key, and selected Tracearr server |
| `POST /api/settings/test/tracearr` | Test a Tracearr URL, API key, and server selection before saving |
| `GET /api/settings/tracearr` | Read the saved Tracearr base URL, API key, and bound Tracearr server |
| `POST /api/settings/test/tracearr` | Test a Tracearr URL and API key before saving |
| `POST /api/settings/tracearr/servers` | Discover the Tracearr servers available for a URL and API key so the settings UI can populate the selector |
| `POST /api/settings/tracearr` | Save the Tracearr connection settings |
| `DELETE /api/settings/tracearr` | Remove the saved Tracearr connection settings |

`server_id` is optional on `POST /api/settings/tracearr`. Leave it out and Maintainerr picks the Tracearr server that tracks your media server; send it only when Tracearr has several servers of that type. Either way the save is refused if no server matches, or if the one you sent tracks a different media server.

### Overlays

| Endpoint | Purpose |
Expand Down
40 changes: 21 additions & 19 deletions docs/Collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ When the specified amount of days that media must live in the collection is pass
Collection handling is a batch process that runs every 12 hours. You can manually trigger it with the `Handle Collections` button on the Collections page.
This runs each collection's configured action (such as delete, unmonitor, or do nothing), but it does not remove items from collections on its own.

If a rule-managed item is still in the collection but its most recent rule evaluation failed, Maintainerr skips the automatic handling action for that item until the rule can be evaluated cleanly again. Manually added items are still eligible for handling.
If a rule-managed item is still in the collection but its most recent rule evaluation failed, Maintainerr skips the automatic handling action for that item until the rule can be evaluated cleanly again. Manually added items are still eligible for handling, unless an exclusion covers them. That means an exclusion for this collection or a global one, and excluding a show or season covers everything inside it.
When a delete-style action removes files, Maintainerr also prunes that media from any other Maintainerr-managed collections that still list it. This prevents already-deleted items from being re-processed while Jellyfin or Emby are still catching up on their next library scan.
If eligible media is actively being streamed, Maintainerr defers it to the next collection-handler run instead of acting on it mid-playback. This is a best-effort snapshot taken once per run, so playback that starts later is only protected on the following pass.

Expand Down Expand Up @@ -83,29 +83,27 @@ The collection-poster endpoints live under `/api/collections/:id`.

### The `Add / Remove Media` modal {#add-remove-media-modal}

Every manual collection and exclusion change runs through one modal. Click `Select items` in the action bar to enter selection mode, check the media you want, then click `Add/Exclude selected`. It is available in three places:
Every manual collection and exclusion change runs through one modal. Click `Select items` in the action bar to enter selection mode, check the media you want, then click `Add/Exclude selected`. It is available on the `Overview`, on a collection's `Media` tab, and on a collection's `Exclusions` tab.

| Page | Scope |
| ------------------------------- | ---------------------------------------------------------------------- |
| `Overview` | The selection can target any collection, or every collection at once |
| A collection's `Media` tab | Locked to that collection, so `Add to collection` is not offered there |
| A collection's `Exclusions` tab | Locked to that collection, so `Add exclusion` is not offered there |
All three offer the same actions. On a collection page the `Collection` list starts on that collection, and you can switch it to another one or to `All collections`.

Pick an `Action` in the modal:

| Action | Effect |
| ----------------------------- | ---------------------------------------------------------------------------- |
| `Add to collection` | Add the selection to the collection you pick |
| `Remove from collection` | Remove the selection from the collection you pick |
| `Remove from all collections` | Remove the selection from every collection it is in |
| `Add exclusion` | Exclude the selection from one collection, or from all of them |
| `Remove exclusion` | Drop the selection's exclusions for one collection, or all of its exclusions |

- The `Collection` list only offers collections from the library you are looking at. A show selection can target a show, season, or episode collection, a season selection a season or episode one, and a movie selection a movie collection.
| Action | Effect |
| ------------------------ | ---------------------------------------------------------------------------- |
| `Add to collection` | Add the selection to the collection you pick |
| `Remove from collection` | Remove the selection from the collection you pick, or from every collection |
| `Add exclusion` | Exclude the selection from one collection, or from all of them |
| `Remove exclusion` | Drop the selection's exclusions for one collection, or all of its exclusions |

- Every action except `Add to collection` can also target `All collections`. An add needs one collection to add to.
- A show selection can target a show, season, or episode collection, a season selection a season or episode one, and a movie selection a movie collection.
- On Plex, a collection only holds items from its own library, so the `Collection` list shows that library's collections and an add from another library is refused. Jellyfin and Emby collections take any library, so all of them are offered.
- You can add search results to a collection too. A search covers every library, so Maintainerr takes the library from the items you picked. On Plex, if they are not all from one library, only the exclusion actions are left.
- If your selection mixes media types, no collection can take it, so only `Add exclusion` and `Remove exclusion` are offered.
- Select exactly one show and you can narrow the action to specific `Seasons`, and from there to specific `Episodes`. The show stays the entry point, so you can still undo the change through the show later. Narrowing is not offered on a show collection's own tab, where the action applies to the show itself.
- Select exactly one show and you can narrow the action to specific `Seasons`, and from there to specific `Episodes`. The show stays the entry point, so you can still undo the change through the show later.
- There is no cap on how many items you can select. Maintainerr sends them to the server 25 at a time, so a large selection becomes several requests rather than one.
- Maintainerr reports a result for each item. If some fail, it tells you which ones and still handles the rest.
- Maintainerr reports a result for each item. If some fail, it tells you which ones and why, and still handles the rest.
- Anything that affects every collection asks you to confirm first.

:::warning
Expand All @@ -118,7 +116,7 @@ Select the media on the `Overview` page and choose `Add to collection`. Manually

### Removing

Choose `Remove from collection` for one collection, or `Remove from all collections` to clear the selection out of every collection it is in.
Choose `Remove from collection`, then pick a collection, or `All collections` to take the selection out of every collection it is in.

To remove a single item, open the collection from the `Collections` page and use the `Remove` button on its card.

Expand All @@ -134,6 +132,10 @@ Use `Postpone` from an item's collection details to delay its scheduled action b

Select the media and choose `Add exclusion`. Pick a single collection to scope the exclusion to that collection's rule group, or `All collections` to exclude it everywhere. `Remove exclusion` works the same way. Excluding a show or season also covers everything it contains.

Excluding also removes the selection from the collections it covers: the one you picked, or every collection when you exclude everywhere. The confirmation says so first.

If a collection or rule run is busy, an exclusion waits up to 30 seconds for it to finish, so it cannot land while the run is acting on the same item. If the run is still going after that, Maintainerr asks you to try again. Removing an exclusion never waits.

An exclusion tied to one specific collection / rule group only applies there. Other rule groups can still add or act on the same item unless you exclude it globally.

Adding a global exclusion removes that item's existing collection-specific exclusions, and the confirmation dialog lists which ones it will drop. If you later remove the global exclusion, those narrower exclusions are not restored automatically.
Expand Down
18 changes: 13 additions & 5 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,16 @@ Tracearr's configuration is required to use its watch history parameters in rule
Tracearr does not backfill media-server history. Only watch events recorded by Tracearr after it was connected to your media server are available to rules.
:::

| Setting | Description |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| URL | The base URL of your Tracearr instance, such as `http://localhost:3000` or `https://tracearr.example.com` |
| API key | The API key from Tracearr settings |
| Tracearr server | The Tracearr server to use. Enter a valid URL and API key first, then select from the servers discovered from that Tracearr instance. |
| Setting | Description |
| --------------- | --------------------------------------------------------------------------------------------------------------------- |
| URL | The base URL of your Tracearr instance, such as `http://localhost:3000` or `https://tracearr.example.com` |
| API key | The API key from Tracearr, under `Settings`, `General`, `API Key` |
| Tracearr server | Only shown when Tracearr has more than one server of your media server's type. Otherwise Maintainerr picks it for you |

Maintainerr uses the Tracearr server that tracks your media server. Watch history belongs to one media server, so the wrong Tracearr server matches nothing and every Tracearr rule reads as unwatched.

- Saving is refused if no Tracearr server matches, or if the one you picked tracks a different media server. Add your media server in Tracearr and let it sync a library first.
- Point Maintainerr at a different media server, even another one of the same type, and the choice is checked again and cleared if it no longer fits.
- Every run checks the server before reading its history. If that fails, Tracearr rule values are unavailable for that run and the log says why, instead of the rules reading as watched by nobody.

`Test Connection` checks the URL and the API key. The server is checked when you save.
13 changes: 11 additions & 2 deletions static/openapi-spec/maintainerr_api_specs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ paths:
$ref: '#/components/schemas/TracearrSetting'
responses:
'201':
description: Tests Tracearr connectivity with a selected server.
description: Tests Tracearr connectivity with the supplied URL and API key.
tags:
- /settings
/api/settings/tracearr/servers:
Expand Down Expand Up @@ -1022,6 +1022,9 @@ paths:
responses:
'201':
description: ''
'409':
description: >-
A collection or rule run held the execution lock for too long.
tags:
- /rules
/api/rules/{id}:
Expand Down Expand Up @@ -1140,6 +1143,9 @@ paths:
description: >-
Rejected without processing: empty, more than 250 media ids, or a
context sent with more than one id.
'409':
description: >-
A collection or rule run held the execution lock for too long.
tags:
- /rules
/api/rules/exclusions/{plexId}:
Expand Down Expand Up @@ -2118,12 +2124,15 @@ components:
api_key:
type: string
server_id:
description: >-
Omit it to let Maintainerr pick the Tracearr server that tracks the
configured media server. Send it only when Tracearr has several
servers of that type.
type: string
format: uuid
required:
- url
- api_key
- server_id
TracearrSettingForm:
type: object
description: >-
Expand Down