Something went wrong. Try again.
Bluesky app fork with some witchin' additions 💫 forked from jollywhoppers.com/witchsky.app
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163import { type AppBskyFeedDefs, type AppBskyFeedGetFeed as GetCustomFeed, BskyAgent, jsonStringToLex,} from '@atproto/api'
import { getAppLanguageAsContentLanguage, getContentLanguages,} from '#/state/preferences/languages'import {type FeedAPI, type FeedAPIResponse} from './types'import {createBskyTopicsHeader, isBlueskyOwnedFeed} from './utils'
export class CustomFeedAPI implements FeedAPI { agent: BskyAgent params: GetCustomFeed.QueryParams userInterests?: string
constructor({ agent, feedParams, userInterests, }: { agent: BskyAgent feedParams: GetCustomFeed.QueryParams userInterests?: string }) { this.agent = agent this.params = feedParams this.userInterests = userInterests }
async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> { const contentLangs = getContentLanguages().join(',') const res = await this.agent.app.bsky.feed.getFeed( { ...this.params, limit: 1, }, {headers: {'Accept-Language': contentLangs}}, ) return res.data.feed[0] }
async fetch({ cursor, limit, }: { cursor: string | undefined limit: number }): Promise<FeedAPIResponse> { const contentLangs = getContentLanguages().join(',') const agent = this.agent const isBlueskyOwned = isBlueskyOwnedFeed(this.params.feed)
const res = agent.did ? await this.agent.app.bsky.feed.getFeed( { ...this.params, cursor, limit, }, { headers: { ...(isBlueskyOwned ? createBskyTopicsHeader(this.userInterests) : {}), 'Accept-Language': contentLangs, }, }, ) : await loggedOutFetch({...this.params, cursor, limit}) if (res.success) { // NOTE // some custom feeds fail to enforce the pagination limit // so we manually truncate here // -prf if (res.data.feed.length > limit) { res.data.feed = res.data.feed.slice(0, limit) } return { cursor: res.data.feed.length ? res.data.cursor : undefined, feed: res.data.feed, } } return { feed: [], } }}
// HACK// we want feeds to give language-specific results immediately when a// logged-out user changes their language. this comes with two problems:// 1. not all languages have content, and// 2. our public caching layer isnt correctly busting against the accept-language header// for now we handle both of these with a manual workaround// -prfasync function loggedOutFetch({ feed, limit, cursor,}: { feed: string limit: number cursor?: string}) { let contentLangs = getAppLanguageAsContentLanguage()
/** * Copied from our root `Agent` class * @see https://github.com/bluesky-social/atproto/blob/60df3fc652b00cdff71dd9235d98a7a4bb828f05/packages/api/src/agent.ts#L120 */ const labelersHeader = { 'atproto-accept-labelers': BskyAgent.appLabelers .map(l => `${l};redact`) .join(', '), }
// manually construct fetch call so we can add the `lang` cache-busting param let res = await fetch( `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${ cursor ? `&cursor=${cursor}` : '' }&limit=${limit}&lang=${contentLangs}`, { method: 'GET', headers: {'Accept-Language': contentLangs, ...labelersHeader}, }, ) let data = res.ok ? (jsonStringToLex(await res.text()) as GetCustomFeed.OutputSchema) : null if (data?.feed?.length) { return { success: true, data, } }
// no data, try again with language headers removed res = await fetch( `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${ cursor ? `&cursor=${cursor}` : '' }&limit=${limit}`, {method: 'GET', headers: {'Accept-Language': '', ...labelersHeader}}, ) data = res.ok ? (jsonStringToLex(await res.text()) as GetCustomFeed.OutputSchema) : null if (data?.feed?.length) { return { success: true, data, } }
return { success: false, data: {feed: []}, }}