Files
SkinbaseNova/app/Services/ThumbnailService.php
2026-02-07 08:23:18 +01:00

88 lines
3.1 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\Storage;
class ThumbnailService
{
protected const CDN_HOST = 'http://files.skinbase.org';
protected const VALID_SIZES = ['sm','md','lg','xl'];
protected const THUMB_SIZES = [
'sm' => ['height' => 240, 'quality' => 78, 'dir' => 'sm'],
'md' => ['height' => 360, 'quality' => 82, 'dir' => 'md'],
'lg' => ['height' => 1200, 'quality' => 85, 'dir' => 'lg'],
'xl' => ['height' => 2400, '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) ? 'sm' : '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) ? 'sm' : '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;
$sizeKey = in_array($sizeKey, self::VALID_SIZES) ? $sizeKey : 'md';
$h = $hash;
$h1 = substr($h, 0, 2);
$h2 = substr($h, 2, 2);
return sprintf('%s/%s/%s/%s/%s.%s', rtrim(self::CDN_HOST, '/'), $sizeKey, $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, 'sm');
$b = self::fromHash($hash, $ext, 'md');
if (!$a || !$b) return null;
return $a . ' 320w, ' . $b . ' 600w';
}
}