When a Kobo device pushes a last-read-place bookmark, the server now converts the KEPUB CFI (with koboSpan wrappers) to a standard EPUB CFI and extracts surrounding text as context_text for use by other devices (KOReader, web reader) during their pull-side CFI conversions. Previously the raw KEPUB CFI was stored verbatim as epubcfi, which meant foliate and CREngine couldn't resolve it (wrong child indices due to koboSpan wrappers), and no context_text was available for the text-search fallback in ConvertStandardToCRE. Changes: - kepub_cfi_converter.go: Add ExtractedContext field to KEPUBConversionResult, populated from the already-computed searchText in both ConvertKEPUBCFIToStandard and ConvertStandardCFIToKEPUB (exact-match and percentage-fallback paths). - kobo.go: Add libraryService field and SetLibraryService setter (mirrors KOReaderHandler pattern). Add convertKoboCFIToStandard helper that resolves EPUB+KEPUB paths, instantiates the converter, and returns the converted CFI + extracted context. The last-read-place branch in Markup now calls this helper for reflowable formats, skipping fixed-layout/comic archives (page-index only). - router.go: Add LibraryService to router Config. - sync.go: Wire LibraryService to KoboHandler via SetLibraryService. - main.go: Pass libraryService through router config. The conversion is purely additive — if no KEPUB file exists on disk (e.g. side-loaded EPUB without kepubify conversion), the handler gracefully skips conversion and stores the raw CFI as before.
51 lines
2.2 KiB
Go
51 lines
2.2 KiB
Go
package router
|
|
|
|
import (
|
|
"bookhoard/internal/handlers"
|
|
)
|
|
|
|
func registerSyncRoutes(cfg *Config) {
|
|
e := cfg.Echo
|
|
|
|
// JWT middleware for protected routes
|
|
jwtMiddleware := createJWTMiddleware(cfg)
|
|
|
|
protected := e.Group("/api", jwtMiddleware)
|
|
|
|
// Create handler for sync-specific routes
|
|
h := handlers.NewHandler(cfg.Queries, cfg.ConnManager, cfg.QueueProcessor, cfg.Cfg)
|
|
|
|
// Book matching and unlinked book resolution routes
|
|
sync := protected.Group("/sync")
|
|
sync.POST("/bulk-link-books", h.BulkLinkBooks)
|
|
sync.POST("/auto-link-books", h.AutoLinkBooks)
|
|
sync.GET("/unlinked-books/:id/suggestions", h.GetUnlinkedBookSuggestions)
|
|
|
|
// KOReader sync routes (device authentication required)
|
|
koreaderSync := e.Group("/api/sync/koreader")
|
|
koreaderSync.POST("/progress", cfg.DeviceAuthMiddleware.Authenticate(cfg.KOReaderHandler.SyncProgress))
|
|
koreaderSync.GET("/metadata/:uuid", cfg.DeviceAuthMiddleware.Authenticate(cfg.KOReaderHandler.GetMetadata))
|
|
koreaderSync.GET("/library", cfg.DeviceAuthMiddleware.Authenticate(cfg.KOReaderHandler.GetLibrary))
|
|
koreaderSync.POST("/bookmarks", cfg.DeviceAuthMiddleware.Authenticate(cfg.KOReaderHandler.SyncBookmarks))
|
|
|
|
// Kobo sync routes (device authentication required)
|
|
// Kobo devices use URL path: /api/sync/kobo/{token}/markup
|
|
// API clients can use Authorization header: Authorization: Bearer {token}
|
|
koboHandler := handlers.NewKoboHandler(cfg.Queries, cfg.ConnManager)
|
|
koboHandler.SetProgressService(cfg.ProgressService)
|
|
koboHandler.SetLibraryService(cfg.LibraryService)
|
|
koboSync := e.Group("/api/sync/kobo/:token")
|
|
koboSync.POST("/markup", cfg.DeviceAuthMiddleware.Authenticate(koboHandler.Markup))
|
|
koboSync.POST("/bookmark", cfg.DeviceAuthMiddleware.Authenticate(koboHandler.Bookmark))
|
|
koboSync.POST("/v1/analytics/gettests", cfg.DeviceAuthMiddleware.Authenticate(koboHandler.AnalyticsGettests))
|
|
koboSync.GET("/v1/initialization", cfg.DeviceAuthMiddleware.Authenticate(koboHandler.Initialization))
|
|
koboSync.POST("/sync-from-server", cfg.DeviceAuthMiddleware.Authenticate(koboHandler.SyncFromServer))
|
|
}
|
|
|
|
func registerWebSocketRoutes(cfg *Config) {
|
|
e := cfg.Echo
|
|
|
|
wsGroup := e.Group("/ws/sync")
|
|
wsGroup.GET("", cfg.WSHandler.HandleWebSocket)
|
|
}
|