Skip to content

Repository files navigation

Pushkinlib

Web-сервис для просмотра локальной библиотеки книг по INPX-индексу с поддержкой OPDS и встроенным ридером.

Возможности

  • 📚 Парсинг INPX — поддержка индексных файлов библиотек
  • 🔍 Полнотекстовый поиск — SQLite FTS5 по названию, серии, авторам и аннотации
  • 🌐 Web-интерфейс — современный SPA на Vue.js
  • 📱 Адаптивный дизайн — работает на мобильных устройствах
  • 📖 OPDS каталог — совместимость с читалками (FBReader, KyBook, Moon+ Reader и др.)
  • 🗂️ Фильтрация — по жанрам, сериям, авторам, годам
  • Быстрая работа — SQLite база данных с индексами
  • 📕 Встроенный ридер FB2 — чтение книг прямо в браузере с тремя режимами отображения
  • 💾 Запоминание позиции — автоматическое сохранение и восстановление места чтения
  • 📊 История чтения — отслеживание прогресса, статусы «Читаю» и «Прочитано», автоопределение завершения
  • 🔊 Озвучка текста (TTS) — синтез речи через Silero TTS: чтение с текущей позиции, выбор голоса, регулировка скорости, непрерывное чтение
  • 🔐 Аутентификация — опциональная многопользовательская авторизация с разделением истории чтения по пользователям

Быстрый старт

Запуск через Docker Compose (рекомендуется)

# Скопируйте пример конфигурации
cp .env.example .env
# Отредактируйте .env — укажите путь к библиотеке и имя INPX файла
nano .env

В .env задаются пути к библиотеке и основные параметры:

# Путь на хосте к папке с книгами (монтируется в контейнер)LIBRARY_PATH=./books# Имя файла индекса INPX внутри папки с книгамиINPX_FILE=test_library.inpx

Docker Compose автоматически подхватывает .env файл и подставляет переменные.

# Запустите контейнер
docker compose -f docker-compose.dev.yaml up -d --build

Сервис будет доступен по адресу http://localhost:9090:

Аутентификация

Pushkinlib поддерживает опциональную многопользовательскую авторизацию. По умолчанию авторизация выключена — сервис работает без логина, история чтения общая.

При включении авторизации:

  • появляется экран логина
  • история чтения и позиции привязываются к пользователю
  • OPDS-каталог защищается HTTP Basic Auth (для читалок)
  • каталог книг, поиск и содержимое книг остаются публичными

Пошаговая настройка

Шаг 1. Сгенерируйте секрет сессий

Секрет нужен для подписи cookie. Без него сессии не переживут перезапуск контейнера.

# Linux / macOS
openssl rand -hex 32
# или
head -c 32 /dev/urandom | base64

Сохраните полученную строку — она понадобится на следующем шаге.

Шаг 2. Добавьте переменные окружения

Откройте ваш docker-compose.yaml (или .env файл) и добавьте четыре переменные:

services:
pushkinlib:
environment:
# ... существующие переменные (PORT, BOOKS_DIR и т.д.) ...# Включить авторизацию
- AUTH_ENABLED=true# Логин администратора (по умолчанию: admin)
- ADMIN_USER=admin# Пароль администратора — ОБЯЗАТЕЛЬНО замените!
- ADMIN_PASS=MyStr0ng_Passw0rd!# Секрет сессий (из шага 1)
- SESSION_SECRET=вставьте-сюда-строку-из-шага-1

Если запускаете без Docker, добавьте те же переменные в .env:

AUTH_ENABLED=trueADMIN_USER=adminADMIN_PASS=MyStr0ng_Passw0rd!SESSION_SECRET=вставьте-сюда-строку-из-шага-1

Шаг 3. Запустите (или перезапустите) сервис

# Docker Compose
docker compose up -d
# или из исходников
./pushkinlib

В логах вы увидите:

Auth enabled, ensuring admin user exists...
Admin user "admin" created successfully

Если пользователь admin уже существовал, пароль будет обновлён.

Шаг 4. Войдите в веб-интерфейс

Откройте http://localhost:9090 — вы увидите экран логина:

  1. Введите логин (admin) и пароль, заданный в ADMIN_PASS
  2. Нажмите Войти
  3. После успешного входа — библиотека, имя пользователя в шапке и кнопка Выйти

