Updated docs and readme
This commit is contained in:
475
README.md
475
README.md
@@ -5,25 +5,6 @@ It's optimized for large libraries (10k–100k+ comics), supports FastAPI + SQLi
|
||||
|
||||
Works great with [Panels for iOS](https://panels.app) and other OPDS readers.
|
||||
|
||||
<a href="https://www.buymeacoffee.com/frederikb" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="41" width="174"></a>
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Features](#-features)
|
||||
- [Quick Start](#-quick-start)
|
||||
- [Installation Methods](#-installation-methods)
|
||||
- [Configuration](#-configuration)
|
||||
- [API Documentation](#-api--endpoints)
|
||||
- [Dashboard](#-dashboard)
|
||||
- [Smart Lists](#-smart-lists)
|
||||
- [Search](#-search)
|
||||
- [Client Setup](#-client-setup)
|
||||
- [Troubleshooting](#-troubleshooting)
|
||||
- [Contributing](#-contributing)
|
||||
- [License](#-license)
|
||||
|
||||
---
|
||||
|
||||
## ✨ Features
|
||||
@@ -41,368 +22,21 @@ Works great with [Panels for iOS](https://panels.app) and other OPDS readers.
|
||||
- 🔄 File system watching for auto-updates
|
||||
- 📱 Mobile-optimized dashboard
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Docker and Docker Compose installed
|
||||
- Comic collection in CBZ format with `ComicInfo.xml` metadata
|
||||
|
||||
### Folder Structure
|
||||
|
||||
Your comics should be organized like this:
|
||||
```
|
||||
/your/comics/
|
||||
├── Batman (2016)/
|
||||
│ ├── Batman (2016) - 001.cbz # contains ComicInfo.xml
|
||||
│ └── Batman (2016) - 002.cbz
|
||||
├── Saga/
|
||||
│ └── Saga - 001.cbz
|
||||
└── ...
|
||||
```
|
||||
|
||||
**Recommended**: I use [ComicRack CE](https://github.com/maforget/ComicRackCE) to organize my comic library and generate proper `ComicInfo.xml` metadata. For a comprehensive guide on setting up an optimal comic library structure and metadata management, see my detailed guide at: **[https://comicrack.baerentsen.space/](https://comicrack.baerentsen.space/)**
|
||||
|
||||
|
||||
### Docker Compose Setup
|
||||
|
||||
Create a `docker-compose.yml` file:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
comicopds:
|
||||
image: gitea.baerentsen.space/frederikbaerentsen/comicopds:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8382:8080"
|
||||
environment:
|
||||
CONTENT_BASE_DIR: /library
|
||||
SERVER_BASE: "http://192.168.10.10:8382" # Replace with your server IP/domain
|
||||
URL_PREFIX: "" # set to "/comics" if behind a reverse proxy subpath
|
||||
DISABLE_AUTH: "false" # set to true to disable authentication
|
||||
OPDS_BASIC_USER: "admin"
|
||||
OPDS_BASIC_PASS: "change-me-please" # Use a strong password!
|
||||
ENABLE_WATCH: "false" # auto-update index on file changes
|
||||
PRECACHE_THUMBS: "false" # set true to pre-cache thumbs on reindex
|
||||
AUTO_INDEX_ON_START: "false" # skip reindexing on each container start
|
||||
volumes:
|
||||
- "./comics:/library:ro"
|
||||
- "./data:/data"
|
||||
```
|
||||
|
||||
### Launch Commands
|
||||
|
||||
```bash
|
||||
# Build and start
|
||||
docker compose build
|
||||
docker compose up -d
|
||||
|
||||
# View logs
|
||||
docker compose logs -f
|
||||
|
||||
# Stop
|
||||
docker compose down
|
||||
```
|
||||
|
||||
### Access Points
|
||||
|
||||
- 📡 **OPDS Feed**: http://localhost:8382/
|
||||
- 📊 **Dashboard**: http://localhost:8382/dashboard
|
||||
- 🧠 **Smart Lists**: http://localhost:8382/search
|
||||
|
||||
<!-- --- -->
|
||||
|
||||
<!-- ## 📖 Documentation
|
||||
|
||||
- Reindex library: click the Reindex button in dashboard
|
||||
- Pre-cache thumbnails: click Pre-cache Thumbnails (generates all covers ahead of time)
|
||||
If covers aren't pre-cached, each cover will be generated when needed.
|
||||
- Search: available in Panels & other OPDS apps
|
||||
- Smart Lists: create saved filters on /search -->
|
||||
<a href="https://www.buymeacoffee.com/frederikb" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="41" width="174"></a>
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration
|
||||
## 📋 Documentation
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Default | Description |
|
||||
|-----------------------|-------------|-------------|
|
||||
| `CONTENT_BASE_DIR` | `/library` | Path inside the container where your comics are stored (mounted volume). |
|
||||
| `PAGE_SIZE` | `50` | Number of entries per page in OPDS feeds. Increase/decrease depending on client performance. |
|
||||
| `SERVER_BASE` | (required) | Public base URL (e.g. `http://10.0.0.1:8382` or `https://comics.example.com`). Used in generated OPDS links. |
|
||||
| `URL_PREFIX` | `""` | Path prefix when serving behind a reverse proxy (e.g. `/comics`). Leave empty if served at root or subdomain. |
|
||||
| `DISABLE_AUTH` | `false` | If `true`, disables authentication completely (public access). |
|
||||
| `OPDS_BASIC_USER` | `admin` | Username for HTTP Basic Auth. Ignored if `DISABLE_AUTH=true`. |
|
||||
| `OPDS_BASIC_PASS` | `change-me` | Password for HTTP Basic Auth. Ignored if `DISABLE_AUTH=true`. |
|
||||
| `ENABLE_WATCH` | `false` | Watch filesystem for changes and update index incrementally. (`true`/`false`). |
|
||||
| `AUTO_INDEX_ON_START` | `false` | If `true`, reindexes library on every container start. Recommended `false` for large libraries. |
|
||||
| `PRECACHE_THUMBS` | `false` | If `true`, enables thumbnail generation when reindexing or via dashboard. |
|
||||
| `PRECACHE_ON_START` | `false` | If `true`, automatically triggers full thumbnail pre-cache at container start. Recommended `false` for large libraries. |
|
||||
| `THUMB_WORKERS` | `3` | Number of parallel workers for thumbnail generation. Tune for your CPU/IO capacity. |
|
||||
|
||||
### 📚 Recommended Settings for Large Libraries (30k–100k+ comics)
|
||||
|
||||
For very large collections, some defaults should be adjusted to avoid long startup times and high resource usage:
|
||||
|
||||
#### Indexing Settings
|
||||
- `AUTO_INDEX_ON_START=false` → prevents reindexing every time the container starts
|
||||
- Use the **Reindex** button on the dashboard when needed instead
|
||||
|
||||
#### Thumbnail Settings
|
||||
- `PRECACHE_ON_START=false` → don't pre-cache on every boot
|
||||
- Run pre-cache manually via the dashboard button after a big import
|
||||
- `THUMB_WORKERS=4`–`6` → if you have enough CPU/IO, increase worker count for faster thumbnail generation
|
||||
|
||||
#### Performance Settings
|
||||
- Keep `PAGE_SIZE=50` unless your client struggles with large feeds
|
||||
- Some OPDS readers work better with smaller pages (e.g. `25`)
|
||||
|
||||
#### Security Settings
|
||||
- For private servers behind a VPN, you can disable auth: `DISABLE_AUTH=true`
|
||||
- Otherwise, keep Basic Auth enabled (`OPDS_BASIC_USER` / `OPDS_BASIC_PASS`)
|
||||
|
||||
These settings ensure the container starts faster, avoids unnecessary reprocessing, and lets you control when heavy tasks (indexing, thumbnailing) happen.
|
||||
|
||||
---
|
||||
|
||||
## 🌐 API & Endpoints
|
||||
|
||||
ComicOPDS exposes both user-facing endpoints (for OPDS clients and the dashboard) and admin/debug endpoints.
|
||||
|
||||
### 📡 OPDS Endpoints
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/` | `GET` | Root OPDS catalog feed (same as `/opds`) |
|
||||
| `/opds` | `GET` | Root OPDS catalog feed. Supports browsing by folder and smart lists. |
|
||||
| `/opds?path=...` | `GET` | Browse into a subfolder (series, publisher, etc.). |
|
||||
| `/opds/search.xml` | `GET` | [OpenSearch 1.1](https://opensearch.org/) descriptor. Tells OPDS clients how to search. |
|
||||
| `/opds/search?q=...&page=...` | `GET` | Perform a search query (returns OPDS feed of matching comics). |
|
||||
| `/download?path=...` | `GET` | Download a `.cbz` file. Supports HTTP range requests. |
|
||||
| `/stream?path=...` | `GET` | Stream a `.cbz` file (content-type `application/vnd.comicbook+zip`). |
|
||||
| `/pse/pages?path=...` | `GET` | OPDS PSE 1.1 page streaming (individual pages as images). Used by Panels and similar clients. |
|
||||
| `/thumb?path=...` | `GET` | Get thumbnail image for a comic (JPEG format). |
|
||||
|
||||
### 📊 Dashboard & Stats
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/dashboard` | `GET` | Dashboard (HTML UI with Bootstrap & Chart.js). |
|
||||
| `/stats.json` | `GET` | JSON with library statistics (total comics, unique series, publishers, etc.). |
|
||||
| `/search` | `GET` | Smart Lists UI (create/edit saved searches). |
|
||||
| `/healthz` | `GET` | Health check endpoint (returns "ok"). |
|
||||
|
||||
### 🛠️ Admin Endpoints
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/admin/reindex` | `POST` | Trigger a full library reindex. Shows progress in dashboard. |
|
||||
| `/admin/thumbs/precache` | `POST` | Trigger full thumbnail pre-cache. Shows progress in dashboard. |
|
||||
| `/index/status` | `GET` | JSON status of current indexing task. |
|
||||
| `/thumbs/status` | `GET` | JSON status of current thumbnail caching task. |
|
||||
| `/thumbs/errors/log` | `GET` | Download the thumbnail extraction error log (`/data/thumbs_errors.log`). |
|
||||
|
||||
### 🧪 Debug Endpoints
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/debug/children?path=...` | `GET` | JSON list of child items (files/folders) under a path. Useful for testing indexing. |
|
||||
| `/debug/fts` | `GET` | Returns `{ "fts5": true/false }` indicating whether SQLite FTS5 is enabled. |
|
||||
|
||||
⚠️ **Note:**
|
||||
- Admin and debug endpoints require Basic Auth unless `DISABLE_AUTH=true` is set.
|
||||
- OPDS endpoints follow the OPDS 1.2 specification and should work with Panels and other compliant OPDS clients.
|
||||
|
||||
---
|
||||
|
||||
## 📊 Dashboard
|
||||
|
||||
> Access through `/dashboard`
|
||||
|
||||
The dashboard provides a comprehensive overview of your comic library:
|
||||
|
||||
### Features
|
||||
- **Library Statistics**: Total comics, unique series, publishers
|
||||
- **Interactive Charts**:
|
||||
- Publishers distribution (doughnut chart)
|
||||
- Publication timeline (line chart)
|
||||
- Top writers (horizontal bar chart)
|
||||
- Format breakdown
|
||||
- **Management Tools**:
|
||||
- Reindex library button
|
||||
- Pre-cache thumbnails button
|
||||
- Progress bars for ongoing operations
|
||||
- **Error Monitoring**:
|
||||
- Thumbnail extraction error counter
|
||||
- Downloadable error log
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Smart Lists
|
||||
|
||||
> Access through `/search`
|
||||
|
||||
Smart Lists allow you to create saved search filters that appear as "virtual folders" in your OPDS feed.
|
||||
|
||||
### Creating Smart Lists
|
||||
|
||||
#### Simple Filters
|
||||
Add filters using the web interface:
|
||||
- `series=Batman`
|
||||
- `year=2024`
|
||||
- `publisher=DC Comics`
|
||||
|
||||
#### Advanced Filters
|
||||
Create complex queries with multiple conditions:
|
||||
|
||||
```
|
||||
series contains 'Scrooge McDuck'
|
||||
volume equals 1953
|
||||
number >= 285
|
||||
number <= 297
|
||||
```
|
||||
|
||||
#### JSON Configuration Example
|
||||
For advanced users, Smart Lists are stored in `/data/smartlist.json`:
|
||||
|
||||
```
|
||||
{
|
||||
"name": "Maul + Vader (1-5)",
|
||||
"slug": "maul-vader-1-5",
|
||||
"groups": [
|
||||
{
|
||||
"rules": [
|
||||
{
|
||||
"not": false,
|
||||
"field": "series",
|
||||
"op": "contains",
|
||||
"value": "Maul"
|
||||
},
|
||||
{
|
||||
"not": false,
|
||||
"field": "number",
|
||||
"op": "<=",
|
||||
"value": "5"
|
||||
},
|
||||
{
|
||||
"not": false,
|
||||
"field": "format",
|
||||
"op": "equals",
|
||||
"value": "Limited Series"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rules": [
|
||||
{
|
||||
"not": false,
|
||||
"field": "series",
|
||||
"op": "contains",
|
||||
"value": "Vader"
|
||||
},
|
||||
{
|
||||
"not": false,
|
||||
"field": "number",
|
||||
"op": "<=",
|
||||
"value": "5"
|
||||
},
|
||||
{
|
||||
"not": false,
|
||||
"field": "format",
|
||||
"op": "equals",
|
||||
"value": "Main Series"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"sort": "series_number",
|
||||
"limit": 0,
|
||||
"distinct_by": "",
|
||||
"distinct_mode": "oldest"
|
||||
}
|
||||
```
|
||||
|
||||
**Maul + Vader (1-5)**:
|
||||
|
||||
- Group 1:
|
||||
- series contains "Maul"
|
||||
- number <= 5
|
||||
- format = "Limited Series"
|
||||
- Group 2:
|
||||
- series contains "Vader"
|
||||
- number <= 5
|
||||
- format = "Main Series"
|
||||
- Sort:
|
||||
- series_number
|
||||
- limit: 0
|
||||
- Distinct: no
|
||||
|
||||
### Supported Operations
|
||||
- `equals`, `contains`, `startswith`, `endswith`
|
||||
- `=`, `!=`, `>=`, `<=`, `>`, `<` (for numeric fields)
|
||||
- `not` modifier for any operation
|
||||
|
||||
### "Distinct by series and volume (latest)"
|
||||
|
||||
When that option is enabled, a smart list will return at most one comic per series and volume.
|
||||
For each series, it picks the latest issue, using this tie-break:
|
||||
|
||||
1. Newer year (cast to integer)
|
||||
2. If year ties: higher number (cast to integer)
|
||||
3. If number ties: newer file mtime (last modified time)
|
||||
|
||||
So you get a de-duplicated "what's the newest issue for each series?" view.
|
||||
|
||||
**Use Cases**:
|
||||
|
||||
- A clean "latest per series" shelf (e.g., to see what's new without 300 issues of Batman).
|
||||
- Weekly pulls / backlog triage: combine with filters like `publisher=Image` or `year >= 2020`.
|
||||
|
||||
**Important details / edge cases**
|
||||
|
||||
- Numeric casting: blank or non-numeric `year`/`number` are treated as `NULL` → effectively `0`, so those won't beat entries with proper numbers (eg. `16A`).
|
||||
|
||||
**Example use**
|
||||
|
||||
- "Latest Image series":
|
||||
- Rules: `publisher = "Image Comics"`, `year >= 2018`
|
||||
- Distinct by series: on
|
||||
|
||||
→ One newest issue per Image series since 2018.
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Search
|
||||
|
||||
ComicOPDS provides powerful search capabilities:
|
||||
|
||||
### Search Technology
|
||||
- **SQLite FTS5**: Full-text search when available
|
||||
- **Fallback**: LIKE queries when FTS5 unavailable
|
||||
|
||||
> Check `/debug/fts`, which returns `{ "fts5": true/false }` indicating whether SQLite FTS5 is enabled.
|
||||
|
||||
### Searchable Fields
|
||||
- `series` - Comic series name
|
||||
- `title` - Individual issue title
|
||||
- `publisher` - Publishing company
|
||||
- `year` - Publication year
|
||||
- `writer` - Writer(s)
|
||||
- `penciller` - Artist(s)
|
||||
- `genre` - Comic genre/category
|
||||
- `characters` - Featured characters
|
||||
- `tags` - Custom tags
|
||||
- `format` - TPB, Main Series, Annual, One-Shot etc.
|
||||
|
||||
### Search Tips
|
||||
- Use quotes for exact phrases: `"Dark Knight"`
|
||||
- Combine terms: `batman joker`
|
||||
- Use wildcards: `bat*` (when FTS5 available)
|
||||
|
||||
---
|
||||
- [Quick Start](docs/quickstart.md)
|
||||
- [Configuration](docs/configuration.md)
|
||||
- [API Documentation](docs/api.md)
|
||||
- [Dashboard](docs/dashboard.md)
|
||||
- [Smart Lists](docs/smartlists.md)
|
||||
- [Search](docs/search.md)
|
||||
- [Client Setup](#-client-setup)
|
||||
- [Troubleshooting](docs/troubleshooting.md)
|
||||
- [License](license)
|
||||
|
||||
## 📱 Clients
|
||||
|
||||
@@ -424,99 +58,16 @@ ComicOPDS provides powerful search capabilities:
|
||||
|
||||
### Client-Specific Notes
|
||||
- Some clients work better with smaller `PAGE_SIZE` (e.g., 25 instead of 50)
|
||||
- Page streaming (PSE 1.2) requires client support
|
||||
- Page streaming (PSE 1.1) requires client support
|
||||
- Thumbnail quality may vary between clients
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### No Comics Appearing
|
||||
- **Check mount**: Ensure your comics folder is mounted at `/library`
|
||||
- **File format**: Only `.cbz` files are supported
|
||||
- **Metadata**: Ensure CBZ files contain `ComicInfo.xml`
|
||||
- **Permissions**: Verify read permissions on comic files
|
||||
|
||||
#### Missing Thumbnails
|
||||
- **First load**: Thumbnails generate on first request
|
||||
- **Check permissions**: Ensure `/data/thumbs` is writable
|
||||
- **View errors**: Check error log via dashboard or `/data/thumbs_errors.log`
|
||||
|
||||
#### Authentication Problems
|
||||
- **Verify credentials**: Check `OPDS_BASIC_USER` and `OPDS_BASIC_PASS`
|
||||
- **Client support**: Ensure your client supports HTTP Basic Auth
|
||||
- **Disable auth**: Set `DISABLE_AUTH=true` for testing
|
||||
|
||||
#### Wrong Links/URLs
|
||||
- **Behind proxy**: Set `SERVER_BASE` and `URL_PREFIX` correctly
|
||||
- **Protocol mismatch**: Ensure HTTP/HTTPS consistency
|
||||
|
||||
### Debug Commands
|
||||
|
||||
```bash
|
||||
# View container logs
|
||||
docker compose logs -f comicopds
|
||||
|
||||
# Check container health
|
||||
docker compose ps
|
||||
|
||||
# Inspect configuration
|
||||
docker compose exec comicopds env | grep -E "(SERVER_BASE|URL_PREFIX|CONTENT_BASE_DIR)"
|
||||
|
||||
# Test internal connectivity
|
||||
docker compose exec comicopds wget -qO- http://localhost:8080/healthz
|
||||
|
||||
# Check FTS5 availability
|
||||
curl -u admin:password http://localhost:8382/debug/fts
|
||||
```
|
||||
|
||||
### Log Files
|
||||
- **Application logs**: `docker compose logs -f`
|
||||
- **Thumbnail errors**: `/data/thumbs_errors.log`
|
||||
|
||||
### Performance Tuning
|
||||
- **Large libraries**: Disable `AUTO_INDEX_ON_START`
|
||||
- **Slow thumbnails**: Increase `THUMB_WORKERS`
|
||||
- **Memory usage**: Reduce `PAGE_SIZE`
|
||||
- **Network issues**: Check `SERVER_BASE` configuration
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
MIT License – use freely, modify, and contribute.
|
||||
|
||||
```
|
||||
Copyright (c) 2024 Frederik Baerentsen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Links
|
||||
|
||||
- **Repository**: [Gitea](https://gitea.baerentsen.space/FrederikBaerentsen/ComicOPDS)
|
||||
- **OPDS Specification**: [OPDS 1.2](https://specs.opds.io/opds-1.2)
|
||||
- **OPDS Page Streaming Extension: [OPDS PSE 1.2](https://anansi-project.github.io/docs/opds-pse/specs/v1.2)
|
||||
- **OPDS Page Streaming Extension**: [OPDS PSE 1.1](https://anansi-project.github.io/docs/opds-pse/specs/v1.1)
|
||||
- **Buy Me a Coffee**: [frederikb](https://www.buymeacoffee.com/frederikb)
|
||||
|
||||
---
|
||||
|
||||
47
docs/api.md
Normal file
47
docs/api.md
Normal file
@@ -0,0 +1,47 @@
|
||||
## 🌐 API & Endpoints
|
||||
|
||||
ComicOPDS exposes both user-facing endpoints (for OPDS clients and the dashboard) and admin/debug endpoints.
|
||||
|
||||
### 📡 OPDS Endpoints
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/` | `GET` | Root OPDS catalog feed (same as `/opds`) |
|
||||
| `/opds` | `GET` | Root OPDS catalog feed. Supports browsing by folder and smart lists. |
|
||||
| `/opds?path=...` | `GET` | Browse into a subfolder (series, publisher, etc.). |
|
||||
| `/opds/search.xml` | `GET` | [OpenSearch 1.1](https://opensearch.org/) descriptor. Tells OPDS clients how to search. |
|
||||
| `/opds/search?q=...&page=...` | `GET` | Perform a search query (returns OPDS feed of matching comics). |
|
||||
| `/download?path=...` | `GET` | Download a `.cbz` file. Supports HTTP range requests. |
|
||||
| `/stream?path=...` | `GET` | Stream a `.cbz` file (content-type `application/vnd.comicbook+zip`). |
|
||||
| `/pse/pages?path=...` | `GET` | OPDS PSE 1.1 page streaming (individual pages as images). Used by Panels and similar clients. |
|
||||
| `/thumb?path=...` | `GET` | Get thumbnail image for a comic (JPEG format). |
|
||||
|
||||
### 📊 Dashboard & Stats
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/dashboard` | `GET` | Dashboard (HTML UI with Bootstrap & Chart.js). |
|
||||
| `/stats.json` | `GET` | JSON with library statistics (total comics, unique series, publishers, etc.). |
|
||||
| `/search` | `GET` | Smart Lists UI (create/edit saved searches). |
|
||||
| `/healthz` | `GET` | Health check endpoint (returns "ok"). |
|
||||
|
||||
### 🛠️ Admin Endpoints
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/admin/reindex` | `POST` | Trigger a full library reindex. Shows progress in dashboard. |
|
||||
| `/admin/thumbs/precache` | `POST` | Trigger full thumbnail pre-cache. Shows progress in dashboard. |
|
||||
| `/index/status` | `GET` | JSON status of current indexing task. |
|
||||
| `/thumbs/status` | `GET` | JSON status of current thumbnail caching task. |
|
||||
| `/thumbs/errors/log` | `GET` | Download the thumbnail extraction error log (`/data/thumbs_errors.log`). |
|
||||
|
||||
### 🧪 Debug Endpoints
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/debug/children?path=...` | `GET` | JSON list of child items (files/folders) under a path. Useful for testing indexing. |
|
||||
| `/debug/fts` | `GET` | Returns `{ "fts5": true/false }` indicating whether SQLite FTS5 is enabled. |
|
||||
|
||||
⚠️ **Note:**
|
||||
- Admin and debug endpoints require Basic Auth unless `DISABLE_AUTH=true` is set.
|
||||
- OPDS endpoints follow the OPDS 1.2 specification and should work with Panels and other compliant OPDS clients.
|
||||
41
docs/configuration.md
Normal file
41
docs/configuration.md
Normal file
@@ -0,0 +1,41 @@
|
||||
## 🔧 Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Default | Description |
|
||||
|-----------------------|-------------|-------------|
|
||||
| `CONTENT_BASE_DIR` | `/library` | Path inside the container where your comics are stored (mounted volume). |
|
||||
| `PAGE_SIZE` | `50` | Number of entries per page in OPDS feeds. Increase/decrease depending on client performance. |
|
||||
| `SERVER_BASE` | (required) | Public base URL (e.g. `http://10.0.0.1:8382` or `https://comics.example.com`). Used in generated OPDS links. |
|
||||
| `URL_PREFIX` | `""` | Path prefix when serving behind a reverse proxy (e.g. `/comics`). Leave empty if served at root or subdomain. |
|
||||
| `DISABLE_AUTH` | `false` | If `true`, disables authentication completely (public access). |
|
||||
| `OPDS_BASIC_USER` | `admin` | Username for HTTP Basic Auth. Ignored if `DISABLE_AUTH=true`. |
|
||||
| `OPDS_BASIC_PASS` | `change-me` | Password for HTTP Basic Auth. Ignored if `DISABLE_AUTH=true`. |
|
||||
| `ENABLE_WATCH` | `false` | Watch filesystem for changes and update index incrementally. (`true`/`false`). |
|
||||
| `AUTO_INDEX_ON_START` | `false` | If `true`, reindexes library on every container start. Recommended `false` for large libraries. |
|
||||
| `PRECACHE_THUMBS` | `false` | If `true`, enables thumbnail generation when reindexing or via dashboard. |
|
||||
| `PRECACHE_ON_START` | `false` | If `true`, automatically triggers full thumbnail pre-cache at container start. Recommended `false` for large libraries. |
|
||||
| `THUMB_WORKERS` | `3` | Number of parallel workers for thumbnail generation. Tune for your CPU/IO capacity. |
|
||||
|
||||
### 📚 Recommended Settings for Large Libraries (30k–100k+ comics)
|
||||
|
||||
For very large collections, some defaults should be adjusted to avoid long startup times and high resource usage:
|
||||
|
||||
#### Indexing Settings
|
||||
- `AUTO_INDEX_ON_START=false` → prevents reindexing every time the container starts
|
||||
- Use the **Reindex** button on the dashboard when needed instead
|
||||
|
||||
#### Thumbnail Settings
|
||||
- `PRECACHE_ON_START=false` → don't pre-cache on every boot
|
||||
- Run pre-cache manually via the dashboard button after a big import
|
||||
- `THUMB_WORKERS=4`–`6` → if you have enough CPU/IO, increase worker count for faster thumbnail generation
|
||||
|
||||
#### Performance Settings
|
||||
- Keep `PAGE_SIZE=50` unless your client struggles with large feeds
|
||||
- Some OPDS readers work better with smaller pages (e.g. `25`)
|
||||
|
||||
#### Security Settings
|
||||
- For private servers behind a VPN, you can disable auth: `DISABLE_AUTH=true`
|
||||
- Otherwise, keep Basic Auth enabled (`OPDS_BASIC_USER` / `OPDS_BASIC_PASS`)
|
||||
|
||||
These settings ensure the container starts faster, avoids unnecessary reprocessing, and lets you control when heavy tasks (indexing, thumbnailing) happen.
|
||||
20
docs/dashboard.md
Normal file
20
docs/dashboard.md
Normal file
@@ -0,0 +1,20 @@
|
||||
## 📊 Dashboard
|
||||
|
||||
> Access through `/dashboard`
|
||||
|
||||
The dashboard provides a comprehensive overview of your comic library:
|
||||
|
||||
### Features
|
||||
- **Library Statistics**: Total comics, unique series, publishers
|
||||
- **Interactive Charts**:
|
||||
- Publishers distribution (doughnut chart)
|
||||
- Publication timeline (line chart)
|
||||
- Top writers (horizontal bar chart)
|
||||
- Format breakdown
|
||||
- **Management Tools**:
|
||||
- Reindex library button
|
||||
- Pre-cache thumbnails button
|
||||
- Progress bars for ongoing operations
|
||||
- **Error Monitoring**:
|
||||
- Thumbnail extraction error counter
|
||||
- Downloadable error log
|
||||
68
docs/quickstart.md
Normal file
68
docs/quickstart.md
Normal file
@@ -0,0 +1,68 @@
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Docker and Docker Compose installed
|
||||
- Comic collection in CBZ format with `ComicInfo.xml` metadata
|
||||
|
||||
### Folder Structure
|
||||
|
||||
Your comics should be organized like this:
|
||||
```
|
||||
/your/comics/
|
||||
├── Batman (2016)/
|
||||
│ ├── Batman (2016) - 001.cbz # contains ComicInfo.xml
|
||||
│ └── Batman (2016) - 002.cbz
|
||||
├── Saga/
|
||||
│ └── Saga - 001.cbz
|
||||
└── ...
|
||||
```
|
||||
|
||||
**Recommended**: I use [ComicRack CE](https://github.com/maforget/ComicRackCE) to organize my comic library and generate proper `ComicInfo.xml` metadata. For a comprehensive guide on setting up an optimal comic library structure and metadata management, see my detailed guide at: **[https://comicrack.baerentsen.space/](https://comicrack.baerentsen.space/)**
|
||||
|
||||
|
||||
### Docker Compose Setup
|
||||
|
||||
Create a `docker-compose.yml` file:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
comicopds:
|
||||
image: gitea.baerentsen.space/frederikbaerentsen/comicopds:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8382:8080"
|
||||
environment:
|
||||
CONTENT_BASE_DIR: /library
|
||||
SERVER_BASE: "http://192.168.10.10:8382" # Replace with your server IP/domain
|
||||
URL_PREFIX: "" # set to "/comics" if behind a reverse proxy subpath
|
||||
DISABLE_AUTH: "false" # set to true to disable authentication
|
||||
OPDS_BASIC_USER: "admin"
|
||||
OPDS_BASIC_PASS: "change-me-please" # Use a strong password!
|
||||
ENABLE_WATCH: "false" # auto-update index on file changes
|
||||
PRECACHE_THUMBS: "false" # set true to pre-cache thumbs on reindex
|
||||
AUTO_INDEX_ON_START: "false" # skip reindexing on each container start
|
||||
volumes:
|
||||
- "./comics:/library:ro"
|
||||
- "./data:/data"
|
||||
```
|
||||
|
||||
### Launch Commands
|
||||
|
||||
```bash
|
||||
# Build and start
|
||||
docker compose build
|
||||
docker compose up -d
|
||||
|
||||
# View logs
|
||||
docker compose logs -f
|
||||
|
||||
# Stop
|
||||
docker compose down
|
||||
```
|
||||
|
||||
### Access Points
|
||||
|
||||
- 📡 **OPDS Feed**: http://localhost:8382/
|
||||
- 📊 **Dashboard**: http://localhost:8382/dashboard
|
||||
- 🧠 **Smart Lists**: http://localhost:8382/search
|
||||
26
docs/search.md
Normal file
26
docs/search.md
Normal file
@@ -0,0 +1,26 @@
|
||||
## 🔍 Search
|
||||
|
||||
ComicOPDS provides powerful search capabilities:
|
||||
|
||||
### Search Technology
|
||||
- **SQLite FTS5**: Full-text search when available
|
||||
- **Fallback**: LIKE queries when FTS5 unavailable
|
||||
|
||||
> Check `/debug/fts`, which returns `{ "fts5": true/false }` indicating whether SQLite FTS5 is enabled.
|
||||
|
||||
### Searchable Fields
|
||||
- `series` - Comic series name
|
||||
- `title` - Individual issue title
|
||||
- `publisher` - Publishing company
|
||||
- `year` - Publication year
|
||||
- `writer` - Writer(s)
|
||||
- `penciller` - Artist(s)
|
||||
- `genre` - Comic genre/category
|
||||
- `characters` - Featured characters
|
||||
- `tags` - Custom tags
|
||||
- `format` - TPB, Main Series, Annual, One-Shot etc.
|
||||
|
||||
### Search Tips
|
||||
- Use quotes for exact phrases: `"Dark Knight"`
|
||||
- Combine terms: `batman joker`
|
||||
- Use wildcards: `bat*` (when FTS5 available)
|
||||
131
docs/smartlists.md
Normal file
131
docs/smartlists.md
Normal file
@@ -0,0 +1,131 @@
|
||||
## 🧠 Smart Lists
|
||||
|
||||
> Access through `/search`
|
||||
|
||||
Smart Lists allow you to create saved search filters that appear as "virtual folders" in your OPDS feed.
|
||||
|
||||
### Creating Smart Lists
|
||||
|
||||
#### Simple Filters
|
||||
Add filters using the web interface:
|
||||
- `series=Batman`
|
||||
- `year=2024`
|
||||
- `publisher=DC Comics`
|
||||
|
||||
#### Advanced Filters
|
||||
Create complex queries with multiple conditions:
|
||||
|
||||
```
|
||||
series contains 'Scrooge McDuck'
|
||||
volume equals 1953
|
||||
number >= 285
|
||||
number <= 297
|
||||
```
|
||||
|
||||
#### JSON Configuration Example
|
||||
For advanced users, Smart Lists are stored in `/data/smartlist.json`:
|
||||
|
||||
```
|
||||
{
|
||||
"name": "Maul + Vader (1-5)",
|
||||
"slug": "maul-vader-1-5",
|
||||
"groups": [
|
||||
{
|
||||
"rules": [
|
||||
{
|
||||
"not": false,
|
||||
"field": "series",
|
||||
"op": "contains",
|
||||
"value": "Maul"
|
||||
},
|
||||
{
|
||||
"not": false,
|
||||
"field": "number",
|
||||
"op": "<=",
|
||||
"value": "5"
|
||||
},
|
||||
{
|
||||
"not": false,
|
||||
"field": "format",
|
||||
"op": "equals",
|
||||
"value": "Limited Series"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rules": [
|
||||
{
|
||||
"not": false,
|
||||
"field": "series",
|
||||
"op": "contains",
|
||||
"value": "Vader"
|
||||
},
|
||||
{
|
||||
"not": false,
|
||||
"field": "number",
|
||||
"op": "<=",
|
||||
"value": "5"
|
||||
},
|
||||
{
|
||||
"not": false,
|
||||
"field": "format",
|
||||
"op": "equals",
|
||||
"value": "Main Series"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"sort": "series_number",
|
||||
"limit": 0,
|
||||
"distinct_by": "",
|
||||
"distinct_mode": "oldest"
|
||||
}
|
||||
```
|
||||
|
||||
**Maul + Vader (1-5)**:
|
||||
|
||||
- Group 1:
|
||||
- series contains "Maul"
|
||||
- number <= 5
|
||||
- format = "Limited Series"
|
||||
- Group 2:
|
||||
- series contains "Vader"
|
||||
- number <= 5
|
||||
- format = "Main Series"
|
||||
- Sort:
|
||||
- series_number
|
||||
- limit: 0
|
||||
- Distinct: no
|
||||
|
||||
### Supported Operations
|
||||
- `equals`, `contains`, `startswith`, `endswith`
|
||||
- `=`, `!=`, `>=`, `<=`, `>`, `<` (for numeric fields)
|
||||
- `not` modifier for any operation
|
||||
|
||||
### "Distinct by series and volume (latest)"
|
||||
|
||||
When that option is enabled, a smart list will return at most one comic per series and volume.
|
||||
For each series, it picks the latest issue, using this tie-break:
|
||||
|
||||
1. Newer year (cast to integer)
|
||||
2. If year ties: higher number (cast to integer)
|
||||
3. If number ties: newer file mtime (last modified time)
|
||||
|
||||
So you get a de-duplicated "what's the newest issue for each series?" view.
|
||||
|
||||
**Use Cases**:
|
||||
|
||||
- A clean "latest per series" shelf (e.g., to see what's new without 300 issues of Batman).
|
||||
- Weekly pulls / backlog triage: combine with filters like `publisher=Image` or `year >= 2020`.
|
||||
|
||||
**Important details / edge cases**
|
||||
|
||||
- Numeric casting: blank or non-numeric `year`/`number` are treated as `NULL` → effectively `0`, so those won't beat entries with proper numbers (eg. `16A`).
|
||||
|
||||
**Example use**
|
||||
|
||||
- "Latest Image series":
|
||||
- Rules: `publisher = "Image Comics"`, `year >= 2018`
|
||||
- Distinct by series: on
|
||||
|
||||
→ One newest issue per Image series since 2018.
|
||||
52
docs/troubleshooting.md
Normal file
52
docs/troubleshooting.md
Normal file
@@ -0,0 +1,52 @@
|
||||
## 🛠️ Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### No Comics Appearing
|
||||
- **Check mount**: Ensure your comics folder is mounted at `/library`
|
||||
- **File format**: Only `.cbz` files are supported
|
||||
- **Metadata**: Ensure CBZ files contain `ComicInfo.xml`
|
||||
- **Permissions**: Verify read permissions on comic files
|
||||
|
||||
#### Missing Thumbnails
|
||||
- **First load**: Thumbnails generate on first request
|
||||
- **Check permissions**: Ensure `/data/thumbs` is writable
|
||||
- **View errors**: Check error log via dashboard or `/data/thumbs_errors.log`
|
||||
|
||||
#### Authentication Problems
|
||||
- **Verify credentials**: Check `OPDS_BASIC_USER` and `OPDS_BASIC_PASS`
|
||||
- **Client support**: Ensure your client supports HTTP Basic Auth
|
||||
- **Disable auth**: Set `DISABLE_AUTH=true` for testing
|
||||
|
||||
#### Wrong Links/URLs
|
||||
- **Behind proxy**: Set `SERVER_BASE` and `URL_PREFIX` correctly
|
||||
- **Protocol mismatch**: Ensure HTTP/HTTPS consistency
|
||||
|
||||
### Debug Commands
|
||||
|
||||
```bash
|
||||
# View container logs
|
||||
docker compose logs -f comicopds
|
||||
|
||||
# Check container health
|
||||
docker compose ps
|
||||
|
||||
# Inspect configuration
|
||||
docker compose exec comicopds env | grep -E "(SERVER_BASE|URL_PREFIX|CONTENT_BASE_DIR)"
|
||||
|
||||
# Test internal connectivity
|
||||
docker compose exec comicopds wget -qO- http://localhost:8080/healthz
|
||||
|
||||
# Check FTS5 availability
|
||||
curl -u admin:password http://localhost:8382/debug/fts
|
||||
```
|
||||
|
||||
### Log Files
|
||||
- **Application logs**: `docker compose logs -f`
|
||||
- **Thumbnail errors**: `/data/thumbs_errors.log`
|
||||
|
||||
### Performance Tuning
|
||||
- **Large libraries**: Disable `AUTO_INDEX_ON_START`
|
||||
- **Slow thumbnails**: Increase `THUMB_WORKERS`
|
||||
- **Memory usage**: Reduce `PAGE_SIZE`
|
||||
- **Network issues**: Check `SERVER_BASE` configuration
|
||||
25
license
Normal file
25
license
Normal file
@@ -0,0 +1,25 @@
|
||||
## 📄 License
|
||||
|
||||
MIT License – use freely, modify, and contribute.
|
||||
|
||||
```
|
||||
Copyright (c) 2024 Frederik Baerentsen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
Reference in New Issue
Block a user