Files
SkinbaseNova/app/Services/WebStories/WorldWebStoryAssetService.php

166 lines
5.2 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\WebStories;
use App\Models\Artwork;
use App\Models\World;
use App\Models\WorldSubmission;
use App\Models\WorldWebStory;
use App\Models\WorldWebStoryPage;
use App\Services\ThumbnailPresenter;
final class WorldWebStoryAssetService
{
public function defaultPublisherLogoPath(): string
{
return 'https://cdn.skinbase.org/images/skinbase_logo_96.webp';
}
/**
* @return array{updated: bool, story: array<string, string>, pages: array<int, array<string, mixed>>}
*/
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 ?? '');
}
}