From 801928aadf38628ab38c069a94373f14b4685ee5 Mon Sep 17 00:00:00 2001 From: Admin Date: Sat, 28 Mar 2026 22:54:35 +0500 Subject: [PATCH] fix(scraper): update status and genres selectors for current novelfire.net HTML MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit novelfire.net changed its book page structure. Old selectors produced empty status and null genres for every book, causing all Meilisearch filters to return zero results. Old → new: - status: (text lowercased for consistent index values) - genres:
(text lowercased for consistent index values) Adds TestParseMetadataSelectors to guard against future regressions. --- backend/internal/novelfire/scraper.go | 22 ++++++++-- backend/internal/novelfire/scraper_test.go | 51 ++++++++++++++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/backend/internal/novelfire/scraper.go b/backend/internal/novelfire/scraper.go index 8b53944..f9e360f 100644 --- a/backend/internal/novelfire/scraper.go +++ b/backend/internal/novelfire/scraper.go @@ -178,12 +178,26 @@ func (s *Scraper) ScrapeMetadata(ctx context.Context, bookURL string) (domain.Bo } } - status := htmlutil.ExtractFirst(root, scraper.Selector{Tag: "span", Class: "status"}) + // Status: novelfire renders Ongoing (or + // "completed", "hiatus") inside the .header-stats block. We take the text + // content and lowercase it so the index value is always canonical lowercase. + var status string + for _, cls := range []string{"ongoing", "completed", "hiatus"} { + if v := htmlutil.ExtractFirst(root, scraper.Selector{Tag: "strong", Class: cls}); v != "" { + status = strings.ToLower(strings.TrimSpace(v)) + break + } + } - genresNode := htmlutil.FindFirst(root, scraper.Selector{Tag: "div", Class: "genres"}) + // Genres: novelfire renders