Files
go-fa-api/pagination.go
2026-05-25 22:27:18 +02:00

59 lines
1.9 KiB
Go

package fa
import (
"strings"
"github.com/PuerkitoBio/goquery"
)
// ListOptions configures the pagination of a simple iterator method like
// [Client.Gallery] or [Client.Notes]. Filtered iterators ([Client.Search],
// [Client.Browse]) use their own option structs that fold the same fields
// in alongside their filter parameters.
//
// Zero values mean "use the SDK defaults": start at page 1, no upper bound
// on pages. Pass [ListOptions{MaxPages: 3}] to bound a crawl.
type ListOptions struct {
// StartPage is the 1-based page to begin iteration on. Zero or 1 = first
// page. Useful for resuming after a known-good page.
StartPage int
// MaxPages bounds the number of pages the iterator will request before
// stopping. Zero (the default) = unbounded; iteration stops when FA
// serves an empty page or omits the "next" link.
MaxPages int
}
// firstPage returns the effective starting page (≥ 1).
func (o ListOptions) firstPage() int {
if o.StartPage < 1 {
return 1
}
return o.StartPage
}
// reachedLimit reports whether the iterator has fetched MaxPages pages and
// should stop. Always false when MaxPages is 0 (unbounded).
func (o ListOptions) reachedLimit(pagesFetched int) bool {
return o.MaxPages > 0 && pagesFetched >= o.MaxPages
}
// detectNextPage returns true if doc shows there is a next page available.
// FA's beta theme renders pagination as either a Next form button or a
// hyperlink with a recognisable label.
func detectNextPage(doc *goquery.Document) bool {
if doc.Find("form button.button.standard:contains('Next')").Length() > 0 {
return true
}
hit := false
doc.Find("a.button.standard, a.button-link, a.pagination-next").EachWithBreak(func(_ int, sel *goquery.Selection) bool {
text := strings.ToLower(trimText(sel))
if strings.Contains(text, "next") || strings.Contains(text, "older") {
hit = true
return false
}
return true
})
return hit
}