fix(favorites): use cursor-based pagination instead of page numbers
FA's /favorites/{user}/ pagination is cursor-addressed by the fave-ID
of the last item on the previous page (e.g.
/favorites/{user}/1951234825/next), not by sequential integers. The
previous URL builder generated /favorites/{user}/{N}/ for N>=2; FA
interpreted that as a malformed cursor and silently returned page 1,
which caused the Favorites iterator to loop forever and the new
FavoritesPage to report HasNext=true on every call.
Changes:
- urls.Favorites(name) returns the first-page URL; new
urls.FavoritesCursor(name, cursor) builds /favorites/.../next URLs.
- FavoritesPage now takes a cursor string; empty = first page.
Returns ListingPage.NextPage as the opaque fave-ID for the next call.
- ListingPage gains NextPage string (decimal page number for
Gallery/Scraps, fave-ID cursor for Favorites) and drops the Page int
field that conflated those two notions.
- Client.Favorites iterator now walks cursors internally; StartPage
is ignored for favorites (documented).
- detectNextPage / nextPageURL now parse the form action so the same
helper works for both page-number and cursor pagination.
- Added regression test that fails on the infinite-loop bug.
- Example: examples/favorites_page demonstrates cursor walking.
This commit is contained in:
@@ -36,10 +36,25 @@ func Scraps(name string, page int) string {
|
||||
return Host + "/scraps/" + safeName(name) + "/" + pageSegment(page)
|
||||
}
|
||||
|
||||
// Favorites returns the URL for a user's favorites page. FA uses a numeric
|
||||
// page parameter; the first page is 1.
|
||||
func Favorites(name string, page int) string {
|
||||
return Host + "/favorites/" + safeName(name) + "/" + pageSegment(page)
|
||||
// Favorites returns the URL for the first page of a user's favorites.
|
||||
// FA paginates favorites with a fave-ID cursor (see [FavoritesCursor]),
|
||||
// not sequential page numbers — passing /favorites/{user}/{N}/ with a
|
||||
// small integer N silently falls back to the first page. Use this for
|
||||
// the first page only; follow the cursor returned in [ListingPage].NextPage
|
||||
// for subsequent pages.
|
||||
func Favorites(name string) string {
|
||||
return Host + "/favorites/" + safeName(name) + "/"
|
||||
}
|
||||
|
||||
// FavoritesCursor returns the URL for a follow-up favorites page,
|
||||
// addressed by the fave-ID cursor FA emits on the previous page's "Next"
|
||||
// form (e.g. /favorites/{user}/1951234825/next). The cursor is opaque
|
||||
// to the SDK — pass through whatever [ListingPage].NextPage gave you.
|
||||
func FavoritesCursor(name, cursor string) string {
|
||||
if cursor == "" {
|
||||
return Favorites(name)
|
||||
}
|
||||
return Host + "/favorites/" + safeName(name) + "/" + cursor + "/next"
|
||||
}
|
||||
|
||||
// Journal returns the URL for a single journal entry.
|
||||
|
||||
Reference in New Issue
Block a user