Сессия хранится в httpOnly cookie и действует 30 дней.

Шаг 5. Создайте дополнительных пользователей

В шапке сайта нажмите Пользователи (кнопка видна только администраторам).

В админ-панели можно:

  • Создать пользователя — заполните логин, пароль (от 6 символов), опционально отображаемое имя и флаг «Администратор»
  • Удалить пользователя (кроме самого себя)
  • Сменить пароль любому пользователю

Те же операции доступны через API:

# Список пользователей
curl -b cookies.txt http://localhost:9090/api/v1/admin/users
# Создание пользователя
curl -b cookies.txt -X POST http://localhost:9090/api/v1/admin/users \
-H 'Content-Type: application/json' \
-d '{"username":"alice","password":"secret123","display_name":"Алиса"}'# Смена пароля
curl -b cookies.txt -X PUT http://localhost:9090/api/v1/admin/users/{id}/password \
-H 'Content-Type: application/json' \
-d '{"password":"newpass789"}'# Удаление пользователя
curl -b cookies.txt -X DELETE http://localhost:9090/api/v1/admin/users/{id}

Шаг 6. Настройте читалку (OPDS)

При включённой авторизации OPDS-каталог требует HTTP Basic Auth. В настройках вашей читалки:

ПараметрЗначение
URL каталогаhttp://ваш-сервер:9090/opds
Логинadmin (или другой ADMIN_USER)
Парольтот же, что в ADMIN_PASS

Проверенные читалки: KOReader, Moon+ Reader, FBReader, KyBook, Bookari.

Справочник переменных окружения

