1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
# book-reader
Browser viewer for books stored as folders of page images. Shows two pages
side by side with a 3D page-turn animation, flips with keyboard, mouse wheel
or click, and remembers where you stopped in each book.
The library is one folder with a subfolder per series. Every folder inside a
series that contains images is a book, named after its folder. Pages are
sorted in natural order (`2.jpg` before `10.jpg`).
```
library/
Series A/ <- images here: the main book "Series A"
Extras/ <- another book of Series A
Series B/
Vol 1/
Vol 2/
```
The library screen (`b`) shows a grid of series; a series with more than one
book opens to its books, a single-book series opens straight away. `/`
searches the current grid, Esc goes back.
## Usage
Create `~/.config/book-reader.conf`:
```sh
LIBRARY="/path/to/library"
PORT=8642
```
Then:
```sh
./rc.book-reader start # prints the URL, e.g. http://127.0.0.1:8642/reader.html
./rc.book-reader stop|restart|status
```
The server is Python's stdlib `http.server`, bound to 127.0.0.1. Its served
root holds only symlinks to `reader.html` and the library, nothing is written
into the library. Runtime files live in `/tmp/book-reader-$UID`.
### Start at boot (Slackware)
```sh
cp rc.book-reader /etc/rc.d/ && chmod 755 /etc/rc.d/rc.book-reader
```
Set `RUNAS=` near the top of the copy to your user name, and add to the
config the path of the viewer, since the copy no longer sits next to it:
```sh
READER="/path/to/book-reader/reader.html"
```
Then in `/etc/rc.d/rc.local`:
```sh
[ -x /etc/rc.d/rc.book-reader ] && /etc/rc.d/rc.book-reader start
```
and the same with `stop` in `/etc/rc.d/rc.local_shutdown`. Started as root,
the script re-executes itself as `RUNAS`, so the server never runs as root and
reads that user's config.
Reading progress is kept in browser localStorage, which is per origin: keep
`PORT` fixed or progress starts over.
## Keys
| Action | Keys |
|---|---|
| Next spread | Right, Space, PgDn (scroll first in fit-width), `l`, wheel down, click right half |
| Previous spread | Left, PgUp, Shift+Space, Backspace, `h`, wheel up, click left half |
| First / last | Home / End |
| Toggle cover-alone offset | `c` |
| Fit width / fit height | `w` (fit-width scrolls, wheel flips at the end of a spread) |
| Library | `b` (Esc closes) |
| Fullscreen | `f` |
## License
Copyright (C) 2026 Danilo M. <danix@danix.xyz>
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License version 2, as published by the
Free Software Foundation. See [LICENSE](LICENSE).
## Development Approach
This project is developed using AI-assisted tools. Code is generated with the help of AI based on human-provided specifications, design decisions, and iterative feedback.
All contributions are reviewed, tested, and curated by the maintainer before being included in the codebase. AI is used as a productivity and exploration tool, while human oversight remains central to all decisions.
The goal is to combine the flexibility of AI-assisted development with standard open-source practices such as transparency, review, and accountability.
|