Various refactoring, better webp image handling
This commit is contained in:
parent
c2d51b2b7e
commit
cd2dcf2873
4
console
4
console
@ -17,6 +17,10 @@ try
|
||||
(new Console([
|
||||
'cache:clear' => Command\CacheClear::class,
|
||||
'cache:refresh' => Command\CachePrime::class,
|
||||
'clear:cache' => Command\CacheClear::class,
|
||||
'clear:thumbnails' => Command\ClearThumbnails::class,
|
||||
'refresh:cache' => Command\CachePrime::class,
|
||||
'refresh:thumbnails' => Command\UpdateThumbnails::class,
|
||||
'regenerate-thumbnails' => Command\UpdateThumbnails::class,
|
||||
'lists:sync' => Command\SyncLists::class,
|
||||
'mal_id:check' => Command\MALIDCheck::class,
|
||||
|
@ -141,6 +141,8 @@ final class JsonAPI {
|
||||
|
||||
$relationship[$dataType][$idKey][$j] = $included[$dataType][$idKey];
|
||||
}
|
||||
|
||||
unset($item['relationships'][$relType]['data']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -221,6 +223,11 @@ final class JsonAPI {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! array_key_exists($dataType, $organized))
|
||||
{
|
||||
$organized[$dataType] = [];
|
||||
}
|
||||
|
||||
if (array_key_exists($idKey, $organized[$dataType]))
|
||||
{
|
||||
$relationship[$dataType][$idKey] = $organized[$dataType][$idKey];
|
||||
@ -298,7 +305,10 @@ final class JsonAPI {
|
||||
$type = $item['type'];
|
||||
$id = $item['id'];
|
||||
|
||||
if (array_key_exists('attributes', $item))
|
||||
{
|
||||
$organized[$type][$id] = $item['attributes'];
|
||||
}
|
||||
|
||||
if (array_key_exists('relationships', $item))
|
||||
{
|
||||
|
@ -235,15 +235,20 @@ final class Model {
|
||||
{
|
||||
$data = $this->getRequest("people/{$id}", [
|
||||
'query' => [
|
||||
'filter' => [
|
||||
'id' => $id,
|
||||
],
|
||||
'fields' => [
|
||||
'characters' => 'canonicalName,slug,image',
|
||||
'characterVoices' => 'mediaCharacter',
|
||||
'anime' => 'canonicalTitle,titles,slug,posterImage',
|
||||
'manga' => 'canonicalTitle,titles,slug,posterImage',
|
||||
'mediaCharacters' => 'role,media,character',
|
||||
'mediaStaff' => 'role,media,person',
|
||||
],
|
||||
'include' => 'castings.character,castings.media'
|
||||
'include' => 'voices.mediaCharacter.media,voices.mediaCharacter.character,staff.media',
|
||||
],
|
||||
]);
|
||||
|
||||
$cacheItem->set($data);
|
||||
$cacheItem->save();
|
||||
}
|
||||
@ -268,7 +273,7 @@ final class Model {
|
||||
'fields' => [
|
||||
'anime' => 'slug,canonicalTitle,posterImage',
|
||||
'manga' => 'slug,canonicalTitle,posterImage',
|
||||
'characters' => 'slug,canonicalName,image'
|
||||
'characters' => 'slug,canonicalName,image',
|
||||
],
|
||||
'include' => 'waifu,favorites.item,stats'
|
||||
]
|
||||
@ -364,13 +369,13 @@ final class Model {
|
||||
* @param string $slug
|
||||
* @return Anime
|
||||
*/
|
||||
public function getAnime(string $slug): Anime
|
||||
public function getAnime(string $slug)
|
||||
{
|
||||
$baseData = $this->getRawMediaData('anime', $slug);
|
||||
|
||||
if (empty($baseData))
|
||||
{
|
||||
return new Anime();
|
||||
return (new Anime([]))->toArray();
|
||||
}
|
||||
|
||||
return $this->animeTransformer->transform($baseData);
|
||||
@ -966,7 +971,7 @@ final class Model {
|
||||
'mediaCharacters' => 'character,role',
|
||||
],
|
||||
'include' => ($type === 'anime')
|
||||
? 'staff,staff.person,categories,mappings,streamingLinks,animeCharacters.character'
|
||||
? 'staff,staff.person,categories,mappings,streamingLinks,animeCharacters.character,characters.character'
|
||||
: 'staff,staff.person,categories,mappings,characters.character',
|
||||
]
|
||||
];
|
||||
|
@ -40,7 +40,9 @@ final class AnimeTransformer extends AbstractTransformer {
|
||||
sort($item['genres']);
|
||||
|
||||
$title = $item['canonicalTitle'];
|
||||
$titles = array_unique(array_diff($item['titles'], [$title]));
|
||||
|
||||
$titles = Kitsu::filterTitles($item);
|
||||
// $titles = array_unique(array_diff($item['titles'], [$title]));
|
||||
|
||||
return new Anime([
|
||||
'age_rating' => $item['ageRating'],
|
||||
|
@ -71,7 +71,14 @@ function loadTomlFile(string $filename): array
|
||||
return Toml::parseFile($filename);
|
||||
}
|
||||
|
||||
function _iterateToml(TomlBuilder $builder, $data, $parentKey = NULL): void
|
||||
/**
|
||||
* Recursively create a toml file from a data array
|
||||
*
|
||||
* @param TomlBuilder $builder
|
||||
* @param iterable $data
|
||||
* @param null $parentKey
|
||||
*/
|
||||
function _iterateToml(TomlBuilder $builder, iterable $data, $parentKey = NULL): void
|
||||
{
|
||||
foreach ($data as $key => $value)
|
||||
{
|
||||
@ -107,7 +114,7 @@ function _iterateToml(TomlBuilder $builder, $data, $parentKey = NULL): void
|
||||
* @param mixed $data
|
||||
* @return string
|
||||
*/
|
||||
function arrayToToml($data): string
|
||||
function arrayToToml(iterable $data): string
|
||||
{
|
||||
$builder = new TomlBuilder();
|
||||
|
||||
@ -197,28 +204,31 @@ function checkFolderPermissions(ConfigInterface $config): array
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the path for the cached image from the original iamge
|
||||
* Generate the path for the cached image from the original image
|
||||
*
|
||||
* @param string $kitsuUrl
|
||||
* @param bool $webp
|
||||
* @return string
|
||||
*/
|
||||
function getLocalImg ($kitsuUrl): string
|
||||
function getLocalImg ($kitsuUrl, $webp = TRUE): string
|
||||
{
|
||||
if ( ! is_string($kitsuUrl))
|
||||
{
|
||||
return 'images/404/404.png';
|
||||
return 'images/placeholder.webp';
|
||||
}
|
||||
|
||||
$parts = parse_url($kitsuUrl);
|
||||
|
||||
if ($parts === FALSE)
|
||||
{
|
||||
return 'images/404/404.png';
|
||||
return 'images/placeholder.webp';
|
||||
}
|
||||
|
||||
$file = basename($parts['path']);
|
||||
$fileParts = explode('.', $file);
|
||||
$ext = array_pop($fileParts);
|
||||
$ext = $webp ? 'webp' : $ext;
|
||||
|
||||
$segments = explode('/', trim($parts['path'], '/'));
|
||||
|
||||
$type = $segments[0] === 'users' ? $segments[1] : $segments[0];
|
||||
@ -241,12 +251,15 @@ function createPlaceholderImage ($path, $width, $height, $text = 'Image Unavaila
|
||||
$width = $width ?? 200;
|
||||
$height = $height ?? 200;
|
||||
|
||||
$img = imagecreate($width, $height);
|
||||
$img = imagecreatetruecolor($width, $height);
|
||||
imagealphablending($img, TRUE);
|
||||
|
||||
$path = rtrim($path, '/');
|
||||
|
||||
// Background is the first color by default
|
||||
imagecolorallocatealpha($img, 255, 255, 255, 127);
|
||||
$fillColor = imagecolorallocatealpha($img, 255, 255, 255, 127);
|
||||
imagefill($img, 0, 0, $fillColor);
|
||||
|
||||
$textColor = imagecolorallocate($img, 64, 64, 64);
|
||||
|
||||
imagealphablending($img, TRUE);
|
||||
@ -266,6 +279,13 @@ function createPlaceholderImage ($path, $width, $height, $text = 'Image Unavaila
|
||||
// Save the images
|
||||
imagesavealpha($img, TRUE);
|
||||
imagepng($img, $path . '/placeholder.png', 9);
|
||||
|
||||
imagedestroy($img);
|
||||
|
||||
$pngImage = imagecreatefrompng($path . '/placeholder.png');
|
||||
imagealphablending($pngImage, TRUE);
|
||||
imagesavealpha($pngImage, TRUE);
|
||||
|
||||
imagewebp($pngImage, $path . '/placeholder.webp');
|
||||
|
||||
imagedestroy($pngImage);
|
||||
}
|
59
src/Command/ClearThumbnails.php
Normal file
59
src/Command/ClearThumbnails.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* Hummingbird Anime List Client
|
||||
*
|
||||
* An API client for Kitsu to manage anime and manga watch lists
|
||||
*
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @package HummingbirdAnimeClient
|
||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||
* @copyright 2015 - 2018 Timothy J. Warren
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version 4.1
|
||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||
*/
|
||||
|
||||
namespace Aviat\AnimeClient\Command;
|
||||
|
||||
/**
|
||||
* Clears out image cache directories
|
||||
*/
|
||||
class ClearThumbnails extends BaseCommand {
|
||||
|
||||
public function execute(array $args, array $options = []): void
|
||||
{
|
||||
$this->clearThumbs();
|
||||
$this->echoBox('All cached images have been removed');
|
||||
}
|
||||
|
||||
public function clearThumbs()
|
||||
{
|
||||
$imgDir = realpath(__DIR__ . '/../../public/images');
|
||||
|
||||
$paths = [
|
||||
'avatars/*.gif',
|
||||
'avatars/*.jpg',
|
||||
'avatars/*.png',
|
||||
'avatars/*.webp',
|
||||
'anime/*.jpg',
|
||||
'anime/*.png',
|
||||
'anime/*.webp',
|
||||
'manga/*.jpg',
|
||||
'manga/*.png',
|
||||
'manga/*.webp',
|
||||
'characters/*.jpg',
|
||||
'characters/*.png',
|
||||
'characters/*.webp',
|
||||
'people/*.jpg',
|
||||
'people/*.png',
|
||||
'people/*.webp',
|
||||
];
|
||||
|
||||
foreach($paths as $path)
|
||||
{
|
||||
$cmd = "rm -rf {$imgDir}/{$path}";
|
||||
exec($cmd);
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ use Aviat\AnimeClient\Controller\Index;
|
||||
* Clears out image cache directories, then re-creates the image cache
|
||||
* for manga and anime
|
||||
*/
|
||||
final class UpdateThumbnails extends BaseCommand {
|
||||
final class UpdateThumbnails extends ClearThumbnails {
|
||||
/**
|
||||
* Model for making requests to Kitsu API
|
||||
* @var \Aviat\AnimeClient\API\Kitsu\Model
|
||||
@ -43,13 +43,11 @@ final class UpdateThumbnails extends BaseCommand {
|
||||
$this->controller = new Index($this->container);
|
||||
$this->kitsuModel = $this->container->get('kitsu-model');
|
||||
|
||||
$this->clearThumbs();
|
||||
// Clear the existing thunbnails
|
||||
parent::execute($args, $options);
|
||||
|
||||
$ids = $this->getImageList();
|
||||
|
||||
// print_r($ids);
|
||||
// echo json_encode($ids, \JSON_PRETTY_PRINT);
|
||||
|
||||
// Resave the images
|
||||
foreach($ids as $type => $typeIds)
|
||||
{
|
||||
@ -64,26 +62,6 @@ final class UpdateThumbnails extends BaseCommand {
|
||||
$this->echoBox('Finished regenerating all thumbnails');
|
||||
}
|
||||
|
||||
public function clearThumbs()
|
||||
{
|
||||
$imgDir = realpath(__DIR__ . '/../../public/images');
|
||||
|
||||
$paths = [
|
||||
'anime/*.jpg',
|
||||
'anime/*.webp',
|
||||
'manga/*.jpg',
|
||||
'manga/*.webp',
|
||||
'characters/*.jpg',
|
||||
'characters/*.webp',
|
||||
];
|
||||
|
||||
foreach($paths as $path)
|
||||
{
|
||||
$cmd = "rm -rf {$imgDir}/{$path}";
|
||||
exec($cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public function getImageList()
|
||||
{
|
||||
$mangaList = $this->kitsuModel->getFullRawMangaList();
|
||||
|
@ -363,9 +363,15 @@ final class Dispatcher extends RoutingBase {
|
||||
? $controllerMap[$routeType]
|
||||
: DEFAULT_CONTROLLER;
|
||||
|
||||
if (array_key_exists($routeType, $controllerMap))
|
||||
// If there's an explicit controller, try to find
|
||||
// the full namespaced class name
|
||||
if (array_key_exists('controller', $route))
|
||||
{
|
||||
$controllerClass = $controllerMap[$routeType];
|
||||
$controllerKey = $route['controller'];
|
||||
if (array_key_exists($controllerKey, $controllerMap))
|
||||
{
|
||||
$controllerClass = $controllerMap[$controllerKey];
|
||||
}
|
||||
}
|
||||
|
||||
// Prepend the controller to the route parameters
|
||||
|
85
src/Helper/Picture.php
Normal file
85
src/Helper/Picture.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* Hummingbird Anime List Client
|
||||
*
|
||||
* An API client for Kitsu to manage anime and manga watch lists
|
||||
*
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @package HummingbirdAnimeClient
|
||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||
* @copyright 2015 - 2018 Timothy J. Warren
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version 4.1
|
||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||
*/
|
||||
|
||||
namespace Aviat\AnimeClient\Helper;
|
||||
|
||||
use Aviat\Ion\Di\ContainerAware;
|
||||
|
||||
/**
|
||||
* Simplify picture elements
|
||||
*/
|
||||
final class Picture {
|
||||
|
||||
use ContainerAware;
|
||||
|
||||
/**
|
||||
* Create the html f
|
||||
*
|
||||
* @param string $webp
|
||||
* @param string $fallbackExt
|
||||
* @param array $picAttrs
|
||||
* @param array $imgAttrs
|
||||
* @return string
|
||||
*/
|
||||
public function __invoke(string $webp, string $fallbackExt = 'jpg', $picAttrs = [], $imgAttrs = []): string
|
||||
{
|
||||
$urlGenerator = $this->container->get('url-generator');
|
||||
$helper = $this->container->get('html-helper');
|
||||
|
||||
// If it is a placeholder image, make the
|
||||
// fallback a png, not a jpg
|
||||
if (strpos($webp, 'placeholder') !== FALSE)
|
||||
{
|
||||
$fallbackExt = 'png';
|
||||
}
|
||||
|
||||
if (strpos($webp, '//') === FALSE)
|
||||
{
|
||||
$webp = $urlGenerator->assetUrl($webp);
|
||||
}
|
||||
|
||||
|
||||
$urlParts = explode('.', $webp);
|
||||
$ext = array_pop($urlParts);
|
||||
$path = implode('.', $urlParts);
|
||||
|
||||
$mime = $ext === 'jpg'
|
||||
? 'image/jpeg'
|
||||
: "image/{$ext}";
|
||||
$fallbackMime = $fallbackExt === 'jpg'
|
||||
? 'image/jpeg'
|
||||
: "image/{$fallbackExt}";
|
||||
|
||||
$fallbackImg = "{$path}.{$fallbackExt}";
|
||||
|
||||
$pictureChildren = [
|
||||
$helper->void('source', [
|
||||
'srcset' => $webp,
|
||||
'type' => $mime,
|
||||
]),
|
||||
$helper->void('source', [
|
||||
'srcset' => $fallbackImg,
|
||||
'type' => $fallbackMime
|
||||
]),
|
||||
$helper->img($fallbackImg, array_merge(['alt' => ''], $imgAttrs)),
|
||||
];
|
||||
|
||||
$sources = implode('', $pictureChildren);
|
||||
|
||||
return $helper->elementRaw('picture', $sources, $picAttrs);
|
||||
}
|
||||
}
|
||||
// End of Picture.php
|
@ -108,7 +108,7 @@ class Anime extends API {
|
||||
* @param string $slug
|
||||
* @return AnimeType
|
||||
*/
|
||||
public function getAnime(string $slug): AnimeType
|
||||
public function getAnime(string $slug)
|
||||
{
|
||||
return $this->kitsuModel->getAnime($slug);
|
||||
}
|
||||
@ -173,14 +173,6 @@ class Anime extends API {
|
||||
|
||||
$results = $requester->makeRequests();
|
||||
|
||||
// Debug info
|
||||
/* $body = Json::decode($results['anilist']);
|
||||
if ($body['errors'])
|
||||
{
|
||||
dump($body);
|
||||
die();
|
||||
} */
|
||||
|
||||
return count($results) > 0;
|
||||
}
|
||||
|
||||
@ -261,13 +253,6 @@ class Anime extends API {
|
||||
|
||||
$results = $requester->makeRequests();
|
||||
|
||||
// Debug info
|
||||
/* $body = Json::decode($results['anilist']);
|
||||
if (isset($body['errors'])) {
|
||||
dump($body);
|
||||
die();
|
||||
} */
|
||||
|
||||
return count($results) > 0;
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace Aviat\AnimeClient;
|
||||
|
||||
const DEFAULT_CONTROLLER = Controller\Index::class;
|
||||
const DEFAULT_CONTROLLER = Controller\Misc::class;
|
||||
const DEFAULT_CONTROLLER_METHOD = 'index';
|
||||
const DEFAULT_CONTROLLER_NAMESPACE = Controller::class;
|
||||
const DEFAULT_LIST_CONTROLLER = Controller\Anime::class;
|
||||
@ -24,7 +24,12 @@ const ERROR_MESSAGE_METHOD = 'errorPage';
|
||||
const NOT_FOUND_METHOD = 'notFound';
|
||||
const SESSION_SEGMENT = 'Aviat\AnimeClient\Auth';
|
||||
const SRC_DIR = __DIR__;
|
||||
const USER_AGENT = "Tim's Anime Client/4.0";
|
||||
const USER_AGENT = "Tim's Anime Client/4.1";
|
||||
|
||||
// Regex patterns
|
||||
const ALPHA_SLUG_PATTERN = '[a-z_]+';
|
||||
const NUM_PATTERN = '[0-9]+';
|
||||
const SLUG_PATTERN = '[a-z0-9\-]+';
|
||||
|
||||
// Why doesn't this already exist?
|
||||
const MILLI_FROM_NANO = 1000 * 1000;
|
||||
|
Loading…
Reference in New Issue
Block a user