Save workspace changes
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ThumbnailService
|
||||
{
|
||||
/**
|
||||
* CDN host is read from config/cdn.php → FILES_CDN_URL env.
|
||||
* Hardcoding the domain is forbidden per upload-agent spec §3A.
|
||||
*/
|
||||
protected static function cdnHost(): string
|
||||
{
|
||||
return rtrim((string) config('cdn.files_url', 'https://files.skinbase.org'), '/');
|
||||
}
|
||||
|
||||
protected static function artworkPrefix(): string
|
||||
{
|
||||
return trim((string) config('uploads.object_storage.prefix', 'artworks'), '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonical size keys: xs · sm · md · lg · xl (+ legacy thumb/sq support).
|
||||
*/
|
||||
protected const VALID_SIZES = ['xs', 'sm', 'md', 'lg', 'xl', 'thumb', 'sq'];
|
||||
|
||||
/** Size aliases for backwards compatibility with old callers. */
|
||||
protected const SIZE_ALIAS = ['thumb' => 'sm'];
|
||||
|
||||
protected const THUMB_SIZES = [
|
||||
'xs' => ['height' => 160, 'quality' => 74, 'dir' => 'xs'],
|
||||
'sm' => ['height' => 320, 'quality' => 78, 'dir' => 'sm'],
|
||||
'sq' => ['height' => 512, 'quality' => 82, 'dir' => 'sq', 'square' => true],
|
||||
'md' => ['height' => 1024, 'quality' => 82, 'dir' => 'md'],
|
||||
'lg' => ['height' => 1920, 'quality' => 85, 'dir' => 'lg'],
|
||||
'xl' => ['height' => 2560, 'quality' => 90, 'dir' => 'xl'],
|
||||
// Legacy compatibility for older paths still expecting /thumb/.
|
||||
'thumb' => ['height' => 320, 'quality' => 78, 'dir' => 'sm'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Build a thumbnail URL from a filePath/hash/id and ext.
|
||||
* Accepts either a direct hash string in $filePath, or an $id + $ext pair.
|
||||
* Legacy size codes (4 -> sm, others -> md) are supported.
|
||||
*/
|
||||
public static function url(?string $filePath, ?int $id = null, ?string $ext = null, $size = 6): string
|
||||
{
|
||||
// If $filePath seems to be a content hash and $ext is provided, build directly
|
||||
if (!empty($filePath) && !empty($ext) && preg_match('/^[0-9a-f]{16,128}$/i', $filePath)) {
|
||||
$sizeKey = is_string($size) ? $size : (($size === 4) ? 'thumb' : 'md');
|
||||
return self::fromHash($filePath, $ext, $sizeKey) ?: '';
|
||||
}
|
||||
|
||||
// Resolve by id when provided
|
||||
if ($id !== null) {
|
||||
try {
|
||||
$artClass = '\\App\\Models\\Artwork';
|
||||
if (class_exists($artClass)) {
|
||||
$art = $artClass::where('id', $id)->orWhere('legacy_id', $id)->first();
|
||||
if ($art) {
|
||||
$hash = $art->hash ?? null;
|
||||
$extToUse = $ext ?? ($art->thumb_ext ?? null);
|
||||
$sizeKey = is_string($size) ? $size : (($size === 4) ? 'thumb' : 'md');
|
||||
if (!empty($hash) && !empty($extToUse)) {
|
||||
return self::fromHash($hash, $extToUse, $sizeKey) ?: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// fallthrough to storage/filePath fallback
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to Storage::url or return provided path
|
||||
if (!empty($filePath)) {
|
||||
try {
|
||||
return Storage::url($filePath);
|
||||
} catch (\Throwable $e) {
|
||||
return $filePath;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build CDN URL from hash and extension.
|
||||
*/
|
||||
public static function fromHash(?string $hash, ?string $ext, string $sizeKey = 'md'): ?string
|
||||
{
|
||||
if (empty($hash) || empty($ext)) return null;
|
||||
// Resolve alias (sm → thumb) then validate
|
||||
$sizeKey = self::SIZE_ALIAS[$sizeKey] ?? $sizeKey;
|
||||
$sizeKey = in_array($sizeKey, self::VALID_SIZES) ? $sizeKey : 'md';
|
||||
$dir = self::THUMB_SIZES[$sizeKey]['dir'] ?? $sizeKey;
|
||||
$h = $hash;
|
||||
$h1 = substr($h, 0, 2);
|
||||
$h2 = substr($h, 2, 2);
|
||||
return sprintf('%s/%s/%s/%s/%s.%s', self::cdnHost(), self::artworkPrefix() . '/' . $dir, $h1, $h2, $h, $ext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build srcset using sm and md sizes for legacy layouts.
|
||||
*/
|
||||
public static function srcsetFromHash(?string $hash, ?string $ext): ?string
|
||||
{
|
||||
$a = self::fromHash($hash, $ext, 'thumb'); // 320px
|
||||
$b = self::fromHash($hash, $ext, 'md'); // 1024px
|
||||
if (!$a || !$b) return null;
|
||||
return $a . ' 320w, ' . $b . ' 1024w';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user