diff --git a/internal/handlers/koreader.go b/internal/handlers/koreader.go index a19775e..d02180f 100644 --- a/internal/handlers/koreader.go +++ b/internal/handlers/koreader.go @@ -2,6 +2,7 @@ package handlers import ( "bookhoard/internal/database" + "bookhoard/internal/services" wsync "bookhoard/internal/sync" "context" "encoding/json" @@ -22,6 +23,7 @@ type KOReaderHandler struct { progressSvc *wsync.ProgressService annotationSvc *wsync.AnnotationService libraryService LibraryPathResolver + bookResolver *services.BookResolver } type LibraryPathResolver interface { @@ -29,7 +31,12 @@ type LibraryPathResolver interface { } func NewKOReaderHandler(db *database.Queries, connManager *wsync.ConnectionManager, queue *wsync.SyncQueueProcessor) *KOReaderHandler { - return &KOReaderHandler{db: db, connManager: connManager, queue: queue} + return &KOReaderHandler{ + db: db, + connManager: connManager, + queue: queue, + bookResolver: services.NewBookResolver(db), + } } func (h *KOReaderHandler) SetProgressService(svc *wsync.ProgressService) { @@ -158,6 +165,7 @@ type KOReaderConflict struct { type KOReaderMetadata struct { UUID string `json:"uuid"` + SHA256 string `json:"sha256,omitempty"` Title string `json:"title"` Authors []string `json:"authors"` Progress KOReaderProgressData `json:"progress"` @@ -192,6 +200,7 @@ type KOReaderLibraryResponse struct { type KOReaderLibraryBook struct { UUID string `json:"uuid"` + SHA256 string `json:"sha256,omitempty"` Title string `json:"title"` Author string `json:"author"` ContentType string `json:"content_type"` @@ -303,8 +312,10 @@ func (h *KOReaderHandler) resolveBookToMediaItem(c *echo.Context, deviceID pgtyp } // Priority 2: SHA-256 provided (medium confidence - 0.9) + // Uses the shared BookResolver, which also checks per-format hashes + // (media_item_formats) so a converted file (KEPUB/PDF) matches too. if book.SHA256 != "" && len(book.SHA256) == 64 { - mediaItem, err := h.db.GetMediaItemBySHA256(ctx, pgtype.Text{String: book.SHA256, Valid: true}) + mediaItem, _, err := h.bookResolver.ResolveBySHA256(ctx, book.SHA256) if err == nil { // Create device file alias if FilePath is provided if book.FilePath != "" { @@ -883,6 +894,7 @@ func (h *KOReaderHandler) GetMetadata(c *echo.Context) error { metadata := KOReaderMetadata{ UUID: bookUUID.String(), + SHA256: mediaItem.FileSha256.String, Title: mediaItem.Title, Authors: []string{mediaItem.Author.String}, Progress: progressData, @@ -989,6 +1001,7 @@ func (h *KOReaderHandler) GetLibrary(c *echo.Context) error { libraryBooks = append(libraryBooks, KOReaderLibraryBook{ UUID: uuid.UUID(item.ID.Bytes).String(), + SHA256: item.FileSha256.String, Title: item.Title, Author: item.Author.String, ContentType: "6", @@ -1045,8 +1058,8 @@ func (h *KOReaderHandler) SyncBookmarks(c *echo.Context) error { } pgBookUUID = pgtype.UUID{Bytes: bookUUID, Valid: true} } else if req.BookSHA256 != "" && len(req.BookSHA256) == 64 { - // Use SHA-256 to find book - mediaItem, err := h.db.GetMediaItemBySHA256(ctx, pgtype.Text{String: req.BookSHA256, Valid: true}) + // Use SHA-256 to find book (format-aware: also checks media_item_formats) + mediaItem, _, err := h.bookResolver.ResolveBySHA256(ctx, req.BookSHA256) if err != nil { return c.JSON(http.StatusNotFound, map[string]string{ "error": "book not found by SHA-256", @@ -1068,7 +1081,7 @@ func (h *KOReaderHandler) SyncBookmarks(c *echo.Context) error { // If bookmark has its own SHA-256, use it for matching if bookmark.BookSHA256 != "" && len(bookmark.BookSHA256) == 64 { - mediaItem, err := h.db.GetMediaItemBySHA256(ctx, pgtype.Text{String: bookmark.BookSHA256, Valid: true}) + mediaItem, _, err := h.bookResolver.ResolveBySHA256(ctx, bookmark.BookSHA256) if err == nil { mediaItemID = mediaItem.ID } @@ -1119,7 +1132,7 @@ func (h *KOReaderHandler) SyncBookmarks(c *echo.Context) error { // If note has its own SHA-256, use it for matching if note.BookSHA256 != "" && len(note.BookSHA256) == 64 { - mediaItem, err := h.db.GetMediaItemBySHA256(ctx, pgtype.Text{String: note.BookSHA256, Valid: true}) + mediaItem, _, err := h.bookResolver.ResolveBySHA256(ctx, note.BookSHA256) if err == nil { mediaItemID = mediaItem.ID } @@ -1169,7 +1182,7 @@ func (h *KOReaderHandler) SyncBookmarks(c *echo.Context) error { // If highlight has its own SHA-256, use it for matching if highlight.BookSHA256 != "" && len(highlight.BookSHA256) == 64 { - mediaItem, err := h.db.GetMediaItemBySHA256(ctx, pgtype.Text{String: highlight.BookSHA256, Valid: true}) + mediaItem, _, err := h.bookResolver.ResolveBySHA256(ctx, highlight.BookSHA256) if err == nil { mediaItemID = mediaItem.ID }