ПеременнаяПо умолчаниюОписание
LIBRARY_PATH./booksПуть на хосте к папке с книгами (для Docker, монтируется в контейнер)
INPX_FILEtest_library.inpxИмя файла индекса INPX внутри папки с книгами
PORT9090Порт веб-сервера
CATALOG_TITLEPushkinlibНазвание каталога
PAGE_SIZE30Количество книг на странице
LOG_LEVELinfoУровень логирования
PUBLIC_BASE_URLhttp://localhost:9090Публичный URL (для OPDS ссылок)
AUTH_ENABLEDfalseВключить авторизацию. При false все маршруты открыты, история общая
ADMIN_USERadminЛогин администратора. Создаётся автоматически при первом запуске
ADMIN_PASSПароль администратора. Обязателен при AUTH_ENABLED=true
SESSION_SECRET(автогенерация)Секрет для подписи сессий. Без явного значения сессии сбрасываются при перезапуске
TTS_SERVER_URLURL TTS-сервера (например, http://tts-server:8000)
TTS_API_KEYAPI-ключ для TTS-сервера (опционально)

Что защищено, а что нет

МаршрутБез авторизацииС авторизацией
Каталог книг, поиск, содержимоеОткрытоОткрыто
TTS (озвучка)ОткрытоОткрыто
Скачивание книгОткрытоОткрыто
Позиции чтения (сохранение/чтение)Открыто (общие)Требует логина (привязаны к пользователю)
История чтенияОткрыта (общая)Требует логина (привязана к пользователю)
OPDS-каталогОткрытHTTP Basic Auth
Переиндексация (/api/v1/admin/reindex)ОткрытаТолько администратор
Управление пользователями (/api/v1/admin/users)Только администратор

Отключение авторизации

Чтобы вернуться в режим без авторизации:

- AUTH_ENABLED=false

Перезапустите сервис. Все маршруты станут открытыми. Данные пользователей сохраняются в базе — при повторном включении всё вернётся.

Быстрый запуск для разработки

Для тестирования с авторизацией используйте готовый overlay-файл:

docker compose -f docker-compose.dev.yaml -f docker-compose.auth.yaml up -d --build

Тестовые данные: логин admin, пароль admin123.

Запуск из исходников

1. Сборка

CGO_ENABLED=1 go build -tags sqlite_fts5 -o pushkinlib ./cmd/pushkinlib

Поиск использует модуль SQLite FTS5, поэтому сборка должна выполняться с включённым CGO и тегом sqlite_fts5.

2. Конфигурация

Скопируйте и настройте конфигурацию:

cp .env.example .env

Основные параметры в .env:

# Путь к библиотеке (при локальном запуске — без Docker)LIBRARY_PATH=./booksINPX_FILE=my_catalog.inpxPORT=9090CATALOG_TITLE=Моя библиотекаPUBLIC_BASE_URL=http://localhost:9090# Авторизация (опционально)AUTH_ENABLED=falseADMIN_USER=adminADMIN_PASS=changemeSESSION_SECRET=random-secret-32-chars

3. Запуск

./pushkinlib

Для отображения дружественных названий жанров в OPDS и веб-интерфейсе используется CSV-файл GENRES_CSV_PATH (по умолчанию ./web/static/genres.csv). Обновите его, если нужно скорректировать переводы жанров.

Встроенный ридер

Pushkinlib включает полноценный ридер для чтения FB2-книг прямо в браузере. Для открытия книги нажмите кнопку «Читать» на карточке.

Режимы отображения

  • Одна страница — по центру экрана, как в Kindle
  • Книжный разворот — две страницы рядом, имитация бумажной книги
  • Бесконечная прокрутка — непрерывный поток текста с ленивой подгрузкой

Настройки ридера

  • Размер шрифта (увеличение/уменьшение)
  • Переключение между светлой и тёмной темой
  • Выбор режима отображения
  • Навигация по оглавлению (TOC)
  • Горячие клавиши: стрелки ←/→ для перелистывания, Escape для закрытия

Сохранение позиции

Позиция чтения автоматически сохраняется в SQLite при каждом перелистывании. При повторном открытии книги чтение продолжается с того же места. Хранятся: номер секции, прогресс внутри секции и общее число секций.

История чтения

Сервис отслеживает все открытые книги и их прогресс:

  • «Читаю» — книга, которую пользователь начал читать, но не закончил
  • «Прочитано» — статус присваивается автоматически при достижении последней секции книги
  • Главная страница — блоки «Продолжить чтение» и «Прочитано» с карточками книг и прогресс-барами
  • Страница истории — полный список с фильтрацией по статусу (Все / Читаю / Прочитано) и процентом прогресса

API истории чтения

GET /api/v1/reading-history?status=reading&limit=20&offset=0

Параметры:

  • status — фильтр: reading, finished или пустое (все)
  • limit — количество результатов (по умолчанию: 20)
  • offset — смещение для пагинации

Сохранение/восстановление позиции

PUT /api/v1/books/{id}/positionGET /api/v1/books/{id}/position

Тело запроса PUT:

{
"section": 5,
"progress": 0.42,
"total_sections": 12
}

Озвучка текста (TTS)

Pushkinlib может озвучивать книги через встроенный проксируемый TTS-сервер на базе Silero. Синтез речи работает на стороне сервера — браузер отправляет текст секции и получает аудио обратно.

Настройка

Для работы TTS необходим отдельный TTS-сервер (OpenAI-совместимый API). Укажите его адрес через переменные окружения:

TTS_SERVER_URL=http://tts-server:8000TTS_API_KEY=sk-your-key# опционально, если на TTS-сервере включена авторизация

В docker-compose.dev.yaml TTS-сервер уже включён как отдельный сервис и стартует автоматически.

Возможности

  • Два режима воспроизведения: озвучка текущей секции и непрерывное чтение (автопереход к следующим секциям)
  • Чтение с текущей позиции: озвучка начинается с параграфа, видимого на экране, а не с начала секции — удобно для длинных глав
  • Выбор голоса: русские голоса Silero (aidar, baya, kseniya, xenia, eugene)
  • Регулировка скорости: от 0.5x до 2.0x
  • Сохранение настроек: выбранный голос и скорость запоминаются в localStorage

TTS API

GET /api/v1/tts/status # Проверка доступности TTS-сервераGET /api/v1/tts/voices # Список доступных голосов и моделейPOST /api/v1/tts/speech # Синтез речи

Тело запроса POST /api/v1/tts/speech:

{
"input": "Текст для озвучки",
"voice": "xenia",
"speed": 1.0,
"model": "v5_ru",
"response_format": "mp3"
}

Ответ — аудиофайл (audio/mpeg для mp3). Максимальная длина текста — 5000 символов; длинные секции автоматически разбиваются на фрагменты ~2000 символов. Все поля кроме input опциональны (по умолчанию: голос xenia, скорость 1.0, формат mp3, модель v5_ru).

Генерация каталога из книг

Если у вас есть папка с книгами, но нет INPX файла, используйте генератор каталога:

1. Сборка генератора

CGO_ENABLED=1 go build -tags sqlite_fts5 -o catalog-generator ./cmd/catalog-generator

2. Подготовка книг

Поместите книги в папку ./sample-data/books/:

sample-data/books/
├── book1.fb2
├── book2.zip
├── book3.epub
└── subfolder/
└── book4.fb2

3. Генерация каталога

./catalog-generator -books=./sample-data/books -name=my_catalog

Опции генератора:

  • -books - папка с книгами (по умолчанию: ./sample-data/books)
  • -output - папка для результатов (по умолчанию: ./sample-data)
  • -name - имя каталога (по умолчанию: generated_catalog)
  • -prefix - префикс для архивов (по умолчанию: books)
  • -max-books - максимум книг в архиве (по умолчанию: 1000)
  • -formats - форматы файлов (по умолчанию: .fb2,.zip,.epub)

4. Использование сгенерированного каталога

После генерации обновите .env:

INPX_PATH=./sample-data/my_catalog.inpxBOOKS_DIR=./sample-data

Поддерживаемые форматы

Извлечение метаданных

  • FB2 - полная поддержка метаданных
  • FB2.ZIP - FB2 файлы в ZIP архивах
  • EPUB - базовая поддержка (название, автор)

Файлы каталога

  • INPX - стандартный формат индексов
  • INP - отдельные файлы индексов

API

При включённой авторизации защищённые эндпоинты возвращают 401 Unauthorized, если пользователь не аутентифицирован. Публичные эндпоинты доступны всегда.

Аутентификация

GET /api/v1/auth/info # Статус авторизации (публичный)POST /api/v1/auth/login # Вход (публичный)POST /api/v1/auth/logout # Выход (требует авторизации)GET /api/v1/auth/me # Информация о текущем пользователе (требует авторизации)

GET /api/v1/auth/info возвращает { "auth_enabled": true/false } — используется фронтендом для определения необходимости показа экрана логина.

POST /api/v1/auth/login принимает { "username": "...", "password": "..." } и устанавливает httpOnly сессионный cookie.

Переиндексация библиотеки

Административная переиндексация очищает текущую SQLite-базу и заново импортирует книги из указанного INPX:

POST /api/v1/admin/reindex # Требует авторизации + права администратора

Пример запроса:

# Без авторизации (AUTH_ENABLED=false)
curl -X POST http://localhost:9090/api/v1/admin/reindex
# С авторизацией (AUTH_ENABLED=true) — сначала получите сессию через /api/v1/auth/login
curl -X POST http://localhost:9090/api/v1/admin/reindex -b "session=<token>"

В ответе возвращается статистика: количество импортированных книг, название коллекции и время выполнения в миллисекундах.

Управление пользователями (API)

Все эндпоинты требуют авторизации с правами администратора.

GET /api/v1/admin/users # Список пользователейPOST /api/v1/admin/users # Создать пользователяDELETE /api/v1/admin/users/{id} # Удалить пользователяPUT /api/v1/admin/users/{id}/password # Сменить пароль пользователя

Создание пользователя (POST):

{
"username": "alice",
"password": "secret123",
"display_name": "Алиса",
"is_admin": false
}

Смена пароля (PUT):

{
"password": "newpass789"
}

Поиск книг (публичный)

GET /api/v1/books?q=запрос&limit=30&offset=0

Параметры:

  • q - поисковый запрос
  • limit - количество результатов (по умолчанию: 30)
  • offset - смещение для пагинации
  • authors[] - фильтр по авторам
  • series[] - фильтр по сериям
  • genres[] - фильтр по жанрам
  • year_from, year_to - фильтр по годам
  • sort_by - сортировка (title, year, date_added, relevance)
  • sort_order - порядок (asc, desc)

Фронтенд отображает дружественные названия жанров, подгружая отображение код → имя из web/static/genres.csv. При необходимости добавьте или скорректируйте пары в этом файле, изменения применяются без пересборки.

Получение книги (публичный)

GET /api/v1/books/{id}

Ридер — содержимое книги

GET /api/v1/books/{id}/content # Метаданные + оглавление (публичный)GET /api/v1/books/{id}/sections/{index} # Содержимое секции (публичный)GET /api/v1/books/{id}/position # Получить позицию (требует авторизации)PUT /api/v1/books/{id}/position # Сохранить позицию (требует авторизации)GET /api/v1/books/{id}/images/{name} # Изображение из книги (публичный)

История чтения (требует авторизации)

GET /api/v1/reading-history?status=reading&limit=20&offset=0

TTS (публичный)

GET /api/v1/tts/status # Статус TTS-сервераGET /api/v1/tts/voices # Доступные голосаPOST /api/v1/tts/speech # Синтез речи (возвращает аудио)

OPDS

OPDS каталог доступен по адресу /opds и поддерживает:

  • Навигацию - по авторам, сериям, жанрам
  • Поиск - совместим с OpenSearch
  • Пагинацию - для больших каталогов
  • Скачивание - прямые ссылки на файлы
  • HTTP Basic Auth - при включённой авторизации (AUTH_ENABLED=true) OPDS требует логин/пароль

Настройка читалок

Добавьте в вашу читалку OPDS каталог:

http://your-server:9090/opds

Если авторизация включена, укажите логин и пароль в настройках читалки (HTTP Basic Auth).

Протестированные читалки:

  • FBReader
  • KyBook
  • Bookari
  • Moon+ Reader

Разработка

Структура проекта

pushkinlib/
├── cmd/
│ ├── pushkinlib/ # Основное приложение
│ └── catalog-generator/ # Генератор каталогов
├── internal/
│ ├── api/ # HTTP API handlers
│ ├── auth/ # Аутентификация
│ ├── catalog/ # Генерация каталогов
│ ├── config/ # Конфигурация
│ ├── covers/ # Обработка обложек
│ ├── inpx/ # Парсинг INPX
│ ├── metadata/ # Извлечение метаданных
│ ├── opds/ # OPDS каталог
│ ├── reader/ # FB2 парсер, конвертер, ридер
│ ├── search/ # Поиск и индексация
│ └── storage/ # База данных (SQLite, миграции)
├── web/static/ # Frontend (Vue.js SPA)
│ └── vendor/ # Локальные JS зависимости
├── tests/e2e/ # Playwright end-to-end тесты
├── scripts/ # Вспомогательные скрипты
└── sample-data/ # Тестовые данные

Управление зависимостями

Web-интерфейс использует локальные копии JavaScript библиотек (Vue.js, Axios) для работы без внешних CDN. Для обновления зависимостей:

./scripts/download-deps.sh

Скрипт автоматически скачивает актуальные версии библиотек из unpkg.com в директорию web/static/vendor/.

Тестирование

# Юнит-тесты (ридер, парсеры)
go test ./internal/reader/... -v
# Все юнит-тесты (требуется SQLite с FTS5)
CGO_ENABLED=1 go test -tags sqlite_fts5 ./...
# Тест парсера INPX
go test ./internal/inpx -v
# Генерация тестового каталога
./catalog-generator -books=./sample-data/books

Playwright e2e тесты

End-to-end тесты проверяют ридер, историю чтения, TTS и аутентификацию в реальном браузере. Тесты автоматически определяют режим авторизации и адаптируются.

# Установка зависимостей (однократно)cd tests/e2e && npm install && npx playwright install --with-deps chromium
# Запуск без авторизации
docker compose -f docker-compose.dev.yaml up -d --build
cd tests/e2e && npx playwright test# Запуск с авторизацией
docker compose -f docker-compose.dev.yaml -f docker-compose.auth.yaml up -d --build
cd tests/e2e && npx playwright test

При AUTH_ENABLED=true тесты автоматически логинятся через API перед каждым тестом. Тесты аутентификации (auth.spec.js) содержат две группы: «Auth Enabled» и «Auth Disabled», каждая из которых пропускается в неподходящем режиме.

Лицензия

MIT License

Вклад в проект

  1. Fork проекта
  2. Создайте feature branch (git checkout -b feature/amazing-feature)
  3. Commit изменения (git commit -m 'Add amazing feature')
  4. Push в branch (git push origin feature/amazing-feature)
  5. Откройте Pull Request

Поддержка

Если у вас возникли вопросы или проблемы, создайте issue в репозитории GitHub.

About

Local inpx lib pushkinlib

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages