API: видео, тип релиза и субтитры в ответе релиза; Atmos и kHz у дорожек
docker / build (push) Successful in 1m18s
docker / build (push) Successful in 1m18s
src/techinfo.py — правила по строкам «Видео:», «Тип релиза:»/«Качество», «Контейнер:», «Продолжительность:», «Субтитры:» и заголовку: поля video (кодек, размер кадра, класс разрешения, fps, битрейт, битность, HDR, профиль DV), release (тип, нормализованный источник, контейнер, продолжительность), subtitles (языки с forced/full/SDH, формат, вшитые). audio дорожек и original: khz и atmos (вход модели не меняется). title_from_html больше не рвёт заголовок rutracker пробелами (<span>/<wbr> на каждом слове). Покрытие на 600 страницах каждого трекера: видео 90/93/100%, e2e озвучки без изменений. Тесты 275 ok. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
89ffe4375b
commit
dc19fe6255
9 files changed
+409
-16
No files matched your search
+54
-5
@@ -38,8 +38,16 @@
|
||||
"studios": [{"studio": "LostFilm", "translation_type": "проф. многоголосый", "lang": "RUS", "is_18plus": false, "episodes": "1-4"}],
|
||||
"translation_types": ["проф. многоголосый"],
|
||||
"is_18plus": false,
|
||||
"original": {"lang": "ENG", "codec": "E-AC3", "channels": 6, "bitrate_kbps": 768, "raw": "English E-AC3+Atmos / 5.1 / 48 kHz / 768 kbps |Original|"},
|
||||
"original": {"lang": "ENG", "codec": "E-AC3", "channels": 6, "bitrate_kbps": 768, "khz": 48, "atmos": true, "raw": "English E-AC3+Atmos / 5.1 / 48 kHz / 768 kbps |Original|"},
|
||||
"series": {"season": "2", "episodes": "1-9", "total": 10, "by_studio": {"LostFilm": "1-4"}, "full_release": []},
|
||||
"video": {"codec": "HEVC", "width": 3840, "height": 2160, "resolution": "2160p", "fps": 23.976, "bitrate_kbps": 24800,
|
||||
"bit_depth": 10, "hdr": ["Dolby Vision", "HDR10+", "HDR10"], "dv_profile": "8", "raw": "MPEG-H HEVC Video / 24,8 Mbps / 3840x2160 / …"},
|
||||
"release": {"quality": "WEB-DL 2160p Dolby Vision", "source": "WEB-DL", "container": "MKV", "duration": "01:38:12", "duration_sec": 5892},
|
||||
"subtitles": {"languages": ["RUS", "UKR", "ENG"],
|
||||
"tracks": [{"lang": "RUS", "forced": true, "full": false, "sdh": false},
|
||||
{"lang": "UKR", "forced": true, "full": true, "sdh": true},
|
||||
{"lang": "ENG", "forced": false, "full": true, "sdh": true}],
|
||||
"format": "softsub (SRT)", "hardsub": false, "raw": "Русские (Forced), Украинские (Forced, 2x Full, SDH), Английские (Full, SDH)"},
|
||||
"title": "Название раздачи",
|
||||
"segmenter": "model",
|
||||
"tracker": "rutracker"
|
||||
@@ -50,14 +58,39 @@
|
||||
|---|---|---|
|
||||
| `tracks` | array | дорожки релиза без дублей (дубль — одинаковые тип + студия) |
|
||||
| `studios` | array | уникальные `{studio, translation_type, lang, is_18plus, episodes}`; `lang` — язык дорожки студии (как в `tracks[].lang`, может быть `null`). Одна студия с русским и украинским дубляжом даёт две записи |
|
||||
| `original` | object \| null | оригинальная дорожка из строки «Аудио … \|Original\|»: `{lang, codec, channels, bitrate_kbps, raw}` (поля могут быть `null`); `null` — такой строки на странице нет |
|
||||
| `original` | object \| null | оригинальная дорожка из строки «Аудио … \|Original\|»: `{lang, codec, channels, bitrate_kbps, khz, atmos, raw}` (поля могут быть `null`, `atmos` — bool); `null` — такой строки на странице нет |
|
||||
| `translation_types` | array of string | отсортированный набор типов (значения — из таблицы классов ниже) |
|
||||
| `is_18plus` | bool | `true`, если 18+ хотя бы у одной дорожки |
|
||||
| `series` | object \| null | сезон, выпущенные серии, «какая студия какие серии» (для Sonarr); `null` — сведений нет |
|
||||
| `video` | object \| null | видео из строки «Видео:» / «Video:» (у nnm — также «Видеокодек», «Размер кадра», «Битрейт видео»), см. ниже; `null` — строки нет |
|
||||
| `release` | object \| null | тип релиза, контейнер, продолжительность, см. ниже; `null` — ничего из этого на странице нет |
|
||||
| `subtitles` | object \| null | субтитры из строк «Субтитры:», «Субтитры 2:», «Язык субтитров:» (нет строк — языки из «Sub (Rus, Eng)» заголовка), см. ниже; `null` — о субтитрах ничего не сказано |
|
||||
| `title` | string \| null | заголовок раздачи, если найден |
|
||||
| `segmenter` | `"model"` \| `"rules"` | чем страница разбита на строки дорожек: обученным сегментатором или запасными правилами |
|
||||
| `tracker` | string | только для `url`: `rutracker`, `nnm`, `kinozal` или `lostfilm` |
|
||||
|
||||
`video` (все поля, кроме `hdr` и `raw`, могут быть `null`):
|
||||
`codec` — `HEVC`, `AVC`, `AV1`, `VP9`, `VC-1`, `MPEG-2`, `XviD`, `DivX`, `MPEG-4`;
|
||||
`width`/`height` — размер кадра; `resolution` — класс по ширине (`2160p`, `1440p`, `1080p`, `720p`; кадр с
|
||||
полосами 1920x800 — тоже `1080p`), для SD — высота кадра (`576p`, `400p`); `fps`; `bitrate_kbps`;
|
||||
`bit_depth` — 8/10/12; `hdr` — массив из `Dolby Vision`, `HDR10+`, `HDR10`, `HLG` или просто `HDR`, если вид
|
||||
не назван (ищется в строке видео, «HDR format», типе релиза и заголовке), пустой — HDR нет; `dv_profile` —
|
||||
профиль Dolby Vision строкой («8», «5»); `raw` — строка видео целиком.
|
||||
|
||||
`release`: `quality` — значение «Тип релиза» / «Качество видео» / «Качество» как на странице (без
|
||||
«\| Исходник: …»); `source` — нормализованный источник: `UHD BDRemux`, `BDRemux`, `WEB-DLRip`, `WEB-DL`, `WEBRip`,
|
||||
`BDRip`, `HDRip`, `Blu-ray`, `DVDRip`, `DVD9`, `DVD5`, `HDTVRip`, `HDTV`, `SATRip`, `TVRip`, `DVB`, `VHSRip`,
|
||||
`DCPRip`, `IPTV`, `CAMRip`, `DVD` (из «Качества», иначе из заголовка); `container` — `MKV`, `MP4`, `AVI`, `M2TS`,
|
||||
`ISO`, `DVD-Video`, `TS`, `WEBM`, `MOV`, `WMV` (kinozal строку контейнера обычно не пишет — тогда `null`);
|
||||
`duration` — «Продолжительность» как на странице («01:38:12», «18 x ~ 00:20:00»); `duration_sec` — секунды,
|
||||
только если это одно значение ЧЧ:ММ:СС фильма (не серии и не список файлов). Любое поле может быть `null`.
|
||||
|
||||
`subtitles`: `languages` — коды языков по порядку (те же коды, что у `lang` дорожки); `tracks` — по записи
|
||||
на язык: `{lang, forced, full, sdh}` (флаги «Forced/форсированные/надписи», «Full/полные», «SDH/для
|
||||
слабослышащих» объединяются по всем строкам); `format` — «Формат субтитров» как на странице или `null`;
|
||||
`hardsub` — субтитры вшиты в видео; `raw` — исходные строки через «; ». «Субтитры: нет/отсутствуют» даёт
|
||||
объект с пустым `languages` — субтитров точно нет; `null` — страница о субтитрах молчит.
|
||||
|
||||
`series`: `season` — номер сезона строкой или `null`; `episodes` — выпущенные серии («1-9»);
|
||||
`total` — всего серий; `by_studio` — `{студия: серии}`; `full_release` — студии без указанных серий
|
||||
(для сериала это значит «озвучены все вышедшие серии»). Подробности — в [integration.md](integration.md).
|
||||
@@ -79,7 +112,7 @@
|
||||
| `lang_source` | `"audio"` \| `"model"` \| `"text"` \| null | откуда язык, в порядке приоритета: строка «Аудио» страницы (`Ukrainian E-AC3 …` → `UKR`, самый надёжный источник), нейросеть (классы `ENG`/`RUS`/`UKR`, порог 0.5; без строки «Аудио» ей приходится угадывать по тексту), слова в тексте («Украинский дубляж») |
|
||||
| `role` | string | `перевод`, `оригинал` (оригинальная дорожка без озвучки) или `комментарии` (комментарии режиссёра и т. п.) |
|
||||
| `official` | bool | в строке «Аудио» есть слова «официальный» / «лицензионный» / «licensed» |
|
||||
| `audio` | object \| null | `{codec, channels, bitrate_kbps}` из строки «Аудио» страницы (`"E-AC3"`, `6`, `768`; `channels` — число каналов, «5.1» → 6); каждое поле может быть `null`; весь объект `null`, если строка не найдена |
|
||||
| `audio` | object \| null | `{codec, channels, bitrate_kbps, khz, atmos}` из строки «Аудио» страницы (`"E-AC3"`, `6`, `768`, `48`, `true`; `channels` — число каналов, «5.1» → 6; `khz` — частота дискретизации, 44.1 / 48; `atmos` — в строке есть «Atmos», кодек при этом остаётся `E-AC3`/`TrueHD`); поля, кроме `atmos`, могут быть `null`; весь объект `null`, если строка не найдена |
|
||||
| `source` | `"page"` \| `"title"` | только в ответе релиза: дорожка найдена в описании или студия взята из заголовка раздачи |
|
||||
| `episodes` | string \| null | серии, которые озвучивает дорожка («1-4», «1,3-5»); `null` — серии не указаны (покрывает весь релиз) |
|
||||
| `episode_ranges` | array | то же в виде `[[1, 4]]`; пусто, если серий нет |
|
||||
@@ -157,7 +190,7 @@ type Track = {
|
||||
lang_source: "model" | "audio" | "text" | "url" | null; // "url" — ссылка lostfilm.tv; null вместе с lang
|
||||
role: "перевод" | "оригинал" | "комментарии"; // никогда null
|
||||
official: boolean;
|
||||
audio: { codec: string | null; channels: number | null; bitrate_kbps: number | null } | null;
|
||||
audio: { codec: string | null; channels: number | null; bitrate_kbps: number | null; khz: number | null; atmos: boolean } | null;
|
||||
// только в ответе релиза (html / url):
|
||||
source: "page" | "title";
|
||||
episodes: string | null; // "1-4", "1,3-5"; null — серии не указаны
|
||||
@@ -167,7 +200,8 @@ type Track = {
|
||||
type Release = {
|
||||
tracks: Track[]; // может быть пустым массивом
|
||||
studios: { studio: string | null; translation_type: string; lang: string | null; is_18plus: boolean; episodes: string | null }[];
|
||||
original: { lang: string | null; codec: string | null; channels: number | null; bitrate_kbps: number | null; raw: string } | null;
|
||||
original: { lang: string | null; codec: string | null; channels: number | null; bitrate_kbps: number | null;
|
||||
khz: number | null; atmos: boolean; raw: string } | null;
|
||||
translation_types: string[];
|
||||
is_18plus: boolean;
|
||||
series: {
|
||||
@@ -177,6 +211,19 @@ type Release = {
|
||||
by_studio: Record<string, string>; // { "LostFilm": "1-4" }, может быть {}
|
||||
full_release: string[]; // студии без указанных серий
|
||||
} | null; // null — ни сезона, ни серий в раздаче нет
|
||||
video: {
|
||||
codec: string | null; width: number | null; height: number | null; resolution: string | null;
|
||||
fps: number | null; bitrate_kbps: number | null; bit_depth: number | null;
|
||||
hdr: string[]; // [] — HDR нет
|
||||
dv_profile: string | null; raw: string;
|
||||
} | null;
|
||||
release: { quality: string | null; source: string | null; container: string | null;
|
||||
duration: string | null; duration_sec: number | null } | null;
|
||||
subtitles: {
|
||||
languages: string[]; // [] — «Субтитры: нет»
|
||||
tracks: { lang: string; forced: boolean; full: boolean; sdh: boolean }[];
|
||||
format: string | null; hardsub: boolean; raw: string | null;
|
||||
} | null; // null — о субтитрах на странице ничего нет
|
||||
title: string | null;
|
||||
segmenter: "model" | "rules";
|
||||
tracker?: "rutracker" | "nnm" | "kinozal" | "lostfilm"; // только для url
|
||||
@@ -226,6 +273,8 @@ Cloudflare: FlareSolverr нестабилен.
|
||||
по тексту; отдельно берётся `original`; определяются `role`, `official`, `audio`.
|
||||
7. **Агрегат релиза.** Дубли (тип + студия) склеиваются; студии из заголовка раздачи, которых нет
|
||||
в описании, добавляются с `source: "title"`; серии и сезон разбираются правилами (`src/episodes.py`).
|
||||
8. **Техданные** (`video`, `release`, `subtitles`) — правилами по строкам «Видео:», «Тип релиза:»,
|
||||
«Контейнер:», «Продолжительность:», «Субтитры:» и заголовку (`src/techinfo.py`), без нейросети.
|
||||
|
||||
Размеченные данные (`data/labels.csv`) используются только при обучении: на них учатся метки
|
||||
`translation_type`, спан студии, 18+ и язык. Схема файла и происхождение меток — в
|
||||
|
||||
@@ -37,12 +37,18 @@ python -m src.predict --url https://kinozal.tv/details.php?id=1 --cookie "uid=..
|
||||
| `studios` | уникальные `{studio, translation_type, is_18plus}` |
|
||||
| `translation_types` | отсортированный список типов релиза |
|
||||
| `is_18plus` | `true`, если 18+ хотя бы у одной дорожки |
|
||||
| `original`, `series` | оригинальная дорожка; сезон и серии |
|
||||
| `video` | кодек, разрешение, fps, битрейт, битность, HDR (Dolby Vision / HDR10+ / HDR10 / HLG) |
|
||||
| `release` | тип релиза («WEB-DL», «BDRemux»…), контейнер, продолжительность |
|
||||
| `subtitles` | языки субтитров с пометками forced / full / SDH, формат, вшитые ли |
|
||||
| `title` | заголовок раздачи (если найден в HTML) |
|
||||
| `tracker` | только для `--url` |
|
||||
|
||||
Дорожки дедуплицируются по (тип, студия). Студии из заголовка раздачи вида
|
||||
`ПМ (LostFilm)`, которых нет в описании, добавляются с `source: "title"`
|
||||
(у остальных `source: "page"`). `--text` по-прежнему возвращает только `tracks`.
|
||||
Все поля и их значения — в [api-reference.md](api-reference.md); `video`, `release`, `subtitles`
|
||||
считаются правилами (`src/techinfo.py`), без нейросети.
|
||||
|
||||
## Python API
|
||||
|
||||
|
||||
+6
-1
@@ -41,7 +41,12 @@ API:
|
||||
| `lang`, `lang_confidence`, `lang_source` | язык дорожки (`RUS`, `UKR`, `ENG`, …); источник: `model` (языковая голова), `audio` (строка «Аудио»), `text` (слова в строке дорожки) или `null` |
|
||||
| `role` | `перевод` / `оригинал` / `комментарии` (по строке «Аудио» и тексту, правилами) |
|
||||
| `official` | в строке «Аудио» сказано «официальный» / «лицензионный» |
|
||||
| `audio` | `{codec, channels, bitrate_kbps}` из строки «Аудио» (или `null`) |
|
||||
| `audio` | `{codec, channels, bitrate_kbps, khz, atmos}` из строки «Аудио» (или `null`) |
|
||||
|
||||
Ответ релиза (`html`/`url`) кроме дорожек несёт `video`, `release` и `subtitles` — разрешение, HDR,
|
||||
тип релиза, контейнер, продолжительность, языки субтитров; поля и значения — в
|
||||
[api-reference.md](api-reference.md). ONNX-путь (Б) их не считает: это правила `src/techinfo.py`,
|
||||
их нужно повторить на стороне клиента или ходить в HTTP-сервис.
|
||||
|
||||
Русский и украинский дубляж одной студии — две отдельные дорожки; так же раздельны обычная
|
||||
дорожка студии и её дорожка 18+ (если на странице две строки «Аудио» с одной студией).
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
| 7 тесты | `run_tests.py`: 57 ok (URL allowlist/SSRF, декодирование, заглушки Cloudflare/логина, title, слияние, агрегат) |
|
||||
| 8 `target/` | сделано |
|
||||
| 10 аудит дорожек | сделано 02.11.2026: `tools/audit_tracks.py` → `reports/tracks_audit.md` (план из 5 пунктов). Пункт 1 — студии из кодек-строк в разметке (`codec_line_rows`, +6 428 строк); модель переобучена: test joint exact 0.891 → 0.906, e2e P/R kinozal 0.745/0.850 → 0.766/0.879, rutracker 0.866/0.859 → 0.877/0.870, nnm 0.845/0.829 → 0.838/0.825. Пункты 2–5 и сегментатор на новой разметке — открыты |
|
||||
| 11 техданные релиза | сделано 02.11.2026: в ответе релиза `video` (кодек, разрешение, fps, битрейт, битность, HDR, профиль DV), `release` (тип, контейнер, продолжительность), `subtitles` (языки, forced/full/SDH, формат, вшитые); у дорожек `audio.khz` и `audio.atmos` — правила `src/techinfo.py`. Покрытие на 600 сохранённых страницах каждого трекера: видео найдено на 90% rutracker / 93% nnm / 100% kinozal, кодек — у 91% / 92% / 97% из них. Заголовок rutracker больше не рвётся пробелами («Галактическо е»). В ONNX-клиентах этих полей нет |
|
||||
|
||||
## Открытые вопросы
|
||||
|
||||
|
||||
Reference in new issue
Block a user