mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {
2 AppBskyFeedDefs,
3 AppBskyFeedGetAuthorFeed as GetAuthorFeed,
4 BskyAgent,
5} from '@atproto/api'
6
7import {FeedAPI, FeedAPIResponse} from './types'
8
9export class AuthorFeedAPI implements FeedAPI {
10 agent: BskyAgent
11 params: GetAuthorFeed.QueryParams
12
13 constructor({
14 agent,
15 feedParams,
16 }: {
17 agent: BskyAgent
18 feedParams: GetAuthorFeed.QueryParams
19 }) {
20 this.agent = agent
21 this.params = feedParams
22 }
23
24 async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> {
25 const res = await this.agent.getAuthorFeed({
26 ...this.params,
27 limit: 1,
28 })
29 return res.data.feed[0]
30 }
31
32 async fetch({
33 cursor,
34 limit,
35 }: {
36 cursor: string | undefined
37 limit: number
38 }): Promise<FeedAPIResponse> {
39 const res = await this.agent.getAuthorFeed({
40 ...this.params,
41 cursor,
42 limit,
43 })
44 if (res.success) {
45 return {
46 cursor: res.data.cursor,
47 feed: this._filter(res.data.feed),
48 }
49 }
50 return {
51 feed: [],
52 }
53 }
54
55 _filter(feed: AppBskyFeedDefs.FeedViewPost[]) {
56 if (this.params.filter === 'posts_and_author_threads') {
57 return feed.filter(post => {
58 const isReply = post.reply
59 const isRepost = AppBskyFeedDefs.isReasonRepost(post.reason)
60 if (!isReply) return true
61 if (isRepost) return true
62 return isReply && isAuthorReplyChain(this.params.actor, post, feed)
63 })
64 }
65
66 return feed
67 }
68}
69
70function isAuthorReplyChain(
71 actor: string,
72 post: AppBskyFeedDefs.FeedViewPost,
73 posts: AppBskyFeedDefs.FeedViewPost[],
74): boolean {
75 // current post is by a different user (shouldn't happen)
76 if (post.post.author.did !== actor) return false
77
78 const replyParent = post.reply?.parent
79
80 if (AppBskyFeedDefs.isPostView(replyParent)) {
81 // reply parent is by a different user
82 if (replyParent.author.did !== actor) return false
83
84 // A top-level post that matches the parent of the current post.
85 const parentPost = posts.find(p => p.post.uri === replyParent.uri)
86
87 /*
88 * Either we haven't fetched the parent at the top level, or the only
89 * record we have is on feedItem.reply.parent, which we've already checked
90 * above.
91 */
92 if (!parentPost) return true
93
94 // Walk up to parent
95 return isAuthorReplyChain(actor, parentPost, posts)
96 }
97
98 // Just default to showing it
99 return true
100}