Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ dist/
# OS specific junk
# macOS
.DS_Store

.opencode/
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.9.0] - 2026-04-27

### Added

- **No Pagination option** — `-no-pagination` flag to disable pagination and show all entries in a single feed.

## [1.8.0] - 2026-03-28

### Added
Expand Down
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,16 @@

## Quick start

Using Docker (replace `v1.8.0` with the [latest release](https://github.com/dubyte/dir2opds/releases) if desired):
Using Docker (replace `v1.9.0` with the [latest release](https://github.com/dubyte/dir2opds/releases) if desired):

```bash
docker run -d -p 8080:8080 -v ./books:/books --name dir2opds ghcr.io/dubyte/dir2opds:v1.8.0
docker run -d -p 8080:8080 -v ./books:/books --name dir2opds ghcr.io/dubyte/dir2opds:v1.9.0
```

```

Then open

Then open `http://localhost:8080` in an OPDS client or browser.

**Using Go:**
Expand Down Expand Up @@ -99,9 +103,11 @@ dir2opds -dir /path/to/books -port 8080
| `-log-format` | Log format: `json` (default), `text` |
| `-mime-map` | Custom MIME types, e.g. `.mobi:application/x-mobipocket-ebook,.azw3:application/vnd.amazon.ebook` |
| `-no-cache` | Add response headers to disable client caching |
| `-no-pagination` | Disable pagination and show all entries in a single feed |
| `-page-size` | Number of entries per page (default: `50`, max: `200`) |
| `-port` | Listen port (default: `8080`) |
| `-search` | Enable basic filename search |
| `-search` | Enable basic filename search |
| `-show-covers` | Use `cover.jpg` or `folder.jpg` as catalog covers |
| `-sort` | Sort entries: `name`, `date`, or `size` (default: `name`) |
| `-url` | The base URL used for absolute links in the feed (e.g., `https://opds.example.com`) |
Expand Down Expand Up @@ -203,8 +209,25 @@ dir2opds -dir /books -page-size 100

# Maximum page size: 200 entries
dir2opds -dir /books -page-size 200

# Disable pagination: show all entries
dir2opds -dir /books -no-pagination
```

### Disabling Pagination

For small libraries or when using clients that work better with complete feeds, you can disable pagination entirely:

```bash
dir2opds -dir /books -no-pagination
```

When `-no-pagination` is set:
- All entries are included in a single feed
- No pagination navigation links are generated
- The `?page=N` query parameter is ignored
- Recommended for libraries with fewer than a few hundred books

### OPDS Feed Links

When pagination is active, feeds include navigation links:
Expand Down
11 changes: 10 additions & 1 deletion internal/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ type OPDS struct {
ExtractMetadata bool
BaseURL string
PageSize int
NoPagination bool
}

type Catalog struct {
Expand Down Expand Up @@ -205,6 +206,14 @@ func (s OPDS) Scan(fPath string, urlPath string, page int) (*Catalog, error) {
page = 1
}

// When NoPagination is enabled, show all entries on a single page
if s.NoPagination {
pageSize = total
if pageSize == 0 {
pageSize = 1 // Avoid division by zero
}
}

start := (page - 1) * pageSize
end := start + pageSize
if start > total {
Expand Down Expand Up @@ -765,7 +774,7 @@ func (s OPDS) makeFeed(catalog *Catalog, req *http.Request) atom.Feed {
Build())
}

if catalog.Total > catalog.PageSize {
if !s.NoPagination && catalog.Total > catalog.PageSize {
totalPages := (catalog.Total + catalog.PageSize - 1) / catalog.PageSize
basePath := req.URL.Path
query := req.URL.Query()
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ var (
baseURL = flag.String("url", "", "The base URL used for absolute links in the feed (e.g., https://opds.example.com).")
logFormat = flag.String("log-format", "json", "Log format: json, text.")
pageSize = flag.Int("page-size", 50, "Number of entries per page (0 for default, max 200).")
noPagination = flag.Bool("no-pagination", false, "Disable pagination and show all entries in a single feed.")
)

func main() {
Expand Down Expand Up @@ -98,6 +99,7 @@ func main() {
ExtractMetadata: *extractMeta,
BaseURL: *baseURL,
PageSize: *pageSize,
NoPagination: *noPagination,
}

http.HandleFunc("/", errorHandler(s.Handler))
Expand Down
Loading