# Сбор датасета: `tools/collect.py` Интерактивный сборщик страниц rutracker / nnm-club / kinozal. Логин делает человек в обычном окне Chrome, скрипт пароли и cookie не видит. ```powershell .venv\Scripts\python tools\collect.py # меню ``` Главное меню состоит из двух пунктов и подменю: 1. **Собрать датасет**: окна, вход, сбор (новые и/или дособрать размеченные), `build`, `prepare_data`. 2. **Переобучить и протестировать**: `prepare_data`, обучение сегментатора в `models/segmenter_v2` (по желанию ещё и основной модели), `tests/run_tests.py`, таблица «правила / старые веса / новые веса» по трекерам и вывод, лучше ли новые; подмена весов только после вашего «y» (старые уходят в `models/segmenter_old_<время>`). 3. Дополнительно: отдельные шаги из таблицы ниже. Подменю «Дополнительно»: | Пункт | Что делает | |---|---| | 1 | Запускает Chrome (один процесс, общий профиль), открывает по **окну на трекер**, ждёт Enter, проверяет статус входа (вошли / гость / не определено) | | 2 | Новые раздачи из списков разделов (`viewforum.php?f=…`, для kinozal — адрес списка). По потоку на трекер, у каждого своё окно. Продолжает с места остановки | | 3 | Дособрать страницы для раздач, которые **уже размечены, но страницы нет** (nnm, kinozal) | | 4 | `data/raw` → `data/pages/*.txt` + новые строки в `data/labels.csv` | | 5 | Импорт старого harvest без браузера (только текст поста) | | 6 | Статус по трекерам | Те же операции без меню: `windows`, `collect`, `backfill`, `build`, `import-legacy`, `status` (см. `python tools/collect.py -h`). ## Интерфейс Главное меню (rich) показывает сводку (размечено, страниц, meta, модели, порт Chrome). Пункт 3 — статистика по трекерам: покрытие и состав датасета (тип, разрешение, кодек, годы, языки). Во время сбора идёт живая панель: по каждому трекеру состояние, прогресс, сохранено, ошибки, скорость (стр/мин по последним сохранениям), время, ETA, текущий раздел и последняя раздача. `Ctrl+C` останавливает сбор после текущей раздачи. ## Метаданные релизов: `data/meta.csv` `build` (и команда `meta`) строит из сохранённых страниц таблицу, одна строка на релиз (`tools/meta.py`; заходить на трекеры повторно не нужно): | Группа | Поля | |---|---| | Название | `title`, `ru_title`, `orig_title`, `year`, `kind` (film / series / cartoon / anime), `is_series`, `season`, `episodes`, `episodes_total`, `section` | | Видео | `quality`, `resolution`, `video_codec`, `hdr`, `bit_depth`, `fps`, `container`, `size_gb`, `duration_min` | | О фильме | `countries`, `genres`, `directors`, `cast`, `age_limit`, `mpaa`, `release_group`, `source_media` | | Звук | `audio_langs`, `orig_audio`, `n_audio`, `audio_tracks` (JSON: язык, кодек, каналы, битрейт, тип DUB/MVO/DVO/AVO/VO/ORIG, студия, серии, 18+) | | Субтитры | `sub_langs`, `sub_forced`, `sub_format` | Для старых данных (импорт `import-legacy`) поля берутся из текста поста; размер раздачи rutracker и nnm виден только на полной странице, поэтому у них он заполнится после дозагрузки (пункт «Дособрать»). ## Переиндексация без перекачки HTML страниц хранится в `data/raw`, поэтому после правки парсеров данные пересобираются без захода на трекеры: пункт 2 «Переобучить» начинается с вопроса «Переиндексировать data/raw?» (то же: `collect.py build --rewrite --relabel`). Страницы, `meta.csv` и метки размеченных релизов строятся заново текущими парсерами; прежний `labels.csv` копируется в `data/labels.bak_<время>.csv`. Не трогаются ручные метки (пункт 6), релизы без HTML (импорт старого harvest) и релизы, по которым парсер ничего не нашёл. ## Обучение по ссылкам Пункт 6 главного меню: вставляете ссылки на раздачи (rutracker / nnm / kinozal), страницы скачиваются вашим Chrome, парсер строит метки, вы правите их в таблице («2 18» — переключить 18+, «3 d» — удалить, «1 t <тип>», «1 s <студия>») и сохраняете. Метки заменяют прежние строки релиза в `data/labels.csv` (`studio_source=manual`), id попадает в `data/manual_ids.txt`: такие релизы всегда в train и повторяются при обучении ×5. Дальше «Переобучить». Метки и инференс берут 18+ и параметры дорожки (кодек, каналы, битрейт) не только из строк «Перевод», но и из строк «Аудио … |Студия| 18+» (`src/audio18.py`): у одной студии может быть обычная дорожка и дорожка 18+. ## Автопоиск разделов При первом запуске пункта 1 (режим «новые раздачи») после входа в аккаунты приложение само находит разделы с зарубежными фильмами и сериалами (`tools/discover.py`) и кэширует их в `data/raw/_sections.json`: * **rutracker, nnm**: разделы выбираются по названию (зарубежное кино и сериалы, мультфильмы, новинки, классика, годовые «Фильмы 2021-2025»; наше кино, азиатское, музыка, Apple, коллекции исключены). Форматы DVD / HD / UHD / 3D и годы покрываются самими разделами. * **kinozal**: ваши списки «все фильмы» (`c=1002`) и «сериалы» (`c=46`), затем сетка год × формат × категория (4K только с 2012 и т. д.). * Лимит делится между разделами поровну, чтобы выборка не состояла из одного. * Раздел, который не удалось проверить, остаётся в списке; результат неполной загрузки кэш не затирает. Искать заново: «Дополнительно» → 7 или `collect.py discover --force`. ## Сохранённые страницы читаемы В `data/raw/<трекер>/.html` лежит снимок страницы «как на сайте»: UTF-8 (``), `` на адрес раздачи (картинки подгружаются с сайта), таблицы стилей вынесены в `data/raw/_css/<хеш>.css` (общие для всех страниц), скрипты убраны, чтобы страница из файла не уходила на сайт. Открывается двойным кликом. Таблицы стилей чужого домена (rutracker, nnm) остаются ссылкой на сайт и работают при наличии интернета. Страницы, сохранённые раньше, чинит `python tools/collect.py repair-html` (кодировка, ``, стили сайта одной загрузкой со страницы трекера; нужен Chrome и вход, `--no-css` — без браузера). Время файлов не меняется, кэши разбора остаются. ## Где что лежит * `data/raw/<трекер>/.html|json` — страница целиком (outerHTML после загрузки вкладок kinozal) и поля для парсера. В git не попадает. * Профиль Chrome — `%LOCALAPPDATA%\dub-ai-harvest\chrome-profile`, вне репозитория (`DUB_CHROME_PROFILE`, `DUB_CHROME_PORT` меняют каталог и порт). * `tools/harvest/harvest_core.py` — перенесённый `dataset.py` (CDP-клиент и парсеры меток), единственная правка — переменные окружения для путей. ## id страниц `release_id` в `labels.csv` совпадает с именем `data/pages/.txt`. Раздачи, размеченные раньше, сохраняют прежний числовой id (их разбиение train/test не меняется); новые получают префикс `rt-`, `nnm-`, `kz-`, чтобы id разных трекеров не пересекались. Коллизий в текущих данных нет, но один id уже встречался в сырых данных двух трекеров. ## Полные и урезанные страницы Импорт старого harvest (пункт 5) даёт страницу из сохранённого текста поста: без шапки сайта, соседних раздач и заголовка. Такие страницы перечислены в `data/pages_postonly.txt`. При обучении и оценке сегментатора их стоит считать отдельно: на инференсе модель видит полную страницу. ## Что в метках слабое Метки строятся парсерами (`tools/harvest/harvest_core.py`), поэтому они повторяют логику правил. Для нарезки внутри строки («Дублированный, многоголосый») нужна ручная проверка — режим ревью ещё не сделан. ## Разнообразная выборка (режим balanced) Списки разделов идут от новых к старым, поэтому чтение подряд даёт только свежие релизы. По умолчанию (`Настройки` → режим `balanced`, `tools/diversity.py`): * страницы раздела берутся **вразброс по всей глубине** (число страниц читается из пагинации; посещённые запоминаются в `_state.json`, круг по разделу продолжается с места остановки); * с каждой страницы берётся не всё, а `per_page` тем (по умолчанию 6) из **самых малочисленных корзин** «год (до 2010 — десятилетие) × качество (4K / 1080 / 720 / SD) × фильм/сериал»; уже собранное считается по `data/meta.csv`; * режим `sequential` — прежнее чтение подряд. ## Скорость переиндексации Разбор HTML (страницы, метки, `meta.csv`) идёт в нескольких процессах: по умолчанию число ядер минус два (до 12); меняется в «Настройки» (`workers`, 0 — авто, 1 — без процессов). `meta.csv` берёт текст из уже записанных `data/pages`, а не разбирает HTML второй раз. На выборке в 600 раздач — 45 с → 8 с при тех же результатах. ## Если сбор «завис» * В панели у трекера теперь видно номер раздачи, которая качается: `скачиваю 6894333`. * Короткая страница (закрытая или перенесённая тема), которая загрузилась и не меняется, принимается через ~5 с; раньше сборщик ждал таймаут 45 с и повторял его. * Раздача дольше 40 с попадает в ошибки как «медленно, N с» (id можно открыть вручную). * Сторож: раздача дольше 150 с — вызов к вкладке обрывается, вкладка переподключается, сбор идёт дальше. ## Скорость и повторный разбор * **Вкладки.** Сбор идёт в нескольких вкладках одного трекера (общий Chrome, общий вход). Число вкладок — пункт меню «Настройки» (1–4, по умолчанию 3), запоминается; в командах `collect` / `backfill` флаг `--tabs`. Больше вкладок — быстрее, но выше риск лимитов и проверок Cloudflare: при ошибках снизьте до 1–2. * **Без лишних пауз.** Ожидание вкладок kinozal и загрузки страниц опрашивает состояние, а не спит фиксированное время; тяжёлые темы не ждут `complete`; удалённые раздачи определяются сразу и запоминаются (`data/raw/_dead.json`). * **Ничего не разбирается дважды.** Сбор пропускает уже сохранённые, размеченные и удалённые раздачи и продолжает списки с места остановки. `build` запоминает «подпись» файлов (`data/raw/_built.json`, `_meta_cache.json`): повторный запуск разбирает только новое и изменённое (на 2800 релизах: 59 с → 2 с). Кэш сбрасывается сам, если поднять `PARSE_VERSION` (collect.py) или `META_VERSION` (meta.py) после правки парсеров; вручную: «Дополнительно» → 4 → «Пересобрать всё заново».