mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Render cached feeds before recommendation refresh
This commit is contained in:
1 parent
687f8c438d
commit
bb6614e3d3
2 files changed
+89
-1
No files matched your search
@@ -1016,8 +1016,21 @@ export function createFeedCoordinator(deps) {
|
||||
|
||||
const recommendationFeed =
|
||||
feedType === FEED_TYPES.FOR_YOU || feedType === FEED_TYPES.EXPLORE;
|
||||
let exploreActivation = null;
|
||||
if (recommendationFeed && typeof this.ensureExploreDataService === "function") {
|
||||
await this.ensureExploreDataService();
|
||||
// Recommendation indexes are an enhancement, not a prerequisite for
|
||||
// showing cached videos. Activating the worker here used to leave a
|
||||
// returning For You view stuck on its static loading markup whenever
|
||||
// worker startup was slow or unavailable.
|
||||
exploreActivation = Promise.resolve(this.ensureExploreDataService()).catch(
|
||||
(error) => {
|
||||
devLogger.warn(
|
||||
`[Application] Recommendation data activation failed for ${feedType}:`,
|
||||
error,
|
||||
);
|
||||
return null;
|
||||
},
|
||||
);
|
||||
} else if (this.exploreDataService?.setActive) {
|
||||
this.exploreDataService.setActive(false);
|
||||
}
|
||||
@@ -1117,6 +1130,23 @@ export function createFeedCoordinator(deps) {
|
||||
if (this.videoListView) {
|
||||
this.videoListView.state.videosMap = this.videosMap;
|
||||
}
|
||||
|
||||
// Re-score once the optional recommendation indexes are ready, but only
|
||||
// if the user is still looking at this feed. The first render above is
|
||||
// deliberately cache-first and must not wait for worker startup.
|
||||
if (exploreActivation) {
|
||||
void exploreActivation.then(() => {
|
||||
if (!this.isFeedActive(feedType)) {
|
||||
return;
|
||||
}
|
||||
return this.refreshFeed(feedType, { reason: "recommendation-data-ready" });
|
||||
}).catch((error) => {
|
||||
devLogger.warn(
|
||||
`[Application] Failed to refresh ${feedType} after recommendation data activation:`,
|
||||
error,
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -85,3 +85,61 @@ test('createFeedCoordinator - loadForYouVideos', async (t) => {
|
||||
assert.strictEqual(app.videoSubscription, 'mock-subscription', 'Should update videoSubscription');
|
||||
});
|
||||
});
|
||||
|
||||
test("loadForYouVideos renders without waiting for recommendation worker activation", async () => {
|
||||
let resolveActivation;
|
||||
const activation = new Promise((resolve) => {
|
||||
resolveActivation = resolve;
|
||||
});
|
||||
let loadVideosStarted = false;
|
||||
const mockDeps = {
|
||||
devLogger: { log: mock.fn(), warn: mock.fn() },
|
||||
userLogger: { warn: mock.fn() },
|
||||
nostrClient: {},
|
||||
getSidebarLoadingMarkup: mock.fn(() => '<div>Loading...</div>'),
|
||||
watchHistoryService: {},
|
||||
subscriptions: {},
|
||||
createActiveNostrSource: mock.fn(),
|
||||
createBlacklistFilterStage: mock.fn(),
|
||||
createDisinterestFilterStage: mock.fn(),
|
||||
createDedupeByRootStage: mock.fn(),
|
||||
createExploreDiversitySorter: mock.fn(),
|
||||
createExploreScorerStage: mock.fn(),
|
||||
createKidsAudienceFilterStage: mock.fn(),
|
||||
createKidsScorerStage: mock.fn(),
|
||||
createKidsScoreSorter: mock.fn(),
|
||||
createModerationStage: mock.fn(),
|
||||
createResolvePostedAtStage: mock.fn(),
|
||||
createTagPreferenceFilterStage: mock.fn(),
|
||||
createWatchHistorySuppressionStage: mock.fn(),
|
||||
createChronologicalSorter: mock.fn(),
|
||||
createSubscriptionAuthorsSource: mock.fn(),
|
||||
registerWatchHistoryFeed: mock.fn(),
|
||||
};
|
||||
const coordinator = createFeedCoordinator(mockDeps);
|
||||
const app = {
|
||||
...coordinator,
|
||||
nostrService: {
|
||||
getFilteredActiveVideos: mock.fn(() => [{ id: "cached" }]),
|
||||
loadVideos: mock.fn(async ({ onVideos }) => {
|
||||
loadVideosStarted = true;
|
||||
onVideos([{ id: "cached", title: "Cached", created_at: 1 }], { reason: "cache" });
|
||||
return [{ id: "cached", title: "Cached", created_at: 1 }];
|
||||
}),
|
||||
getVideoSubscription: mock.fn(() => null),
|
||||
getVideosMap: mock.fn(() => new Map()),
|
||||
},
|
||||
videoListView: { state: {}, render: mock.fn() },
|
||||
mountVideoListView: mock.fn(() => ({ innerHTML: "" })),
|
||||
checkRelayHealthWarning: mock.fn(),
|
||||
setFeedTelemetryContext: mock.fn(),
|
||||
isAuthorBlocked: mock.fn(() => false),
|
||||
refreshFeed: mock.fn(async () => {}),
|
||||
ensureExploreDataService: mock.fn(() => activation),
|
||||
blacklistedEventIds: new Set(),
|
||||
};
|
||||
|
||||
await app.loadForYouVideos(false);
|
||||
assert.equal(loadVideosStarted, true);
|
||||
resolveActivation();
|
||||
});
|
||||
Reference in new issue
Block a user