'thumb']; protected const THUMB_SIZES = [ 'thumb' => ['height' => 320, 'quality' => 78, 'dir' => 'thumb'], 'sq' => ['height' => 512, 'quality' => 82, 'dir' => 'sq', 'square' => true], 'sm' => ['height' => 320, 'quality' => 78, 'dir' => 'thumb'], // alias for thumb 'md' => ['height' => 1024, 'quality' => 82, 'dir' => 'md'], 'lg' => ['height' => 1920, 'quality' => 85, 'dir' => 'lg'], 'xl' => ['height' => 2560, 'quality' => 90, 'dir' => 'xl'], ]; /** * 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(), $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'; } }