Ugly Progress Commit
* Cache and resize images - not just cache them * Convert to webp on cache * Show webp images if available * Settings Form Generation (doesn't yet save)
This commit is contained in:
parent
0102a0b3ee
commit
616ae1ea82
1
.gitignore
vendored
1
.gitignore
vendored
@ -31,3 +31,4 @@ public/images/avatars/**
|
||||
public/images/manga/**
|
||||
public/images/characters/**
|
||||
public/images/people/**
|
||||
public/mal_mappings.json
|
@ -200,7 +200,7 @@ return [
|
||||
'verb' => 'get',
|
||||
'tokens' => [
|
||||
'type' => '[a-z0-9\-]+',
|
||||
'file' => '[a-z0-9\-]+\.[a-z]{3}'
|
||||
'file' => '[a-z0-9\-]+\.[a-z]{3,4}'
|
||||
]
|
||||
],
|
||||
'cache_purge' => [
|
||||
|
@ -81,6 +81,11 @@ return function ($configArray = []) {
|
||||
$menuHelper->setContainer($container);
|
||||
return $menuHelper;
|
||||
});
|
||||
$htmlHelper->set('field', function() use ($container) {
|
||||
$formHelper = new Helper\Form();
|
||||
$formHelper->setContainer($container);
|
||||
return $formHelper;
|
||||
});
|
||||
|
||||
return $htmlHelper;
|
||||
});
|
||||
@ -156,6 +161,11 @@ return function ($configArray = []) {
|
||||
$container->set('manga-collection-model', function($container) {
|
||||
return new Model\MangaCollection($container);
|
||||
});
|
||||
$container->set('settings-model', function($container) {
|
||||
$model = new Model\Settings($container->get('config'));
|
||||
$model->setContainer($container);
|
||||
return $model;
|
||||
});
|
||||
|
||||
// Miscellaneous Classes
|
||||
$container->set('auth', function($container) {
|
||||
|
32
app/views/_form.php
Normal file
32
app/views/_form.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
// Higher scoped variables:
|
||||
// $fields
|
||||
// $hiddenFields
|
||||
// $nestedPrefix
|
||||
if ( ! function_exists('subfieldRender'))
|
||||
{
|
||||
function subfieldRender ($nestedPrefix, $fields, &$hiddenFields, $helper, $section)
|
||||
{
|
||||
include '_form.php';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<?php foreach ($fields as $name => $field): ?>
|
||||
<?php $fieldname = ($section === 'config' || $nestedPrefix !== 'config') ? "{$nestedPrefix}[{$name}]" : "{$nestedPrefix}[{$section}][{$name}]"; ?>
|
||||
<?php if ($field['type'] === 'subfield'): ?>
|
||||
<section>
|
||||
<h4><?= $field['title'] ?></h4>
|
||||
<?php subfieldRender($fieldname, $field['fields'], $hiddenFields, $helper, $section); ?>
|
||||
</section>
|
||||
<?php elseif ( ! empty($field['display'])): ?>
|
||||
<article>
|
||||
<label for="<?= $fieldname ?>"><?= $field['title'] ?></label><br />
|
||||
<small><?= $field['description'] ?></small><br />
|
||||
<?= $helper->field($fieldname, $field); ?>
|
||||
</article>
|
||||
<?php else: ?>
|
||||
<?php $hiddenFields[] = $helper->field($fieldname, $field); ?>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
@ -6,7 +6,12 @@
|
||||
<?php if ($auth->isAuthenticated()): ?>
|
||||
<button title="Increment episode count" class="plus_one" hidden>+1 Episode</button>
|
||||
<?php endif ?>
|
||||
<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['anime']['id']}.jpg") ?>" alt=""/>
|
||||
<picture>
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/anime/{$item['anime']['id']}.webp") ?>" type="image/webp">
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/anime/{$item['anime']['id']}.jpg") ?>" type="image/jpeg">
|
||||
<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['anime']['id']}.jpg") ?>" alt="" />
|
||||
</picture>
|
||||
|
||||
<div class="name">
|
||||
<a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]); ?>">
|
||||
<span class="canonical"><?= $item['anime']['title'] ?></span>
|
||||
|
@ -1,7 +1,11 @@
|
||||
<main class="details fixed">
|
||||
<section class="flex flex-no-wrap">
|
||||
<div>
|
||||
<img class="cover" width="402" height="284" src="<?= $urlGenerator->assetUrl("images/anime/{$show_data['id']}.jpg") ?>" alt="" />
|
||||
<picture class="cover">
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/anime/{$show_data['id']}-original.webp") ?>" type="image/webp">
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/anime/{$show_data['id']}-original.jpg") ?>" type="image/jpeg">
|
||||
<img src="<?= $urlGenerator->assetUrl("images/anime/{$show_data['id']}-original.jpg") ?>" alt="" />
|
||||
</picture>
|
||||
<br />
|
||||
<br />
|
||||
<table class="media_details">
|
||||
@ -96,9 +100,11 @@
|
||||
<?= $helper->a($link, $char['name']); ?>
|
||||
</div>
|
||||
<a href="<?= $link ?>">
|
||||
<?= $helper->img($urlGenerator->assetUrl("images/characters/{$id}.jpg"), [
|
||||
'width' => '225'
|
||||
]) ?>
|
||||
<picture>
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/characters/{$id}.webp") ?>" type="image/webp">
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/characters/{$id}.jpg") ?>" type="image/jpeg">
|
||||
<img src="<?= $urlGenerator->assetUrl("images/characters/{$id}.jpg") ?>" alt="" />
|
||||
</picture>
|
||||
</a>
|
||||
</article>
|
||||
<?php endif ?>
|
||||
|
@ -2,7 +2,11 @@
|
||||
<main class="details fixed">
|
||||
<section class="flex flex-no-wrap">
|
||||
<div>
|
||||
<img class="cover" width="284" src="<?= $urlGenerator->assetUrl("images/characters/{$data[0]['id']}.jpg") ?>" alt="" />
|
||||
<picture class="cover">
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/characters/{$data[0]['id']}-original.webp") ?>" type="image/webp">
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/characters/{$data[0]['id']}-original.jpg") ?>" type="image/jpeg">
|
||||
<img src="<?= $urlGenerator->assetUrl("images/characters/{$data[0]['id']}-original.jpg") ?>" alt="" />
|
||||
</picture>
|
||||
</div>
|
||||
<div>
|
||||
<h2><?= $data[0]['attributes']['name'] ?></h2>
|
||||
|
@ -1,6 +1,10 @@
|
||||
<article class="media" id="a-<?= $item['hummingbird_id'] ?>">
|
||||
<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.jpg") ?>"
|
||||
alt="<?= $item['title'] ?> cover image"/>
|
||||
<picture>
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.webp") ?>" type="image/webp">
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.jpg") ?>" type="image/jpeg">
|
||||
<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.jpg") ?>" alt="<?= $item['title'] ?> cover image" />
|
||||
</picture>
|
||||
|
||||
<div class="name">
|
||||
<a href="<?= $url->generate('anime.details', ['id' => $item['slug']]) ?>">
|
||||
<?= $item['title'] ?>
|
||||
|
@ -23,7 +23,11 @@
|
||||
<?php /* <button class="plus_one_volume">+1 Volume</button> */ ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<img src="<?= $urlGenerator->assetUrl('images/manga', "{$item['manga']['id']}.jpg") ?>" />
|
||||
<picture>
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/manga/{$item['manga']['id']}.webp") ?>" type="image/webp">
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/manga/{$item['manga']['id']}.jpg") ?>" type="image/jpeg">
|
||||
<img src="<?= $urlGenerator->assetUrl("images/manga/{$item['manga']['id']}.jpg") ?>" alt="" />
|
||||
</picture>
|
||||
<div class="name">
|
||||
<a href="<?= $url->generate('manga.details', ['id' => $item['manga']['slug']]) ?>">
|
||||
<?= $escape->html($item['manga']['title']) ?>
|
||||
|
@ -1,7 +1,11 @@
|
||||
<main class="details fixed">
|
||||
<section class="flex flex-no-wrap">
|
||||
<div>
|
||||
<img class="cover" src="<?= $urlGenerator->assetUrl('images/manga', "{$data['id']}.jpg") ?>" alt="<?= $data['title'] ?> cover image" />
|
||||
<picture class="cover">
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/manga/{$data['id']}-original.webp") ?>" type="image/webp">
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/manga/{$data['id']}-original.jpg") ?>" type="image/jpeg">
|
||||
<img src="<?= $urlGenerator->assetUrl("images/manga/{$data['id']}-original.jpg") ?>" alt="" />
|
||||
</picture>
|
||||
<br />
|
||||
<br />
|
||||
<table>
|
||||
@ -47,9 +51,14 @@
|
||||
<?= $helper->a($link, $char['name']); ?>
|
||||
</div>
|
||||
<a href="<?= $link ?>">
|
||||
<?= $helper->img($urlGenerator->assetUrl('images/characters', "{$id}.jpg"), [
|
||||
<picture>
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/characters/{$id}.webp") ?>" type="image/webp">
|
||||
<source srcset="<?= $urlGenerator->assetUrl("images/characters/{$id}.jpg") ?>" type="image/jpeg">
|
||||
<img src="<?= $urlGenerator->assetUrl("images/characters/{$id}.jpg") ?>" alt="" />
|
||||
</picture>
|
||||
<?php /*<?= $helper->img($urlGenerator->assetUrl('images/characters', "{$id}.jpg"), [
|
||||
'width' => '225'
|
||||
]) ?>
|
||||
]) ?> */ ?>
|
||||
</a>
|
||||
</article>
|
||||
<?php endif ?>
|
||||
|
@ -1,60 +1,42 @@
|
||||
<?php
|
||||
use function Aviat\AnimeClient\loadTomlByFile;
|
||||
|
||||
$settings = loadTomlByFile($config->get('config_dir'));
|
||||
|
||||
if ( ! $auth->isAuthenticated())
|
||||
{
|
||||
echo '<h1>Not Authorized</h1>';
|
||||
return;
|
||||
}
|
||||
|
||||
$sectionMapping = [
|
||||
'config' => 'General Settings',
|
||||
'cache' => 'Caching',
|
||||
'database' => 'Collection Database Settings',
|
||||
];
|
||||
|
||||
function render_settings_form ($data, $file)
|
||||
{
|
||||
ob_start();
|
||||
foreach ($data as $key => $value)
|
||||
{
|
||||
?>
|
||||
<tr>
|
||||
<td><label for="<?= $key ?>"><?= $key ?></label></td>
|
||||
<td>
|
||||
<?php if (is_scalar($value)): ?>
|
||||
<input
|
||||
type="text"
|
||||
id="<?= $key ?>"
|
||||
name="config[<?= $file ?>][<?= $key ?>]"
|
||||
value="<?= $value ?>"
|
||||
/>
|
||||
<?php else: ?>
|
||||
<table><?= render_settings_form($value, $file); ?></table>
|
||||
<?php endif ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
|
||||
$buffer = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
$hiddenFields = [];
|
||||
$nestedPrefix = 'config';
|
||||
?>
|
||||
|
||||
<pre><?= print_r($_POST, TRUE) ?></pre>
|
||||
|
||||
<?php foreach($settings as $file => $properties): ?>
|
||||
<form action="<?= $_SERVER['REQUEST_URI'] ?>" method="POST">
|
||||
<table class="form">
|
||||
<caption><?= $file ?></caption>
|
||||
<tbody>
|
||||
<?= render_settings_form($properties, $file); ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="submit">Save Changes</button>
|
||||
<main class='form'>
|
||||
<button type="submit">Save Changes</button>
|
||||
<br />
|
||||
<?php foreach ($form as $section => $fields): ?>
|
||||
<fieldset class="box">
|
||||
<legend><?= $sectionMapping[$section] ?></legend>
|
||||
<section class='form'>
|
||||
<?php require __DIR__ . '/_form.php' ?>
|
||||
</section>
|
||||
</fieldset>
|
||||
<?php endforeach ?>
|
||||
|
||||
<hr />
|
||||
<?php foreach ($hiddenFields as $field): ?>
|
||||
<?= $field ?>
|
||||
<?php endforeach ?>
|
||||
<button type="submit">Save Changes</button>
|
||||
</main>
|
||||
</form>
|
||||
<?php endforeach ?>
|
||||
|
||||
|
||||
|
||||
|
2
public/css/app.min.css
vendored
2
public/css/app.min.css
vendored
File diff suppressed because one or more lines are too long
@ -384,6 +384,12 @@ a:hover, a:active {
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.details picture.cover,
|
||||
picture.cover {
|
||||
display: initial;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.media > img,
|
||||
.character > img,
|
||||
.small_character > img {
|
||||
@ -915,3 +921,23 @@ CSS Tabs
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Settings page forms
|
||||
-----------------------------------------------------------------------------*/
|
||||
fieldset.box {
|
||||
display: inline-block;
|
||||
vertical-align:top;
|
||||
width:40%;
|
||||
margin: 2em;
|
||||
}
|
||||
|
||||
fieldset.box section {
|
||||
margin: 0 auto;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
fieldset.box article {
|
||||
margin: auto;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
|
@ -86,11 +86,11 @@ class Controller {
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Controller constructor.
|
||||
*
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
* @param ContainerInterface $container
|
||||
* @throws \Aviat\Ion\Di\Exception\ContainerException
|
||||
* @throws \Aviat\Ion\Di\Exception\NotFoundException
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
@ -140,10 +140,9 @@ class Controller {
|
||||
/**
|
||||
* Set the current url in the session as the target of a future redirect
|
||||
*
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
* @param string|null $url
|
||||
* @return void
|
||||
* @param string|NULL $url
|
||||
* @throws \Aviat\Ion\Di\Exception\ContainerException
|
||||
* @throws \Aviat\Ion\Di\Exception\NotFoundException
|
||||
*/
|
||||
public function setSessionRedirect(string $url = NULL): void
|
||||
{
|
||||
@ -180,8 +179,8 @@ class Controller {
|
||||
* Redirect to the url previously set in the session
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
* @throws \Aviat\Ion\Di\Exception\ContainerException
|
||||
* @throws \Aviat\Ion\Di\Exception\NotFoundException
|
||||
* @return void
|
||||
*/
|
||||
public function sessionRedirect()
|
||||
@ -205,8 +204,8 @@ class Controller {
|
||||
* @param string $template
|
||||
* @param array $data
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
* @throws \Aviat\Ion\Di\Exception\ContainerException
|
||||
* @throws \Aviat\Ion\Di\Exception\NotFoundException
|
||||
* @return string
|
||||
*/
|
||||
protected function loadPartial($view, string $template, array $data = [])
|
||||
@ -239,8 +238,8 @@ class Controller {
|
||||
* @param string $template
|
||||
* @param array $data
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
* @throws \Aviat\Ion\Di\Exception\ContainerException
|
||||
* @throws \Aviat\Ion\Di\Exception\NotFoundException
|
||||
* @return void
|
||||
*/
|
||||
protected function renderFullPage($view, string $template, array $data)
|
||||
@ -269,8 +268,8 @@ class Controller {
|
||||
* @param string $title
|
||||
* @param string $message
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
* @throws \Aviat\Ion\Di\Exception\ContainerException
|
||||
* @throws \Aviat\Ion\Di\Exception\NotFoundException
|
||||
* @return void
|
||||
*/
|
||||
public function notFound(
|
||||
@ -292,8 +291,8 @@ class Controller {
|
||||
* @param string $message
|
||||
* @param string $long_message
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
* @throws \Aviat\Ion\Di\Exception\ContainerException
|
||||
* @throws \Aviat\Ion\Di\Exception\NotFoundException
|
||||
* @return void
|
||||
*/
|
||||
public function errorPage(int $httpCode, string $title, string $message, string $long_message = ''): void
|
||||
@ -313,7 +312,7 @@ class Controller {
|
||||
*/
|
||||
public function redirectToDefaultRoute(): void
|
||||
{
|
||||
$defaultType = $this->config->get(['routes', 'route_config', 'default_list']) ?? 'anime';
|
||||
$defaultType = $this->config->get('default_list') ?? 'anime';
|
||||
$this->redirect($this->urlGenerator->defaultUrl($defaultType), 303);
|
||||
}
|
||||
|
||||
@ -360,8 +359,8 @@ class Controller {
|
||||
* @param string $type
|
||||
* @param string $message
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
* @throws \Aviat\Ion\Di\Exception\ContainerException
|
||||
* @throws \Aviat\Ion\Di\Exception\NotFoundException
|
||||
* @return string
|
||||
*/
|
||||
protected function showMessage($view, string $type, string $message): string
|
||||
@ -380,8 +379,8 @@ class Controller {
|
||||
* @param HtmlView|null $view
|
||||
* @param int $code
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
* @throws \Aviat\Ion\Di\Exception\ContainerException
|
||||
* @throws \Aviat\Ion\Di\Exception\NotFoundException
|
||||
* @return void
|
||||
*/
|
||||
protected function outputHTML(string $template, array $data = [], $view = NULL, int $code = 200)
|
||||
@ -393,6 +392,7 @@ class Controller {
|
||||
|
||||
$view->setStatusCode($code);
|
||||
$this->renderFullPage($view, $template, $data);
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -407,8 +407,9 @@ class Controller {
|
||||
{
|
||||
(new JsonView($this->container))
|
||||
->setStatusCode($code)
|
||||
->setOutput($data)
|
||||
->send();
|
||||
->setOutput($data);
|
||||
// ->send();
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,12 +20,21 @@ use function Amp\Promise\wait;
|
||||
|
||||
use Aviat\AnimeClient\Controller as BaseController;
|
||||
use Aviat\AnimeClient\API\{HummingbirdClient, JsonAPI};
|
||||
use Aviat\Ion\Di\ContainerInterface;
|
||||
use Aviat\Ion\View\HtmlView;
|
||||
|
||||
/**
|
||||
* Controller for handling routes that don't fit elsewhere
|
||||
*/
|
||||
final class Index extends BaseController {
|
||||
private $settingsModel;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
|
||||
$this->settingsModel = $container->get('settings-model');
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges the API cache
|
||||
@ -91,6 +100,7 @@ final class Index extends BaseController {
|
||||
*/
|
||||
public function anilistCallback()
|
||||
{
|
||||
dump($_GET);
|
||||
$this->outputHTML('blank', [
|
||||
'title' => 'Oauth!'
|
||||
]);
|
||||
@ -169,8 +179,10 @@ final class Index extends BaseController {
|
||||
public function settings()
|
||||
{
|
||||
$auth = $this->container->get('auth');
|
||||
$form = $this->settingsModel->getSettingsForm();
|
||||
$this->outputHTML('settings', [
|
||||
'auth' => $auth,
|
||||
'form' => $form,
|
||||
'config' => $this->config,
|
||||
'title' => $this->config->get('whose_list') . "'s Settings",
|
||||
]);
|
||||
@ -191,6 +203,7 @@ final class Index extends BaseController {
|
||||
*
|
||||
* @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
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
* @throws \InvalidArgumentException
|
||||
@ -199,26 +212,30 @@ final class Index extends BaseController {
|
||||
* @throws \Throwable
|
||||
* @return void
|
||||
*/
|
||||
public function images(string $type, string $file): void
|
||||
public function images(string $type, string $file, $display = TRUE): void
|
||||
{
|
||||
$kitsuUrl = 'https://media.kitsu.io/';
|
||||
[$id, $ext] = explode('.', basename($file));
|
||||
$fileName = str_replace('-original', '', $file);
|
||||
[$id, $ext] = explode('.', basename($fileName));
|
||||
switch ($type)
|
||||
{
|
||||
case 'anime':
|
||||
$kitsuUrl .= "anime/poster_images/{$id}/small.{$ext}";
|
||||
$kitsuUrl .= "anime/poster_images/{$id}/small.jpg";
|
||||
$width = 220;
|
||||
break;
|
||||
|
||||
case 'avatars':
|
||||
$kitsuUrl .= "users/avatars/{$id}/original.{$ext}";
|
||||
$kitsuUrl .= "users/avatars/{$id}/original.jpg";
|
||||
break;
|
||||
|
||||
case 'manga':
|
||||
$kitsuUrl .= "manga/poster_images/{$id}/small.{$ext}";
|
||||
$kitsuUrl .= "manga/poster_images/{$id}/small.jpg";
|
||||
$width = 220;
|
||||
break;
|
||||
|
||||
case 'characters':
|
||||
$kitsuUrl .= "characters/images/{$id}/original.{$ext}";
|
||||
$kitsuUrl .= "characters/images/{$id}/original.jpg";
|
||||
$width = 225;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -231,9 +248,38 @@ final class Index extends BaseController {
|
||||
$data = wait($response->getBody());
|
||||
|
||||
$baseSavePath = $this->config->get('img_cache_path');
|
||||
file_put_contents("{$baseSavePath}/{$type}/{$id}.{$ext}", $data);
|
||||
header('Content-type: ' . $response->getHeader('content-type')[0]);
|
||||
echo $data;
|
||||
$filePrefix = "{$baseSavePath}/{$type}/{$id}";
|
||||
|
||||
[$origWidth, $origHeight] = getimagesizefromstring($data);
|
||||
$gdImg = imagecreatefromstring($data);
|
||||
$resizedImg = imagescale($gdImg, $width ?? $origWidth);
|
||||
|
||||
// save the webp versions
|
||||
imagewebp($gdImg, "{$filePrefix}-original.webp");
|
||||
imagewebp($resizedImg, "{$filePrefix}.webp");
|
||||
|
||||
// save the scaled jpeg file
|
||||
imagejpeg($resizedImg, "{$filePrefix}.jpg");
|
||||
|
||||
imagedestroy($gdImg);
|
||||
imagedestroy($resizedImg);
|
||||
|
||||
// And the original
|
||||
file_put_contents("{$filePrefix}-original.jpg", $data);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
115
src/FormGenerator.php
Normal file
115
src/FormGenerator.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?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;
|
||||
|
||||
use Aviat\Ion\
|
||||
{
|
||||
ArrayWrapper, StringWrapper
|
||||
};
|
||||
use Aviat\Ion\Di\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Helper object to manage form generation, especially for config editing
|
||||
*/
|
||||
final class FormGenerator {
|
||||
use ArrayWrapper;
|
||||
use StringWrapper;
|
||||
|
||||
/**
|
||||
* Injection Container
|
||||
* @var ContainerInterface $container
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Html generation helper
|
||||
*
|
||||
* @var \Aura\Html\HelperLocator
|
||||
*/
|
||||
protected $helper;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->helper = $container->get('html-helper');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the html structure of the form
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $form
|
||||
* @return string
|
||||
*/
|
||||
public function generate(string $name, array $form)
|
||||
{
|
||||
$type = $form['type'];
|
||||
|
||||
if ($form['display'] === FALSE)
|
||||
{
|
||||
return $this->helper->input([
|
||||
'type' => 'hidden',
|
||||
'name' => $name,
|
||||
'value' => $form['value'],
|
||||
]);
|
||||
}
|
||||
|
||||
$params = [
|
||||
'name' => $name,
|
||||
'value' => $form['value'],
|
||||
'attribs' => [
|
||||
'id' => $name,
|
||||
],
|
||||
];
|
||||
|
||||
switch($type)
|
||||
{
|
||||
case 'boolean':
|
||||
/* $params['type'] = 'checkbox';
|
||||
$params['attribs']['label'] = $form['description'];
|
||||
$params['attribs']['value'] = TRUE;
|
||||
$params['attribs']['value_unchecked'] = '0'; */
|
||||
|
||||
$params['type'] = 'radio';
|
||||
$params['options'] = [
|
||||
'1' => 'Yes',
|
||||
'0' => 'No',
|
||||
];
|
||||
unset($params['attribs']['id']);
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
$params['type'] = 'text';
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
$params['type'] = 'select';
|
||||
$params['options'] = array_flip($form['options']);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (['readonly', 'disabled'] as $key)
|
||||
{
|
||||
if ($form[$key] !== FALSE)
|
||||
{
|
||||
$params['attribs'][$key] = $form[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->helper->input($params);
|
||||
}
|
||||
}
|
41
src/Helper/Form.php
Normal file
41
src/Helper/Form.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?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\AnimeClient\FormGenerator;
|
||||
use Aviat\Ion\Di\ContainerAware;
|
||||
|
||||
/**
|
||||
* MenuGenerator helper wrapper
|
||||
*/
|
||||
final class Form {
|
||||
|
||||
use ContainerAware;
|
||||
|
||||
/**
|
||||
* Create the html for the selected menu
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $form
|
||||
* @return string
|
||||
*/
|
||||
public function __invoke(string $name, array $form)
|
||||
{
|
||||
return (new FormGenerator($this->container))->generate($name, $form);
|
||||
}
|
||||
}
|
||||
// End of Menu.php
|
286
src/Model/Settings.php
Normal file
286
src/Model/Settings.php
Normal file
@ -0,0 +1,286 @@
|
||||
<?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\Model;
|
||||
|
||||
use Aviat\AnimeClient\Types\{Config, UndefinedPropertyException};
|
||||
|
||||
use Aviat\Ion\ConfigInterface;
|
||||
use Aviat\Ion\Di\ContainerAware;
|
||||
use Aviat\Ion\StringWrapper;
|
||||
|
||||
/**
|
||||
* Model for handling settings control panel
|
||||
*/
|
||||
final class Settings {
|
||||
use ContainerAware;
|
||||
use StringWrapper;
|
||||
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* Map the config values to types and form fields
|
||||
*/
|
||||
private const SETTINGS_MAP = [
|
||||
'anilist' => [
|
||||
|
||||
],
|
||||
'config' => [
|
||||
'kitsu_username' => [
|
||||
'type' => 'string',
|
||||
'title' => 'Kitsu Username',
|
||||
'default' => '',
|
||||
'readonly' => TRUE,
|
||||
'description' => 'Username of the account to pull list data from.',
|
||||
],
|
||||
'whose_list' => [
|
||||
'type' => 'string',
|
||||
'title' => 'Whose List',
|
||||
'default' => 'Somebody',
|
||||
'readonly' => TRUE,
|
||||
'description' => 'Name of the owner of the list data.',
|
||||
],
|
||||
'show_anime_collection' => [
|
||||
'type' => 'boolean',
|
||||
'title' => 'Show Anime Collection',
|
||||
'default' => FALSE,
|
||||
'description' => 'Should the anime collection be shown?',
|
||||
],
|
||||
'show_manga_collection' => [
|
||||
'type' => 'boolean',
|
||||
'title' => 'Show Manga Collection',
|
||||
'default' => FALSE,
|
||||
'description' => 'Should the manga collection be shown?',
|
||||
],
|
||||
'asset_path' => [
|
||||
'type' => 'string',
|
||||
'display' => FALSE,
|
||||
'description' => 'Path to public directory, where images/css/javascript are located',
|
||||
],
|
||||
'default_list' => [
|
||||
'type' => 'select',
|
||||
'title' => 'Default List',
|
||||
'description' => 'Which list to show by default.',
|
||||
'options' => [
|
||||
'Anime' => 'anime',
|
||||
'Manga' => 'manga',
|
||||
],
|
||||
],
|
||||
'default_anime_list_path' => [ //watching|plan_to_watch|on_hold|dropped|completed|all
|
||||
'type' => 'select',
|
||||
'title' => 'Default Anime List Section',
|
||||
'description' => 'Which part of the anime list to show by default.',
|
||||
'options' => [
|
||||
'Watching' => 'watching',
|
||||
'Plan to Watch' => 'plan_to_watch',
|
||||
'On Hold' => 'on_hold',
|
||||
'Dropped' => 'dropped',
|
||||
'Completed' => 'completed',
|
||||
'All' => 'all',
|
||||
]
|
||||
],
|
||||
'default_manga_list_path' => [ //reading|plan_to_read|on_hold|dropped|completed|all
|
||||
'type' => 'select',
|
||||
'title' => 'Default Manga List Section',
|
||||
'description' => 'Which part of the manga list to show by default.',
|
||||
'options' => [
|
||||
'Reading' => 'reading',
|
||||
'Plan to Read' => 'plan_to_read',
|
||||
'On Hold' => 'on_hold',
|
||||
'Dropped' => 'dropped',
|
||||
'Completed' => 'completed',
|
||||
'All' => 'all',
|
||||
]
|
||||
]
|
||||
],
|
||||
'cache' => [
|
||||
'driver' => [
|
||||
'type' => 'select',
|
||||
'title' => 'Cache Type',
|
||||
'description' => 'The Cache backend',
|
||||
'options' => [
|
||||
'APCu' => 'apcu',
|
||||
'Memcached' => 'memcached',
|
||||
'Redis' => 'redis',
|
||||
'No Cache' => 'null'
|
||||
],
|
||||
],
|
||||
'connection' => [
|
||||
'type' => 'subfield',
|
||||
'title' => 'Connection',
|
||||
'fields' => [
|
||||
'host' => [
|
||||
'type' => 'string',
|
||||
'title' => 'Cache Host',
|
||||
'description' => 'Host of the cache backend to connect to',
|
||||
],
|
||||
'port' => [
|
||||
'type' => 'string',
|
||||
'title' => 'Cache Port',
|
||||
'description' => 'Port of the cache backend to connect to',
|
||||
],
|
||||
'password' => [
|
||||
'type' => 'string',
|
||||
'title' => 'Cache Password',
|
||||
'description' => 'Password to connect to cache backend',
|
||||
],
|
||||
'database' => [
|
||||
'type' => 'string',
|
||||
'title' => 'Cache Database',
|
||||
'description' => 'Cache database number for Redis',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'database' => [
|
||||
'type' => [
|
||||
'type' => 'select',
|
||||
'title' => 'Database Type',
|
||||
'options' => [
|
||||
'MySQL' => 'mysql',
|
||||
'PostgreSQL' => 'pgsql',
|
||||
'SQLite' => 'sqlite',
|
||||
],
|
||||
'description' => 'Type of database to connect to',
|
||||
],
|
||||
'host' => [
|
||||
'type' => 'string',
|
||||
'title' => 'Host',
|
||||
'description' => 'The host of the database server',
|
||||
],
|
||||
'user' => [
|
||||
'type' => 'string',
|
||||
'title' => 'User',
|
||||
'description' => 'Database connection user',
|
||||
],
|
||||
'pass' => [
|
||||
'type' => 'string',
|
||||
'title' => 'Password',
|
||||
'description' => 'Database connection password'
|
||||
],
|
||||
'port' => [
|
||||
'type' => 'string',
|
||||
'title' => 'Port',
|
||||
'description' => 'Database connection port'
|
||||
],
|
||||
'database' => [
|
||||
'type' => 'string',
|
||||
'title' => 'Database Name',
|
||||
'description' => 'Name of the database/schema to connect to',
|
||||
],
|
||||
'file' => [
|
||||
'type' => 'string',
|
||||
'title' => 'Database File',
|
||||
'description' => 'Path to the database file, if required by the current database type.'
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct(ConfigInterface $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function getSettings()
|
||||
{
|
||||
$settings = [
|
||||
'config' => [],
|
||||
];
|
||||
|
||||
foreach(static::SETTINGS_MAP as $file => $values)
|
||||
{
|
||||
if ($file === 'config')
|
||||
{
|
||||
$keys = array_keys($values);
|
||||
foreach($keys as $key)
|
||||
{
|
||||
$settings['config'][$key] = $this->config->get($key);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$settings[$file] = $this->config->get($file);
|
||||
}
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
public function getSettingsForm()
|
||||
{
|
||||
$output = [];
|
||||
|
||||
$settings = $this->getSettings();
|
||||
|
||||
foreach($settings as $file => $values)
|
||||
{
|
||||
foreach(static::SETTINGS_MAP[$file] as $key => $value)
|
||||
{
|
||||
if ($value['type'] === 'subfield')
|
||||
{
|
||||
foreach($value['fields'] as $k => $field)
|
||||
{
|
||||
$value['fields'][$k]['value'] = $values[$key][$k] ?? '';
|
||||
$value['fields'][$k]['display'] = TRUE;
|
||||
$value['fields'][$k]['readonly'] = FALSE;
|
||||
$value['fields'][$k]['disabled'] = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_scalar($values[$key]))
|
||||
{
|
||||
$value['value'] = $values[$key];
|
||||
}
|
||||
|
||||
foreach (['readonly', 'disabled'] as $flag)
|
||||
{
|
||||
if ( ! array_key_exists($flag, $value))
|
||||
{
|
||||
$value[$flag] = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! array_key_exists('display', $value))
|
||||
{
|
||||
$value['display'] = TRUE;
|
||||
}
|
||||
|
||||
$output[$file][$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function validateSettings(array $settings): bool
|
||||
{
|
||||
try
|
||||
{
|
||||
new Config($settings);
|
||||
}
|
||||
catch (UndefinedPropertyException $e)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
public function saveSettingsFile()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user