HummingBirdAnimeClient/src/AnimeClient/Controller/Images.php

194 lines
4.7 KiB
PHP

<?php declare(strict_types=1);
/**
* Hummingbird Anime List Client
*
* An API client for Kitsu to manage anime and manga watch lists
*
* PHP version 7.4
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2020 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 5
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\Controller;
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
use function Amp\Promise\wait;
use function Aviat\AnimeClient\getResponse;
use function Aviat\AnimeClient\createPlaceholderImage;
use Aviat\AnimeClient\Controller as BaseController;
use Throwable;
/**
* Controller for handling routes that don't fit elsewhere
*/
final class Images extends BaseController {
/**
* Get image covers from kitsu
*
* @param string $type The category of image
* @param string $file The filename to look for
* @param bool $display Whether to output the image to the server
* @return void
* @throws NotFoundException
* @throws Throwable
* @throws ContainerException
*/
public function cache(string $type, string $file, $display = TRUE): void
{
$currentUrl = (string)$this->request->getUri();
$kitsuUrl = 'https://media.kitsu.io/';
$fileName = str_replace('-original', '', $file);
[$id, $ext] = explode('.', basename($fileName));
$baseSavePath = $this->config->get('img_cache_path');
// Kitsu doesn't serve webp, but for most use cases,
// jpg is a safe assumption
$tryJpg = ['anime','characters','manga','people'];
if ($ext === 'webp' && \in_array($type, $tryJpg, TRUE))
{
$ext = 'jpg';
$currentUrl = str_replace('webp', 'jpg', $currentUrl);
}
$typeMap = [
'anime' => [
'kitsuUrl' => "anime/poster_images/{$id}/medium.{$ext}",
'width' => 220,
'height' => 312,
],
'avatars' => [
'kitsuUrl' => "users/avatars/{$id}/original.{$ext}",
'width' => null,
'height' => null,
],
'characters' => [
'kitsuUrl' => "characters/images/{$id}/original.{$ext}",
'width' => 225,
'height' => 350,
],
'manga' => [
'kitsuUrl' => "manga/poster_images/{$id}/medium.{$ext}",
'width' => 220,
'height' => 312,
],
'people' => [
'kitsuUrl' => "people/images/{$id}/original.{$ext}",
'width' => null,
'height' => null,
],
];
$imageType = $typeMap[$type] ?? NULL;
if (NULL === $imageType)
{
$this->getPlaceholder($baseSavePath, 200, 200);
return;
}
$kitsuUrl .= $imageType['kitsuUrl'];
$width = $imageType['width'];
$height = $imageType['height'];
$filePrefix = "{$baseSavePath}/{$type}/{$id}";
$response = getResponse($kitsuUrl);
if ($response->getStatus() !== 200)
{
// Try a few different file types before giving up
// webm => jpg => png => gif
$nextType = [
'jpg' => 'png',
'png' => 'gif',
];
if (array_key_exists($ext, $nextType))
{
$newUrl = str_replace($ext, $nextType[$ext], $currentUrl);
$this->redirect($newUrl, 303);
return;
}
if ($display)
{
$this->getPlaceholder("{$baseSavePath}/{$type}", $width, $height);
}
else
{
createPlaceholderImage("{$baseSavePath}/{$type}", $width, $height);
}
return;
}
$data = wait($response->getBody()->buffer());
[$origWidth] = getimagesizefromstring($data);
$gdImg = imagecreatefromstring($data);
$resizedImg = imagescale($gdImg, $width ?? $origWidth);
if ($ext === 'gif')
{
file_put_contents("{$filePrefix}.gif", $data);
\imagepalletetotruecolor($gdImg);
}
// save the webp versions
imagewebp($gdImg, "{$filePrefix}-original.webp");
imagewebp($resizedImg, "{$filePrefix}.webp");
// save the scaled jpeg file
imagejpeg($resizedImg, "{$filePrefix}.jpg");
// And the original
file_put_contents("{$filePrefix}-original.jpg", $data);
imagedestroy($gdImg);
imagedestroy($resizedImg);
if ($display)
{
$contentType = ($ext === 'webp')
? 'image/webp'
: $response->getHeader('content-type')[0];
$outputFile = (strpos($file, '-original') !== FALSE)
? "{$filePrefix}-original.{$ext}"
: "{$filePrefix}.{$ext}";
header("Content-Type: {$contentType}");
echo file_get_contents($outputFile);
}
}
/**
* Get a placeholder for a missing image
*
* @param string $path
* @param int|null $width
* @param int|null $height
*/
private function getPlaceholder (string $path, ?int $width = 200, ?int $height = NULL): void
{
$height = $height ?? $width;
$filename = $path . '/placeholder.png';
if ( ! file_exists($path . '/placeholder.png'))
{
createPlaceholderImage($path, $width, $height);
}
header('Content-Type: image/png');
echo file_get_contents($filename);
}
}