mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(popular-posts): rank by time-decayed popularity instead of raw reply count
This commit is contained in:
@@ -5,9 +5,24 @@ import { getCommentMediaInfo, getHasThumbnail } from '../lib/utils/media-utils';
|
||||
const MAX_POSTS = 8;
|
||||
const MAX_PER_SUB = 3;
|
||||
|
||||
// Activity relevance halves every 3 days
|
||||
const HALF_LIFE_SECONDS = 72 * 3600;
|
||||
|
||||
/**
|
||||
* Ranked by replyCount instead of a static threshold so the box
|
||||
* adapts to both low- and high-activity periods.
|
||||
* Time-decayed popularity: replyCount divided by age of latest
|
||||
* activity so a stale post with many old replies loses to a newer
|
||||
* post with a few recent replies.
|
||||
*/
|
||||
function popularityScore(post: Comment, nowSeconds: number): number {
|
||||
const lastActivity = post.lastReplyTimestamp ?? post.timestamp ?? 0;
|
||||
const ageSeconds = Math.max(0, nowSeconds - lastActivity);
|
||||
const replies = post.replyCount ?? 0;
|
||||
return Math.max(replies, 0.1) / (1 + ageSeconds / HALF_LIFE_SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ranked by time-decayed popularity so the box surfaces posts with
|
||||
* recent engagement rather than stale all-time reply leaders.
|
||||
*
|
||||
* Grow-only commit: once a post enters the grid it never shifts or
|
||||
* disappears — new posts fill remaining slots until the cap is reached.
|
||||
@@ -33,6 +48,8 @@ const usePopularPosts = (subplebbits: Subplebbit[]) => {
|
||||
const candidates = useMemo(() => {
|
||||
if (committedRef.current.posts.length >= MAX_POSTS) return [];
|
||||
|
||||
const nowSeconds = Math.floor(Date.now() / 1000);
|
||||
|
||||
try {
|
||||
const uniqueLinks = new Set<string>();
|
||||
const allPosts: Comment[] = [];
|
||||
@@ -57,15 +74,11 @@ const usePopularPosts = (subplebbits: Subplebbit[]) => {
|
||||
}
|
||||
}
|
||||
|
||||
subPosts.sort((a, b) => (b.replyCount ?? 0) - (a.replyCount ?? 0));
|
||||
subPosts.sort((a, b) => popularityScore(b, nowSeconds) - popularityScore(a, nowSeconds));
|
||||
allPosts.push(...subPosts.slice(0, MAX_PER_SUB));
|
||||
}
|
||||
|
||||
// Primary: most replies first. Tiebreaker: newest first.
|
||||
allPosts.sort((a, b) => {
|
||||
const diff = (b.replyCount ?? 0) - (a.replyCount ?? 0);
|
||||
return diff !== 0 ? diff : (b.timestamp ?? 0) - (a.timestamp ?? 0);
|
||||
});
|
||||
allPosts.sort((a, b) => popularityScore(b, nowSeconds) - popularityScore(a, nowSeconds));
|
||||
|
||||
return allPosts;
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user