, pages: array>} */ public function buildAssets(WorldWebStory $story, bool $force = false, bool $dryRun = false): array { $story->loadMissing(['world', 'orderedPages.artwork']); $world = $story->world; $storyChanges = []; $pageChanges = []; $primaryImage = $this->bestWorldImage($story); if (($force || blank($story->poster_portrait_path)) && filled($primaryImage)) { $storyChanges['poster_portrait_path'] = $primaryImage; } if (($force || blank($story->poster_square_path)) && filled($primaryImage)) { $storyChanges['poster_square_path'] = $primaryImage; } if ($force || blank($story->publisher_logo_path)) { $storyChanges['publisher_logo_path'] = $this->defaultPublisherLogoPath(); } foreach ($story->orderedPages as $page) { $changes = []; $background = $this->bestPageBackground($page, $world, $primaryImage); if (($force || blank($page->background_path)) && filled($background)) { $changes['background_path'] = $background; } if (($force || blank($page->background_mobile_path)) && filled($background)) { $changes['background_mobile_path'] = $background; } if (($force || blank($page->alt_text)) && filled($page->headline)) { $changes['alt_text'] = (string) $page->headline; } if ($changes !== []) { $pageChanges[(int) $page->id] = $changes; if (! $dryRun) { $page->forceFill($changes)->save(); } } } if ($storyChanges !== [] && ! $dryRun) { $story->forceFill($storyChanges)->save(); } return [ 'updated' => $storyChanges !== [] || $pageChanges !== [], 'story' => $storyChanges, 'pages' => $pageChanges, ]; } public function storyBasePath(WorldWebStory $story): string { $slug = trim((string) ($story->world?->slug ?: $story->slug)); return 'web-stories/worlds/' . $slug; } private function bestWorldImage(WorldWebStory $story): ?string { $world = $story->world; if ($world instanceof World) { foreach ([$world->ogImageUrl(), $world->coverUrl(), $world->teaserImageUrl()] as $candidate) { if (filled($candidate)) { return (string) $candidate; } } $artwork = $this->bestWorldArtwork($world); if ($artwork instanceof Artwork) { return $this->artworkImage($artwork); } } return null; } private function bestPageBackground(WorldWebStoryPage $page, ?World $world, ?string $fallback): ?string { if ($page->artwork instanceof Artwork) { $artworkImage = $this->artworkImage($page->artwork); if (filled($artworkImage)) { return $artworkImage; } } if ($world instanceof World) { $artwork = $this->bestWorldArtwork($world); if ($artwork instanceof Artwork) { $artworkImage = $this->artworkImage($artwork); if (filled($artworkImage)) { return $artworkImage; } } } return $fallback; } private function bestWorldArtwork(World $world): ?Artwork { $relatedArtworkIds = $world->worldRelations() ->where('related_type', 'artwork') ->orderByDesc('is_featured') ->orderBy('sort_order') ->pluck('related_id') ->map(fn ($id) => (int) $id) ->filter() ->values(); if ($relatedArtworkIds->isNotEmpty()) { return Artwork::query() ->whereIn('id', $relatedArtworkIds) ->get() ->sortBy(fn (Artwork $artwork): int => (int) ($relatedArtworkIds->search((int) $artwork->id) ?? PHP_INT_MAX)) ->first(); } $submission = WorldSubmission::query() ->with('artwork') ->where('world_id', $world->id) ->where('status', WorldSubmission::STATUS_LIVE) ->orderByDesc('is_featured') ->orderByDesc('featured_at') ->orderByDesc('id') ->first(); return $submission?->artwork; } private function artworkImage(Artwork $artwork): ?string { $preview = ThumbnailPresenter::present($artwork, 'xl'); return (string) ($preview['url'] ?? $artwork->thumbnail_url ?? $artwork->thumb_url ?? ''); } }