forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {type AppBskyFeedDefs, type BskyAgent} from '@atproto/api'
2
3import {PROD_DEFAULT_FEED} from '#/lib/constants'
4import {CustomFeedAPI} from './custom'
5import {FollowingFeedAPI} from './following'
6import {type FeedAPI, type FeedAPIResponse} from './types'
7
8// HACK
9// the feed API does not include any facilities for passing down
10// non-post elements. adding that is a bit of a heavy lift, and we
11// have just one temporary usecase for it: flagging when the home feed
12// falls back to discover.
13// we use this fallback marker post to drive this instead. see Feed.tsx
14// for the usage.
15// -prf
16export const FALLBACK_MARKER_POST: AppBskyFeedDefs.FeedViewPost = {
17 post: {
18 uri: 'fallback-marker-post',
19 cid: 'fake',
20 record: {},
21 author: {
22 did: 'did:fake',
23 handle: 'fake.com',
24 },
25 indexedAt: new Date().toISOString(),
26 },
27}
28
29export class HomeFeedAPI implements FeedAPI {
30 agent: BskyAgent
31 following: FollowingFeedAPI
32 discover: CustomFeedAPI
33 usingDiscover = false
34 itemCursor = 0
35 userInterests?: string
36
37 constructor({
38 userInterests,
39 agent,
40 }: {
41 userInterests?: string
42 agent: BskyAgent
43 }) {
44 this.agent = agent
45 this.following = new FollowingFeedAPI({agent})
46 this.discover = new CustomFeedAPI({
47 agent,
48 feedParams: {feed: PROD_DEFAULT_FEED('whats-hot')},
49 })
50 this.userInterests = userInterests
51 }
52
53 reset() {
54 this.following = new FollowingFeedAPI({agent: this.agent})
55 this.discover = new CustomFeedAPI({
56 agent: this.agent,
57 feedParams: {feed: PROD_DEFAULT_FEED('whats-hot')},
58 userInterests: this.userInterests,
59 })
60 this.usingDiscover = false
61 this.itemCursor = 0
62 }
63
64 async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> {
65 if (this.usingDiscover) {
66 return this.discover.peekLatest()
67 }
68 return this.following.peekLatest()
69 }
70
71 async fetch({
72 cursor,
73 limit,
74 }: {
75 cursor: string | undefined
76 limit: number
77 }): Promise<FeedAPIResponse> {
78 if (!cursor) {
79 this.reset()
80 }
81
82 let returnCursor
83 let posts: AppBskyFeedDefs.FeedViewPost[] = []
84
85 if (!this.usingDiscover) {
86 const res = await this.following.fetch({cursor, limit})
87 returnCursor = res.cursor
88 posts = posts.concat(res.feed)
89 if (!returnCursor) {
90 cursor = ''
91 posts.push(FALLBACK_MARKER_POST)
92 this.usingDiscover = true
93 }
94 }
95
96 if (this.usingDiscover && !__DEV__) {
97 const res = await this.discover.fetch({cursor, limit})
98 returnCursor = res.cursor
99 posts = posts.concat(res.feed)
100 }
101
102 return {
103 cursor: returnCursor,
104 feed: posts,
105 }
106 }
107}