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