- Features
- Screenshots
- Installation
- Usage
- KoReader Setup
- Supported Data
- Generated Site Structure
- Credits
- Disclaimer
- 📚 Book Library Overview: Displays your currently reading, completed and unread books (EPUBs only!)
- 🎨 Modern UI: Beautiful design powered by Tailwind CSS with clean typography and responsive layout
- 📝 Annotations, Highlights & Ratings: All your KoReader highlights, notes, star ratings, and review notes (summary note) are shown together on each book's details page with elegant formatting
- 📊 Reading Statistics: Track your reading habits with detailed statistics including reading time, pages read, customizable activity heatmaps, and weekly breakdowns
- 📅 Reading Calendar: Monthly calendar view showing your reading activity with books read on each day and monthly statistics
- 🎉 Yearly Recap: Celebrate your reading year with a timeline of completions, monthly summaries (finished books, hours read), and rich per‑book details
- 📈 Per-Book Statistics: Detailed statistics for each book including session count, average session duration, reading speed, and last read date
- 🔍 Search & Filter: Search through your library by title, author, or series, with filters for reading status
- 🚀 Static Site: Generates a complete static website you can host anywhere
- 🖥️ Server Mode: Built-in web server with live file watching for use with reverse proxy
- 📱 Responsive: Optimized for desktop, tablet, and mobile with adaptive grid layouts
Using Home Assistant? Install KOShelf as an add-on with just one click below.
Deploy Koshelf easily using the community-maintained Docker image.
- Create a docker-compose.yml file:
services:
koshelf:
image: ghcr.io/devtigro/koshelf:latest
ports:
- "3000:3000"
volumes:
- /path/to/your/books:/books:ro
- /path/to/your/settings:/settings:ro
restart: unless-stopped- Update the volume paths:
- Replace
/path/to/your/bookswith the absolute path to your book library - Replace
/path/to/your/settingswith the absolute path to your settings directory
- Start the container:
docker compose up -d- Access Koshelf at http://localhost:3000
Docker Image Repository: koshelf-docker
The easiest way to get started is to download a prebuilt binary from the releases page. Binaries are available for:
- Windows (x64)
- macOS (Apple Silicon, Intel & Universal)
- Linux (x64 and ARM64)
Please note that KoShelf is a command line tool, so you will need to execute it from within a terminal (macOS/Linux) or PowerShell/Command Prompt on Windows. Simply double-clicking the executable won't work since it requires command line arguments to function properly.
Note for Windows users: Windows Defender will likely flag and delete the Windows binary as a virus (more information here). This is a false positive if you downloaded the binary directly from this repo. To use the binary:
- Restore it from Windows Defender's protection history (Windows Security > Virus & threat protection > Protection history > Restore)
- Launch the binary from PowerShell or Windows Terminal with arguments - double-clicking will cause it to close immediately since no arguments are provided
If you've never used a command line before, here's how to get started:
Windows:
- Press
Win + R, typepowershell, and press Enter - Navigate to where you downloaded the KoShelf binary (e.g.,
cd C:\Users\YourName\Downloads) - Run the tool with your desired arguments (see examples below)
macOS and Linux:
- Press
Cmd + Space, typeterminal, and press Enter - Navigate to where you downloaded the KoShelf binary (e.g.,
cd ~/Downloads) - Make the file executable:
chmod +x koshelf(should not be needed on macOS as the binary is signed) - Run the tool with your desired arguments (see examples below)
Example:
# Navigate to your downloads folder
cd ~/Downloads # macOS/Linux
cd C:\Users\YourName\Downloads # Windows
# Run KoShelf with your books folder
./koshelf --books-path /path/to/your/books --output ./my-library-sitePro tip: On most terminals, you can drag and drop the downloaded binary file directly into the terminal window. This will automatically insert the full file path, allowing you to immediately add your arguments and run the command.
If you plan to use KoShelf frequently and use Linux or macOS, you can move the binary to /usr/local/bin/ to make it available system-wide. This allows you to run koshelf from anywhere without specifying the full path:
# Move the binary to system PATH (requires sudo)
sudo mv koshelf /usr/local/bin/
# Now you can run it from anywhere
koshelf --books-path ~/Books --output ~/my-library-siteIf you prefer to build from source or need a custom build:
- Rust 1.70+ (for building)
- Node.js and npm (for Tailwind CSS compilation)
git clone https://github.com/paviro/KOShelf
cd koshelf
# Build the Rust binary
cargo build --releaseThe binary will be available at target/release/koshelf.
Note: Tailwind CSS will be compiled during build and added to the binary.
./koshelf --books-path /path/to/your/books --output ./my-library-siteKoShelf can operate in several modes:
- Static Site Generation: Generate a static site once and exit (default when
--outputis specified without--watch) - Web Server Mode: Builds a static site in a temporary folder and serves it, automatically rebuilds on book changes (default when
--outputis not specified) - Watch Mode: Generate a static site, rebuilding when book files change (when both
--outputand--watchare specified)
-b, --books-path: Path to your folder containing EPUB files and KoReader metadata (optional if--statistics-dbis provided)--docsettings-path: Path to KOReader'sdocsettingsfolder for users who store metadata separately (requires--books-path, mutually exclusive with--hashdocsettings-path)--hashdocsettings-path: Path to KOReader'shashdocsettingsfolder for users who store metadata by content hash (requires--books-path, mutually exclusive with--docsettings-path)-s, --statistics-db: Path to thestatistics.sqlite3file for additional reading stats (optional if--books-pathis provided)-o, --output: Output directory for the generated site-p, --port: Port for web server mode (default: 3000)-w, --watch: Enable file watching with static output (requires--output)-t, --title: Site title (default: "KoShelf")--include-unread: Include unread books (EPUBs without KoReader metadata)--heatmap-scale-max: Maximum value for heatmap color intensity scaling (e.g., "auto", "1h", "1h30m", "45min"). Values above this will still be shown but use the highest color intensity. Default is "auto" for automatic scaling--timezone: Timezone to interpret timestamps (IANA name, e.g.,Australia/Sydney); defaults to system local--day-start-time: Logical day start time asHH:MM(default:00:00)--min-pages-per-day: Minimum pages read per book per day to be counted in statistics (optional)--min-time-per-day: Minimum reading time per book per day to be counted in statistics (e.g., "15m", "1h") (optional)Note: If both
--min-pages-per-dayand--min-time-per-dayare provided, a book's data for a day is counted if either condition is met for that book on that day. These filters apply per book per day, meaning each book must individually meet the threshold for each day to be included in statistics.--include-all-stats: By default, statistics are filtered to only include books present in your--books-pathdirectory. This prevents deleted books or external files (like Wallabag articles) from skewing your recap and statistics. Use this flag to include statistics for all books in the database, regardless of whether they exist in your library.--github: Print GitHub repository URL
# Generate site from Books folder
./koshelf -b ~/Books -o ~/my-reading-site -t "My Reading Journey"
# Generate site with statistics and unread books included
./koshelf -b ~/Books -o ~/my-reading-site --statistics-db ~/KOReaderSettings/statistics.sqlite3 --include-unread
# Start web server with live file watching and statistics
./koshelf -b ~/Books -s ~/KOReaderSettings/statistics.sqlite3 -p 8080
# Generate static site with file watching and statistics
./koshelf --books-path ~/Books -o ~/my-reading-site --statistics-db ~/KOReaderSettings/statistics.sqlite3 --watch
# Generate site with custom heatmap color scaling (2 hours = highest intensity)
./koshelf -b ~/Books -s ~/KOReaderSettings/statistics.sqlite3 -o ~/my-reading-site --heatmap-scale-max 2h
# Generate site with custom heatmap color scaling (1.5 hours = highest intensity)
./koshelf -b ~/Books -s ~/KOReaderSettings/statistics.sqlite3 -o ~/my-reading-site --heatmap-scale-max 1h30m
# Generate site with explicit timezone and non-midnight day start (good for night owls)
./koshelf -b ~/Books -s ~/KOReaderSettings/statistics.sqlite3 -o ~/my-reading-site --timezone Australia/Sydney --day-start-time 03:00
# Using hashdocsettings (metadata stored by content hash)
./koshelf -b ~/Books -o ~/my-reading-site --hashdocsettings-path ~/KOReaderSettings/hashdocsettings
# Using docsettings (metadata stored in central folder by path)
./koshelf -b ~/Books -o ~/my-reading-site --docsettings-path ~/KOReaderSettings/docsettingsKOReader offers three ways to store book metadata (reading progress, highlights, annotations). KOShelf supports all three:
By default, KOReader creates .sdr folders next to each book file:
Books/
├── Book Title.epub
├── Book Title.sdr/
│ └── metadata.epub.lua
├── Another Book.epub
├── Another Book.sdr/
│ └── metadata.epub.lua
└── ...
This is the simplest setup - just point --books-path to your books folder.
If you select "hashdocsettings" in KOReader settings, metadata is stored in a central folder organized by content hash:
KOReaderSettings/
└── hashdocsettings/
├── 57/
│ └── 570615f811d504e628db1ef262bea270.sdr/
│ └── metadata.epub.lua
└── a3/
└── a3b2c1d4e5f6...sdr/
└── metadata.epub.lua
Usage:
./koshelf --books-path ~/Books --hashdocsettings-path ~/KOReaderSettings/hashdocsettingsIf you select "docsettings" in KOReader settings, KOReader mirrors your book folder structure in a central folder and stores the metadata there:
KOReaderSettings/
└── docsettings/
└── home/
└── user/
└── Books/
├── Book Title.sdr/
│ └── metadata.epub.lua
└── Another Book.sdr/
└── metadata.epub.lua
Note: Unlike KOReader, KOShelf matches books by filename only, since the folder structure reflects the device path (which may differ from your local path). If you have multiple books with the same filename, KOShelf will show an error - use hashdocsettings or book folder instead.
Usage:
./koshelf --books-path ~/Books --docsettings-path ~/KOReaderSettings/docsettingsAlthough KOReader supports more than just EPUBs, this tool does not, and probably never will, as I don't use them and this is a weekend project that probably won't be maintained much.
Although there are many ways to use this tool here is how I use it:
- Syncthing Sync: I use Syncthing to sync both my books folder and KoReader settings folder from my e-reader to my server
- Books and Statistics: I point to the synced books folder with
--books-pathand tostatistics.sqlite3in the synced KoReader settings folder with--statistics-db - Web Server Mode: I then run KoShelf in web server mode (without
--output) - it will automatically rebuild when files change - Nginx Reverse Proxy: I use an nginx reverse proxy for HTTPS and to restrict access
My actual setup:
# My server command - runs continuously with file watching and statistics
./koshelf --books-path ~/syncthing/Books \
--statistics-db ~/syncthing/KOReaderSettings/statistics.sqlite3 \
--port 3000This way, every time Syncthing pulls updates from my e-reader, the website automatically updates with my latest reading progress, new highlights, and updated statistics.
- Book title
- Authors
- Description (sanitized HTML)
- Cover image
- Language
- Publisher
- Series information (name and number)
- Identifiers (ISBN, ASIN, Goodreads, DOI, etc.)
- Subjects/Genres
- Reading status (reading/complete)
- Highlights and annotations with chapter information
- Notes attached to highlights
- Reading progress percentage
- Rating (stars out of 5)
- Summary note (the one you can fill out at the end of the book)
- Total reading time and pages
- Weekly reading statistics
- Reading activity heatmap with customizable scaling (automatic or fixed maximum)
- Per-book reading sessions and statistics
- Reading speed calculations
- Session duration tracking
- Book completions (used by Yearly Recap)
site/
├── index.html # Main library page
├── recap/ # Yearly Recap pages (latest year linked in sidebar)
│ ├── 2025/
│ │ └── index.html
│ ├── 2024/
│ │ └── index.html
│ └── ...
├── statistics/
│ └── index.html # Reading statistics dashboard
├── calendar/
│ └── index.html # Reading calendar view
├── books/ # Individual book pages
│ ├── list.json # Manifest of all books (convenience only; not used by frontend)
│ ├── book-id1/
│ │ ├── index.html # Book detail page with annotations
│ │ ├── details.md # Markdown export (human-readable)
│ │ └── details.json # JSON export (machine-readable)
│ └── book-id2/
│ ├── index.html
│ ├── details.md
│ └── details.json
└── assets/
├── covers/ # Optimized book covers
│ ├── book-id1.webp
│ └── book-id2.webp
├── css/
│ ├── style.css # Compiled Tailwind CSS
│ └── event-calendar.min.css # Event calendar library styles
├── js/
│ ├── book_list.js # Search and filtering functionality
│ ├── lazy-loading.js # Image lazy loading
│ ├── statistics.js # Statistics page functionality
│ ├── calendar.js # Calendar functionality
│ ├── heatmap.js # Activity heatmap visualization
│ └── event-calendar.min.js # Event calendar library
└── json/ # Data files used by the frontend (when available)
├── calendar/ # Calendar data split by month
│ ├── available_months.json # List of months with calendar data
│ ├── 2024-01.json # January 2024 events and book data
│ ├── 2024-02.json # February 2024 events and book data
│ └── ... # Additional monthly files
└── statistics/ # Statistics data
├── week_0.json # Weekly statistics data
├── week_1.json
├── ...
├── daily_activity_2023.json # Daily activity data for heatmap
├── daily_activity_2024.json
└── ...
Design and feature inspiration taken from KoInsight - an excellent alternative that focuses more on statistics and also supports acting as a KOReader sync server. If you're primarily interested in reading stats rather than highlights and annotations, definitely check it out!
The calendar feature is powered by EventCalendar - a lightweight, full-featured JavaScript event calendar library.
Styled with Tailwind CSS for modern, responsive design.
This is a weekend project and was built for personal use - it relies heavily on AI-generated code. While I've tested everything and use it daily, I take no responsibility for any issues you might encounter. Use at your own risk.




