Commit Graph

17 Commits

Author SHA1 Message Date
chesirecatt 0320d2d331 Мусор в оглавлении сканов: фильтр поворота, проверка заголовков, вход для DjVu
Причиной мусорных заголовков у Брикмана оказался не порог кегля, а повёрнутый
на 90° текст: боковые врезки и подписи к таблицам распознаются в кашу
(«aoHegoduenueArdng») и попадают в h1, потому что кегль у них крупный. Замер:
105 строк из 17 300, все до одной брак. Блоки с неgоризонтальным направлением
строки выбрасываются целиком (is_rotated).

Остаток — подписи внутри иллюстраций — понижается до <p>, а не удаляется:
looks_garbled() в bookhtml.py, шесть признаков структуры, любых двух хватает.
Проверка повторяется после склейки соседних заголовков: по отдельности «LF»,
«FF» и «TIT» проходят как аббревиатуры, склеенные — обрывок таблицы.
Вместе: 99 h1 у Брикмана против 48.

djvu2html.py — третий вход конвейера. Родной текстовый слой DjVu чище нашего
OCR (у Праты 10,9 против 2,8 слов со смесью алфавитов на 10 000), а через PDF
он не проходит: ddjvu -format=pdf кладёт страницы картинками.

Самопроверки: djvu2html.py --selftest, pdf2html.py --selftest --selftest.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XCiPWRi3Jqy4saD2LwU1Dp
2026-08-25 19:03:08 +03:00
chesirecatt 356b9ddb22 OCR-слой: моно-признак не по флагу, кегль округляется, листинги склеиваются
Невидимый слой tesseract набран GlyphLessFont с выставленным моно-битом, и
is_mono() опознавала книгу как один сплошной листинг: измерено на Ansible после
OCR — pre 10498, p 0. Кегль в таком слое подгоняется под рамку слова и гуляет
внутри абзаца (9.0, 9.2, 9.4), из-за чего гистограмма размазывалась и основной
кегль книги определялся неверно; в OCR-слое он округляется до целого. Каждая
строка кода приходит отдельным блоком — соседние pre склеиваются переводом
строки, иначе листинг рассыпается на десяток однострочных.

Признак OCR-слоя считается по выборке страниц, обычные PDF идут прежним путём.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 19:42:14 +03:00
Илья Поляков 1a2c03f999 Мягкий перенос U+00AD: русские PDF рвали слова пополам
Питер и ДМК переносят строку мягким дефисом, а не обычным. Ветка склейки
проверяла только "-", поэтому строки соединялись через пробел: «введен ные»,
«Практиче ски». Теперь U+00AD снимается при склейке, остатки внутри строки
удаляются, а в ошибочно опознанных листингах перенос со строкой схлопывается.

Измерено на Шоттсе (Питер, 2020, 544 стр.): было 8 мягких переносов на
проверенной выборке, стало ноль.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2PNJCFFXvizoNjTFuTaqi
2026-08-24 11:50:26 +03:00
chesirecatt f19410d9ce Вход fb2 и метаданные цикла в EPUB
fb2html.py — третий вход в конвейер. FB2 в домашней библиотеке основной формат
(704 тысячи файлов), и без него конвейер до них не дотягивался. Разметка fb2
семантическая, поэтому задача та же, что у epub2html.py: свести чужие теги к
нашим. Уровень заголовка берётся из вложенности section.

pack_epub.py: --series и --series-index. Пишутся в двух видах — calibre-совместимый
meta понимают почти все читалки, belongs-to-collection требует EPUB 3. Без них
читалка не выстраивает книги цикла по порядку.
2026-08-21 19:45:37 +03:00
chesirecatt 43d6cfc456 glossary.py: двуязычный глоссарий из параллельных изданий цикла 2026-08-21 18:41:45 +03:00
chesirecatt 14c7fad763 Счётчик абзацев, вернувшихся на языке оригинала: упражнения вида [2] модель не переводит 2026-08-21 17:47:48 +03:00
chesirecatt 7ed6e500ca Перевод не возобновляем: --all переводит все главы заново, механизм progress не работает 2026-08-21 17:36:10 +03:00
chesirecatt a21a4d713b Автоматический подбор порогов вместо ручного + упаковка EPUB без calibre
Ручная настройка block_kind() под каждую книгу оказалась неприменима: у части
изданий имена шрифтов вычищены до «Fd820825», а флаги стилей у всех спанов
равны 4, то есть ни курсива, ни моноширинности по ним не видно. Пороги теперь
считаются из самого файла:

- кегль основного текста — по гистограмме символов;
- кегль глав — по частоте блочных кеглей, а не множителем от текста: иначе
  подзаголовки разделов попадают в главы и оглавление пухнет до трёхсот пунктов;
- глава отличается от раздела положением в верхней трети полосы, и правило
  применяется, только если глав так набирается хотя бы пять;
- красная строка — по распределению x0.

Листинг опознаётся флагом моноширинности, а при его отсутствии — кеглем мельче
основного текста плюс плотностью кодовой пунктуации.

Отсев картинок: мельче 24 pt (линейки и буллеты) и крупнее 60% площади полосы
(подложка отсканированной страницы). На «Программисте-прагматике» второе
правило убрало 370 сканов полос и уменьшило EPUB со 124 МБ до 17 МБ.

pack_epub.py собирает EPUB на стандартной библиотеке: calibre для упаковки не
нужен, а его установка требует root. Книга режется по h1, оглавление NCX
строится само. Тест test_pack_epub.py проверяет несжатый mimetype первым файлом,
экранирование разметки в метаданных, сохранение переносов в листинге и то, что
преамбула до первой главы не теряется.
2026-08-20 20:11:03 +03:00
chesirecatt 1bacd38292 Восстановление структуры EPUB по CSS для дампов из PDF
Дамп, собранный конвертером из PDF, теряет всю семантику: ни заголовков, ни
листингов, только абзацы с обфусцированными классами. Такие книги уезжали в
перевод одним куском, а код — вместе с текстом.

Теперь при нулевом числе заголовков или листингов разметка восстанавливается из
таблицы стилей книги: три самых крупных кегля становятся уровнями заголовков,
моноширинная гарнитура — листингом, соседние строки листинга склеиваются в один
блок. Книга со своей разметкой в этот путь не попадает.

Проверено на двух настоящих книгах: дамп APoSD — 1833 плоских абзаца стали 29
главами и 58 листингами; Страуструп с собственной разметкой не изменился.
2026-08-20 19:11:51 +03:00
chesirecatt db9fe5e0fa EPUB как второй вход в конвейер; листинги кода не переводятся и не ломают приёмку
- epub2html.py: EPUB -> тот же XHTML, что pdf2html.py, только стандартная
  библиотека. Уровень глав определяется по книге, а не берётся из <h1>:
  в EPUB там обычно название и части.
- pdf2html.py: листинг узнаётся по флагу моноширинного шрифта PyMuPDF,
  переносы и отступы внутри <pre> сохраняются, де-дефисация к коду не
  применяется.
- translate.py: <pre> исключён из проверок языка (английский код утягивал
  долю кириллицы ниже порога приёмки), рабочий каталог привязан к книге,
  устаревшие главы прошлого прогона чистятся, инлайновый <code> переживает
  переводчика.
- bookhtml.py: общий каркас документа и CSS для обоих входов.
- Тесты: test_epub2html.py на собранном в памяти EPUB, четыре новых случая
  в test_translate.py.
2026-08-20 17:58:09 +03:00
Илья Поляков 6c81673b4f Локальная озвучка через Silero: нормализатор русского текста под TTS, рендер по главам, замечание про AVX2 2026-08-03 14:58:54 +03:00
Илья Поляков 3bbd75b1c3 Озвучка: фрагменты режутся группами (не по абзацу), защита от тихого обрыва склейки, досинтез потерянных фрагментов 2026-08-03 11:23:11 +03:00
Илья Поляков a0c26b41bf Нарезка аудиокниги по главам: треки с ID3-тегами вместо одного слитного файла 2026-08-03 11:02:32 +03:00
Илья Поляков 93c40c76bf Обвязка озвучки: снятие маркеров разметки для TTS и проверка целостности синтеза 2026-08-03 10:48:04 +03:00
Илья Поляков b92a0a39c0 Проверка языка результата перевода: совпадения числа абзацев недостаточно; недостающие зависимости стороннего репозитория 2026-08-03 10:31:35 +03:00
Илья Поляков 9c7658df5e Стадия перевода: мост к book_translator без модификации стороннего репозитория 2026-08-03 07:59:12 +03:00
Илья Поляков 495d80f326 Оформить репозиторий как скил pdf-to-kindle: SKILL.md, скрипт в scripts/, установка симлинком 2026-08-03 07:32:11 +03:00