- Rust 80.6%
- Shell 19.4%
| .forgejo/workflows | ||
| data | ||
| scripts | ||
| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
inpx_creator_rs
Rust-утилита для генерации совместимых с Flibusta файлов .inpx по SQL-дампам и локальным zip-архивам с поддержкой инкрементального merge.
Проект также используется как backend для сценария обновления через scripts/run_cycle.sh: скачивание daily-архивов, скачивание SQL, сборка недельных архивов, месячная упаковка и итоговое обновление flibusta.inpx.
Проект рассчитан на большие библиотеки, где полная пересборка слишком дорогая и на практике нужен инкрементальный режим.
Что делает утилита
- импортирует таблицы Flibusta из SQL-дампов во временную SQLite-базу
- строит содержимое INPX по метаданным из БД и содержимому архивов
- поддерживает локальную группированную раскладку
classic, пригодную для использования сinpx-web:https://github.com/bookpauk/inpx-web - поддерживает раскладку
archive, где каждому входному zip соответствует свой.inp - умеет инкрементально сливать новые данные с уже существующим
.inpx - умеет читать метаданные FB2 из новых архивов глубже, чем просто по SQL
- содержит pipeline-подкоманды для скачивания и сборки архивов, которые использует
run_cycle.sh
Реализованные возможности
SQL import- читает SQL-дампы из каталога
--sql-dir
- читает SQL-дампы из каталога
Выходные метафайлыcollection.infoversion.infostructure.infoв локальном группированном режимеarchives.infoв локальном группированном режиме
Раскладкиclassicпо умолчанию:fb2|usr+ язык +ok|del+ жанровый/meta-суффиксarchive: один.inpна один входной zip-архив
Инкрементальный merge--merge-base existing.inpx- дедупликация и замена по
LIBID - merge содержимого
archives.info - удаление старых архивов из
archives.info, если новый архив полностью перекрывает их числовой диапазон в том же потокеfb2илиusr
Обработка подмножества архивов--archives-list path/to/list.txt— один архив в строке- полезно для weekly-обновлений, когда нужно обработать только новые архивы
MetaGenres--metagenres /path/to/metagenres.xls- использует лист
libgenrelist-meta(GenreCode -> meta) для более точного выбора суффиксов вclassic
Глубокий разбор FB2--read-fb2 none|last|all--prefer-fb2 ignore|merge|complement|replace- читает FB2 прямо из zip для новых и выбранных записей и использует sequence и метаданные из самих книг
Файлы MetaGenres в репозитории
Оба файла лежат в data/:
data/metagenres.xls— исходный файлdata/metagenres.csv— UTF-8-копия для удобного diff и ревью
Поведение загрузчика для --metagenres:
- если путь оканчивается на
.csv, используется CSV-парсер - иначе, для
.xlsили.xlsx, используется парсер табличного файла
Для автоматизации рекомендуется:
- использовать
--metagenres ./data/metagenres.csv - хранить
data/metagenres.xlsкак исходный upstream-артефакт
Сборка
cargo build --release
Сценарий обновления
Основная точка входа:
./scripts/run_cycle.sh
run_cycle.sh работает как оркестратор и делегирует загрузку и сборку бинарнику inpx_creator_rs.
Текущая логика работы:
- при каждом запуске скачиваются daily-архивы
- по воскресеньям скачиваются SQL, собираются недельные архивы и обновляется
flibusta.inpx - первого числа месяца при необходимости скачиваются SQL, хвостовые daily-архивы превращаются в weekly, затем собираются месячные архивы и обновляется
flibusta.inpx - если первое число выпадает на воскресенье, weekly-архивы все равно собираются, но промежуточный weekly merge в INPX пропускается, потому что сразу после него идет monthly merge
Удержание weekly-архивов:
scripts/run_cycle.shуправляет этим черезKEEP_WEEKLY- текущее значение по умолчанию —
KEEP_WEEKLY=0, то есть weekly-архивы удаляются после включения в monthly
Режим обработки:
PROCESS_MODE="all"— обрабатывать и FB2, и USRPROCESS_MODE="fb2"— обрабатывать только FB2PROCESS_MODE="usr"— обрабатывать только USR
Если нужен облегченный вариант библиотеки без USR-архивов, можно использовать PROCESS_MODE="fb2".
Схема именования архивов:
- daily FB2:
f.fb2.*.zip - daily USR:
f.n.*.zip - weekly FB2:
a.fb2-<start>-<end>.zip - weekly USR:
a.usr-<start>-<end>.zip - итоговые архивы библиотеки FB2:
f.fb2-<start>-<end>.zip - итоговые архивы библиотеки USR:
f.usr-<start>-<end>.zip
Для weekly и monthly используется сквозная нумерация по общей цепочке FB2 + non-FB2:
- если у одного потока отсутствует первый или последний диапазон, имя архива все равно берется по общим границам обоих потоков
- например,
a.fb2-864865-865122.zipиa.usr-864865-865122.zipдопустимы даже если в USR нет архива864960-865019
Структура каталога после распаковки релиза
inpx_creator_rs-linux-x86_64/
inpx_creator_rs
README.md
data/
metagenres.csv
metagenres.xls
scripts/
run_cycle.sh
sql/ # распакованные SQL-дампы
runtime/
state/ # urllist, last_* маркеры, временные INPX, backup
logs/ # run_cycle.log
fb2_daily/ # daily FB2 zip до weekly-упаковки
usr_daily/ # daily USR zip до weekly-упаковки
sql_daily/ # скачанные .sql.gz
tmp/
Обновлятор предполагается распаковывать в один каталог на NAS, например в /Media/Flibusta.Net/inpx_creator_rs-linux-x86_64. Все служебные данные остаются внутри этой папки, а боевая библиотека и production flibusta.inpx могут жить отдельно.
Модель путей по умолчанию в scripts/run_cycle.sh:
LIBRARY_ROOT=/volume1/Media/Flibusta.Net- недельные и месячные архивы пишутся в
$LIBRARY_ROOT - production
flibusta.inpxчитается и обновляется по пути$LIBRARY_ROOT/flibusta.inpx - SQL-дампы и служебное состояние хранятся внутри каталога обновлятора
Недостающие внутренние каталоги создаются автоматически при запуске run_cycle.sh.
Webhook-уведомления
В scripts/run_cycle.sh есть переменная WEBHOOK_URL.
Она используется для отправки HTTP webhook-уведомлений в двух случаях:
- если сам сценарий завершился ошибкой
- если обнаружена дыра в сквозной нумерации архивов перед weekly или monthly сборкой
Проверка дыр учитывает общую последовательность FB2 и non-FB2:
- если для диапазона есть только
f.fb2.*.zipили толькоf.n.*.zip, это не считается дырой само по себе - ошибкой считается только настоящий разрыв в общей цепочке диапазонов или пересечение несовместимых диапазонов
Если уведомления не нужны, оставьте:
WEBHOOK_URL=""
Если webhook включен, скрипт отправляет JSON с типом события, текстом сообщения, именем хоста и временем события.
Развертывание
После распаковки пакета:
- При необходимости поправьте путь
LIBRARY_ROOTвscripts/run_cycle.sh. - При необходимости выберите режим обработки через
PROCESS_MODEвscripts/run_cycle.sh. - Проверьте запуск бинарника:
./inpx_creator_rs --help
- Запустите цикл обновления:
./scripts/run_cycle.sh
Справка по CLI
Основной режим сборки INPX:
--sql-dir <PATH> Каталог SQL-дампов (по умолчанию: ./sql)
--out <PATH> Путь к выходному .inpx
--db-name <NAME> Имя библиотеки в метаданных (по умолчанию: flibusta)
--archives-dir <PATH> Каталог локальных zip-архивов
--process <fb2|usr|all> Фильтр типа книг (по умолчанию: fb2)
--layout <classic|archive> Режим раскладки (по умолчанию: classic)
--merge-base <PATH> Существующий .inpx для инкрементального merge
--archives-list <PATH> Список архивов для обработки, по одному в строке
--metagenres <PATH> Путь к metagenres.xls или metagenres.csv
--read-fb2 <none|last|all> Режим глубокого чтения FB2 (по умолчанию: none)
--prefer-fb2 <ignore|merge|complement|replace>
Приоритет FB2 по отношению к данным из БД (по умолчанию: ignore)
Pipeline-подкоманды:
download-daily --source-url <URL> [--process <fb2|usr|all>] --data-dir <PATH> --fb2-daily-dir <PATH> --usr-daily-dir <PATH>
download-sql --source-url <URL> --data-dir <PATH> --sql-daily-dir <PATH> --output-sql-dir <PATH>
make-archives --fb2-daily-dir <PATH> --usr-daily-dir <PATH> --output-dir <PATH> [--fb2-prefix <PREFIX>] [--usr-prefix <PREFIX>]
pack-archives --archives-dir <PATH> --input-prefix <PREFIX> --output-prefix <PREFIX> [--range-prefix <PREFIX>]... [--keep-source]
Значение параметров
--sql-dir <PATH>- каталог с SQL-дампами
lib.libbook.sqlи другими таблицами - используется для построения временного SQLite-каталога
- каталог с SQL-дампами
--out <PATH>- путь к итоговому
.inpx - если параметр не задан, имя генерируется автоматически из имени базы и даты дампа
- путь к итоговому
--db-name <NAME>- логическое имя коллекции, записываемое в
collection.info
- логическое имя коллекции, записываемое в
--archives-dir <PATH>- каталог с локальными zip-архивами
*.zip - включает локальный offline-режим сборки INPX
- каталог с локальными zip-архивами
--process <fb2|usr|all>fb2: включать только FB2-книги и FB2-архивыusr: включать только non-FB2-книги и архивыall: включать оба потока
--layout <classic|archive>classic: группирует строки поtype + lang + del + suffixarchive: создает по одному.inpна каждый входной архив
--merge-base <PATH>- существующий
.inpx, который используется как базовый для merge - merge удаляет старые записи по
LIBID, добавляет новые и переиспользует исторические suffix-группы
- существующий
--archives-list <PATH>- текстовый файл со списком архивов, по одному имени в строке
- в текущем запуске будут обработаны только эти архивы
- это основной режим для weekly/monthly инкрементальных обновлений
--metagenres <PATH>- путь к
metagenres.xlsилиmetagenres.csv - используется для более точного выбора meta-категории в
classic
- путь к
--read-fb2 <none|last|all>none: не читать FB2 XML из архивовlast: читать FB2 только для пропущенных книг сbook_id > max_db_book_idall: читать FB2 для всех подходящих новых или отсутствующих записей
--prefer-fb2 <ignore|merge|complement|replace>- задает приоритет между данными БД и FB2
ignore: доверять только БДmerge: если в FB2 есть sequence, заменить sequence-поля из БДcomplement: использовать sequence из FB2 только если в БД оно пустоеreplace: заменять author/genre/title/sequence/lang/keywords значениями из FB2, если они есть
Типовые сценарии
1. Полная локальная сборка grouped INPX
./inpx_creator_rs \
--sql-dir ./sql \
--archives-dir /volume1/Media/Flibusta.Net \
--layout classic \
--metagenres ./data/metagenres.csv \
--process all \
--out ./flibusta_full_local.inpx
2. Недельное инкрементальное обновление
Подготовьте список новых архивов, например ./runtime/state/archives_weekly.txt.
./inpx_creator_rs \
--sql-dir ./sql \
--archives-dir /volume1/Media/Flibusta.Net \
--archives-list ./runtime/state/archives_weekly.txt \
--merge-base /volume1/Media/Flibusta.Net/flibusta.inpx \
--layout classic \
--metagenres ./data/metagenres.csv \
--process all \
--read-fb2 all \
--prefer-fb2 merge \
--out ./runtime/state/flibusta_next.inpx
Пояснение по параметрам:
./inpx_creator_rs— запуск бинарника--sql-dir ./sql— использовать локально скачанные SQL-дампы внутри обновлятора--archives-dir /volume1/Media/Flibusta.Net— читать архивы из боевой библиотеки--archives-list ./runtime/state/archives_weekly.txt— обрабатывать только новые архивы текущего цикла--merge-base /volume1/Media/Flibusta.Net/flibusta.inpx— брать существующий production INPX как базу--layout classic— использовать классическую группировку--metagenres ./data/metagenres.csv— использовать локальное отображение жанров в meta-категории--process all— обрабатывать и FB2, и USR--read-fb2 all— глубоко читать FB2 для новых и отсутствующих записей--prefer-fb2 merge— sequence из FB2 имеет приоритет при наличии--out ./runtime/state/flibusta_next.inpx— писать временный результат внутрь служебного каталога обновлятора
Почему это быстро:
- сканируются только архивы, перечисленные в
--archives-list - используется merge с существующим
.inpx, а не полная пересборка - глубокий разбор FB2 ограничен новыми или нужными файлами
Для режима только FB2 в run_cycle.sh установите:
PROCESS_MODE="fb2"
3. Месячная упаковка с перекрывающимися weekly-диапазонами
Если monthly-архив перекрывает диапазоны, уже присутствующие в weekly-архивах, merge оставляет более новый архив и удаляет полностью перекрытые старые диапазоны из archives.info.
Команда та же, что и для weekly, но в --archives-list нужно передать список monthly-архивов.
4. Режим archive-per-inp
./inpx_creator_rs \
--sql-dir ./sql \
--archives-dir /volume1/Media/Flibusta.Net \
--layout archive \
--process all \
--out ./flibusta_archive_layout.inpx
5. Скачивание daily-архивов
./inpx_creator_rs download-daily \
--source-url https://flibusta.is/daily/ \
--process fb2 \
--data-dir ./runtime/state \
--fb2-daily-dir ./runtime/fb2_daily \
--usr-daily-dir ./runtime/usr_daily
6. Скачивание и распаковка SQL-дампов
./inpx_creator_rs download-sql \
--source-url https://flibusta.is/sql/ \
--data-dir ./runtime/state \
--sql-daily-dir ./runtime/sql_daily \
--output-sql-dir ./sql
7. Сборка weekly-архивов из daily-хвоста
./inpx_creator_rs make-archives \
--fb2-daily-dir ./runtime/fb2_daily \
--usr-daily-dir ./runtime/usr_daily \
--output-dir /volume1/Media/Flibusta.Net \
--fb2-prefix a.fb2 \
--usr-prefix a.usr
8. Сборка monthly-архива из weekly-архивов
./inpx_creator_rs pack-archives \
--archives-dir /volume1/Media/Flibusta.Net \
--input-prefix a.fb2 \
--output-prefix f.fb2
Глубокий разбор FB2
Из секции title-info читаются:
genreauthor(last-name,first-name,middle-name)book-titlesequence(name,number)langkeywords
Режимы:
--read-fb2 none— не разбирать FB2 XML--read-fb2 last— разбирать FB2 только для отсутствующих книг сbook_id > max_db_book_id--read-fb2 all— разбирать все подходящие новые книги
Приоритет:
ignore— доверять только БДmerge— предпочитать sequence из FB2complement— брать sequence из FB2 только если в БД его нетreplace— заменять поля БД данными FB2, если они присутствуют
Совместимость
- строки
.inpиспользуют разделитель\x04и окончания\r\n - локальная grouped-структура использует формат:
AUTHOR;GENRE;TITLE;SERIES;SERNO;FILE;SIZE;LIBID;DEL;EXT;DATE;INSNO;FOLDER;LANG;LIBRATE;KEYWORDS;
- именование групп в
classicулучшается за счет:- наследования suffix из
--merge-base - отображения через
metagenres.xls - fallback-логики по keyword и genre
- наследования suffix из
Цель этой комбинации — быть максимально близкой к существующему поведению именования в flibusta.inpx.
Практические замечания для больших библиотек
- для NAS и слабых серверов предпочтителен инкрементальный режим с
--archives-listи--merge-base metagenres.xlsстоит хранить рядом с остальными релизными файлами обновлятора- режим
--read-fb2 all --prefer-fb2 mergeполезен, когда weekly-данные требуют исправления sequence без полной пересборки - старый
.inpxимеет смысл сохранять как rollback-точку перед заменой production-файла - для обычной эксплуатации лучше использовать
run_cycle.sh, а подкоманды вызывать вручную только для диагностики, восстановления или разовых операций
Что было основой
Проект не возник с нуля. В качестве ориентиров и практической базы использовались следующие материалы:
InpxCreator:https://github.com/rupor-github/InpxCreator- исходные shell-скрипты для обновления библиотеки:
https://booktracker.org/viewtopic.php?t=102232
Итоговая реализация написана отдельно, потому что в исходных решениях были ограничения, которые мешали текущему сценарию эксплуатации, инкрементальному обновлению и более удобной автоматизации.
Быстрая проверка
cargo check
cargo test