feat(anime): rename NFO Diagnostics to Anime Settings + add edit endpoints
Replaces the read-only 'NFO Diagnostics' page with a full per-anime
Settings page reached from the right-click context menu on series cards.
Users can now view and edit key, name, folder, tmdb_id, tvdb_id and site
for each anime; changes are persisted to the DB and optionally written
back to the NFO file or used to regenerate it.
Backend
- Rename NfoDiagnosticsResponse -> NfoSettingsResponse,
NfoSeriesDiagnostics -> NfoSeriesSettings
- Rename get_nfo_diagnostics -> get_nfo_settings,
repair_nfo -> repair_nfo_settings
- Fix nfo.py bug: repair was calling non-existent
update_series_nfo_status(); now uses update_nfo_status() and an
explicit AnimeSeriesService.update(nfo_path=...)
- New endpoints on /api/anime/{key}:
GET /settings -> AnimeSettingsResponse
PUT /settings -> AnimeSettingsResponse
(body: name/folder/tmdb_id/tvdb_id/site,
options: apply_to_nfo, rename_disk)
POST /regenerate-nfo -> AnimeSettingsRegenerateNfoResponse
- New Pydantic models: AnimeSettingsResponse,
AnimeSettingsUpdateRequest, AnimeSettingsRegenerateNfoResponse
- /anime/settings page route; /settings/nfo now 301-redirects to it
Frontend
- New AniWorld.AnimeSettingsManager JS module (single-page form,
no tabs) with public API init/loadSeries/saveSettings/regenerateNfo/
validateField/populateForm/showSaveSuccess/showError
- New anime-settings.html template + anime-settings.css
- Right-click menu: data-action 'nfo-diagnostics' replaced by
'anime-settings' (label 'Anime Settings'), navigates to
/anime/settings?key=...
- Library 'Open NFO Diagnostics' link renamed to 'Open Anime Settings'
Bug fix
- context-menu click handler was calling hide() BEFORE building the
navigation URL, which cleared currentSeriesKey to null and produced
/anime/settings?key=null. Captures the key into a local const first.
Regression-locked by tests/frontend/unit/context_menu.test.js.
Tests
- 21 new pytest tests in tests/api/test_anime_settings_endpoints.py
(GET/PUT/regenerate-nfo, auth, validation, nfo-repair bug regression)
- tests/api/test_nfo_endpoints.py trimmed to 6 focused tests
- 31 new Vitest unit tests for AnimeSettingsManager
- 5 new Vitest unit tests for ContextMenu (incl. source-invariant
regression guard for the hide()-before-key bug)
- 5 new Playwright E2E tests covering right-click, direct nav,
legacy /settings/nfo redirect, and context-menu labels
- New vitest.config.js (environment: happy-dom)
Docs
- Docs/API.md: new section 'Anime Settings Endpoints'
- Docs/CHANGELOG.md: documents the rename and the context-menu bug fix
Verified
- pytest: 27/27 (21 new + 6 trimmed nfo)
- vitest: 36/36 (31 anime-settings + 5 context-menu)
- playwright e2e: 5/5
This commit is contained in:
130
Docs/API.md
130
Docs/API.md
@@ -826,14 +826,32 @@ Source: [src/server/api/config.py](../src/server/api/config.py#L189-L247)
|
||||
|
||||
Prefix: `/api/nfo`
|
||||
|
||||
Source: [src/server/api/nfo.py](../src/server/api/nfo.py#L1-L684)
|
||||
Source: [src/server/api/nfo.py](../src/server/api/nfo.py)
|
||||
|
||||
These endpoints manage tvshow.nfo metadata files and associated media (poster, logo, fanart) for anime series. NFO files use Kodi/XBMC format and are scraped from TMDB API.
|
||||
These endpoints manage tvshow.nfo metadata files for anime series. The
|
||||
per-anime settings page (replacing the old "NFO Diagnostics" UI) lives
|
||||
at `/api/anime/{key}/settings` — see section **7. Anime Settings
|
||||
Endpoints** below.
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
- TMDB API key must be configured in settings
|
||||
- NFO service returns 503 if API key not configured
|
||||
- NFO endpoints return 503 if the API key is missing
|
||||
|
||||
### Anime Settings — New Endpoints
|
||||
|
||||
For the UI-driven settings page (renamed from NFO Diagnostics), the
|
||||
following endpoints replace the older `/api/nfo/{serie_id}/*` flow:
|
||||
|
||||
| Method | Path | Purpose |
|
||||
| --- | --- | --- |
|
||||
| GET | `/api/anime/{key}/settings` | Return all editable fields for a series |
|
||||
| PUT | `/api/anime/{key}/settings` | Update name/folder/tmdb_id/tvdb_id/site, optionally regenerate tvshow.nfo |
|
||||
| POST | `/api/anime/{key}/regenerate-nfo` | Regenerate tvshow.nfo using TMDB |
|
||||
|
||||
See [AnimeSettingsResponse](../src/server/models/anime.py) for the
|
||||
response shape, and [section 7](#7-anime-settings-endpoints-new) for
|
||||
full documentation.
|
||||
|
||||
### GET /api/nfo/{serie_id}/check
|
||||
|
||||
@@ -1594,3 +1612,109 @@ GET /api/anime?page=2&per_page=50
|
||||
```
|
||||
|
||||
Source: [src/server/api/anime.py](../src/server/api/anime.py#L180-L220)
|
||||
|
||||
## 7. Anime Settings Endpoints (New)
|
||||
|
||||
Replaces the old "NFO Diagnostics" page with a per-anime settings UI
|
||||
that views and edits anime metadata directly in the database.
|
||||
|
||||
Source: [src/server/api/anime.py](../src/server/api/anime.py)
|
||||
|
||||
### GET /api/anime/{anime_key}/settings
|
||||
|
||||
Return the full editable settings payload for a single anime series.
|
||||
|
||||
**Authentication:** Required
|
||||
|
||||
**Path Parameters:**
|
||||
|
||||
- `anime_key` (string): Series unique key (e.g., `attack-on-titan`)
|
||||
|
||||
**Response (200 OK):** [`AnimeSettingsResponse`](../src/server/models/anime.py)
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "attack-on-titan",
|
||||
"name": "Attack on Titan",
|
||||
"site": "aniworld.to",
|
||||
"folder": "Attack on Titan (2013)",
|
||||
"year": 2013,
|
||||
"tmdb_id": 1429,
|
||||
"tvdb_id": 789,
|
||||
"has_nfo": true,
|
||||
"nfo_path": "/anime/Attack on Titan (2013)/tvshow.nfo",
|
||||
"nfo_created_at": "2026-01-15T10:30:00+00:00",
|
||||
"nfo_updated_at": "2026-01-15T10:30:00+00:00",
|
||||
"loading_status": "completed",
|
||||
"episode_count": 25,
|
||||
"missing_episode_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
|
||||
- `401 Unauthorized` — Not authenticated.
|
||||
- `404 Not Found` — Series with the given key does not exist.
|
||||
|
||||
### PUT /api/anime/{anime_key}/settings
|
||||
|
||||
Update editable fields for a single anime series. Optional flags
|
||||
control whether the on-disk folder is renamed and whether
|
||||
`tvshow.nfo` is regenerated.
|
||||
|
||||
**Authentication:** Required
|
||||
|
||||
**Request Body** ([`AnimeSettingsUpdateRequest`](../src/server/models/anime.py)):
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `name` | string | no | Display name (1–500 chars) |
|
||||
| `folder` | string | no | Filesystem folder name |
|
||||
| `tmdb_id` | int | no | TMDB ID (positive integer, max 10 digits) |
|
||||
| `tvdb_id` | int | no | TVDB ID (positive integer, max 10 digits) |
|
||||
| `site` | string | no | Provider site URL |
|
||||
| `apply_to_nfo` | bool | no | If true, regenerate `tvshow.nfo` with the new values (requires `tmdb_id`) |
|
||||
| `rename_disk` | bool | no | If true and `folder` changed, rename the folder on disk |
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
curl -X PUT "http://127.0.0.1:8000/api/anime/attack-on-titan/settings" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"tmdb_id": 9999, "apply_to_nfo": true}'
|
||||
```
|
||||
|
||||
**Response (200 OK):** Updated [`AnimeSettingsResponse`](../src/server/models/anime.py).
|
||||
|
||||
**Errors:**
|
||||
|
||||
- `400 Bad Request` — `apply_to_nfo=true` but the series has no `tmdb_id`.
|
||||
- `401 Unauthorized` — Not authenticated.
|
||||
- `404 Not Found` — Series with the given key does not exist.
|
||||
- `422 Unprocessable Entity` — Validation failure (empty name, invalid
|
||||
folder, non-positive `tmdb_id`/`tvdb_id`, oversized id, path traversal).
|
||||
|
||||
### POST /api/anime/{anime_key}/regenerate-nfo
|
||||
|
||||
Regenerate `tvshow.nfo` for a single anime using TMDB.
|
||||
|
||||
**Authentication:** Required
|
||||
|
||||
**Response (200 OK):** [`AnimeSettingsRegenerateNfoResponse`](../src/server/models/anime.py)
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "NFO regenerated. 2 tags updated.",
|
||||
"nfo_path": "/anime/Attack on Titan (2013)/tvshow.nfo",
|
||||
"repaired_tags": ["title", "tmdbid"]
|
||||
}
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
|
||||
- `400 Bad Request` — Series has no `tmdb_id`.
|
||||
- `401 Unauthorized` — Not authenticated.
|
||||
- `404 Not Found` — Series with the given key does not exist.
|
||||
- `500 Internal Server Error` — TMDB or NFO regeneration failure.
|
||||
|
||||
Reference in New Issue
Block a user