Обновлен контекст
This commit is contained in:
1 parent
ab4953ffd1
commit
a51a7e1a76
1 file changed
+175
-142
+175
-142
@@ -1,142 +1,175 @@
|
||||
# Выжимка из контекста: Домашняя библиотека
|
||||
|
||||
## Что построено
|
||||
|
||||
**Локальный OPDS-каталог + веб-интерфейс** для копии библиотеки lib.rus.ec (~579 000 книг) на TV-приставке с Armbian.
|
||||
|
||||
## Железо и окружение
|
||||
|
||||
- **Устройство**: TV-приставка Vontar, Armbian, ARM
|
||||
- **Диски**: `/mnt/hdd` — основной
|
||||
- **Docker**: контейнеры Immich (фото), Home Assistant, qBittorrent, Adminer
|
||||
- **PostgreSQL**: используется общий с Immich (`immich_postgres`), база `books`
|
||||
- Пароль: `Karabas@Barabas`, пользователь: `postgres`
|
||||
- **Фиксированный IP**: `172.20.0.4` (сеть `immich_immich_net`, подсеть `172.20.0.0/16`)
|
||||
- **OPDS-сервер**: контейнер `opds_server` на порту **8085** (порт 8080 занят qBittorrent)
|
||||
- **Адрес библиотеки**: `http://192.168.30.2:8085/`
|
||||
|
||||
## Расположение файлов
|
||||
|
||||
```
|
||||
/mnt/hdd/opds/ # проект OPDS
|
||||
├── opds_server.py # главный Flask-сервер
|
||||
├── db_utils.py # подключение к БД
|
||||
├── author_utils.py # работа с авторами
|
||||
├── book_utils.py # извлечение fb2, обложки, конвертация
|
||||
├── parse_inpx.py # импорт книг
|
||||
├── parse_genres.py # загрузка жанров
|
||||
├── genres.xml # справочник жанров fb2
|
||||
├── Dockerfile
|
||||
└── docker-compose.yml
|
||||
|
||||
/mnt/hdd/share/Torrents/Downloaded/Libruks/
|
||||
├── Библиотека Либрусек для архивов 17-08-2026.inpx
|
||||
├── Библиотека Либрусек для архивов 18-09-2026.inpx
|
||||
├── Libruks1086.zip
|
||||
└── Архивы Либрусек/ # 3726 zip-архивов с fb2
|
||||
├── fb2-000065-005477.zip
|
||||
├── fb2-069327-070122.zip
|
||||
└── ... (по диапазонам ID)
|
||||
|
||||
/root/docker-compose.yml # Immich (с фиксированным IP postgres)
|
||||
```
|
||||
|
||||
## Структура базы данных
|
||||
|
||||
| Таблица | Назначение |
|
||||
|---------|-----------|
|
||||
| `authors` | Авторы (нормализованные: full_name, last_name, first_name, middle_name, name_hash, first_letter) |
|
||||
| `series` | Серии (name, name_hash, first_letter) |
|
||||
| `genres` | Жанры (code, title_ru, title_en, parent_code, root_code, is_root, is_custom, genre_alt[]) |
|
||||
| `books` | Книги (title, internal_id, internal_id2, file_size, format, added_date, language, source, series_id, series_number, fts) |
|
||||
| `book_authors` | Связь книг↔авторов (book_id, author_id, position) |
|
||||
| `book_genres` | Связь книг↔жанров (book_id, genre_id) |
|
||||
|
||||
**Особенности:**
|
||||
- Полнотекстовый поиск через `fts tsvector` (русский язык)
|
||||
- Хеши (MD5) для быстрого поиска
|
||||
- Поле `source` для поддержки нескольких источников
|
||||
- Нормализация: авторы/серии/жанры вынесены в отдельные таблицы
|
||||
|
||||
## Формат inpx (lib.rus.ec)
|
||||
|
||||
Текстовый файл с разделителем `\x04`:
|
||||
```
|
||||
AUTHOR \x04 GENRE \x04 TITLE \x04 SERIES \x04 SERNO \x04 FILE \x04 SIZE \x04 LIBID \x04 DEL \x04 EXT \x04 DATE \x04 LANG \x04 KEYWORDS
|
||||
```
|
||||
|
||||
- Авторы: `Фамилия,Имя,Отчество` через `:` для нескольких
|
||||
- Жанры: коды fb2 через `:` (например, `sf_history:network_literature`)
|
||||
- Особенность архивов: **fb2 внутри zip-архивов может быть вложенным zip** — нужно распаковывать дважды
|
||||
|
||||
## Что реализовано в веб-интерфейсе
|
||||
|
||||
- ✅ Главная с поиском и навигацией
|
||||
- ✅ Поиск (полнотекстовый + по автору)
|
||||
- ✅ Авторы с группировкой по алфавиту (умная навигация: Па → Пел → Пелевин)
|
||||
- ✅ Страница автора (серии, книги, сборники с пометкой соавторов)
|
||||
- ✅ Страница книги (обложка, аннотация, оглавление)
|
||||
- ✅ Чтение глав (конвертация fb2→HTML на лету, встроенные картинки, навигация ← пред/оглавление↑/след →)
|
||||
- ✅ Скачивание fb2 (с обработкой вложенных zip)
|
||||
- ✅ OPDS 1.2 для читалок (FBReader)
|
||||
|
||||
## Что НЕ реализовано / в планах
|
||||
|
||||
- ❌ Страница серий (список + страница серии с книгами)
|
||||
- ❌ Страница жанров (дерево + фильтрация)
|
||||
- ❌ Обложки с ленивой загрузкой (обсуждали: заглушка → загрузка в фоне → кэш в `/mnt/hdd/opds/covers/`)
|
||||
- ❌ OPDS 2.0 (обсуждали как второй эндпоинт `/opds2`)
|
||||
- ❌ Редактирование жанров (кастомные жанры с `is_custom=TRUE` ждут ручного заполнения)
|
||||
- ❌ Языковой фильтр (56 языков в базе, но основные — ru)
|
||||
|
||||
## Ключевые решения
|
||||
|
||||
- **Язык в скобках**: для не-русских книг показывать `(en)`, `(uk)` и т.д.
|
||||
- **Сборники**: если авторов >1 — пометка `👥 соавторы: X, Y` (до 3) или `👥 N авторов` (больше)
|
||||
- **Порядок книг автора**: от новых к старым (`added_date DESC NULLS LAST`)
|
||||
- **Серии на странице автора**: все, где автор участвует, по алфавиту
|
||||
- **Название**: "Домашняя библиотека" (не "Моя библиотека")
|
||||
- **Модульная структура**: разбить на модули (db, author, book, series, genre utils)
|
||||
- **Git**: хранить всю информацию в репозитории
|
||||
|
||||
## Текущие проблемы / нюансы
|
||||
|
||||
1. **IP PostgreSQL менялся** после перезагрузки → исправлено фиксированным IP `172.20.0.4`
|
||||
2. **Сеть Immich** конфликтовала с adminer → adminer отключён, сеть пересоздана как `immich_immich_net`
|
||||
3. **Вложенные zip в архивах** → `get_book_fb2` распаковывает дважды
|
||||
4. **VACUUM** нельзя в транзакции → `autocommit=True` перед VACUUM
|
||||
5. **Дубликаты авторов** (`Лукьяненко,Сергей,` и `Лукьяненко,Сергей`) → исправлено нормализацией при импорте
|
||||
6. **string_agg(DISTINCT ... ORDER BY ...)** — ошибка в PostgreSQL → переписано на подзапросы
|
||||
|
||||
## Полезные команды
|
||||
|
||||
```bash
|
||||
# Обновление библиотеки новым inpx
|
||||
docker compose exec opds python parse_inpx.py \
|
||||
"/path/to/новый.inpx" \
|
||||
"dbname=books user=postgres password=Karabas@Barabas host=172.20.0.4" \
|
||||
"lib.rus.ec"
|
||||
|
||||
# Проверка количества книг
|
||||
docker exec -it immich_postgres psql -U postgres -d books -c "SELECT COUNT(*) FROM books;"
|
||||
|
||||
# Кастомные жанры
|
||||
docker exec -it immich_postgres psql -U postgres -d books -c "
|
||||
SELECT g.code, COUNT(bg.book_id) as cnt
|
||||
FROM genres g JOIN book_genres bg ON bg.genre_id = g.id
|
||||
WHERE g.is_custom = TRUE GROUP BY g.code ORDER BY cnt DESC;"
|
||||
|
||||
# Пересборка OPDS
|
||||
cd /mnt/hdd/opds && docker compose up -d --build
|
||||
```
|
||||
|
||||
## Следующий шаг
|
||||
|
||||
Создание Git-репозитория `opds-library` со структурой:
|
||||
- `sql/` — схема БД
|
||||
- `scripts/` — парсеры
|
||||
- `app/` — Flask-сервер (модули)
|
||||
- `data/` — genres.xml
|
||||
- `docker-compose.yml`, `Dockerfile`, `README.md`
|
||||
|
||||
С этого места продолжаем.
|
||||
# Выжимка из контекста: Домашняя библиотека
|
||||
|
||||
## Что построено
|
||||
|
||||
**Локальный OPDS-каталог + веб-интерфейс** для копии библиотеки lib.rus.ec (~579 000 книг) на TV-приставке с Armbian.
|
||||
|
||||
## Железо и окружение
|
||||
|
||||
- **Устройство**: TV-приставка Vontar, Armbian, ARM
|
||||
- **Диски**: `/mnt/hdd` — основной
|
||||
- **Docker**: контейнеры Immich (фото), Home Assistant, qBittorrent, Adminer
|
||||
- **PostgreSQL**: используется общий с Immich (`immich_postgres`), база `books`
|
||||
- Пароль: `Karabas@Barabas`, пользователь: `postgres`
|
||||
- **Фиксированный IP**: `172.20.0.4` (сеть `immich_immich_net`, подсеть `172.20.0.0/16`)
|
||||
- **OPDS-сервер**: контейнер `opds_server` на порту **8085** (порт 8080 занят qBittorrent)
|
||||
- **Адрес библиотеки**: `http://192.168.30.2:8085/`
|
||||
|
||||
## Расположение файлов
|
||||
|
||||
```
|
||||
/mnt/hdd/opds/ # проект OPDS
|
||||
├── opds_server.py # главный Flask-сервер
|
||||
├── db_utils.py # подключение к БД
|
||||
├── author_utils.py # работа с авторами
|
||||
├── book_utils.py # извлечение fb2, обложки, конвертация
|
||||
├── parse_inpx.py # импорт книг
|
||||
├── parse_genres.py # загрузка жанров
|
||||
├── genres.xml # справочник жанров fb2
|
||||
├── Dockerfile
|
||||
└── docker-compose.yml
|
||||
|
||||
/mnt/hdd/share/Torrents/Downloaded/Libruks/
|
||||
├── Библиотека Либрусек для архивов 17-08-2026.inpx
|
||||
├── Библиотека Либрусек для архивов 18-09-2026.inpx
|
||||
├── Libruks1086.zip
|
||||
└── Архивы Либрусек/ # 3726 zip-архивов с fb2
|
||||
├── fb2-000065-005477.zip
|
||||
├── fb2-069327-070122.zip
|
||||
└── ... (по диапазонам ID)
|
||||
|
||||
/root/docker-compose.yml # Immich (с фиксированным IP postgres)
|
||||
```
|
||||
|
||||
## Структура базы данных
|
||||
|
||||
| Таблица | Назначение |
|
||||
|---------|-----------|
|
||||
| `authors` | Авторы (нормализованные: full_name, last_name, first_name, middle_name, name_hash, first_letter) |
|
||||
| `series` | Серии (name, name_hash, first_letter) |
|
||||
| `genres` | Жанры (code, title_ru, title_en, parent_code, root_code, is_root, is_custom, genre_alt[]) |
|
||||
| `books` | Книги (title, internal_id, internal_id2, file_size, format, added_date, language, source, series_id, series_number, fts) |
|
||||
| `book_authors` | Связь книг↔авторов (book_id, author_id, position) |
|
||||
| `book_genres` | Связь книг↔жанров (book_id, genre_id) |
|
||||
|
||||
**Особенности:**
|
||||
- Полнотекстовый поиск через `fts tsvector` (русский язык)
|
||||
- Хеши (MD5) для быстрого поиска
|
||||
- Поле `source` для поддержки нескольких источников
|
||||
- Нормализация: авторы/серии/жанры вынесены в отдельные таблицы
|
||||
|
||||
## Формат inpx (lib.rus.ec)
|
||||
|
||||
Текстовый файл с разделителем `\x04`:
|
||||
```
|
||||
AUTHOR \x04 GENRE \x04 TITLE \x04 SERIES \x04 SERNO \x04 FILE \x04 SIZE \x04 LIBID \x04 DEL \x04 EXT \x04 DATE \x04 LANG \x04 KEYWORDS
|
||||
```
|
||||
|
||||
- Авторы: `Фамилия,Имя,Отчество` через `:` для нескольких
|
||||
- Жанры: коды fb2 через `:` (например, `sf_history:network_literature`)
|
||||
- Особенность архивов: **fb2 внутри zip-архивов может быть вложенным zip** — нужно распаковывать дважды
|
||||
|
||||
## Что реализовано в веб-интерфейсе
|
||||
|
||||
- ✅ Главная с поиском и навигацией
|
||||
- ✅ Поиск (полнотекстовый + по автору)
|
||||
- ✅ Авторы с группировкой по алфавиту (умная навигация: Па → Пел → Пелевин)
|
||||
- ✅ Страница автора (серии, книги, сборники с пометкой соавторов)
|
||||
- ✅ Страница книги (обложка, аннотация, оглавление)
|
||||
- ✅ Чтение глав (конвертация fb2→HTML на лету, встроенные картинки, навигация ← пред/оглавление↑/след →)
|
||||
- ✅ Скачивание fb2 (с обработкой вложенных zip)
|
||||
- ✅ OPDS 1.2 для читалок (FBReader)
|
||||
|
||||
## Что НЕ реализовано / в планах
|
||||
|
||||
- ❌ Страница серий (список + страница серии с книгами)
|
||||
- ❌ Страница жанров (дерево + фильтрация)
|
||||
- ❌ Обложки с ленивой загрузкой (обсуждали: заглушка → загрузка в фоне → кэш в `/mnt/hdd/opds/covers/`)
|
||||
- ❌ OPDS 2.0 (обсуждали как второй эндпоинт `/opds2`)
|
||||
- ❌ Редактирование жанров (кастомные жанры с `is_custom=TRUE` ждут ручного заполнения)
|
||||
- ❌ Языковой фильтр (56 языков в базе, но основные — ru)
|
||||
|
||||
## Новый импорт: сканирование файловой системы
|
||||
|
||||
**Проблема INPX:** файл содержит ссылки на книги, которых нет на диске (удалены, не скачаны).
|
||||
|
||||
**Решение:** скрипт-сканер каталога — альтернатива INPX.
|
||||
|
||||
### Логика работы
|
||||
1. Принимает каталог как параметр
|
||||
2. Обходит все файлы в каталоге и подкаталогах
|
||||
3. Определяет новые/изменённые файлы через таблицу `file_scan_log`
|
||||
4. Новые/изменённые файлы → распаковка → парсинг FB2 → добавление в БД
|
||||
5. Исчезнувшие файлы → удаление связанных книг из БД
|
||||
|
||||
### Поддержка форматов
|
||||
- `.zip` → внутри может быть `.zip` → внутри может быть `.fb2`
|
||||
- Вложенность: до 3 уровней
|
||||
- RAR: бонусная поддержка
|
||||
|
||||
### Таблица `file_scan_log`
|
||||
| Поле | Тип | Назначение |
|
||||
|------|-----|-----------|
|
||||
| file_path | TEXT | Полный путь к файлу |
|
||||
| file_size | INTEGER | Размер файла |
|
||||
| file_hash | TEXT | MD5/SHA256 хеш содержимого |
|
||||
| updated_at | TIMESTAMP | Последнее обновление |
|
||||
|
||||
### Удаление книг
|
||||
- Файл исчез с диска → книга удаляется из БД безвозвратно
|
||||
- Файл изменён → старые книги удаляются, парсится заново
|
||||
|
||||
### Источник
|
||||
- Отдельная строка в `books.source` (например, `"file_scan"`)
|
||||
|
||||
## Ключевые решения
|
||||
|
||||
- **Язык в скобках**: для не-русских книг показывать `(en)`, `(uk)` и т.д.
|
||||
- **Сборники**: если авторов >1 — пометка `👥 соавторы: X, Y` (до 3) или `👥 N авторов` (больше)
|
||||
- **Порядок книг автора**: от новых к старым (`added_date DESC NULLS LAST`)
|
||||
- **Серии на странице автора**: все, где автор участвует, по алфавиту
|
||||
- **Название**: "Домашняя библиотека" (не "Моя библиотека")
|
||||
- **Модульная структура**: разбить на модули (db, author, book, series, genre utils)
|
||||
- **Git**: хранить всю информацию в репозитории
|
||||
|
||||
## Текущие проблемы / нюансы
|
||||
|
||||
1. **IP PostgreSQL менялся** после перезагрузки → исправлено фиксированным IP `172.20.0.4`
|
||||
2. **Сеть Immich** конфликтовала с adminer → adminer отключён, сеть пересоздана как `immich_immich_net`
|
||||
3. **Вложенные zip в архивах** → `get_book_fb2` распаковывает дважды
|
||||
4. **VACUUM** нельзя в транзакции → `autocommit=True` перед VACUUM
|
||||
5. **Дубликаты авторов** (`Лукьяненко,Сергей,` и `Лукьяненко,Сергей`) → исправлено нормализацией при импорте
|
||||
6. **string_agg(DISTINCT ... ORDER BY ...)** — ошибка в PostgreSQL → переписано на подзапросы
|
||||
|
||||
## Полезные команды
|
||||
|
||||
```bash
|
||||
# Обновление библиотеки новым inpx
|
||||
docker compose exec opds python parse_inpx.py \
|
||||
"/path/to/новый.inpx" \
|
||||
"dbname=books user=postgres password=Karabas@Barabas host=172.20.0.4" \
|
||||
"lib.rus.ec"
|
||||
|
||||
# Проверка количества книг
|
||||
docker exec -it immich_postgres psql -U postgres -d books -c "SELECT COUNT(*) FROM books;"
|
||||
|
||||
# Кастомные жанры
|
||||
docker exec -it immich_postgres psql -U postgres -d books -c "
|
||||
SELECT g.code, COUNT(bg.book_id) as cnt
|
||||
FROM genres g JOIN book_genres bg ON bg.genre_id = g.id
|
||||
WHERE g.is_custom = TRUE GROUP BY g.code ORDER BY cnt DESC;"
|
||||
|
||||
# Пересборка OPDS
|
||||
cd /mnt/hdd/opds && docker compose up -d --build
|
||||
```
|
||||
|
||||
## Следующий шаг
|
||||
|
||||
Создание Git-репозитория `opds-library` со структурой:
|
||||
- `sql/` — схема БД
|
||||
- `scripts/` — парсеры
|
||||
- `app/` — Flask-сервер (модули)
|
||||
- `data/` — genres.xml
|
||||
- `docker-compose.yml`, `Dockerfile`, `README.md`
|
||||
|
||||
С этого места продолжаем.
|
||||
Reference in new issue
Block a user