diff --git a/scraper/internal/orchestrator/orchestrator_test.go b/scraper/internal/orchestrator/orchestrator_test.go index 5e08378..d1366c6 100644 --- a/scraper/internal/orchestrator/orchestrator_test.go +++ b/scraper/internal/orchestrator/orchestrator_test.go @@ -155,8 +155,9 @@ func (s *mockStore) SaveBrowsePage(_ context.Context, _, _ string) error { retur func (s *mockStore) GetBrowsePage(_ context.Context, _ string) (string, bool, error) { return "", false, nil } -func (s *mockStore) BrowseHTMLKey(_ string, _ int) string { return "" } -func (s *mockStore) BrowseCoverKey(_, _ string) string { return "" } +func (s *mockStore) BrowseHTMLKey(_ string, _ int) string { return "" } +func (s *mockStore) BrowseFilteredHTMLKey(_ string, _ int, _, _, _ string) string { return "" } +func (s *mockStore) BrowseCoverKey(_, _ string) string { return "" } func (s *mockStore) SaveBrowseAsset(_ context.Context, _ string, _ []byte, _ string) error { return nil } diff --git a/scraper/internal/server/handlers_browse.go b/scraper/internal/server/handlers_browse.go index 85b879e..033e208 100644 --- a/scraper/internal/server/handlers_browse.go +++ b/scraper/internal/server/handlers_browse.go @@ -80,7 +80,7 @@ func (s *Server) handleBrowse(w http.ResponseWriter, r *http.Request) { defer cancel() // ── Cache-first: try MinIO snapshot (new key layout) ───────────────── - cacheKey := s.store.BrowseHTMLKey(novelFireDomain, pageNum) + cacheKey := s.store.BrowseFilteredHTMLKey(novelFireDomain, pageNum, sortBy, genre, status) if html, ok, err := s.store.GetBrowsePage(ctx, cacheKey); err == nil && ok && len(html) > 0 { novels, hasNext := parseBrowsePage(strings.NewReader(html)) s.log.Debug("browse: served from cache", "key", cacheKey) diff --git a/scraper/internal/storage/hybrid.go b/scraper/internal/storage/hybrid.go index cd89cfb..967f147 100644 --- a/scraper/internal/storage/hybrid.go +++ b/scraper/internal/storage/hybrid.go @@ -330,6 +330,10 @@ func (h *HybridStore) BrowseHTMLKey(domain string, page int) string { return BrowseHTMLKey(domain, page) } +func (h *HybridStore) BrowseFilteredHTMLKey(domain string, page int, sort, genre, status string) string { + return BrowseFilteredHTMLKey(domain, page, sort, genre, status) +} + func (h *HybridStore) BrowseCoverKey(domain, slug string) string { return BrowseCoverKey(domain, slug) } diff --git a/scraper/internal/storage/minio.go b/scraper/internal/storage/minio.go index c64f2a4..797cdf0 100644 --- a/scraper/internal/storage/minio.go +++ b/scraper/internal/storage/minio.go @@ -223,10 +223,33 @@ func (m *MinioClient) PresignAudio(ctx context.Context, key string, expires time // BrowseHTMLKey returns the MinIO object key for a SingleFile HTML snapshot. // Layout: {domain}/html/page-{n}.html +// This uses the default (popular/all/all) filter combination. func BrowseHTMLKey(domain string, page int) string { return fmt.Sprintf("%s/html/page-%d.html", domain, page) } +// BrowseFilteredHTMLKey returns the MinIO object key for a browse page snapshot +// that includes filter parameters (sort, genre, status) in the key so that +// different filter combinations are cached independently. +// Layout: {domain}/html/{sort}-{genre}-{status}/page-{n}.html +// Falls back to BrowseHTMLKey when all filters are at their default values +// (sort=popular, genre=all, status=all) for cache compatibility. +func BrowseFilteredHTMLKey(domain string, page int, sort, genre, status string) string { + if (sort == "" || sort == "popular") && (genre == "" || genre == "all") && (status == "" || status == "all") { + return BrowseHTMLKey(domain, page) + } + if sort == "" { + sort = "popular" + } + if genre == "" { + genre = "all" + } + if status == "" { + status = "all" + } + return fmt.Sprintf("%s/html/%s-%s-%s/page-%d.html", domain, sort, genre, status, page) +} + // BrowseCoverKey returns the MinIO object key for a cached book cover image. // Layout: {domain}/assets/book-covers/{slug}.jpg func BrowseCoverKey(domain, slug string) string { diff --git a/scraper/internal/storage/store.go b/scraper/internal/storage/store.go index 5b54bae..ae23918 100644 --- a/scraper/internal/storage/store.go +++ b/scraper/internal/storage/store.go @@ -156,6 +156,9 @@ type Store interface { // BrowseHTMLKey returns the MinIO object key for a SingleFile HTML snapshot. // Layout: {domain}/html/page-{n}.html BrowseHTMLKey(domain string, page int) string + // BrowseFilteredHTMLKey returns the MinIO object key for a browse page snapshot + // that incorporates sort/genre/status so different filter combos are cached separately. + BrowseFilteredHTMLKey(domain string, page int, sort, genre, status string) string // BrowseCoverKey returns the MinIO object key for a cached book cover image. // Layout: {domain}/assets/book-covers/{slug}.jpg BrowseCoverKey(domain, slug string) string