minor fixes

This commit is contained in:
2026-04-09 08:50:36 +02:00
parent 23d363a50c
commit a2457f4e49
75 changed files with 3848 additions and 387 deletions

View File

@@ -244,6 +244,15 @@ final class HomepageService
}
public function getHomepageGroups(?\App\Models\User $viewer = null): array
{
if (! $viewer) {
return Cache::remember('homepage.groups', self::CACHE_TTL, fn (): array => $this->buildHomepageGroups());
}
return $this->buildHomepageGroups($viewer);
}
private function buildHomepageGroups(?\App\Models\User $viewer = null): array
{
$featured = $this->groupDiscovery->surfaceCards($viewer, 'featured', 4);
$spotlight = $featured[0] ?? null;
@@ -314,6 +323,10 @@ final class HomepageService
return $this->getRisingFromDb($limit);
}
if ($this->collectionHasNoRisingMomentum($this->searchResultCollection($results))) {
return $this->getRisingLowSignalFromDb($limit);
}
return $items
->map(fn ($a) => $this->serializeArtwork($a))
->values()
@@ -348,6 +361,26 @@ final class HomepageService
->all();
}
private function getRisingLowSignalFromDb(int $limit): array
{
return Artwork::public()
->published()
->with(self::ARTWORK_SERIALIZATION_RELATIONS)
->leftJoinSub($this->risingRecentActivitySubquery(), 'recent_rising_activity', function ($join): void {
$join->on('recent_rising_activity.artwork_id', '=', 'artworks.id');
})
->select('artworks.*')
->where('artworks.published_at', '>=', now()->subDays(30))
->orderByRaw('COALESCE(recent_rising_activity.recent_signal_24h, 0) DESC')
->orderByDesc('artworks.published_at')
->orderByDesc('artworks.id')
->limit($limit)
->get()
->map(fn ($a) => $this->serializeArtwork($a))
->values()
->all();
}
/**
* Trending: up to 12 artworks sorted by Ranking V2 `ranking_score`.
*
@@ -466,26 +499,38 @@ final class HomepageService
try {
$since = now()->subWeek();
$rows = DB::table('artworks')
->join('users as u', 'u.id', '=', 'artworks.user_id')
$weeklyUploads = Artwork::query()
->selectRaw('user_id, COUNT(*) as weekly_uploads')
->where('is_public', true)
->where('is_approved', true)
->whereNull('deleted_at')
->whereNotNull('published_at')
->where('published_at', '<=', now())
->where('published_at', '>=', $since)
->groupBy('user_id');
$rows = DB::table('users as u')
->leftJoin('user_profiles as up', 'up.user_id', '=', 'u.id')
->leftJoin('artwork_awards as aw', 'aw.artwork_id', '=', 'artworks.id')
->leftJoin('artwork_stats as s', 's.artwork_id', '=', 'artworks.id')
->leftJoin('user_statistics as us', 'us.user_id', '=', 'u.id')
->leftJoinSub($weeklyUploads, 'weekly_uploads', function ($join): void {
$join->on('weekly_uploads.user_id', '=', 'u.id');
})
->select(
'u.id',
'u.name',
'u.username',
'up.avatar_hash',
DB::raw('COUNT(DISTINCT artworks.id) as upload_count'),
DB::raw('SUM(CASE WHEN artworks.published_at >= \'' . $since->toDateTimeString() . '\' THEN 1 ELSE 0 END) as weekly_uploads'),
DB::raw('COALESCE(SUM(s.views), 0) as total_views'),
DB::raw('COUNT(DISTINCT aw.id) as total_awards')
DB::raw('COALESCE(us.uploads_count, 0) as upload_count'),
DB::raw('COALESCE(weekly_uploads.weekly_uploads, 0) as weekly_uploads'),
DB::raw('COALESCE(us.artwork_views_received_count, 0) as total_views'),
DB::raw('COALESCE(us.awards_received_count, 0) as total_awards')
)
->where('artworks.is_public', true)
->where('artworks.is_approved', true)
->whereNull('artworks.deleted_at')
->whereNotNull('artworks.published_at')
->groupBy('u.id', 'u.name', 'u.username', 'up.avatar_hash')
->whereNull('u.deleted_at')
->where('u.is_active', true)
->where(function ($query): void {
$query->where('us.uploads_count', '>', 0)
->orWhere('weekly_uploads.weekly_uploads', '>', 0);
})
->orderByDesc('weekly_uploads')
->orderByDesc('total_awards')
->orderByDesc('total_views')
@@ -494,18 +539,23 @@ final class HomepageService
$userIds = $rows->pluck('id')->all();
// Pick one random artwork thumbnail per creator for the card background.
$thumbsByUser = Artwork::public()
$latestArtworkIds = Artwork::public()
->published()
->whereIn('user_id', $userIds)
->whereNotNull('hash')
->whereNotNull('thumb_ext')
->inRandomOrder()
->selectRaw('MAX(id) as id')
->groupBy('user_id')
->pluck('id')
->all();
$thumbsByUser = Artwork::query()
->whereIn('id', $latestArtworkIds)
->get(['id', 'user_id', 'hash', 'thumb_ext'])
->groupBy('user_id');
->keyBy('user_id');
return $rows->map(function ($u) use ($thumbsByUser) {
$artworkForBg = $thumbsByUser->get($u->id)?->first();
$artworkForBg = $thumbsByUser->get($u->id);
$bgThumb = $artworkForBg ? $artworkForBg->thumbUrl('md') : null;
return [
@@ -792,6 +842,37 @@ final class HomepageService
return $artworks;
}
private function collectionHasNoRisingMomentum(Collection $items): bool
{
if ($items->isEmpty()) {
return true;
}
return $items->every(function ($item): bool {
$heat = (float) ($item->heat_score ?? $item->stats?->heat_score ?? 0);
$velocity = (float) ($item->engagement_velocity ?? $item->stats?->engagement_velocity ?? 0);
return $heat <= 0.0 && $velocity <= 0.0;
});
}
private function risingRecentActivitySubquery()
{
$since = now()->startOfHour()->subHours(24);
return DB::table('artwork_metric_snapshots_hourly as rising_snapshots')
->selectRaw('rising_snapshots.artwork_id')
->selectRaw('(
COALESCE(MAX(rising_snapshots.views_count) - MIN(rising_snapshots.views_count), 0)
+ (COALESCE(MAX(rising_snapshots.downloads_count) - MIN(rising_snapshots.downloads_count), 0) * 3)
+ (COALESCE(MAX(rising_snapshots.favourites_count) - MIN(rising_snapshots.favourites_count), 0) * 4)
+ (COALESCE(MAX(rising_snapshots.comments_count) - MIN(rising_snapshots.comments_count), 0) * 5)
+ (COALESCE(MAX(rising_snapshots.shares_count) - MIN(rising_snapshots.shares_count), 0) * 6)
) as recent_signal_24h')
->where('rising_snapshots.bucket_hour', '>=', $since)
->groupBy('rising_snapshots.artwork_id');
}
private function serializeArtwork(Artwork $artwork, string $preferSize = 'md'): array
{
$thumbMd = $artwork->thumbUrl('md');