2024-05-13 08:47:26 +00:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/url"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Client struct {
|
|
|
|
handle string
|
|
|
|
baseURL string
|
|
|
|
filters PostsFilter
|
|
|
|
account Account
|
|
|
|
posts []Post
|
2024-05-18 13:22:23 +00:00
|
|
|
replies map[string]string
|
2024-05-13 08:47:26 +00:00
|
|
|
orphans []string
|
2024-05-18 13:22:23 +00:00
|
|
|
postIdMap map[string]int
|
|
|
|
output []int
|
2024-05-13 08:47:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type PostsFilter struct {
|
|
|
|
ExcludeReplies bool
|
|
|
|
ExcludeReblogs bool
|
|
|
|
Limit int
|
|
|
|
SinceId string
|
|
|
|
MinId string
|
|
|
|
MaxId string
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(userURL string, filters PostsFilter, threaded bool) (Client, error) {
|
|
|
|
var client Client
|
|
|
|
parsedURL, err := url.Parse(userURL)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return client, fmt.Errorf("error parsing user url: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
baseURL := fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host)
|
|
|
|
acc := strings.TrimPrefix(parsedURL.Path, "/")
|
|
|
|
handle := strings.TrimPrefix(acc, "@")
|
|
|
|
|
2024-05-18 14:08:07 +00:00
|
|
|
account, err := FetchAccount(baseURL, handle)
|
2024-05-13 08:47:26 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return client, err
|
|
|
|
}
|
|
|
|
|
2024-05-18 14:08:07 +00:00
|
|
|
posts, err := FetchPosts(baseURL, account.Id, filters)
|
2024-05-13 08:47:26 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return client, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var orphans []string
|
|
|
|
client = Client{
|
2024-05-18 13:22:23 +00:00
|
|
|
baseURL: baseURL,
|
|
|
|
handle: handle,
|
|
|
|
filters: filters,
|
|
|
|
account: account,
|
|
|
|
posts: posts,
|
|
|
|
postIdMap: make(map[string]int),
|
|
|
|
replies: make(map[string]string),
|
|
|
|
orphans: orphans,
|
2024-05-13 08:47:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
client.populateIdMap()
|
|
|
|
|
|
|
|
if threaded {
|
|
|
|
client.generateReplies()
|
2024-05-18 13:22:23 +00:00
|
|
|
} else {
|
|
|
|
for i := range client.posts {
|
2024-05-18 14:08:07 +00:00
|
|
|
client.output = append(client.output, i)
|
2024-05-18 13:22:23 +00:00
|
|
|
}
|
2024-05-13 08:47:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return client, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c Client) Account() Account {
|
|
|
|
return c.account
|
|
|
|
}
|
|
|
|
|
2024-05-18 13:22:23 +00:00
|
|
|
func (c Client) Posts() []*Post {
|
|
|
|
var p []*Post
|
|
|
|
|
|
|
|
for _, i := range c.output {
|
|
|
|
p = append(p, &c.posts[i])
|
|
|
|
}
|
|
|
|
|
|
|
|
return p
|
2024-05-13 08:47:26 +00:00
|
|
|
}
|
|
|
|
|
2024-05-18 13:22:23 +00:00
|
|
|
func (c *Client) populateIdMap() {
|
|
|
|
for i, post := range c.posts {
|
|
|
|
c.postIdMap[post.Id] = i
|
2024-05-13 08:47:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-18 13:22:23 +00:00
|
|
|
func (c *Client) flushReplies(post *Post, descendants *[]*Post) {
|
|
|
|
if pid, ok := c.replies[post.Id]; ok {
|
|
|
|
reply := c.posts[c.postIdMap[pid]]
|
|
|
|
*descendants = append(*descendants, &reply)
|
|
|
|
c.flushReplies(&reply, descendants)
|
2024-05-13 08:47:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-18 13:22:23 +00:00
|
|
|
func (c *Client) generateReplies() {
|
|
|
|
for i := range c.posts {
|
|
|
|
post := &c.posts[i]
|
2024-05-13 08:47:26 +00:00
|
|
|
if post.InReplyToId == "" {
|
|
|
|
c.flushReplies(post, &post.descendants)
|
2024-05-18 13:22:23 +00:00
|
|
|
c.output = append(c.output, i)
|
2024-05-13 08:47:26 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-05-18 13:22:23 +00:00
|
|
|
if _, ok := c.postIdMap[post.InReplyToId]; ok {
|
|
|
|
// TODO: Exclude from list of posts that gets rendered to disc
|
|
|
|
c.replies[post.InReplyToId] = post.Id
|
2024-05-13 08:47:26 +00:00
|
|
|
} else {
|
|
|
|
c.orphans = append(c.orphans, post.Id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|