diff --git a/app/Jobs/HomeFeedPipeline/FeedInsertRemotePipeline.php b/app/Jobs/HomeFeedPipeline/FeedInsertRemotePipeline.php index 97ca56e94..006dfaced 100644 --- a/app/Jobs/HomeFeedPipeline/FeedInsertRemotePipeline.php +++ b/app/Jobs/HomeFeedPipeline/FeedInsertRemotePipeline.php @@ -16,11 +16,23 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\Middleware\WithoutOverlapping; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Log; +use Throwable; class FeedInsertRemotePipeline implements ShouldBeUniqueUntilProcessing, ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + /** + * Remote statuses published more than this many days ago are not + * inserted into home feeds. + * + * The home timeline is scored by status id, and a remote status gets + * its id when we first store it, not when it was published. Without + * this guard an old post that is fetched for the first time (a boost, + * an edit, a reply to it) lands at the top of every follower's feed. + */ + public const MAX_AGE_DAYS = 7; + protected $sid; protected $pid; @@ -101,6 +113,10 @@ class FeedInsertRemotePipeline implements ShouldBeUniqueUntilProcessing, ShouldQ return; } + if (self::isTooOld($status)) { + return; + } + $ids = FollowerService::localFollowerIds($pid); if (! $ids || ! count($ids)) { @@ -132,4 +148,19 @@ class FeedInsertRemotePipeline implements ShouldBeUniqueUntilProcessing, ShouldQ } } } + + public static function isTooOld(string|\DateTimeInterface|null $createdAt): bool + { + if ($createdAt === null || $createdAt === '') { + return true; + } + + try { + $published = now()->parse($createdAt); + } catch (Throwable) { + return true; + } + + return $published->lt(now()->subDays(self::MAX_AGE_DAYS)); + } } diff --git a/app/Util/ActivityPub/Helpers.php b/app/Util/ActivityPub/Helpers.php index 1c87aa75c..6c91d2eab 100644 --- a/app/Util/ActivityPub/Helpers.php +++ b/app/Util/ActivityPub/Helpers.php @@ -989,7 +989,8 @@ class Helpers { if ( config('instance.timeline.network.cached') && - self::isEligibleForNetwork($status) + self::isEligibleForNetwork($status) && + ! FeedInsertRemotePipeline::isTooOld($status->created_at) ) { $urlDomain = parse_url($url, PHP_URL_HOST); $filteredDomains = self::getFilteredDomains();