mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {
2 AppBskyFeedDefs,
3 AppBskyFeedGetFeed as GetCustomFeed,
4 AtpAgent,
5 BskyAgent,
6} from '@atproto/api'
7
8import {getContentLanguages} from '#/state/preferences/languages'
9import {FeedAPI, FeedAPIResponse} from './types'
10
11export class CustomFeedAPI implements FeedAPI {
12 getAgent: () => BskyAgent
13 params: GetCustomFeed.QueryParams
14
15 constructor({
16 getAgent,
17 feedParams,
18 }: {
19 getAgent: () => BskyAgent
20 feedParams: GetCustomFeed.QueryParams
21 }) {
22 this.getAgent = getAgent
23 this.params = feedParams
24 }
25
26 async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> {
27 const contentLangs = getContentLanguages().join(',')
28 const res = await this.getAgent().app.bsky.feed.getFeed(
29 {
30 ...this.params,
31 limit: 1,
32 },
33 {headers: {'Accept-Language': contentLangs}},
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 contentLangs = getContentLanguages().join(',')
46 const agent = this.getAgent()
47 const res = agent.session
48 ? await this.getAgent().app.bsky.feed.getFeed(
49 {
50 ...this.params,
51 cursor,
52 limit,
53 },
54 {
55 headers: {
56 'Accept-Language': contentLangs,
57 },
58 },
59 )
60 : await loggedOutFetch({...this.params, cursor, limit})
61 if (res.success) {
62 // NOTE
63 // some custom feeds fail to enforce the pagination limit
64 // so we manually truncate here
65 // -prf
66 if (res.data.feed.length > limit) {
67 res.data.feed = res.data.feed.slice(0, limit)
68 }
69 return {
70 cursor: res.data.feed.length ? res.data.cursor : undefined,
71 feed: res.data.feed,
72 }
73 }
74 return {
75 feed: [],
76 }
77 }
78}
79
80// HACK
81// we want feeds to give language-specific results immediately when a
82// logged-out user changes their language. this comes with two problems:
83// 1. not all languages have content, and
84// 2. our public caching layer isnt correctly busting against the accept-language header
85// for now we handle both of these with a manual workaround
86// -prf
87async function loggedOutFetch({
88 feed,
89 limit,
90 cursor,
91}: {
92 feed: string
93 limit: number
94 cursor?: string
95}) {
96 let contentLangs = getContentLanguages().join(',')
97
98 // manually construct fetch call so we can add the `lang` cache-busting param
99 let res = await AtpAgent.fetch!(
100 `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${
101 cursor ? `&cursor=${cursor}` : ''
102 }&limit=${limit}&lang=${contentLangs}`,
103 'GET',
104 {'Accept-Language': contentLangs},
105 undefined,
106 )
107 if (res.body?.feed?.length) {
108 return {
109 success: true,
110 data: res.body,
111 }
112 }
113
114 // no data, try again with language headers removed
115 res = await AtpAgent.fetch!(
116 `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${
117 cursor ? `&cursor=${cursor}` : ''
118 }&limit=${limit}`,
119 'GET',
120 {'Accept-Language': ''},
121 undefined,
122 )
123 if (res.body?.feed?.length) {
124 return {
125 success: true,
126 data: res.body,
127 }
128 }
129
130 return {
131 success: false,
132 data: {feed: []},
133 }
134}