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