From 6e13c5c116949aacf1a3b9649994c1317c4d3b54 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 22 Sep 2026 22:39:26 -0600 Subject: [PATCH 1/2] Add alias to horizon --- app/Util/Lexer/RestrictedNames.php | 3 +++ routes/web.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/app/Util/Lexer/RestrictedNames.php b/app/Util/Lexer/RestrictedNames.php index c2a32aac2..dc8f45425 100644 --- a/app/Util/Lexer/RestrictedNames.php +++ b/app/Util/Lexer/RestrictedNames.php @@ -99,6 +99,9 @@ class RestrictedNames 'mix-manifest.json', 'robots.txt', + // Horizon + 'horizon', + // Reserved routes 'a', 'app', diff --git a/routes/web.php b/routes/web.php index d4188fe96..b361ba3af 100644 --- a/routes/web.php +++ b/routes/web.php @@ -526,6 +526,8 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['localization'])->grou }); Route::get('g/{hid}', [GroupController::class, 'groupShortLinkRedirect']); + Route::redirect('/horizon', '/admin/horizon'); + Route::get('stories/{username}', [ProfileController::class, 'stories']); Route::get('p/{id}', [StatusController::class, 'shortcodeRedirect']); Route::get('c/{collection}', [CollectionController::class, 'show']); From c18a76f4dab169307ee0720829fdb1eb784fac38 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 22 Sep 2026 23:06:52 -0600 Subject: [PATCH 2/2] Update FollowerService, change mutuals algorithm --- app/Services/FollowerService.php | 53 +++++++++++++------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/app/Services/FollowerService.php b/app/Services/FollowerService.php index 8e024815d..7505fa121 100644 --- a/app/Services/FollowerService.php +++ b/app/Services/FollowerService.php @@ -25,7 +25,7 @@ class FollowerService const FOLLOWERS_INTER_KEY = 'pf:services:follow:followers:inter:id:'; - const FOLLOWERS_MUTUALS_KEY = 'pf:services:follow:mutuals:'; + const FOLLOWERS_MUTUALS_KEY = 'pf:services:follow:mutuals:v2:'; public static function add($actor, $target, $refresh = true) { @@ -165,7 +165,6 @@ class FollowerService } FollowServiceWarmCache::dispatch($id)->onQueue('low'); } - } public static function audience($profile, $scope = null) @@ -285,6 +284,22 @@ class FollowerService return []; } + protected static function warmMutuals($profileId): string + { + $mutualsKey = self::FOLLOWERS_MUTUALS_KEY.$profileId; + + $ttl = Redis::ttl($mutualsKey); + if ($ttl === -2 || $ttl < 300) { + Redis::zinterstore($mutualsKey, [ + self::FOLLOWING_KEY.$profileId, + self::FOLLOWERS_KEY.$profileId, + ], ['aggregate' => 'max']); + Redis::expire($mutualsKey, 7200); + } + + return $mutualsKey; + } + /** * Get mutual followers for DM suggestions using Redis set intersection * This is extremely fast as it operates entirely in Redis memory @@ -308,26 +323,18 @@ class FollowerService self::cacheSyncCheck($profileId, 'followers'); self::cacheSyncCheck($profileId, 'following'); - $followingKey = self::FOLLOWING_KEY.$profileId; - $followersKey = self::FOLLOWERS_KEY.$profileId; - $mutualsKey = self::FOLLOWERS_MUTUALS_KEY.$profileId; - - $ttl = Redis::ttl($mutualsKey); - if ($ttl === -2 || $ttl < 300) { - Redis::zinterstore($mutualsKey, [$followingKey, $followersKey]); - Redis::expire($mutualsKey, 7200); - } + $mutualsKey = self::warmMutuals($profileId); $start = 0; if ($cursor) { - $cursorRank = Redis::zrank($mutualsKey, $cursor); - if ($cursorRank !== false) { + $cursorRank = Redis::zrevrank($mutualsKey, $cursor); + if (is_int($cursorRank)) { $start = $cursorRank + 1; } } - $mutuals = Redis::zrange($mutualsKey, $start, $start + $limit); + $mutuals = Redis::zrevrange($mutualsKey, $start, $start + $limit); $hasMore = count($mutuals) > $limit; if ($hasMore) { @@ -377,28 +384,12 @@ class FollowerService ]; } - /** - * Get mutual count efficiently using Redis intersection - * - * @param int $profileId - * @return int - */ public static function getMutualCount($profileId) { self::cacheSyncCheck($profileId, 'followers'); self::cacheSyncCheck($profileId, 'following'); - $followingKey = self::FOLLOWING_KEY.$profileId; - $followersKey = self::FOLLOWERS_KEY.$profileId; - $mutualsKey = self::FOLLOWERS_MUTUALS_KEY.$profileId; - - $ttl = Redis::ttl($mutualsKey); - if ($ttl === -2 || $ttl < 300) { - Redis::zinterstore($mutualsKey, [$followingKey, $followersKey]); - Redis::expire($mutualsKey, 7200); - } - - return Redis::zcard($mutualsKey); + return Redis::zcard(self::warmMutuals($profileId)); } public static function delCache($id)