其他
需要自托管图书库管理时,用 Grimmory…
自托管管理电子书、PDF、漫画,支持多用户、阅读同步、元数据丰富、自动导入与 OPDS/Kobo 兼容。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 57/100 ×0.15
适用场景
需要自托管图书库管理时,用 Grimmo特定
解决思路
- 创建 `.env` 文件,设置:`APP_USER_ID=1000`、`APP_GROUP_ID=1000`、`TZ=Etc/UTC`、`DATABASE_URL=jdbc:mariadb://mariadb:3306/grimmory`、`DB_USER=grimmory`、`DB_PASSWORD=${DB_PASSWORD}`、`DISK_TYPE=LOCAL`、`DB_USER_ID=1000`、`DB_GROUP_ID=1000`、`MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}`、`MYSQL_DATABASE=grimmory`。
- 创建 `docker-compose.yml` 定义 `grimmory` 服务:镜像 `grimmory/grimmory:latest`(备选 `ghcr.io/grimmory-tools/grimmory:latest`),容器名 `grimmory`,环境变量 `USER_ID=${APP_USER_ID}`、`GROUP_ID=${APP_GROUP_ID}`、`TZ=${TZ}`、`DATABASE_URL=${DATABASE_URL}`、`DATABASE_USERNAME=${DB_USER}`、`DATABASE_PASSWORD=${DB_PASSWORD}`、`DISK_TYPE=${DISK_TYPE}`,依赖 `mariadb` 且 `condition: service_healthy`,端口 `6060:6060`,卷 `./data:/app/data`、`./books:/books`、`./bookdrop:/bookdrop`,健康检查 `wget -q -O - http://localhost:6060/api/v1/healthcheck`(间隔 60s,重试 5 次,启动期 60s,超时 10s),重启策略 `unless-stopped`。
- 在 `docker-compose.yml` 中定义 `mariadb` 服务:镜像 `lscr.io/linuxserver/mariadb:11.4.5`,容器名 `mariadb`,环境变量 `PUID=${DB_USER_ID}`、`PGID=${DB_GROUP_ID}`、`TZ=${TZ}`、`MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}`、`MYSQL_DATABASE=${MYSQL_DATABASE}`、`MYSQL_USER=${DB_USER}`、`MYSQL_PASSWORD=${DB_PASSWORD}`,卷 `./mariadb/config:/config`,重启策略 `unless-stopped`,健康检查 `["CMD", "mariadb-admin", "ping", "-h", "localhost"]`(间隔 5s,超时 5s,重试 10 次)。
- 启动服务:运行 `docker compose up -d`。
- 查看应用日志:运行 `docker compose logs -f grimmory`。
- 检查健康状态:运行 `curl http://localhost:6060/api/v1/healthcheck`。
- 打开 `http://localhost:6060` 并创建管理员账户。
- 设置卷目录布局:`./data/`(应用数据、缩略图、用户配置),`./books/`(书籍文件,挂载到 `/books`),`./bookdrop/`(自动导入拖放区,挂载到 `/bookdrop`),`./mariadb/`(MariaDB 数据)。
- 通过环境变量配置:`USER_ID`(应用进程 UID,默认 1000),`GROUP_ID`(应用进程 GID,默认 1000),`TZ`(时区字符串,默认 `Etc/UTC`),`DATABASE_URL`(JDBC 连接字符串,必需),`DATABASE_USERNAME`(数据库用户名,必需),`DATABASE_PASSWORD`(数据库密码,必需),`DISK_TYPE`(`LOCAL` 或 `NETWORK`,默认 `LOCAL`)。
- 使用 BookDrop 自动导入:将文件放入 `./bookdrop/` 目录,Grimmory 会持续监视、检测新文件并解析、从 Google Books 和 Open Library 获取元数据、排队等待审核,在 UI 中审核并确认导入。
- 在 `docker-compose.yml` 中为 BookDrop 映射卷:`- ./bookdrop:/bookdrop`。
- 对于 NFS、SMB 或其他网络挂载文件系统,设置 `DISK_TYPE=NETWORK`,这会禁用破坏性 UI 操作(删除、移动、重命名),但保留阅读、元数据和同步功能。
- 使用 REST API:所有端点位于 `/api/v1/` 下。健康检查 `GET http://localhost:6060/api/v1/healthcheck`;书籍 `GET http://localhost:6060/api/v1/books`,`GET http://localhost:6060/api/v1/books/{id}`,`POST http://localhost:6060/api/v1/books`,`PUT http://localhost:6060/api/v1/books/{id}`,`DELETE http://localhost:6060/api/v1/books/{id}`;书架 `GET http://localhost:6060/api/v1/shelves`,`POST http://localhost:6060/api/v1/shelves`;OPDS 目录 `GET http://localhost:6060/opds`。
- 编写 Java 客户端查询 API(使用 OkHttp):创建 `GrimmoryClient` 类,包含 `OkHttpClient` 和 `ObjectMapper`,构造函数接收 `baseUrl` 和 `token`,方法 `getBooks()` 发送请求到 `baseUrl + "/api/v1/books"`,添加 `Authorization: Bearer <token>` 头,执行请求并返回响应体字符串。
- 编写 Spring Boot 控制器模式:使用 `@RestController` 和 `@RequestMapping("/api/v1/books")`,注入 `BookService`,定义 `GET` 方法 `getAllBooks` 接收分页参数 `page` 默认 0、`size` 默认 20、`search` 可选,返回 `Page<BookDto>`;`GET /{id}` 返回 `BookDto`;`POST` 创建书籍返回 `201 Created`;`PUT /{id}/metadata` 更新元数据。
- 编写 JPA 实体模式:创建 `@Entity @Table(name = "books")` 的 `Book` 类,使用 `@Data`, `@Builder`, `@NoArgsConstructor`, `@AllArgsConstructor`,字段 `id` 自增主键,`title` 非空,`author`, `isbn`, `format`, `file_path`, `cover_path`, `reading_progress`,多对多关联 `Set<Shelf> shelves` 使用 `@ManyToMany` 和 `@JoinTable(name = "book_shelf", joinColumns = @JoinColumn(name = "book_id"), inverseJoinColumns = @JoinColumn(name = "shelf_id"))`,`createdAt` 使用 `@CreationTimestamp`,`updatedAt` 使用 `@UpdateTimestamp`。
- 编写元数据丰富服务:创建 `MetadataService`,注入 `GoogleBooksClient`, `OpenLibraryClient`, `BookRepository`,方法 `enrichMetadata(Long bookId)`:根据 ID 查找书籍,先尝试 `googleBooksClient.search(book.getTitle(), book.getAuthor())`,如果为空则回退到 `openLibraryClient.search(book.getIsbn())`,如果找到元数据则设置描述、封面 URL、出版社、出版日期并保存,返回 `BookDto`。
- 集成 OPDS:使用任何 OPDS 兼容的阅读器应用(Kybook, Chunky, Moon+ Reader 等)连接 `http://<your-host>:6060/opds`,使用 Grimmory 用户名和密码认证。
- 配置 Kobo 同步:通过 Grimmory 设置中的设备同步功能连接,应用暴露与 Kobo API 兼容的同步端点。
- 配置 KOReader 同步:配置 KOReader 的同步插件指向 Grimmory 实例 URL。
- 本地多用户认证:从管理面板 `http://localhost:6060` 创建用户,每个用户有独立的书架、阅读进度和偏好。
- OIDC 认证:通过环境变量配置(参考文档,如 `OIDC_ISSUER_URI`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET`)。
- 从源码构建:克隆仓库 `git clone https://github.com/grimmory-tools/grimmory.git`,进入目录 `cd grimmory`,使用 Maven 构建 `./mvnw clean package -DskipTests`,或构建 Docker 镜像 `docker build -t grimmory:local .`,在 `docker-compose.yml` 中使用本地构建(注释掉 `image`,取消注释 `build: .`)。
- 常用 Docker 命令:启动 `docker compose up -d`;停止 `docker compose down`;查看应用日志 `docker compose logs -f grimmory`;查看数据库日志 `docker compose logs -f mariadb`;仅重启应用 `docker compose restart grimmory`;拉取最新镜像并重新部署 `docker compose pull && docker compose up -d`;进入容器 shell `docker exec -it grimmory /bin/bash`;进入数据库 shell `docker exec -it mariadb mariadb -u grimmory -p grimmory`。
- 故障排除:容器无法启动 — DB 连接被拒绝:检查 MariaDB 健康 `docker compose ps mariadb`(应显示 "healthy"),查看日志 `docker compose logs mariadb`,确保 `DATABASE_URL` 主机匹配服务名 `mariadb:3306`。
- 故障排除:BookDrop 后书籍不出现:验证文件权限,UID/GID 必须匹配 `APP_USER_ID`/`APP_GROUP_ID`,`ls -la ./bookdrop/`,检查应用日志 `docker compose logs -f grimmory | grep -i bookdrop`。
- 故障排除:`./books` 或 `./data` 权限被拒绝:设置所有权匹配 `APP_USER_ID` / `APP_GROUP_ID`,`sudo chown -R 1000:1000 ./books ./data ./bookdrop`。
- 故障排除:OPDS 无法从阅读器应用访问:确认端口 6060 可从设备访问 `curl http://<host-ip>:6060/api/v1/healthcheck`,检查防火墙规则。
- 故障排除:高内存使用:MariaDB 和 Grimmory 一起至少需要 ~512 MB RAM,对于大型图书馆(10k+ 本书)分配 1–2 GB。
- 故障排除:元数据不丰富:Google Books 和 Open Library 需要出站互联网访问,验证 DNS 和网络 `docker exec -it grimmory curl -s "https://www.googleapis.com/books/v1/volumes?q=test"`。
- 贡献前:打开 issue 并获得维护者批准;包括截图/视频证明和粘贴的测试输出;遵循 `CONTRIBUTING.md` 中的后端和前端约定;AI 辅助代码允许但必须运行、测试并理解每一行。
- 提交前运行测试:`./mvnw test`;检查代码风格:`./mvnw checkstyle:check`。
适用边界 · 注意事项
- 没有 Docker 和 Docker Compose 环境时。
- 只需要简单的本地电子书阅读器,不需要自托管、多用户、同步功能时。
- 服务器资源极其有限(内存小于 512 MB)且无法分配时。