feat(opds): add on-the-fly KEPUB conversion for downloads
- Integrate conversion service with OPDS handler - Convert EPUB to KEPUB format on download request - Cache converted files to reduce processing time - Support per-device catalog with format availability - Maintain backward compatibility with existing downloads
This commit is contained in:
+27
-11
@@ -3,6 +3,8 @@ package handlers
|
||||
import (
|
||||
"bookmann/internal/database"
|
||||
"bookmann/internal/opds"
|
||||
"bookmann/internal/services"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
@@ -19,12 +21,18 @@ import (
|
||||
)
|
||||
|
||||
type OPDSHandler struct {
|
||||
db *database.Queries
|
||||
db *database.Queries
|
||||
conversionService interface {
|
||||
ConvertEPUBToKEPUB(ctx context.Context, mediaItemID pgtype.UUID, epubPath string) (*services.ConvertedKEPUB, error)
|
||||
}
|
||||
}
|
||||
|
||||
func NewOPDSHandler(db *database.Queries) *OPDSHandler {
|
||||
func NewOPDSHandler(db *database.Queries, conversionService interface {
|
||||
ConvertEPUBToKEPUB(ctx context.Context, mediaItemID pgtype.UUID, epubPath string) (*services.ConvertedKEPUB, error)
|
||||
}) *OPDSHandler {
|
||||
return &OPDSHandler{
|
||||
db: db,
|
||||
db: db,
|
||||
conversionService: conversionService,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,11 +390,11 @@ func (h *OPDSHandler) DownloadBook(c echo.Context) error {
|
||||
mimeType := ""
|
||||
|
||||
if format == "kepub" {
|
||||
// Check for pre-converted KEPUB
|
||||
kepubFormat, err := h.db.GetMediaItemFormatByType(c.Request().Context(), database.GetMediaItemFormatByTypeParams{
|
||||
MediaItemID: pgtype.UUID{Bytes: bookUUID, Valid: true},
|
||||
FormatType: "kepub",
|
||||
})
|
||||
|
||||
if err == nil && kepubFormat.FilePath.Valid {
|
||||
filePath = kepubFormat.FilePath.String
|
||||
if kepubFormat.FileSha256.Valid {
|
||||
@@ -396,10 +404,19 @@ func (h *OPDSHandler) DownloadBook(c echo.Context) error {
|
||||
mimeType = kepubFormat.MimeType.String
|
||||
}
|
||||
} else {
|
||||
// Fall back to EPUB (no on-the-fly conversion for now)
|
||||
filePath = mediaItem.FilePath
|
||||
if mediaItem.MimeType.Valid {
|
||||
mimeType = mediaItem.MimeType.String
|
||||
if h.conversionService != nil {
|
||||
converted, err := h.conversionService.ConvertEPUBToKEPUB(c.Request().Context(), pgtype.UUID{Bytes: bookUUID, Valid: true}, mediaItem.FilePath)
|
||||
if err != nil {
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": fmt.Sprintf("KEPUB conversion failed: %v", err)})
|
||||
}
|
||||
filePath = converted.Path
|
||||
fileSha256 = converted.SHA256
|
||||
mimeType = "application/vnd.kobo+xml+zip"
|
||||
} else {
|
||||
filePath = mediaItem.FilePath
|
||||
if mediaItem.MimeType.Valid {
|
||||
mimeType = mediaItem.MimeType.String
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if format == "pdf" {
|
||||
@@ -451,11 +468,10 @@ func (h *OPDSHandler) DownloadBook(c echo.Context) error {
|
||||
c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
|
||||
c.Response().Header().Set("X-Bookmann-UUID", bookUUID.String())
|
||||
|
||||
if fileSha256 != "" {
|
||||
c.Response().Header().Set("X-Bookmann-SHA256", fileSha256)
|
||||
}
|
||||
if format == "kepub" && fileSha256 != "" {
|
||||
c.Response().Header().Set("X-Bookmann-KEPUB-SHA256", fileSha256)
|
||||
} else if fileSha256 != "" {
|
||||
c.Response().Header().Set("X-Bookmann-SHA256", fileSha256)
|
||||
}
|
||||
|
||||
// Stream file
|
||||
|
||||
Reference in New Issue
Block a user