-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: gallery dynamic meta image (#188)
- Loading branch information
1 parent
071c493
commit 393c45e
Showing
20 changed files
with
953 additions
and
316 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Console\Commands; | ||
|
||
use Illuminate\Console\Command; | ||
use Illuminate\Support\Facades\DB; | ||
|
||
class PruneMetaImages extends Command | ||
{ | ||
/** | ||
* The name and signature of the console command. | ||
* | ||
* @var string | ||
*/ | ||
protected $signature = 'prune-meta-images'; | ||
|
||
/** | ||
* The console command description. | ||
* | ||
* @var string | ||
*/ | ||
protected $description = 'Removes unused meta images'; | ||
|
||
/** | ||
* Execute the console command. | ||
*/ | ||
public function handle(): int | ||
{ | ||
$validImages = array_map(fn ($item) => $item->image_name, DB::select(get_query('gallery.get_meta_images'))); | ||
// Convert to associative array so we can use `isset` | ||
$validImages = array_combine($validImages, $validImages); | ||
|
||
$directory = storage_path(sprintf('meta/galleries/')); | ||
|
||
if (is_dir($directory)) { | ||
// Open directory | ||
if ($handle = opendir($directory)) { | ||
// Loop through each file in the directory | ||
while (false !== ($file = readdir($handle))) { | ||
// Check if file is a PNG and not in validImages | ||
if (pathinfo($file, PATHINFO_EXTENSION) === 'png' && ! isset($validImages[$file])) { | ||
// Delete the file | ||
unlink($directory.$file); | ||
} | ||
} | ||
|
||
// Close directory handle | ||
closedir($handle); | ||
} | ||
} | ||
|
||
return Command::SUCCESS; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Http\Controllers; | ||
|
||
use App\Models\Gallery; | ||
use Illuminate\Support\Facades\Cache; | ||
use Spatie\Browsershot\Browsershot; | ||
use Spatie\Image\Image; | ||
use Spatie\Image\Manipulations; | ||
use Symfony\Component\HttpFoundation\BinaryFileResponse; | ||
|
||
class MetaImageController extends Controller | ||
{ | ||
public function __invoke(Gallery $gallery): BinaryFileResponse | ||
{ | ||
$imagePath = $this->getImagePath($gallery); | ||
|
||
$this->generateMetaImage($gallery, $imagePath); | ||
|
||
return response()->file($imagePath); | ||
} | ||
|
||
private function generateMetaImage(Gallery $gallery, string $imagePath): void | ||
{ | ||
Cache::lock($gallery->slug.'_meta_image', config('dashbrd.browsershot.timeout') + 15)->get(function () use ($gallery, $imagePath) { | ||
if ($this->shouldGenerateMetaImage($imagePath)) { | ||
$screenshotPath = $this->takeScreenshot($gallery); | ||
|
||
$this->storeMetaImage($imagePath, $screenshotPath); | ||
} | ||
}); | ||
} | ||
|
||
private function shouldGenerateMetaImage(string $imagePath): bool | ||
{ | ||
return ! file_exists($imagePath); | ||
} | ||
|
||
private function getImagePath(Gallery $gallery): string | ||
{ | ||
return storage_path(sprintf('meta/galleries/%s.png', $this->getImageName($gallery))); | ||
} | ||
|
||
/** | ||
* IMPORTANT: Ensure this method is in sync with the query in `queries/gallery.get_meta_images.sql` | ||
*/ | ||
private function getImageName(Gallery $gallery): string | ||
{ | ||
$parts[] = $gallery->nfts()->orderByPivot('order_index', 'asc')->limit(4)->pluck('id')->join('.'); | ||
|
||
$parts[] = $gallery->nfts()->count(); | ||
|
||
$parts[] = $gallery->name; | ||
|
||
return $gallery->slug.'_'.md5(implode('_', $parts)); | ||
} | ||
|
||
private function takeScreenshot(Gallery $gallery): string | ||
{ | ||
$tempPath = storage_path('tmp/'.$gallery->slug.'_screenshot.png'); | ||
|
||
app(Browsershot::class)->url(route('galleries.view', ['gallery' => $gallery->slug])) | ||
->windowSize(1480, 768) | ||
->timeout(config('dashbrd.browsershot.timeout')) | ||
->waitForFunction("document.querySelectorAll('[data-testid=GalleryNfts__nft]').length > 0 && Array.from(document.querySelectorAll('[data-testid=GalleryNfts__nft]')).slice(0, 4).every(el => ! el.querySelector('[data-testid=Skeleton]'))") | ||
->setNodeBinary(config('dashbrd.browsershot.node_binary')) | ||
->setNpmBinary(config('dashbrd.browsershot.npm_binary')) | ||
->save($tempPath); | ||
|
||
$this->resizeScreenshot($tempPath); | ||
|
||
return $tempPath; | ||
} | ||
|
||
private function resizeScreenshot(string $screenshotPath): void | ||
{ | ||
$image = Image::load($screenshotPath); | ||
|
||
$image->width(1006)->crop(Manipulations::CROP_TOP, 1006, 373); | ||
|
||
$image->save($screenshotPath); | ||
} | ||
|
||
private function storeMetaImage(string $imagePath, string $screenshotPath): string | ||
{ | ||
$template = Image::load(resource_path('images/gallery/gallery_template.png')); | ||
|
||
$template | ||
->watermark($screenshotPath) | ||
->watermarkPosition(Manipulations::POSITION_BOTTOM); | ||
|
||
$template->save($imagePath); | ||
|
||
unlink($screenshotPath); | ||
|
||
return $imagePath; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.