about summary refs log tree commit diff
path: root/src/lib
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-09-20 19:47:56 -0700
committerGitHub <noreply@github.com>2023-09-20 19:47:56 -0700
commit5a945c2024855b89dfb99f81a2c4d226bb39dc32 (patch)
tree3a42e8e8d79c281606c2b7d9bff9380df596d8c7 /src/lib
parent68dd3210d11bf8a15c319768d3e338c629a69d4b (diff)
downloadvoidsky-5a945c2024855b89dfb99f81a2c4d226bb39dc32.tar.zst
Prefilter the mergefeed to ensure a better mix of following and custom feeds (#1498)
* Prefilter the mergefeed to ensure a better mix of following and custom feeds

* Test suite improvements & tests for the mergefeed (#1499)

* Disable invite codes test for now

* Update test sim to latest iphone

* Introduce TestCtrls driver

* Add mergefeed tests
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/api/feed-manip.ts33
-rw-r--r--src/lib/api/feed/merge.ts31
-rw-r--r--src/lib/constants.ts10
3 files changed, 54 insertions, 20 deletions
diff --git a/src/lib/api/feed-manip.ts b/src/lib/api/feed-manip.ts
index ef57fc4f2..8f259a910 100644
--- a/src/lib/api/feed-manip.ts
+++ b/src/lib/api/feed-manip.ts
@@ -128,23 +128,32 @@ export class FeedTuner {
   tune(
     feed: FeedViewPost[],
     tunerFns: FeedTunerFn[] = [],
-    {dryRun}: {dryRun: boolean} = {dryRun: false},
+    {dryRun, maintainOrder}: {dryRun: boolean; maintainOrder: boolean} = {
+      dryRun: false,
+      maintainOrder: false,
+    },
   ): FeedViewPostsSlice[] {
     let slices: FeedViewPostsSlice[] = []
 
-    // arrange the posts into thread slices
-    for (let i = feed.length - 1; i >= 0; i--) {
-      const item = feed[i]
-
-      const selfReplyUri = getSelfReplyUri(item)
-      if (selfReplyUri) {
-        const parent = slices.find(item2 => item2.isNextInThread(selfReplyUri))
-        if (parent) {
-          parent.insert(item)
-          continue
+    if (maintainOrder) {
+      slices = feed.map(item => new FeedViewPostsSlice([item]))
+    } else {
+      // arrange the posts into thread slices
+      for (let i = feed.length - 1; i >= 0; i--) {
+        const item = feed[i]
+
+        const selfReplyUri = getSelfReplyUri(item)
+        if (selfReplyUri) {
+          const parent = slices.find(item2 =>
+            item2.isNextInThread(selfReplyUri),
+          )
+          if (parent) {
+            parent.insert(item)
+            continue
+          }
         }
+        slices.unshift(new FeedViewPostsSlice([item]))
       }
-      slices.unshift(new FeedViewPostsSlice([item]))
     }
 
     // run the custom tuners
diff --git a/src/lib/api/feed/merge.ts b/src/lib/api/feed/merge.ts
index 51a619589..f93278263 100644
--- a/src/lib/api/feed/merge.ts
+++ b/src/lib/api/feed/merge.ts
@@ -4,6 +4,7 @@ import {RootStoreModel} from 'state/index'
 import {timeout} from 'lib/async/timeout'
 import {bundleAsync} from 'lib/async/bundle'
 import {feedUriToHref} from 'lib/strings/url-helpers'
+import {FeedTuner} from '../feed-manip'
 import {FeedAPI, FeedAPIResponse, FeedSourceInfo} from './types'
 
 const REQUEST_WAIT_MS = 500 // 500ms
@@ -43,7 +44,7 @@ export class MergeFeedAPI implements FeedAPI {
 
     // always keep following topped up
     if (this.following.numReady < limit) {
-      promises.push(this.following.fetchNext(30))
+      promises.push(this.following.fetchNext(60))
     }
 
     // pick the next feeds to sample from
@@ -84,7 +85,8 @@ export class MergeFeedAPI implements FeedAPI {
     const i = this.itemCursor++
     const candidateFeeds = this.customFeeds.filter(f => f.numReady > 0)
     const canSample = candidateFeeds.length > 0
-    const hasFollows = this.following.numReady > 0
+    const hasFollows = this.following.hasMore
+    const hasFollowsReady = this.following.numReady > 0
 
     // this condition establishes the frequency that custom feeds are woven into follows
     const shouldSample =
@@ -98,7 +100,11 @@ export class MergeFeedAPI implements FeedAPI {
       // time to sample, or the user isnt following anybody
       return candidateFeeds[this.sampleCursor++ % candidateFeeds.length].take(1)
     }
-    // not time to sample
+    if (!hasFollowsReady) {
+      // stop here so more follows can be fetched
+      return []
+    }
+    // provide follow
     return this.following.take(1)
   }
 
@@ -174,6 +180,13 @@ class MergeFeedSource {
 }
 
 class MergeFeedSource_Following extends MergeFeedSource {
+  tuner = new FeedTuner()
+
+  reset() {
+    super.reset()
+    this.tuner.reset()
+  }
+
   async fetchNext(n: number) {
     return this._fetchNextInner(n)
   }
@@ -183,10 +196,16 @@ class MergeFeedSource_Following extends MergeFeedSource {
     limit: number,
   ): Promise<AppBskyFeedGetTimeline.Response> {
     const res = await this.rootStore.agent.getTimeline({cursor, limit})
-    // filter out mutes pre-emptively to ensure better mixing
-    res.data.feed = res.data.feed.filter(
-      post => !post.post.author.viewer?.muted,
+    // run the tuner pre-emptively to ensure better mixing
+    const slices = this.tuner.tune(
+      res.data.feed,
+      this.rootStore.preferences.getFeedTuners('home'),
+      {
+        dryRun: false,
+        maintainOrder: true,
+      },
     )
+    res.data.feed = slices.map(slice => slice.rootItem)
     return res
   }
 }
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index 001cdf8c3..1a7949e6a 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -83,8 +83,14 @@ export async function DEFAULT_FEEDS(
     // local dev
     const aliceDid = await resolveHandle('alice.test')
     return {
-      pinned: [`at://${aliceDid}/app.bsky.feed.generator/alice-favs`],
-      saved: [`at://${aliceDid}/app.bsky.feed.generator/alice-favs`],
+      pinned: [
+        `at://${aliceDid}/app.bsky.feed.generator/alice-favs`,
+        `at://${aliceDid}/app.bsky.feed.generator/alice-favs2`,
+      ],
+      saved: [
+        `at://${aliceDid}/app.bsky.feed.generator/alice-favs`,
+        `at://${aliceDid}/app.bsky.feed.generator/alice-favs2`,
+      ],
     }
   } else if (IS_STAGING(serviceUrl)) {
     // staging