Ugly Progress Commit
All checks were successful
timw4mail/HummingBirdAnimeClient/develop This commit looks good
All checks were successful
timw4mail/HummingBirdAnimeClient/develop This commit looks good
* Update Person pages to have series organized by character for Voice Acting * Miscellaneous style updates * Add placeholder images for items missing images
This commit is contained in:
parent
14be365a16
commit
50b65d66e1
@ -1,6 +1,6 @@
|
|||||||
<main class="details fixed">
|
<main class="details fixed">
|
||||||
<section class="flex flex-no-wrap">
|
<section class="flex">
|
||||||
<div>
|
<aside class="info">
|
||||||
<picture class="cover">
|
<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.webp") ?>" type="image/webp">
|
||||||
<source srcset="<?= $urlGenerator->assetUrl("images/anime/{$show_data['id']}-original.jpg") ?>" type="image/jpeg">
|
<source srcset="<?= $urlGenerator->assetUrl("images/anime/{$show_data['id']}-original.jpg") ?>" type="image/jpeg">
|
||||||
@ -40,8 +40,8 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</aside>
|
||||||
<div>
|
<article class="text">
|
||||||
<h2><a rel="external" href="<?= $show_data['url'] ?>"><?= $show_data['title'] ?></a></h2>
|
<h2><a rel="external" href="<?= $show_data['url'] ?>"><?= $show_data['title'] ?></a></h2>
|
||||||
<?php foreach ($show_data['titles'] as $title): ?>
|
<?php foreach ($show_data['titles'] as $title): ?>
|
||||||
<h3><?= $title ?></h3>
|
<h3><?= $title ?></h3>
|
||||||
@ -85,13 +85,13 @@
|
|||||||
<h4>Trailer</h4>
|
<h4>Trailer</h4>
|
||||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/<?= $show_data['trailer_id'] ?>" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/<?= $show_data['trailer_id'] ?>" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</div>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<?php if (count($characters) > 0): ?>
|
<?php if (count($characters) > 0): ?>
|
||||||
<hr />
|
<br />
|
||||||
<h2>Characters</h2>
|
<h2>Characters</h2>
|
||||||
<section class="align_center media-wrap">
|
<section class="media-wrap flex flex-wrap flex-justify-start">
|
||||||
<?php foreach($characters as $id => $char): ?>
|
<?php foreach($characters as $id => $char): ?>
|
||||||
<?php if ( ! empty($char['image']['original'])): ?>
|
<?php if ( ! empty($char['image']['original'])): ?>
|
||||||
<article class="character">
|
<article class="character">
|
||||||
|
@ -4,18 +4,29 @@ use Aviat\AnimeClient\API\Kitsu;
|
|||||||
?>
|
?>
|
||||||
<main class="details fixed">
|
<main class="details fixed">
|
||||||
<section class="flex flex-no-wrap">
|
<section class="flex flex-no-wrap">
|
||||||
<div>
|
<aside class="info cover">
|
||||||
<picture class="cover">
|
<picture>
|
||||||
<source srcset="<?= $urlGenerator->assetUrl("images/characters/{$data[0]['id']}-original.webp") ?>" type="image/webp">
|
<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">
|
<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="" />
|
<img src="<?= $urlGenerator->assetUrl("images/characters/{$data[0]['id']}-original.jpg") ?>" alt="" />
|
||||||
</picture>
|
</picture>
|
||||||
</div>
|
<?php if ( ! empty($data[0]['attributes']['otherNames'])): ?>
|
||||||
<div>
|
<h3>Nicknames / Other names</h3>
|
||||||
<h2><?= $data[0]['attributes']['name'] ?></h2>
|
<?php foreach ($data[0]['attributes']['otherNames'] as $name): ?>
|
||||||
|
<h4><?= $name ?></h4>
|
||||||
|
<?php endforeach ?>
|
||||||
|
<?php endif ?>
|
||||||
|
</aside>
|
||||||
|
<article class="text">
|
||||||
|
<h2><?= $data['name'] ?></h2>
|
||||||
|
<?php foreach ($data['names'] as $name): ?>
|
||||||
|
<h3><?= $name ?></h3>
|
||||||
|
<?php endforeach ?>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
<p class="description"><?= $data[0]['attributes']['description'] ?></p>
|
<p class="description"><?= $data[0]['attributes']['description'] ?></p>
|
||||||
</div>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<?php if (array_key_exists('anime', $data['included']) || array_key_exists('manga', $data['included'])): ?>
|
<?php if (array_key_exists('anime', $data['included']) || array_key_exists('manga', $data['included'])): ?>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<main class="details fixed">
|
<main class="details fixed">
|
||||||
<section class="flex flex-no-wrap">
|
<section class="flex flex-no-wrap">
|
||||||
<div>
|
<aside class="info">
|
||||||
<picture class="cover">
|
<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.webp") ?>" type="image/webp">
|
||||||
<source srcset="<?= $urlGenerator->assetUrl("images/manga/{$data['id']}-original.jpg") ?>" type="image/jpeg">
|
<source srcset="<?= $urlGenerator->assetUrl("images/manga/{$data['id']}-original.jpg") ?>" type="image/jpeg">
|
||||||
@ -28,8 +28,8 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</aside>
|
||||||
<div>
|
<article class="text">
|
||||||
<h2><a rel="external" href="<?= $data['url'] ?>"><?= $data['title'] ?></a></h2>
|
<h2><a rel="external" href="<?= $data['url'] ?>"><?= $data['title'] ?></a></h2>
|
||||||
<?php foreach($data['titles'] as $title): ?>
|
<?php foreach($data['titles'] as $title): ?>
|
||||||
<h3><?= $title ?></h3>
|
<h3><?= $title ?></h3>
|
||||||
@ -37,12 +37,12 @@
|
|||||||
|
|
||||||
<br />
|
<br />
|
||||||
<p><?= nl2br($data['synopsis']) ?></p>
|
<p><?= nl2br($data['synopsis']) ?></p>
|
||||||
</div>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<?php if (count($characters) > 0): ?>
|
<?php if (count($characters) > 0): ?>
|
||||||
<h2>Characters</h2>
|
<h2>Characters</h2>
|
||||||
<section class="media-wrap">
|
<section class="media-wrap flex flex-wrap flex-justify-start">
|
||||||
<?php foreach($characters as $id => $char): ?>
|
<?php foreach($characters as $id => $char): ?>
|
||||||
<?php if ( ! empty($char['image']['original'])): ?>
|
<?php if ( ! empty($char['image']['original'])): ?>
|
||||||
<article class="character">
|
<article class="character">
|
||||||
|
62
app/views/person/character-mapping.php
Normal file
62
app/views/person/character-mapping.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
use function Aviat\AnimeClient\getLocalImg;
|
||||||
|
use Aviat\AnimeClient\API\Kitsu;
|
||||||
|
?>
|
||||||
|
<?php foreach ($entries as $type => $casting): ?>
|
||||||
|
<?php if($type === 'characters'): ?>
|
||||||
|
<table class="min-table">
|
||||||
|
<tr>
|
||||||
|
<th>Character</th>
|
||||||
|
<th>Series</th>
|
||||||
|
</tr>
|
||||||
|
<?php foreach ($casting as $cid => $character): ?>
|
||||||
|
<tr>
|
||||||
|
<td style="width:229px">
|
||||||
|
<article class="character">
|
||||||
|
<?php
|
||||||
|
$link = $url->generate('character', ['slug' => $character['character']['slug']]);
|
||||||
|
?>
|
||||||
|
<a href="<?= $link ?>">
|
||||||
|
<?php $imgPath = ($character['character']['image'] === NULL)
|
||||||
|
? $urlGenerator->assetUrl('images/characters/empty.png')
|
||||||
|
: $urlGenerator->assetUrl(getLocalImg($character['character']['image']['original']));
|
||||||
|
?>
|
||||||
|
<img src="<?= $imgPath ?>" alt="" />
|
||||||
|
<div class="name">
|
||||||
|
<?= $character['character']['canonicalName'] ?>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</article>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<section class="align_left media-wrap">
|
||||||
|
<?php foreach ($character['media'] as $sid => $series): ?>
|
||||||
|
<article class="media">
|
||||||
|
<?php
|
||||||
|
$link = $url->generate('anime.details', ['id' => $series['slug']]);
|
||||||
|
$titles = Kitsu::filterTitles($series);
|
||||||
|
?>
|
||||||
|
<a href="<?= $link ?>">
|
||||||
|
<img
|
||||||
|
src="<?= $urlGenerator->assetUrl("images/anime/{$sid}.jpg") ?>"
|
||||||
|
width="220" alt=""
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<div class="name">
|
||||||
|
<a href="<?= $link ?>">
|
||||||
|
<?= array_shift($titles) ?>
|
||||||
|
<?php foreach ($titles as $title): ?>
|
||||||
|
<br />
|
||||||
|
<small><?= $title ?></small>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</section>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</table>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php endforeach ?>
|
@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
use function Aviat\AnimeClient\getLocalImg;
|
|
||||||
use Aviat\AnimeClient\API\Kitsu;
|
use Aviat\AnimeClient\API\Kitsu;
|
||||||
?>
|
?>
|
||||||
<main class="details fixed">
|
<main class="details fixed">
|
||||||
@ -27,7 +26,11 @@ use Aviat\AnimeClient\API\Kitsu;
|
|||||||
<h3>Castings</h3>
|
<h3>Castings</h3>
|
||||||
<?php foreach ($castings as $role => $entries): ?>
|
<?php foreach ($castings as $role => $entries): ?>
|
||||||
<h4><?= $role ?></h4>
|
<h4><?= $role ?></h4>
|
||||||
|
<?php if($role === 'Voice Actor'): ?>
|
||||||
|
<?php include 'character-mapping.php' ?>
|
||||||
|
<?php else: ?>
|
||||||
<?php foreach ($entries as $type => $casting): ?>
|
<?php foreach ($entries as $type => $casting): ?>
|
||||||
|
<?php if ($type === 'characters') continue; ?>
|
||||||
<?php if ( ! empty($entries['manga'])): ?>
|
<?php if ( ! empty($entries['manga'])): ?>
|
||||||
<h5><?= ucfirst($type) ?></h5>
|
<h5><?= ucfirst($type) ?></h5>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
@ -68,6 +71,7 @@ use Aviat\AnimeClient\API\Kitsu;
|
|||||||
</section>
|
</section>
|
||||||
<br />
|
<br />
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
<?php endif ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</section>
|
</section>
|
@ -24,6 +24,7 @@
|
|||||||
"aura/session": "^2.0",
|
"aura/session": "^2.0",
|
||||||
"aviat/banker": "^1.0.0",
|
"aviat/banker": "^1.0.0",
|
||||||
"aviat/ion": "^2.4.1",
|
"aviat/ion": "^2.4.1",
|
||||||
|
"ext-iconv": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-gd":"*",
|
"ext-gd":"*",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
|
@ -20,6 +20,8 @@ use Aviat\AnimeClient\Types\Config as ConfigType;
|
|||||||
|
|
||||||
use function Aviat\Ion\_dir;
|
use function Aviat\Ion\_dir;
|
||||||
|
|
||||||
|
setlocale(LC_CTYPE, 'en_US');
|
||||||
|
|
||||||
// Work around the silly timezone error
|
// Work around the silly timezone error
|
||||||
$timezone = ini_get('date.timezone');
|
$timezone = ini_get('date.timezone');
|
||||||
if ($timezone === '' || $timezone === FALSE)
|
if ($timezone === '' || $timezone === FALSE)
|
||||||
|
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
@ -91,6 +91,10 @@ a:hover, a:active {
|
|||||||
flex-wrap: nowrap
|
flex-wrap: nowrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex-align-start {
|
||||||
|
align-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
.flex-align-end {
|
.flex-align-end {
|
||||||
align-items: flex-end
|
align-items: flex-end
|
||||||
}
|
}
|
||||||
@ -99,6 +103,10 @@ a:hover, a:active {
|
|||||||
align-content: space-around
|
align-content: space-around
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex-justify-start {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
.flex-justify-space-around {
|
.flex-justify-space-around {
|
||||||
justify-content: space-around
|
justify-content: space-around
|
||||||
}
|
}
|
||||||
@ -107,6 +115,10 @@ a:hover, a:active {
|
|||||||
align-self: center
|
align-self: center
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex-space-evenly {
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
.flex {
|
.flex {
|
||||||
display: flex
|
display: flex
|
||||||
}
|
}
|
||||||
@ -671,7 +683,13 @@ picture.cover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.fixed {
|
.fixed {
|
||||||
max-width: 93rem;
|
max-width: 100rem;
|
||||||
|
/* max-width: 80%; */
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fixed .text {
|
||||||
|
max-width: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.details .cover {
|
.details .cover {
|
||||||
@ -684,14 +702,10 @@ picture.cover {
|
|||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.details .flex > div {
|
.details .flex > * {
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.details .media_details {
|
|
||||||
max-width: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.details .media_details td {
|
.details .media_details td {
|
||||||
padding: 0 1.5rem;
|
padding: 0 1.5rem;
|
||||||
}
|
}
|
||||||
@ -752,6 +766,15 @@ picture.cover {
|
|||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aside.info {
|
||||||
|
max-width: 390px;
|
||||||
|
}
|
||||||
|
|
||||||
|
aside.info picture, aside.info img {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
User page styles
|
User page styles
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
|
BIN
public/images/placeholder.png
Normal file
BIN
public/images/placeholder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 242 B |
@ -101,27 +101,28 @@ final class JsonAPI {
|
|||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single data item
|
// Single data item
|
||||||
else if (array_key_exists('id', $props['data']))
|
if (array_key_exists('id', $props['data']))
|
||||||
{
|
{
|
||||||
$idKey = $props['data']['id'];
|
$idKey = $props['data']['id'];
|
||||||
$typeKey = $props['data']['type'];
|
$dataType = $props['data']['type'];
|
||||||
$relationship =& $item['relationships'][$relType];
|
$relationship =& $item['relationships'][$relType];
|
||||||
unset($relationship['data']);
|
unset($relationship['data']);
|
||||||
|
|
||||||
if (in_array($relType, $singular))
|
if (\in_array($relType, $singular, TRUE))
|
||||||
{
|
{
|
||||||
$relationship = $included[$typeKey][$idKey];
|
$relationship = $included[$dataType][$idKey];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($relType === $typeKey)
|
if ($relType === $dataType)
|
||||||
{
|
{
|
||||||
$relationship[$idKey] = $included[$typeKey][$idKey];
|
$relationship[$idKey] = $included[$dataType][$idKey];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$relationship[$typeKey][$idKey] = $included[$typeKey][$idKey];
|
$relationship[$dataType][$idKey] = $included[$dataType][$idKey];
|
||||||
}
|
}
|
||||||
// Multiple data items
|
// Multiple data items
|
||||||
else
|
else
|
||||||
@ -129,16 +130,16 @@ final class JsonAPI {
|
|||||||
foreach($props['data'] as $j => $datum)
|
foreach($props['data'] as $j => $datum)
|
||||||
{
|
{
|
||||||
$idKey = $props['data'][$j]['id'];
|
$idKey = $props['data'][$j]['id'];
|
||||||
$typeKey = $props['data'][$j]['type'];
|
$dataType = $props['data'][$j]['type'];
|
||||||
$relationship =& $item['relationships'][$relType];
|
$relationship =& $item['relationships'][$relType];
|
||||||
|
|
||||||
if ($relType === $typeKey)
|
if ($relType === $dataType)
|
||||||
{
|
{
|
||||||
$relationship[$idKey] = $included[$typeKey][$idKey];
|
$relationship[$idKey] = $included[$dataType][$idKey];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$relationship[$typeKey][$idKey][$j] = $included[$typeKey][$idKey];
|
$relationship[$dataType][$idKey][$j] = $included[$dataType][$idKey];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,29 +202,33 @@ final class JsonAPI {
|
|||||||
{
|
{
|
||||||
foreach($items as $id => $item)
|
foreach($items as $id => $item)
|
||||||
{
|
{
|
||||||
if (array_key_exists('relationships', $item) && is_array($item['relationships']))
|
if (array_key_exists('relationships', $item) && \is_array($item['relationships']))
|
||||||
{
|
{
|
||||||
foreach($item['relationships'] as $relType => $props)
|
foreach($item['relationships'] as $relType => $props)
|
||||||
{
|
{
|
||||||
if (array_key_exists('data', $props) && is_array($props['data']) && array_key_exists('id', $props['data']))
|
if (array_key_exists('data', $props) && \is_array($props['data']) && array_key_exists('id', $props['data']))
|
||||||
{
|
{
|
||||||
if (array_key_exists($props['data']['id'], $organized[$props['data']['type']]))
|
$idKey = $props['data']['id'];
|
||||||
|
$dataType = $props['data']['type'];
|
||||||
|
|
||||||
|
if ( ! array_key_exists($dataType, $organized))
|
||||||
{
|
{
|
||||||
$idKey = $props['data']['id'];
|
$organized[$dataType] = [];
|
||||||
$typeKey = $props['data']['type'];
|
}
|
||||||
|
|
||||||
|
$relationship =& $organized[$type][$id]['relationships'][$relType];
|
||||||
|
unset($relationship['links']);
|
||||||
|
unset($relationship['data']);
|
||||||
|
|
||||||
$relationship =& $organized[$type][$id]['relationships'][$relType];
|
if ($relType === $dataType)
|
||||||
unset($relationship['links']);
|
{
|
||||||
unset($relationship['data']);
|
$relationship[$idKey] = $included[$dataType][$idKey];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ($relType === $typeKey)
|
if (array_key_exists($idKey, $organized[$dataType]))
|
||||||
{
|
{
|
||||||
$relationship[$idKey] = $included[$typeKey][$idKey];
|
$relationship[$dataType][$idKey] = $organized[$dataType][$idKey];
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$relationship[$typeKey][$idKey] = $organized[$typeKey][$idKey];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,11 +229,26 @@ final class Model {
|
|||||||
*/
|
*/
|
||||||
public function getPerson(string $id): array
|
public function getPerson(string $id): array
|
||||||
{
|
{
|
||||||
return $this->getRequest("people/{$id}", [
|
$cacheItem = $this->cache->getItem("kitsu-person-{$id}");
|
||||||
'query' => [
|
|
||||||
'include' => 'castings,castings.media,staff,staff.media,voices'
|
if ( ! $cacheItem->isHit())
|
||||||
],
|
{
|
||||||
]);
|
$data = $this->getRequest("people/{$id}", [
|
||||||
|
'query' => [
|
||||||
|
'fields' => [
|
||||||
|
'characters' => 'canonicalName,slug,image',
|
||||||
|
'anime' => 'canonicalTitle,titles,slug,posterImage',
|
||||||
|
'manga' => 'canonicalTitle,titles,slug,posterImage',
|
||||||
|
],
|
||||||
|
'include' => 'castings.character,castings.media'
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$cacheItem->set($data);
|
||||||
|
$cacheItem->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cacheItem->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -206,14 +206,14 @@ function getLocalImg ($kitsuUrl): string
|
|||||||
{
|
{
|
||||||
if ( ! is_string($kitsuUrl))
|
if ( ! is_string($kitsuUrl))
|
||||||
{
|
{
|
||||||
return '/404';
|
return 'images/404/404.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
$parts = parse_url($kitsuUrl);
|
$parts = parse_url($kitsuUrl);
|
||||||
|
|
||||||
if ($parts === FALSE)
|
if ($parts === FALSE)
|
||||||
{
|
{
|
||||||
return '/404';
|
return 'images/404/404.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = basename($parts['path']);
|
$file = basename($parts['path']);
|
||||||
@ -221,11 +221,51 @@ function getLocalImg ($kitsuUrl): string
|
|||||||
$ext = array_pop($fileParts);
|
$ext = array_pop($fileParts);
|
||||||
$segments = explode('/', trim($parts['path'], '/'));
|
$segments = explode('/', trim($parts['path'], '/'));
|
||||||
|
|
||||||
// dump($segments);
|
|
||||||
|
|
||||||
$type = $segments[0] === 'users' ? $segments[1] : $segments[0];
|
$type = $segments[0] === 'users' ? $segments[1] : $segments[0];
|
||||||
|
|
||||||
$id = $segments[count($segments) - 2];
|
$id = $segments[count($segments) - 2];
|
||||||
|
|
||||||
return implode('/', ['images', $type, "{$id}.{$ext}"]);
|
return implode('/', ['images', $type, "{$id}.{$ext}"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a transparent placeholder image
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param int $width
|
||||||
|
* @param int $height
|
||||||
|
* @param string $text
|
||||||
|
*/
|
||||||
|
function createPlaceholderImage ($path, $width, $height, $text = 'Image Unavailable')
|
||||||
|
{
|
||||||
|
$width = $width ?? 200;
|
||||||
|
$height = $height ?? 200;
|
||||||
|
|
||||||
|
$img = imagecreate($width, $height);
|
||||||
|
|
||||||
|
$path = rtrim($path, '/');
|
||||||
|
|
||||||
|
// Background is the first color by default
|
||||||
|
imagecolorallocatealpha($img, 255, 255, 255, 127);
|
||||||
|
$textColor = imagecolorallocate($img, 64, 64, 64);
|
||||||
|
|
||||||
|
imagealphablending($img, TRUE);
|
||||||
|
|
||||||
|
// Generate placeholder text
|
||||||
|
$fontSize = 10;
|
||||||
|
$fontWidth = imagefontwidth($fontSize);
|
||||||
|
$fontHeight = imagefontheight($fontSize);
|
||||||
|
$length = strlen($text);
|
||||||
|
$textWidth = $length * $fontWidth;
|
||||||
|
$fxPos = (int) ceil((imagesx($img) - $textWidth) / 2);
|
||||||
|
$fyPos = (int) ceil((imagesy($img) - $fontHeight) / 2);
|
||||||
|
|
||||||
|
// Add the image text
|
||||||
|
imagestring($img, $fontSize, $fxPos, $fyPos, $text, $textColor);
|
||||||
|
|
||||||
|
// Save the images
|
||||||
|
imagesavealpha($img, TRUE);
|
||||||
|
imagepng($img, $path . '/placeholder.png', 9);
|
||||||
|
|
||||||
|
imagedestroy($img);
|
||||||
|
}
|
@ -59,6 +59,14 @@ class Character extends BaseController {
|
|||||||
|
|
||||||
$data = JsonAPI::organizeData($rawData);
|
$data = JsonAPI::organizeData($rawData);
|
||||||
|
|
||||||
|
$data['names'] = array_unique(
|
||||||
|
array_merge(
|
||||||
|
[ $data[0]['attributes']['canonicalName'] ],
|
||||||
|
$data[0]['attributes']['names']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$data['name'] = array_shift($data['names']);
|
||||||
|
|
||||||
if (array_key_exists('included', $data))
|
if (array_key_exists('included', $data))
|
||||||
{
|
{
|
||||||
if (array_key_exists('anime', $data['included']))
|
if (array_key_exists('anime', $data['included']))
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
|
|
||||||
|
use function Aviat\AnimeClient\createPlaceholderImage;
|
||||||
use function Amp\Promise\wait;
|
use function Amp\Promise\wait;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Controller as BaseController;
|
use Aviat\AnimeClient\Controller as BaseController;
|
||||||
@ -269,45 +270,60 @@ final class Index extends BaseController {
|
|||||||
$fileName = str_replace('-original', '', $file);
|
$fileName = str_replace('-original', '', $file);
|
||||||
[$id, $ext] = explode('.', basename($fileName));
|
[$id, $ext] = explode('.', basename($fileName));
|
||||||
|
|
||||||
|
$baseSavePath = $this->config->get('img_cache_path');
|
||||||
|
|
||||||
$typeMap = [
|
$typeMap = [
|
||||||
'anime' => [
|
'anime' => [
|
||||||
'kitsuUrl' => "anime/poster_images/{$id}/medium.{$ext}",
|
'kitsuUrl' => "anime/poster_images/{$id}/medium.{$ext}",
|
||||||
'width' => 220,
|
'width' => 220,
|
||||||
|
'height' => 312,
|
||||||
],
|
],
|
||||||
'avatars' => [
|
'avatars' => [
|
||||||
'kitsuUrl' => "users/avatars/{$id}/original.{$ext}",
|
'kitsuUrl' => "users/avatars/{$id}/original.{$ext}",
|
||||||
'width' => null,
|
'width' => null,
|
||||||
|
'height' => null,
|
||||||
],
|
],
|
||||||
'characters' => [
|
'characters' => [
|
||||||
'kitsuUrl' => "characters/images/{$id}/original.{$ext}",
|
'kitsuUrl' => "characters/images/{$id}/original.{$ext}",
|
||||||
'width' => 225,
|
'width' => 225,
|
||||||
|
'height' => 350,
|
||||||
],
|
],
|
||||||
'manga' => [
|
'manga' => [
|
||||||
'kitsuUrl' => "manga/poster_images/{$id}/medium.{$ext}",
|
'kitsuUrl' => "manga/poster_images/{$id}/medium.{$ext}",
|
||||||
'width' => 220,
|
'width' => 220,
|
||||||
|
'height' => 312,
|
||||||
],
|
],
|
||||||
'people' => [
|
'people' => [
|
||||||
'kitsuUrl' => "people/images/{$id}/original.{$ext}",
|
'kitsuUrl' => "people/images/{$id}/original.{$ext}",
|
||||||
'width' => null,
|
'width' => null,
|
||||||
|
'height' => null,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
if ( ! array_key_exists($type, $typeMap))
|
if ( ! array_key_exists($type, $typeMap))
|
||||||
{
|
{
|
||||||
$this->notFound();
|
$this->getPlaceholder($baseSavePath, 100, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$kitsuUrl .= $typeMap[$type]['kitsuUrl'];
|
$kitsuUrl .= $typeMap[$type]['kitsuUrl'];
|
||||||
$width = $typeMap[$type]['width'];
|
$width = $typeMap[$type]['width'];
|
||||||
|
$height = $typeMap[$type]['height'];
|
||||||
|
|
||||||
$promise = (new HummingbirdClient)->request($kitsuUrl);
|
$promise = (new HummingbirdClient)->request($kitsuUrl);
|
||||||
$response = wait($promise);
|
$response = wait($promise);
|
||||||
|
|
||||||
|
if ($response->getStatus() !== 200)
|
||||||
|
{
|
||||||
|
if ($display)
|
||||||
|
{
|
||||||
|
$this->getPlaceholder("{$baseSavePath}/{$type}", $width, $height);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$data = wait($response->getBody());
|
$data = wait($response->getBody());
|
||||||
|
|
||||||
// echo "Fetching {$kitsuUrl}\n";
|
|
||||||
|
|
||||||
$baseSavePath = $this->config->get('img_cache_path');
|
|
||||||
$filePrefix = "{$baseSavePath}/{$type}/{$id}";
|
$filePrefix = "{$baseSavePath}/{$type}/{$id}";
|
||||||
|
|
||||||
[$origWidth] = getimagesizefromstring($data);
|
[$origWidth] = getimagesizefromstring($data);
|
||||||
@ -371,4 +387,19 @@ final class Index extends BaseController {
|
|||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
@ -62,11 +62,12 @@ final class People extends BaseController {
|
|||||||
|
|
||||||
if (array_key_exists('included', $data) && array_key_exists('castings', $data['included']))
|
if (array_key_exists('included', $data) && array_key_exists('castings', $data['included']))
|
||||||
{
|
{
|
||||||
|
$viewData['included'] = $data['included'];
|
||||||
$viewData['castings'] = $this->organizeCast($data['included']['castings']);
|
$viewData['castings'] = $this->organizeCast($data['included']['castings']);
|
||||||
$viewData['castCount'] = count($viewData['castings']);
|
$viewData['castCount'] = count($viewData['castings']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->outputHTML('person', $viewData);
|
$this->outputHTML('person/index', $viewData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function organizeCast(array $cast): array
|
protected function organizeCast(array $cast): array
|
||||||
@ -82,6 +83,52 @@ final class People extends BaseController {
|
|||||||
|
|
||||||
$roleName = $role['attributes']['role'];
|
$roleName = $role['attributes']['role'];
|
||||||
$media = $role['relationships']['media'];
|
$media = $role['relationships']['media'];
|
||||||
|
$chars = $role['relationships']['character']['characters'] ?? [];
|
||||||
|
|
||||||
|
if ( ! array_key_exists($roleName, $output))
|
||||||
|
{
|
||||||
|
$output[$roleName] = [
|
||||||
|
'characters' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty($chars))
|
||||||
|
{
|
||||||
|
$relatedMedia = [];
|
||||||
|
|
||||||
|
if (array_key_exists('anime', $media))
|
||||||
|
{
|
||||||
|
foreach($media['anime'] as $sid => $series)
|
||||||
|
{
|
||||||
|
$relatedMedia[$sid] = $series['attributes'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($chars as $cid => $character)
|
||||||
|
{
|
||||||
|
// To make sure all the media are properly associated,
|
||||||
|
// merge the found media for this iteration with
|
||||||
|
// existing media, making sure to preserve array keys
|
||||||
|
$existingMedia = array_key_exists($cid, $output[$roleName]['characters'])
|
||||||
|
? $output[$roleName]['characters'][$cid]['media']
|
||||||
|
: [];
|
||||||
|
|
||||||
|
$includedMedia = array_replace_recursive($existingMedia, $relatedMedia);
|
||||||
|
|
||||||
|
uasort($includedMedia, function ($a, $b) {
|
||||||
|
return $a['canonicalTitle'] <=> $b['canonicalTitle'];
|
||||||
|
});
|
||||||
|
|
||||||
|
$output[$roleName]['characters'][$cid] = [
|
||||||
|
'character' => $character['attributes'],
|
||||||
|
'media' => $includedMedia,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
uasort($output[$roleName]['characters'], function ($a, $b) {
|
||||||
|
return $a['character']['canonicalName'] <=> $b['character']['canonicalName'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (array_key_exists('anime', $media))
|
if (array_key_exists('anime', $media))
|
||||||
{
|
{
|
||||||
@ -99,7 +146,7 @@ final class People extends BaseController {
|
|||||||
{
|
{
|
||||||
$output[$roleName]['manga'][$sid] = $series;
|
$output[$roleName]['manga'][$sid] = $series;
|
||||||
}
|
}
|
||||||
uasort($output[$roleName]['anime'], function ($a, $b) {
|
uasort($output[$roleName]['manga'], function ($a, $b) {
|
||||||
return $a['attributes']['canonicalTitle'] <=> $b['attributes']['canonicalTitle'];
|
return $a['attributes']['canonicalTitle'] <=> $b['attributes']['canonicalTitle'];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user