Справочник API: точные строки классов, схемы полей с null, коды и тело ошибок
docker / build (push) Successful in 35s
docker / build (push) Successful in 35s
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
e2acebadc6
commit
4e83474652
1 file changed
+83
-1
+83
-1
@@ -54,7 +54,7 @@
|
|||||||
| `series` | object \| null | сезон, выпущенные серии, «какая студия какие серии» (для Sonarr); `null` — сведений нет |
|
| `series` | object \| null | сезон, выпущенные серии, «какая студия какие серии» (для Sonarr); `null` — сведений нет |
|
||||||
| `title` | string \| null | заголовок раздачи, если найден |
|
| `title` | string \| null | заголовок раздачи, если найден |
|
||||||
| `segmenter` | `"model"` \| `"rules"` | чем страница разбита на строки дорожек: обученным сегментатором или запасными правилами |
|
| `segmenter` | `"model"` \| `"rules"` | чем страница разбита на строки дорожек: обученным сегментатором или запасными правилами |
|
||||||
| `tracker` | string | только для `url`: `rutracker`, `nnmclub` или `kinozal` |
|
| `tracker` | string | только для `url`: `rutracker`, `nnm` или `kinozal` |
|
||||||
|
|
||||||
`series`: `season` — номер сезона строкой или `null`; `episodes` — выпущенные серии («1-9»);
|
`series`: `season` — номер сезона строкой или `null`; `episodes` — выпущенные серии («1-9»);
|
||||||
`total` — всего серий; `by_studio` — `{студия: серии}`; `full_release` — студии без указанных серий
|
`total` — всего серий; `by_studio` — `{студия: серии}`; `full_release` — студии без указанных серий
|
||||||
@@ -86,6 +86,22 @@
|
|||||||
|
|
||||||
### translation_type: 14 классов
|
### translation_type: 14 классов
|
||||||
|
|
||||||
|
Точные строки (регистр, пробелы и точки после префикса — как есть; сортировка — по алфавиту, так их
|
||||||
|
возвращает `GET /health` → `classes`):
|
||||||
|
|
||||||
|
```json
|
||||||
|
["авт. двухголосый", "авт. многоголосый", "авт. одноголосый", "двухголосый", "люб. двухголосый",
|
||||||
|
"люб. многоголосый", "люб. одноголосый", "многоголосый", "неизвестно", "одноголосый",
|
||||||
|
"проф. двухголосый", "проф. дубляж", "проф. многоголосый", "проф. одноголосый"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Для клиентов, которые сводят класс к своим типам (Dub / MVO / DVO / AVO), надёжно сопоставление по
|
||||||
|
**подстроке** нижнего регистра: `дубляж` → дубляж; `многоголос` → многоголосый; `двухголос` →
|
||||||
|
двухголосый; `одноголос` → одноголосый; ровно `неизвестно` → тип не определён (такие дорожки обычно
|
||||||
|
пропускают). Подстрока `дублирован` в классах **не встречается** (дублированные страницы сводятся к
|
||||||
|
`проф. дубляж`). Префикс (`проф.`/`люб.`/`авт.`/нет) — отдельный признак. Если набор классов в будущей
|
||||||
|
модели изменится, ориентируйтесь на `/health` → `classes`, а неизвестное значение не считайте ошибкой.
|
||||||
|
|
||||||
Класс — составная метка «кто делал × сколько голосов». Других значений сервис не возвращает.
|
Класс — составная метка «кто делал × сколько голосов». Других значений сервис не возвращает.
|
||||||
|
|
||||||
| Значение | Кто озвучивал | Вид |
|
| Значение | Кто озвучивал | Вид |
|
||||||
@@ -113,6 +129,72 @@
|
|||||||
доверять осторожно. Состав и названия классов задаёт обучение; актуальный список для конкретной
|
доверять осторожно. Состав и названия классов задаёт обучение; актуальный список для конкретной
|
||||||
модели — `GET /health` → `classes`.
|
модели — `GET /health` → `classes`.
|
||||||
|
|
||||||
|
## Схема полей и допустимые null
|
||||||
|
|
||||||
|
Дорожка (`tracks[]`), нотация TypeScript. Все ключи **присутствуют всегда** (значение может быть
|
||||||
|
`null`, но ключ не пропускается), кроме помеченных «только в ответе релиза».
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type Track = {
|
||||||
|
segment: string; // никогда null
|
||||||
|
translation_type: string; // один из 14 классов, никогда null
|
||||||
|
type_confidence: number; // 0..1
|
||||||
|
studio_span: string | null; // null — автора в тексте нет
|
||||||
|
studio: string | null; // null вместе со studio_span
|
||||||
|
studio_confidence: number | null; // null вместе со studio_span
|
||||||
|
is_18plus: boolean;
|
||||||
|
age_confidence: number; // 0..1
|
||||||
|
lang: string | null; // 3-буквенный код или null
|
||||||
|
lang_confidence: number | null; // не null только при lang_source == "model"
|
||||||
|
lang_source: "model" | "audio" | "text" | null; // null вместе с lang
|
||||||
|
role: "перевод" | "оригинал" | "комментарии"; // никогда null
|
||||||
|
official: boolean;
|
||||||
|
audio: { codec: string | null; channels: number | null; bitrate_kbps: number | null } | null;
|
||||||
|
// только в ответе релиза (html / url):
|
||||||
|
source: "page" | "title";
|
||||||
|
episodes: string | null; // "1-4", "1,3-5"; null — серии не указаны
|
||||||
|
episode_ranges: [number, number][]; // [[1,4]]; пустой массив, если серий нет
|
||||||
|
};
|
||||||
|
|
||||||
|
type Release = {
|
||||||
|
tracks: Track[]; // может быть пустым массивом
|
||||||
|
studios: { studio: string | null; translation_type: string; is_18plus: boolean; episodes: string | null }[];
|
||||||
|
translation_types: string[];
|
||||||
|
is_18plus: boolean;
|
||||||
|
series: {
|
||||||
|
season: string | null; // "2"
|
||||||
|
episodes: string | null; // выпущенные серии, "1-9"
|
||||||
|
total: number | null; // всего серий
|
||||||
|
by_studio: Record<string, string>; // { "LostFilm": "1-4" }, может быть {}
|
||||||
|
full_release: string[]; // студии без указанных серий
|
||||||
|
} | null; // null — ни сезона, ни серий в раздаче нет
|
||||||
|
title: string | null;
|
||||||
|
segmenter: "model" | "rules";
|
||||||
|
tracker?: "rutracker" | "nnm" | "kinozal"; // только для url
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Ответ на `text` — `{"tracks": [Track]}` (без полей релиза и без `source`/`episodes`/`episode_ranges`).
|
||||||
|
Клиентам стоит читать ответ толерантно: неизвестные поля игнорировать, отсутствующие считать `null`.
|
||||||
|
|
||||||
|
## Ошибки
|
||||||
|
|
||||||
|
Тело любой ошибки — JSON `{"detail": "<сообщение>"}`; у `401` добавлен заголовок
|
||||||
|
`WWW-Authenticate: Bearer`.
|
||||||
|
|
||||||
|
| Код | Когда | Пример `detail` |
|
||||||
|
|---|---|---|
|
||||||
|
| 400 | передано не ровно одно из `text` / `html` / `url` | «нужно ровно одно поле: text (дорожка), html (страница) или url (ссылка на раздачу)» |
|
||||||
|
| 400 | пустой `text`; страница не разобрана; хост ссылки не из разрешённых (rutracker / nnmclub / kinozal); страница недоступна или слишком большая; трекер отдал заглушку Cloudflare или форму входа без FlareSolverr/`cookie`; ошибка FlareSolverr | текст причины на русском («неподдерживаемый хост: …», «страница недоступна: …», «FlareSolverr: …») |
|
||||||
|
| 401 | задан `DUB_API_TOKEN`, а токена нет или он неверный | «нужен токен: Authorization: Bearer <токен> или X-API-Key» |
|
||||||
|
| 422 | тело запроса не JSON-объект или поля не тех типов (валидация FastAPI; `detail` — массив) | `[{"loc": [...], "msg": "...", "type": "..."}]` |
|
||||||
|
| 502 | сетевая ошибка при скачивании страницы по `url` (соединение, DNS, таймаут) | «не удалось загрузить страницу: …» |
|
||||||
|
|
||||||
|
`GET /health` не требует токена и возвращает: `status`, `model`, `device`, `classes`, `segmenter`
|
||||||
|
(`"model"`/`"rules"`), `flaresolverr` (bool), `auth` (bool). Страница, на которой не найдено дорожек,
|
||||||
|
— не ошибка: ответ `200` с `"tracks": []`. Повторяйте запрос при `502` и при ответах `400` про
|
||||||
|
Cloudflare: FlareSolverr нестабилен.
|
||||||
|
|
||||||
## Принцип работы
|
## Принцип работы
|
||||||
|
|
||||||
1. **Получение страницы.** `url` скачивается самим сервисом: сначала напрямую, при 403/503 или
|
1. **Получение страницы.** `url` скачивается самим сервисом: сначала напрямую, при 403/503 или
|
||||||
|
|||||||
Reference in new issue
Block a user