diff --git a/internal/handlers/media.go b/internal/handlers/media.go index 799f184..e85c4d5 100644 --- a/internal/handlers/media.go +++ b/internal/handlers/media.go @@ -704,69 +704,6 @@ func (mh *MediaHandler) GetMediaItem(c *echo.Context) error { }) } -// ListMediaItemsFiltered handles GET /api/media-items/filtered -func (mh *MediaHandler) ListMediaItemsFiltered(c *echo.Context) error { - userID := c.Get("user_id").(string) - libraryID := c.QueryParam("library_id") - sort := c.QueryParam("sort") - limit, _ := strconv.Atoi(c.QueryParam("limit")) - offset, _ := strconv.Atoi(c.QueryParam("offset")) - - authorFilter := c.QueryParam("author_filter") - seriesFilter := c.QueryParam("series_filter") - genreFilter := c.QueryParam("genre_filter") - languageFilter := c.QueryParam("language_filter") - yearMin, _ := strconv.Atoi(c.QueryParam("year_min")) - yearMax, _ := strconv.Atoi(c.QueryParam("year_max")) - hasCover, _ := strconv.ParseBool(c.QueryParam("has_cover")) - - if limit == 0 { - limit = 50 - } - - if offset < 0 { - offset = 0 - } - - if sort == "" { - sort = "created_at DESC" - } - - if limit > maxPaginationLimit { - limit = maxPaginationLimit - } - - libUUID, err := uuid.Parse(libraryID) - if err != nil { - return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid library id"}) - } - - userUUID, err := uuid.Parse(userID) - if err != nil { - return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid user id"}) - } - - items, err := mh.db.ListMediaItemsFiltered(c.Request().Context(), database.ListMediaItemsFilteredParams{ - LibraryID: pgtype.UUID{Bytes: libUUID, Valid: true}, - UserID: pgtype.UUID{Bytes: userUUID, Valid: true}, - AuthorFilter: pgtype.Text{String: authorFilter, Valid: true}, - SeriesFilter: pgtype.Text{String: seriesFilter, Valid: true}, - GenreFilter: pgtype.Text{String: genreFilter, Valid: true}, - LanguageFilter: pgtype.Text{String: languageFilter, Valid: true}, - YearMin: pgtype.Int4{Int32: int32(yearMin), Valid: true}, - YearMax: pgtype.Int4{Int32: int32(yearMax), Valid: true}, - HasCover: pgtype.Bool{Bool: hasCover, Valid: true}, - Sort: pgtype.Text{String: sort, Valid: true}, - Limit: pgtype.Int4{Int32: int32(limit), Valid: true}, - Offset: pgtype.Int4{Int32: int32(offset), Valid: true}, - }) - if err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) - } - - return c.JSON(http.StatusOK, map[string]interface{}{"data": items}) -} - // CreateMediaRating handles POST /api/media-items/:id/rating func (mh *MediaHandler) CreateMediaRating(c *echo.Context) error { userID := c.Get("user_id").(string) @@ -1471,6 +1408,12 @@ func (mh *MediaHandler) SearchMediaItems(c *echo.Context) error { yearMax, _ := strconv.Atoi(c.QueryParam("year_max")) hasCover := c.QueryParam("has_cover") == "true" + // Extract sort parameter + sortParam := c.QueryParam("sort") + if sortParam == "" { + sortParam = "title ASC" // Default sort + } + // Build search params params := services.SearchParams{ UserID: userID.ID, @@ -1483,6 +1426,7 @@ func (mh *MediaHandler) SearchMediaItems(c *echo.Context) error { YearMin: yearMin, YearMax: yearMax, HasCover: hasCover, + Sort: sortParam, Limit: limit, Offset: offset, } diff --git a/internal/router/frontend.go b/internal/router/frontend.go index 37d5577..8783430 100644 --- a/internal/router/frontend.go +++ b/internal/router/frontend.go @@ -175,7 +175,7 @@ func registerFrontendRoutes(cfg *Config) { } // Fetch first page of books for SSR - var books []database.ListMediaItemsFilteredRow + var books []database.SearchMediaItemsUnifiedRow var bookInfoList []handlers.BookInfo totalCount := 0 limit := 50 @@ -196,23 +196,26 @@ func registerFrontendRoutes(cfg *Config) { } } - books, err = cfg.Queries.ListMediaItemsFiltered(c.Request().Context(), database.ListMediaItemsFilteredParams{ + books, err = cfg.Queries.SearchMediaItemsUnified(c.Request().Context(), database.SearchMediaItemsUnifiedParams{ LibraryID: pgtype.UUID{Bytes: libUUID, Valid: true}, UserID: pgtype.UUID{Bytes: userUUID, Valid: true}, - AuthorFilter: pgtype.Text{String: "", Valid: false}, - SeriesFilter: pgtype.Text{String: "", Valid: false}, - GenreFilter: pgtype.Text{String: "", Valid: false}, - LanguageFilter: pgtype.Text{String: "", Valid: false}, - YearMin: pgtype.Int4{Valid: false}, - YearMax: pgtype.Int4{Valid: false}, - HasCover: pgtype.Bool{Valid: false}, + AuthorFilter: pgtype.Text{String: "", Valid: true}, // Changed: Valid=true for empty string + SeriesFilter: pgtype.Text{String: "", Valid: true}, // Changed + GenreFilter: pgtype.Text{String: "", Valid: true}, // Changed + LanguageFilter: pgtype.Text{String: "", Valid: true}, // Changed + YearMin: pgtype.Int4{Int32: 0, Valid: true}, // Changed: use 0 as default + YearMax: pgtype.Int4{Int32: 0, Valid: true}, // Changed + HasCover: pgtype.Bool{Bool: false, Valid: true}, // Changed + SearchQuery: pgtype.Text{String: "", Valid: true}, // NEW: Required + IsExactSearch: pgtype.Bool{Bool: false, Valid: true}, // NEW: Required + SearchPattern: pgtype.Text{Valid: false}, // NEW: Empty for no exact search Sort: pgtype.Text{String: "created_at DESC", Valid: true}, Limit: pgtype.Int4{Int32: int32(limit), Valid: true}, Offset: pgtype.Int4{Int32: int32(offset), Valid: true}, }) if err != nil { - log.Printf("ListMediaItemsFiltered failed: %v", err) + log.Printf("SearchMediaItemsUnified failed: %v", err) // Continue without books - will show empty state } else { // Convert database rows to BookInfo structs (matching BuildSections pattern) diff --git a/internal/router/media.go b/internal/router/media.go index e157235..8c1f4f3 100644 --- a/internal/router/media.go +++ b/internal/router/media.go @@ -14,7 +14,6 @@ func registerMediaRoutes(cfg *Config) { // Media item routes (all authenticated users) protected.GET("/media-items", cfg.MediaHandler.ListMediaItems) - protected.GET("/media-items/filtered", cfg.MediaHandler.ListMediaItemsFiltered) protected.GET("/media-items/:id", cfg.MediaHandler.GetMediaItem) // Media rating routes (all authenticated users)