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 get params() {
25 const params = {...this._params}
26 params.includePins =
27 params.filter === 'posts_with_replies' ||
28 params.filter === 'posts_and_author_threads'
29 return params
30 }
31
32 async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> {
33 const res = await this.agent.getAuthorFeed({
34 ...this.params,
35 limit: 1,
36 })
37 return res.data.feed[0]
38 }
39
40 async fetch({
41 cursor,
42 limit,
43 }: {
44 cursor: string | undefined
45 limit: number
46 }): Promise<FeedAPIResponse> {
47 const res = await this.agent.getAuthorFeed({
48 ...this.params,
49 cursor,
50 limit,
51 })
52 if (res.success) {
53 return {
54 cursor: res.data.cursor,
55 feed: this._filter(res.data.feed),
56 }
57 }
58 return {
59 feed: [],
60 }
61 }
62
63 _filter(feed: AppBskyFeedDefs.FeedViewPost[]) {
64 if (this.params.filter === 'posts_and_author_threads') {
65 return feed.filter(post => {
66 const isReply = post.reply
67 const isRepost = AppBskyFeedDefs.isReasonRepost(post.reason)
68 const isPin = AppBskyFeedDefs.isReasonPin(post.reason)
69 if (!isReply) return true
70 if (isRepost || isPin) return true
71 return isReply && isAuthorReplyChain(this.params.actor, post, feed)
72 })
73 }
74
75 return feed
76 }
77}
78
79function isAuthorReplyChain(
80 actor: string,
81 post: AppBskyFeedDefs.FeedViewPost,
82 posts: AppBskyFeedDefs.FeedViewPost[],
83): boolean {
84 // current post is by a different user (shouldn't happen)
85 if (post.post.author.did !== actor) return false
86
87 const replyParent = post.reply?.parent
88
89 if (AppBskyFeedDefs.isPostView(replyParent)) {
90 // reply parent is by a different user
91 if (replyParent.author.did !== actor) return false
92
93 // A top-level post that matches the parent of the current post.
94 const parentPost = posts.find(p => p.post.uri === replyParent.uri)
95
96 /*
97 * Either we haven't fetched the parent at the top level, or the only
98 * record we have is on feedItem.reply.parent, which we've already checked
99 * above.
100 */
101 if (!parentPost) return true
102
103 // Walk up to parent
104 return isAuthorReplyChain(actor, parentPost, posts)
105 }
106
107 // Just default to showing it
108 return true
109}