feat(opds): library folder navigation and library-scoped search
The device catalog flattened every visible library into one list, so
duplicate copies of the same book each got an entry and search had no
library context. The root feed is now a standard OPDS 1.1 navigation feed
that mirrors the web UI's library model:
- Root /catalog: an "All Books" entry first (the previous flat cross-
library behavior, also still served at ?all=1 for clients that want
the single flat list), followed by one folder entry per visible
library with live book counts from GetVisibleLibraryMediaCounts.
- New GET /library/:libraryId/catalog: acquisition feed scoped to one
visible library (403 when the device owner cannot see it), paginated,
with an up-link back to the root.
- Scoped search: each library feed's rel="search" OpenSearch template
pins &library_id=<id>, so opening search from inside a library folder
searches only that library — clients substitute only {searchTerms},
so no client-side changes are required. Root search stays global.
- Global search entries now carry the owning library as a category (and
as a fallback summary when the book has no description), so duplicate
copies are distinguishable in unscoped result lists.
The acquisition entry builder is extracted into addAcquisitionEntries and
shared by the all-books and per-library feeds. bookhoard.koplugin needs
no changes: it only registers the root URL, and KOReader's stock OPDS
client renders navigation feeds natively.
Tests: TestOPDSLibraryFolders covers the nav-feed shape, flat ?all=1
mode, scoped catalog isolation, scoped/global search behavior, and 403s
for libraries outside the device's visibility. Library names avoid the
word "test" on purpose — setupDeviceTest re-runs setupTestServer's
setup-time cleanup, which deletes every library whose name contains it.
This commit is contained in:
@@ -19,6 +19,7 @@ func registerOPDSRoutes(cfg *Config) {
|
||||
opds := e.Group("/opds/devices")
|
||||
opds.Use(cfg.DeviceAuthMiddleware.Authenticate)
|
||||
opds.GET("/:deviceId/catalog", cfg.OPDSHandler.GetDeviceCatalog)
|
||||
opds.GET("/:deviceId/library/:libraryId/catalog", cfg.OPDSHandler.GetLibraryCatalog)
|
||||
opds.GET("/:deviceId/search", cfg.OPDSHandler.SearchDeviceCatalog)
|
||||
opds.GET("/:deviceId/nav", cfg.OPDSHandler.GetDeviceNavigation)
|
||||
opds.GET("/:deviceId/download/:bookId", cfg.OPDSHandler.DownloadBook)
|
||||
|
||||
Reference in New Issue
Block a user