Files

75 lines
2.2 KiB
PHP
Raw Permalink Normal View History

2026-08-09 12:43:21 +03:00
<?php
namespace App\Jobs;
use App\Models\Tool;
2026-08-11 00:06:19 +03:00
use App\Support\FaviconResolver;
2026-08-09 12:43:21 +03:00
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
2026-08-11 00:06:19 +03:00
use Illuminate\Http\Client\Response;
2026-08-09 12:43:21 +03:00
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class MirrorToolLogo implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
2026-08-11 00:06:19 +03:00
public function __construct(public Tool $tool) {}
2026-08-09 12:43:21 +03:00
2026-08-11 00:06:19 +03:00
public function handle(FaviconResolver $resolver): void
2026-08-09 12:43:21 +03:00
{
2026-08-11 00:06:19 +03:00
$tool = $this->tool->fresh();
// The tool may have been deleted, or already mirrored by an earlier
// run of this same job, since this was queued.
if (! $tool || $tool->hasLocalLogo()) {
2026-08-09 12:43:21 +03:00
return;
}
2026-08-11 00:06:19 +03:00
// logo_url is a hint, not a guarantee -- it's often a guessed
// `{domain}/favicon.ico` that 404s or isn't actually an image.
// Fall back to properly resolving the site's real favicon.
$response = ($tool->logo_url ? $this->fetchImage($tool->logo_url) : null)
?? $this->fetchImage($resolver->resolve($tool->url));
2026-08-09 12:43:21 +03:00
2026-08-11 00:06:19 +03:00
if (! $response) {
2026-08-09 12:43:21 +03:00
return;
}
$extension = match ($response->header('Content-Type')) {
'image/png' => 'png',
'image/jpeg' => 'jpg',
'image/webp' => 'webp',
'image/x-icon', 'image/vnd.microsoft.icon' => 'ico',
2026-08-11 00:06:19 +03:00
default => 'png',
2026-08-09 12:43:21 +03:00
};
2026-08-11 00:06:19 +03:00
$path = "tools/{$tool->slug}-".Str::random(8).".{$extension}";
2026-08-09 12:43:21 +03:00
Storage::disk('public')->put($path, $response->body());
2026-08-11 00:06:19 +03:00
$tool->update(['logo_url' => Storage::disk('public')->url($path)]);
}
private function fetchImage(?string $url): ?Response
{
if (! $url) {
return null;
}
try {
$response = Http::timeout(10)->get($url);
} catch (\Throwable) {
return null;
}
return $response->successful() && str_starts_with((string) $response->header('Content-Type'), 'image/')
? $response
: null;
2026-08-09 12:43:21 +03:00
}
}