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 }