refactor: use errors.Is()/errors.AsType() for error comparison and rename shadowed variables
Replace direct error equality checks (err == pgx.ErrNoRows, err != http.ErrServerClosed) with the idiomatic errors.Is() function throughout handlers, services, middleware, and app startup. This correctly handles wrapped error chains. Also replace a raw type assertion (*HTTPError) with errors.AsType[*HTTPError]() in the error handler middleware for consistency. Additionally, rename shadowed variables for clarity: - sidecar.go: config -> sidecarConfig, systemConfig (shadowed package-level vars) - media_scanner.go: uuid -> uuidString (shadowed the uuid package import)
This commit is contained in:
+2
-1
@@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -40,7 +41,7 @@ func (a *App) StartServer(addr string) error {
|
||||
|
||||
// Start HTTP server in background
|
||||
go func() {
|
||||
if err := a.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
if err := a.server.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) {
|
||||
log.Fatalf("Server failed to start: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -3,6 +3,7 @@ package handlers
|
||||
import (
|
||||
"bookhoard/internal/database"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
@@ -98,7 +99,7 @@ func (h *AnalyticsHandler) GetReadingStats(c *echo.Context) error {
|
||||
CreatedAt_2: pgtype.Timestamptz{Time: endTime, Valid: true},
|
||||
})
|
||||
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get reading history")
|
||||
}
|
||||
|
||||
@@ -211,7 +212,7 @@ func (h *AnalyticsHandler) GetDeviceUsage(c *echo.Context) error {
|
||||
ctx := context.Background()
|
||||
|
||||
usage, err := h.db.GetUserDeviceUsage(ctx, user.ID)
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get device usage")
|
||||
}
|
||||
|
||||
@@ -263,7 +264,7 @@ func (h *AnalyticsHandler) GetPopularBooks(c *echo.Context) error {
|
||||
Limit: limitInt,
|
||||
})
|
||||
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get popular books")
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"bookhoard/internal/database"
|
||||
"bookhoard/internal/middleware"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -887,7 +888,7 @@ func (h *AuthHandler) DeleteUser(c *echo.Context) error {
|
||||
// Delete user (this will cascade to delete all related data)
|
||||
err = h.db.DeleteUser(c.Request().Context(), targetUserUUID)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
if c.Request().Header.Get("HX-Request") == "true" {
|
||||
return c.HTML(http.StatusNotFound, `<div class="text-red-500">User not found</div>`)
|
||||
}
|
||||
@@ -940,7 +941,7 @@ func (h *AuthHandler) UpdateUserMaxDevices(c *echo.Context) error {
|
||||
MaxDevices: pgtype.Int4{Int32: req.MaxDevices, Valid: true},
|
||||
})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusNotFound, map[string]string{"error": "user not found"})
|
||||
}
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
wsync "bookhoard/internal/sync"
|
||||
"bookhoard/internal/utils"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -891,7 +892,7 @@ func (h *CollectionHandler) PreviewCollection(c *echo.Context) error {
|
||||
|
||||
_, err = h.db.GetLibrary(c.Request().Context(), pgtype.UUID{Bytes: libUUID, Valid: true})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "library not found"})
|
||||
}
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
wsync "bookhoard/internal/sync"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -83,7 +84,7 @@ func (h *ConflictHandler) GetConflictsData(c *echo.Context) ([]ConflictDetailRes
|
||||
conflicts, err = h.db.ListSyncConflictsByUser(ctx, user.ID)
|
||||
}
|
||||
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
@@ -150,7 +151,7 @@ func (h *ConflictHandler) GetConflict(c *echo.Context) error {
|
||||
conflictUUID := pgtype.UUID{Bytes: [16]byte(conflictID), Valid: true}
|
||||
conflict, err := h.db.GetSyncConflict(context.Background(), conflictUUID)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return echo.NewHTTPError(http.StatusNotFound, "conflict not found")
|
||||
}
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get conflict")
|
||||
@@ -214,7 +215,7 @@ func (h *ConflictHandler) ResolveConflict(c *echo.Context) error {
|
||||
conflictUUID := pgtype.UUID{Bytes: [16]byte(conflictID), Valid: true}
|
||||
conflict, err := h.db.GetSyncConflict(context.Background(), conflictUUID)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return echo.NewHTTPError(http.StatusNotFound, "conflict not found")
|
||||
}
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get conflict")
|
||||
@@ -292,7 +293,7 @@ func (h *ConflictHandler) applyProgressResolution(mediaItemID pgtype.UUID, userI
|
||||
MediaItemID: mediaItemID,
|
||||
UserID: userID,
|
||||
})
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -380,7 +381,7 @@ func (h *ConflictHandler) DeleteConflict(c *echo.Context) error {
|
||||
conflictUUID := pgtype.UUID{Bytes: [16]byte(conflictID), Valid: true}
|
||||
conflict, err := h.db.GetSyncConflict(context.Background(), conflictUUID)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return echo.NewHTTPError(http.StatusNotFound, "conflict not found")
|
||||
}
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "failed to get conflict")
|
||||
@@ -641,7 +642,7 @@ func (h *ConflictHandler) applyResolution(mediaItemID pgtype.UUID, userID pgtype
|
||||
MediaItemID: mediaItemID,
|
||||
UserID: userID,
|
||||
})
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"bookhoard/internal/utils"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -728,7 +729,7 @@ func (mh *MediaHandler) GetMediaItem(c *echo.Context) error {
|
||||
|
||||
item, err := mh.db.GetMediaItem(c.Request().Context(), pgtype.UUID{Bytes: mediaUUID, Valid: true})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusNotFound, map[string]string{"error": "media item not found"})
|
||||
}
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
@@ -836,7 +837,7 @@ func (mh *MediaHandler) GetMediaRating(c *echo.Context) error {
|
||||
UserID: pgtype.UUID{Bytes: userUUID, Valid: true},
|
||||
})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusOK, map[string]interface{}{"rating": nil})
|
||||
}
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
@@ -894,7 +895,7 @@ func (mh *MediaHandler) GetMediaReadingProgress(c *echo.Context) error {
|
||||
UserID: pgtype.UUID{Bytes: userUUID, Valid: true},
|
||||
})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"current_page": 0,
|
||||
"total_pages": nil,
|
||||
@@ -1026,7 +1027,7 @@ func (mh *MediaHandler) CreateMediaItem(c *echo.Context) error {
|
||||
|
||||
_, err = mh.db.GetLibrary(c.Request().Context(), pgtype.UUID{Bytes: req.LibraryID, Valid: true})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "library not found"})
|
||||
}
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
@@ -1237,7 +1238,7 @@ func (mh *MediaHandler) GetMediaNote(c *echo.Context) error {
|
||||
|
||||
note, err := mh.db.GetMediaNote(c.Request().Context(), pgtype.UUID{Bytes: noteUUID, Valid: true})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusNotFound, map[string]string{"error": "note not found"})
|
||||
}
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
@@ -1377,7 +1378,7 @@ func (mh *MediaHandler) GetMediaHighlight(c *echo.Context) error {
|
||||
|
||||
highlight, err := mh.db.GetMediaHighlight(c.Request().Context(), pgtype.UUID{Bytes: highlightUUID, Valid: true})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusNotFound, map[string]string{"error": "highlight not found"})
|
||||
}
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
wsync "bookhoard/internal/sync"
|
||||
"bookhoard/internal/utils"
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -43,7 +44,7 @@ func (h *Handler) GetUniversalProgress(c *echo.Context) error {
|
||||
UserID: pgtype.UUID{Bytes: user.ID.Bytes, Valid: true},
|
||||
})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"media_item_id": mediaItemID,
|
||||
"progress": nil,
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bookhoard/internal/database"
|
||||
"bookhoard/internal/services"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -63,7 +64,7 @@ func (h *ReaderHandler) ShowReader(c *echo.Context) error {
|
||||
// Get media item
|
||||
mediaItem, err := h.db.GetMediaItem(c.Request().Context(), pgtype.UUID{Bytes: parsedUUID, Valid: true})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusNotFound, map[string]string{"error": "Media item not found"})
|
||||
}
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to fetch media item"})
|
||||
@@ -108,7 +109,7 @@ func (h *ReaderHandler) ShowReader(c *echo.Context) error {
|
||||
MediaItemID: pgtype.UUID{Bytes: parsedUUID, Valid: true},
|
||||
UserID: userData.ID,
|
||||
})
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
progress = database.ReadingProgress{}
|
||||
}
|
||||
|
||||
@@ -316,7 +317,7 @@ func (h *ReaderHandler) GetReadingSpeed(c *echo.Context) error {
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
// Return zero values if no reading has occurred
|
||||
return c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"words_per_minute": 0,
|
||||
@@ -597,7 +598,7 @@ func (h *ReaderHandler) ParseEbook(c *echo.Context) error {
|
||||
// Fetch media item
|
||||
mediaItem, err := h.db.GetMediaItem(c.Request().Context(), pgtype.UUID{Bytes: parsedUUID, Valid: true})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(404, map[string]string{"error": "Media item not found"})
|
||||
}
|
||||
return c.JSON(500, map[string]string{"error": "Failed to fetch media item"})
|
||||
|
||||
@@ -3,6 +3,7 @@ package handlers
|
||||
import (
|
||||
"bookhoard/internal/database"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
@@ -52,7 +53,7 @@ func (h *AuthHandler) RefreshAccessToken(c *echo.Context) error {
|
||||
|
||||
tokenInfo, err := h.db.GetRefreshToken(c.Request().Context(), tokenUUID)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "invalid or expired refresh token"})
|
||||
}
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "failed to validate refresh token"})
|
||||
@@ -88,7 +89,7 @@ func (h *AuthHandler) Logout(c *echo.Context) error {
|
||||
}
|
||||
|
||||
err = h.db.RevokeRefreshToken(c.Request().Context(), tokenUUID)
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "failed to revoke refresh token"})
|
||||
}
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ func (h *SidecarHandler) GetSidecarConfig(c *echo.Context) error {
|
||||
}
|
||||
|
||||
// Build sidecar config
|
||||
config := SidecarConfig{
|
||||
sidecarConfig := SidecarConfig{
|
||||
Version: "1.0",
|
||||
Bookhoard: SidecarBookhoardConfig{
|
||||
OPDSCatalog: opdsCatalogURL,
|
||||
@@ -188,7 +188,7 @@ func (h *SidecarHandler) GetSidecarConfig(c *echo.Context) error {
|
||||
LastUpdated: time.Now().Format(time.RFC3339),
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, config)
|
||||
return c.JSON(http.StatusOK, sidecarConfig)
|
||||
}
|
||||
|
||||
// DownloadSidecarConfig generates a .bookhoard.json file for device setup
|
||||
@@ -352,8 +352,8 @@ func (h *SidecarHandler) GetSystemConfiguration(c *echo.Context) error {
|
||||
|
||||
// Build config map
|
||||
result := make(map[string]string)
|
||||
for _, config := range configs {
|
||||
result[config.Key] = config.Value
|
||||
for _, systemConfig := range configs {
|
||||
result[systemConfig.Key] = systemConfig.Value
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, result)
|
||||
|
||||
@@ -2,6 +2,7 @@ package handlers
|
||||
|
||||
import (
|
||||
"bookhoard/internal/database"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
@@ -47,7 +48,7 @@ func (h *SystemSettingsHandler) UpdateScanSettings(c *echo.Context) error {
|
||||
SettingValue: scanFrequencyValue,
|
||||
})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusNotFound, map[string]string{"error": "system setting not found"})
|
||||
}
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
@@ -58,7 +59,7 @@ func (h *SystemSettingsHandler) UpdateScanSettings(c *echo.Context) error {
|
||||
SettingValue: autoScanValue,
|
||||
})
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusNotFound, map[string]string{"error": "system setting not found"})
|
||||
}
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
@@ -74,7 +75,7 @@ func (h *SystemSettingsHandler) UpdateScanSettings(c *echo.Context) error {
|
||||
func (h *SystemSettingsHandler) GetScanSettings(c *echo.Context) error {
|
||||
scanFrequencySetting, err := h.db.GetSystemSetting(c.Request().Context(), "scan_poll_interval_seconds")
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusOK, ScanSettingsResponse{
|
||||
ScanPollIntervalSeconds: 60,
|
||||
AutoScanEnabled: true,
|
||||
@@ -85,7 +86,7 @@ func (h *SystemSettingsHandler) GetScanSettings(c *echo.Context) error {
|
||||
|
||||
autoScanSetting, err := h.db.GetSystemSetting(c.Request().Context(), "auto_scan_enabled")
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return c.JSON(http.StatusOK, ScanSettingsResponse{
|
||||
ScanPollIntervalSeconds: 60,
|
||||
AutoScanEnabled: true,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
@@ -83,7 +84,7 @@ func WrapHandler(fn func(*echo.Context) error) echo.HandlerFunc {
|
||||
return func(c *echo.Context) error {
|
||||
err := fn(c)
|
||||
if err != nil {
|
||||
if httpErr, ok := err.(*HTTPError); ok {
|
||||
if httpErr, ok := errors.AsType[*HTTPError](err); ok {
|
||||
return RespondWithHTTPError(c, httpErr)
|
||||
}
|
||||
return RespondWithError(c, http.StatusInternalServerError, "Internal server error", err)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"bookhoard/internal/services"
|
||||
"bookhoard/templates"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
@@ -73,7 +74,7 @@ func registerReaderRoutes(cfg *Config) {
|
||||
MediaItemID: pgtype.UUID{Bytes: parsedUUID, Valid: true},
|
||||
UserID: uuidToPGType(userUUID),
|
||||
})
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
progress = database.ReadingProgress{}
|
||||
}
|
||||
// Get bookmarks
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
_ "image/jpeg"
|
||||
@@ -590,7 +591,7 @@ func (s *MediaScanner) processMediaFile(ctx context.Context, path string) (bool,
|
||||
fmt.Printf("Media item already exists with same size, skipping: %s\n", path)
|
||||
return false, nil
|
||||
}
|
||||
} else if err != pgx.ErrNoRows {
|
||||
} else if !errors.Is(err, pgx.ErrNoRows) {
|
||||
fmt.Printf("Database error checking media item existence: %v\n", err)
|
||||
return false, fmt.Errorf("failed to check if media item exists: %v", err)
|
||||
}
|
||||
@@ -2605,7 +2606,7 @@ func (s *MediaScanner) scanDirectory(ctx context.Context, dirPath string) {
|
||||
LibraryID: libraryID,
|
||||
})
|
||||
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
if _, err := s.processMediaFile(ctx, path); err != nil {
|
||||
s.errors++
|
||||
} else {
|
||||
@@ -2780,7 +2781,7 @@ func (s *MediaScanner) SyncFilesystemWithDatabase(ctx context.Context) error {
|
||||
FilePath: relPath,
|
||||
LibraryID: libraryID,
|
||||
})
|
||||
if err == pgx.ErrNoRows {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
// New file found - scan it
|
||||
absPath := folder + "/" + relPath
|
||||
if _, err := os.Stat(absPath); err == nil {
|
||||
@@ -2848,19 +2849,19 @@ func (s *MediaScanner) extractOPFIdentifiers(epubPath string) (opfIdentifier, op
|
||||
return "", "", "low", nil
|
||||
}
|
||||
|
||||
var identifier, uuid string
|
||||
var identifier, uuidString string
|
||||
for _, id := range identifiers {
|
||||
id = strings.TrimSpace(id)
|
||||
|
||||
// Check for UUID format (urn:uuid:)
|
||||
if trimmed, found := strings.CutPrefix(strings.ToLower(id), "urn:uuid:"); found {
|
||||
uuid = trimmed
|
||||
uuidString = trimmed
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if it's a plain UUID (8-4-4-4-12 format)
|
||||
if isValidUUID(id) {
|
||||
uuid = id
|
||||
uuidString = id
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -2879,9 +2880,9 @@ func (s *MediaScanner) extractOPFIdentifiers(epubPath string) (opfIdentifier, op
|
||||
}
|
||||
}
|
||||
|
||||
confidence = s.determineHashConfidence(uuid, identifier)
|
||||
confidence = s.determineHashConfidence(uuidString, identifier)
|
||||
|
||||
return identifier, uuid, confidence, nil
|
||||
return identifier, uuidString, confidence, nil
|
||||
}
|
||||
|
||||
// isValidUUID checks if string is a valid UUID (8-4-4-4-12 format)
|
||||
|
||||
@@ -3,6 +3,7 @@ package services
|
||||
import (
|
||||
"bookhoard/internal/database"
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
@@ -214,7 +215,7 @@ func (s *SearchService) SearchFieldValues(ctx context.Context, params FieldSearc
|
||||
// Shared between JSON endpoint and HTML rendering
|
||||
func (s *SearchService) ExecuteSearch(ctx context.Context, params SearchParams) ([]database.SearchMediaItemsUnifiedRow, int, error) {
|
||||
results, err := s.SearchMediaItemsUnified(ctx, params)
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user