diff --git a/scraper/internal/server/ui.go b/scraper/internal/server/ui.go index 9127a63..d1fb22f 100644 --- a/scraper/internal/server/ui.go +++ b/scraper/internal/server/ui.go @@ -557,33 +557,66 @@ const rankingTmpl = ` - -
-
- Fetch up to page: - {{range .PageNums}} + + {{if gt .TotalPages 1}} +
+
+ Page: + {{$cur := .CurrentPage}} + {{range .DisplayNums}} {{if eq .Num 0}} + {{else if eq .Num $cur}} + {{.Num}} {{else}} -
- - -
+ + {{.Num}} + {{end}} {{end}}
-

- Each page = ~20 novels from - novelfire.net popular -

+

Showing {{.TotalItems}} cached novels · page {{.CurrentPage}} of {{.TotalPages}}

+ {{end}} + + +
+ + + Fetch more from novelfire.net + +
+
+ Fetch up to page: + {{range .FetchNums}} + {{if eq .Num 0}} + + {{else}} +
+ + +
+ {{end}} + {{end}} +
+

+ Each page ≈ 20 novels from + novelfire.net popular +

+
+
@@ -777,8 +810,11 @@ func rankingPageNums(total int) []pageNum { return out } -// handleRanking serves the ranking page from the cached ranking.md file. +const rankingPageSize = 20 + +// handleRanking serves the ranking page from the cached ranking.json file. // It does NOT trigger a live scrape; use POST /ranking/refresh for that. +// Supports ?page=N for browsing through cached items (20 per page). func (s *Server) handleRanking(w http.ResponseWriter, r *http.Request) { rankingItems, err := s.writer.ReadRankingItems() if err != nil { @@ -790,16 +826,52 @@ func (s *Server) handleRanking(w http.ResponseWriter, r *http.Request) { cachedAt = info.ModTime().Format("Jan 2, 2006 at 15:04") } + // Parse requested display page (1-indexed). + currentPage := 1 + if p := r.URL.Query().Get("page"); p != "" { + if n, err2 := strconv.Atoi(p); err2 == nil && n > 0 { + currentPage = n + } + } + + totalItems := len(rankingItems) + totalPages := 1 + if totalItems > 0 { + totalPages = (totalItems + rankingPageSize - 1) / rankingPageSize + } + if currentPage > totalPages { + currentPage = totalPages + } + + // Slice items for the current display page. + start := (currentPage - 1) * rankingPageSize + end := start + rankingPageSize + if end > totalItems { + end = totalItems + } + pageItems := rankingItems + if totalItems > 0 { + pageItems = rankingItems[start:end] + } + t := template.Must(template.New("ranking").Parse(rankingTmpl)) var buf bytes.Buffer _ = t.Execute(&buf, struct { - Books interface{} - CachedAt string - PageNums []pageNum + Books interface{} + CachedAt string + FetchNums []pageNum + DisplayNums []pageNum + CurrentPage int + TotalPages int + TotalItems int }{ - Books: toRankingViewItems(rankingItems, s.writer.LocalSlugs()), - CachedAt: cachedAt, - PageNums: rankingPageNums(100), + Books: toRankingViewItems(pageItems, s.writer.LocalSlugs()), + CachedAt: cachedAt, + FetchNums: rankingPageNums(100), + DisplayNums: rankingPageNums(totalPages), + CurrentPage: currentPage, + TotalPages: totalPages, + TotalItems: totalItems, }) s.respond(w, r, "Rankings", buf.String()) }