package fa import ( "context" "fmt" "iter" "time" "github.com/PuerkitoBio/goquery" "git.anthrove.art/public/go-fa-api/internal/urls" ) // Journal is a single journal entry, as seen on /journal/{id}/. type Journal struct { ID JournalID Title string Author UserRef PostedAt time.Time BodyHTML string BodyText string } // GetJournal fetches a journal entry by its numeric ID. func (c *Client) GetJournal(ctx context.Context, id JournalID) (*Journal, error) { if id <= 0 { return nil, fmt.Errorf("fa: GetJournal: id must be > 0") } var out *Journal err := c.fetch(ctx, urls.Journal(int64(id)), func(doc *goquery.Document) error { j, err := parseJournal(id, doc) if err != nil { return err } out = j return nil }) if err != nil { return nil, err } return out, nil } // UserJournals iterates a user's journals across pages. The iterator yields // each [Journal] preview (full body included on FA's listing page). // // Use [ListOptions.MaxPages] to bound the crawl. func (c *Client) UserJournals(ctx context.Context, name string, opts ListOptions) iter.Seq2[*Journal, error] { return func(yield func(*Journal, error) bool) { page := opts.firstPage() pagesFetched := 0 for { if opts.reachedLimit(pagesFetched) { return } var ( items []*Journal hasNext bool ) err := c.fetch(ctx, urls.UserJournals(name, page), func(doc *goquery.Document) error { items, hasNext = parseUserJournalsPage(doc) return nil }) if err != nil { yield(nil, err) return } pagesFetched++ for _, j := range items { if !yield(j, nil) { return } } if !hasNext { return } page++ } } }