4.1 Beta...ish #12
@ -1,21 +0,0 @@
|
|||||||
test:7.1:
|
|
||||||
stage: test
|
|
||||||
before_script:
|
|
||||||
- sh build/docker_install.sh > /dev/null
|
|
||||||
- apk add --no-cache php7-phpdbg
|
|
||||||
- curl -sS https://getcomposer.org/installer | php
|
|
||||||
- php composer.phar install --ignore-platform-reqs
|
|
||||||
image: php:7.1-alpine
|
|
||||||
script:
|
|
||||||
- phpdbg -qrr -- ./vendor/bin/phpunit --coverage-text --colors=never
|
|
||||||
|
|
||||||
test:7.2:
|
|
||||||
stage: test
|
|
||||||
before_script:
|
|
||||||
- sh build/docker_install.sh > /dev/null
|
|
||||||
- apk add --no-cache php7-phpdbg
|
|
||||||
- curl -sS https://getcomposer.org/installer | php
|
|
||||||
- php composer.phar install --ignore-platform-reqs
|
|
||||||
image: php:7.2-alpine
|
|
||||||
script:
|
|
||||||
- phpdbg -qrr -- ./vendor/bin/phpunit --coverage-text --colors=never
|
|
@ -7,6 +7,8 @@
|
|||||||
* Updated console command to sync Kitsu and Anilist data (Kitsu can sync MAL, and MAL's API broke, so MAL sync was removed)
|
* Updated console command to sync Kitsu and Anilist data (Kitsu can sync MAL, and MAL's API broke, so MAL sync was removed)
|
||||||
* Added page to update settings without having to edit config files
|
* Added page to update settings without having to edit config files
|
||||||
* Defaulted to secure (HTTPS) urls
|
* Defaulted to secure (HTTPS) urls
|
||||||
|
* Updated Character pages to show voice actors
|
||||||
|
* Added People pages, showing which works they contributed to, and in what role
|
||||||
|
|
||||||
## Version 4
|
## Version 4
|
||||||
* Updated to use Kitsu API after discontinuation of Hummingbird
|
* Updated to use Kitsu API after discontinuation of Hummingbird
|
||||||
|
@ -174,6 +174,14 @@ return [
|
|||||||
'slug' => '[a-z0-9\-]+'
|
'slug' => '[a-z0-9\-]+'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
'person' => [
|
||||||
|
'path' => '/people/{id}',
|
||||||
|
'action' => 'index',
|
||||||
|
'params' => [],
|
||||||
|
'tokens' => [
|
||||||
|
'id' => '[a-z0-9\-]+'
|
||||||
|
]
|
||||||
|
],
|
||||||
'user_info' => [
|
'user_info' => [
|
||||||
'path' => '/me',
|
'path' => '/me',
|
||||||
'action' => 'me',
|
'action' => 'me',
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php use Aviat\AnimeClient\API\Kitsu; ?>
|
<?php
|
||||||
|
use function Aviat\AnimeClient\getLocalImg;
|
||||||
|
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>
|
<div>
|
||||||
@ -89,14 +92,19 @@
|
|||||||
<th>Cast Member</th>
|
<th>Cast Member</th>
|
||||||
<th>Series</th>
|
<th>Series</th>
|
||||||
</tr>
|
</tr>
|
||||||
<?php foreach($casting as $c):?>
|
<?php foreach($casting as $cid => $c):?>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width:229px">
|
<td style="width:229px">
|
||||||
<article class="character">
|
<article class="character">
|
||||||
<img src="<?= $c['person']['image'] ?>" alt="" />
|
<?php
|
||||||
|
$link = $url->generate('person', ['id' => $c['person']['id']]);
|
||||||
|
?>
|
||||||
|
<a href="<?= $link ?>">
|
||||||
|
<img src="<?= $urlGenerator->assetUrl(getLocalImg($c['person']['image'])) ?>" alt="" />
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<?= $c['person']['name'] ?>
|
<?= $c['person']['name'] ?>
|
||||||
</div>
|
</div>
|
||||||
|
</a>
|
||||||
</article>
|
</article>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -108,7 +116,7 @@
|
|||||||
$titles = Kitsu::filterTitles($series['attributes']);
|
$titles = Kitsu::filterTitles($series['attributes']);
|
||||||
?>
|
?>
|
||||||
<a href="<?= $link ?>">
|
<a href="<?= $link ?>">
|
||||||
<img src="<?= $series['attributes']['posterImage']['small'] ?>" width="220" alt="" />
|
<img src="<?= $urlGenerator->assetUrl(getLocalImg($series['attributes']['posterImage']['small'])) ?>" width="220" alt="" />
|
||||||
</a>
|
</a>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<a href="<?= $link ?>">
|
<a href="<?= $link ?>">
|
||||||
|
74
app/views/person.php
Normal file
74
app/views/person.php
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
use function Aviat\AnimeClient\getLocalImg;
|
||||||
|
use Aviat\AnimeClient\API\Kitsu;
|
||||||
|
?>
|
||||||
|
<main class="details fixed">
|
||||||
|
<section class="flex flex-no-wrap">
|
||||||
|
<div>
|
||||||
|
<picture class="cover">
|
||||||
|
<source
|
||||||
|
srcset="<?= $urlGenerator->assetUrl("images/people/{$data['id']}-original.webp") ?>"
|
||||||
|
type="image/webp"
|
||||||
|
>
|
||||||
|
<source
|
||||||
|
srcset="<?= $urlGenerator->assetUrl("images/people/{$data['id']}-original.jpg") ?>"
|
||||||
|
type="image/jpeg"
|
||||||
|
>
|
||||||
|
<img src="<?= $urlGenerator->assetUrl("images/people/{$data['id']}-original.jpg") ?>" alt="" />
|
||||||
|
</picture>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2><?= $data['attributes']['name'] ?></h2>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<?php if ($castCount > 0): ?>
|
||||||
|
<h3>Castings</h3>
|
||||||
|
<?php foreach ($castings as $role => $entries): ?>
|
||||||
|
<h4><?= $role ?></h4>
|
||||||
|
<?php foreach ($entries as $type => $casting): ?>
|
||||||
|
<?php if ( ! empty($entries['manga'])): ?>
|
||||||
|
<h5><?= ucfirst($type) ?></h5>
|
||||||
|
<?php endif ?>
|
||||||
|
<section class="align_left media-wrap">
|
||||||
|
<?php foreach ($casting as $sid => $series): ?>
|
||||||
|
<article class="media">
|
||||||
|
<?php
|
||||||
|
$link = $url->generate('anime.details', ['id' => $series['attributes']['slug']]);
|
||||||
|
$titles = Kitsu::filterTitles($series['attributes']);
|
||||||
|
?>
|
||||||
|
<a href="<?= $link ?>">
|
||||||
|
<picture>
|
||||||
|
<source
|
||||||
|
srcset="<?= $urlGenerator->assetUrl("images/{$type}/{$sid}.webp") ?>"
|
||||||
|
type="image/webp"
|
||||||
|
/>
|
||||||
|
<source
|
||||||
|
srcset="<?= $urlGenerator->assetUrl("images/{$type}/{$sid}.jpg") ?>"
|
||||||
|
type="image/jpeg"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src="<?= $urlGenerator->assetUrl("images/{$type}/{$sid}.jpg") ?>"
|
||||||
|
width="220" alt=""
|
||||||
|
/>
|
||||||
|
</picture>
|
||||||
|
</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>
|
||||||
|
<br />
|
||||||
|
<?php endforeach ?>
|
||||||
|
<?php endforeach ?>
|
||||||
|
<?php endif ?>
|
||||||
|
</section>
|
||||||
|
</main>
|
@ -61,6 +61,11 @@ final class JsonAPI {
|
|||||||
// Inline organized data
|
// Inline organized data
|
||||||
foreach($data['data'] as $i => &$item)
|
foreach($data['data'] as $i => &$item)
|
||||||
{
|
{
|
||||||
|
if ( ! is_array($item))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (array_key_exists('relationships', $item))
|
if (array_key_exists('relationships', $item))
|
||||||
{
|
{
|
||||||
foreach($item['relationships'] as $relType => $props)
|
foreach($item['relationships'] as $relType => $props)
|
||||||
|
@ -103,7 +103,7 @@ final class ListItem implements ListItemInterface {
|
|||||||
|
|
||||||
$request = $this->requestBuilder->newRequest('GET', "library-entries/{$id}")
|
$request = $this->requestBuilder->newRequest('GET', "library-entries/{$id}")
|
||||||
->setQuery([
|
->setQuery([
|
||||||
'include' => 'media,media.genres,media.mappings'
|
'include' => 'media,media.categories,media.mappings'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($authHeader !== FALSE)
|
if ($authHeader !== FALSE)
|
||||||
|
@ -221,6 +221,21 @@ final class Model {
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get information about a person
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getPerson(string $id): array
|
||||||
|
{
|
||||||
|
return $this->getRequest("people/{$id}", [
|
||||||
|
'query' => [
|
||||||
|
'include' => 'castings,castings.media,staff,staff.media,voices'
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get profile information for the configured user
|
* Get profile information for the configured user
|
||||||
*
|
*
|
||||||
@ -585,7 +600,7 @@ final class Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$transformed = $this->mangaTransformer->transform($baseData);
|
$transformed = $this->mangaTransformer->transform($baseData);
|
||||||
$transformed['included'] = $baseData['included'];
|
$transformed['included'] = JsonAPI::organizeIncluded($baseData['included']);
|
||||||
return $transformed;
|
return $transformed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -936,8 +951,8 @@ final class Model {
|
|||||||
'characters' => 'slug,name,image'
|
'characters' => 'slug,name,image'
|
||||||
],
|
],
|
||||||
'include' => ($type === 'anime')
|
'include' => ($type === 'anime')
|
||||||
? 'categories,mappings,streamingLinks,animeCharacters.character'
|
? 'staff,staff.person,categories,mappings,streamingLinks,animeCharacters.character'
|
||||||
: 'categories,mappings,mangaCharacters.character,castings.character',
|
: 'staff,staff.person,categories,mappings,mangaCharacters.character,castings.character',
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -19,6 +19,10 @@ namespace Aviat\AnimeClient;
|
|||||||
use Aviat\Ion\ConfigInterface;
|
use Aviat\Ion\ConfigInterface;
|
||||||
use Yosymfony\Toml\{Toml, TomlBuilder};
|
use Yosymfony\Toml\{Toml, TomlBuilder};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
//! TOML Functions
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load configuration options from .toml files
|
* Load configuration options from .toml files
|
||||||
*
|
*
|
||||||
@ -67,30 +71,6 @@ function loadTomlFile(string $filename): array
|
|||||||
return Toml::parseFile($filename);
|
return Toml::parseFile($filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the array sequential, not associative?
|
|
||||||
*
|
|
||||||
* @param mixed $array
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
function isSequentialArray($array): bool
|
|
||||||
{
|
|
||||||
if ( ! is_array($array))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
$i = 0;
|
|
||||||
foreach ($array as $k => $v)
|
|
||||||
{
|
|
||||||
if ($k !== $i++)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _iterateToml(TomlBuilder $builder, $data, $parentKey = NULL): void
|
function _iterateToml(TomlBuilder $builder, $data, $parentKey = NULL): void
|
||||||
{
|
{
|
||||||
foreach ($data as $key => $value)
|
foreach ($data as $key => $value)
|
||||||
@ -147,6 +127,34 @@ function tomlToArray(string $toml): array
|
|||||||
return Toml::parse($toml);
|
return Toml::parse($toml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
//! Misc Functions
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the array sequential, not associative?
|
||||||
|
*
|
||||||
|
* @param mixed $array
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function isSequentialArray($array): bool
|
||||||
|
{
|
||||||
|
if ( ! is_array($array))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$i = 0;
|
||||||
|
foreach ($array as $k => $v)
|
||||||
|
{
|
||||||
|
if ($k !== $i++)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that folder permissions are correct for proper operation
|
* Check that folder permissions are correct for proper operation
|
||||||
*
|
*
|
||||||
@ -187,3 +195,37 @@ function checkFolderPermissions(ConfigInterface $config): array
|
|||||||
|
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the path for the cached image from the original iamge
|
||||||
|
*
|
||||||
|
* @param string $kitsuUrl
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getLocalImg ($kitsuUrl): string
|
||||||
|
{
|
||||||
|
if ( ! is_string($kitsuUrl))
|
||||||
|
{
|
||||||
|
return '/404';
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = parse_url($kitsuUrl);
|
||||||
|
|
||||||
|
if ($parts === FALSE)
|
||||||
|
{
|
||||||
|
return '/404';
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = basename($parts['path']);
|
||||||
|
$fileParts = explode('.', $file);
|
||||||
|
$ext = array_pop($fileParts);
|
||||||
|
$segments = explode('/', trim($parts['path'], '/'));
|
||||||
|
|
||||||
|
// dump($segments);
|
||||||
|
|
||||||
|
$type = $segments[0] === 'users' ? $segments[1] : $segments[0];
|
||||||
|
|
||||||
|
$id = $segments[count($segments) - 2];
|
||||||
|
|
||||||
|
return implode('/', ['images', $type, "{$id}.{$ext}"]);
|
||||||
|
}
|
@ -16,20 +16,8 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\Command;
|
namespace Aviat\AnimeClient\Command;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\{
|
use Aviat\AnimeClient\API\JsonAPI;
|
||||||
FailedResponseException,
|
|
||||||
JsonAPI,
|
|
||||||
ParallelAPIRequest
|
|
||||||
};
|
|
||||||
use Aviat\AnimeClient\API\Anilist\Transformer\{
|
|
||||||
AnimeListTransformer as AALT,
|
|
||||||
MangaListTransformer as AMLT
|
|
||||||
};
|
|
||||||
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
|
|
||||||
use Aviat\AnimeClient\Controller\Index;
|
use Aviat\AnimeClient\Controller\Index;
|
||||||
use Aviat\AnimeClient\Types\FormItem;
|
|
||||||
use Aviat\Ion\Json;
|
|
||||||
use DateTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears out image cache directories, then re-creates the image cache
|
* Clears out image cache directories, then re-creates the image cache
|
||||||
@ -69,9 +57,11 @@ final class UpdateThumbnails extends BaseCommand {
|
|||||||
{
|
{
|
||||||
$this->controller->images($type, "{$id}.jpg", FALSE);
|
$this->controller->images($type, "{$id}.jpg", FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->echoBox("Finished regenerating {$type} thumbnails");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->echoBox('Finished regenerating thumbnails');
|
$this->echoBox('Finished regenerating all thumbnails');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function clearThumbs()
|
public function clearThumbs()
|
||||||
|
@ -275,10 +275,11 @@ final class Anime extends BaseController {
|
|||||||
*/
|
*/
|
||||||
public function details(string $animeId): void
|
public function details(string $animeId): void
|
||||||
{
|
{
|
||||||
$show_data = $this->model->getAnime($animeId);
|
$data = $this->model->getAnime($animeId);
|
||||||
$characters = [];
|
$characters = [];
|
||||||
|
$staff = [];
|
||||||
|
|
||||||
if ($show_data->title === '')
|
if ($data->title === '')
|
||||||
{
|
{
|
||||||
$this->notFound(
|
$this->notFound(
|
||||||
$this->config->get('whose_list') .
|
$this->config->get('whose_list') .
|
||||||
@ -290,22 +291,56 @@ final class Anime extends BaseController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists('characters', $show_data['included']))
|
if (array_key_exists('characters', $data['included']))
|
||||||
{
|
{
|
||||||
foreach($show_data['included']['characters'] as $id => $character)
|
|
||||||
|
|
||||||
|
foreach($data['included']['characters'] as $id => $character)
|
||||||
{
|
{
|
||||||
$characters[$id] = $character['attributes'];
|
$characters[$id] = $character['attributes'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('mediaStaff', $data['included']))
|
||||||
|
{
|
||||||
|
foreach ($data['included']['mediaStaff'] as $id => $person)
|
||||||
|
{
|
||||||
|
$personDetails = [];
|
||||||
|
foreach ($person['relationships']['person']['people'] as $p)
|
||||||
|
{
|
||||||
|
$personDetails = $p['attributes'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$role = $person['attributes']['role'];
|
||||||
|
|
||||||
|
if ( ! array_key_exists($role, $staff))
|
||||||
|
{
|
||||||
|
$staff[$role] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$staff[$role][$id] = [
|
||||||
|
'name' => $personDetails['name'] ?? '??',
|
||||||
|
'image' => $personDetails['image'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uasort($characters, function ($a, $b) {
|
||||||
|
return $a['name'] <=> $b['name'];
|
||||||
|
});
|
||||||
|
|
||||||
|
// dump($characters);
|
||||||
|
// dump($staff);
|
||||||
|
|
||||||
$this->outputHTML('anime/details', [
|
$this->outputHTML('anime/details', [
|
||||||
'title' => $this->formatTitle(
|
'title' => $this->formatTitle(
|
||||||
$this->config->get('whose_list') . "'s Anime List",
|
$this->config->get('whose_list') . "'s Anime List",
|
||||||
'Anime',
|
'Anime',
|
||||||
$show_data->title
|
$data->title
|
||||||
),
|
),
|
||||||
'characters' => $characters,
|
'characters' => $characters,
|
||||||
'show_data' => $show_data,
|
'show_data' => $data,
|
||||||
|
'staff' => $staff,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
|
|
||||||
|
use function Aviat\AnimeClient\getLocalImg;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Controller as BaseController;
|
use Aviat\AnimeClient\Controller as BaseController;
|
||||||
use Aviat\AnimeClient\API\JsonAPI;
|
use Aviat\AnimeClient\API\JsonAPI;
|
||||||
use Aviat\Ion\ArrayWrapper;
|
use Aviat\Ion\ArrayWrapper;
|
||||||
@ -23,7 +25,7 @@ use Aviat\Ion\ArrayWrapper;
|
|||||||
/**
|
/**
|
||||||
* Controller for character description pages
|
* Controller for character description pages
|
||||||
*/
|
*/
|
||||||
final class Character extends BaseController {
|
class Character extends BaseController {
|
||||||
|
|
||||||
use ArrayWrapper;
|
use ArrayWrapper;
|
||||||
|
|
||||||
@ -57,6 +59,23 @@ final class Character extends BaseController {
|
|||||||
|
|
||||||
$data = JsonAPI::organizeData($rawData);
|
$data = JsonAPI::organizeData($rawData);
|
||||||
|
|
||||||
|
if (array_key_exists('included', $data))
|
||||||
|
{
|
||||||
|
if (array_key_exists('anime', $data['included']))
|
||||||
|
{
|
||||||
|
uasort($data['included']['anime'], function ($a, $b) {
|
||||||
|
return $a['attributes']['canonicalTitle'] <=> $b['attributes']['canonicalTitle'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('manga', $data['included']))
|
||||||
|
{
|
||||||
|
uasort($data['included']['manga'], function ($a, $b) {
|
||||||
|
return $a['attributes']['canonicalTitle'] <=> $b['attributes']['canonicalTitle'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$viewData = [
|
$viewData = [
|
||||||
'title' => $this->formatTitle(
|
'title' => $this->formatTitle(
|
||||||
'Characters',
|
'Characters',
|
||||||
@ -67,11 +86,14 @@ final class Character extends BaseController {
|
|||||||
'castings' => []
|
'castings' => []
|
||||||
];
|
];
|
||||||
|
|
||||||
if (array_key_exists('included', $data) && array_key_exists('castings', $data['included']))
|
if (array_key_exists('included', $data))
|
||||||
|
{
|
||||||
|
if (array_key_exists('castings', $data['included']))
|
||||||
{
|
{
|
||||||
$viewData['castings'] = $this->organizeCast($data['included']['castings']);
|
$viewData['castings'] = $this->organizeCast($data['included']['castings']);
|
||||||
$viewData['castCount'] = $this->getCastCount($viewData['castings']);
|
$viewData['castCount'] = $this->getCastCount($viewData['castings']);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->outputHTML('character', $viewData);
|
$this->outputHTML('character', $viewData);
|
||||||
}
|
}
|
||||||
@ -121,25 +143,26 @@ final class Character extends BaseController {
|
|||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getCastCount(array $cast): int
|
protected function getCastCount(array $cast): int
|
||||||
{
|
{
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
|
||||||
foreach($cast as $role)
|
foreach($cast as $role)
|
||||||
{
|
{
|
||||||
if (
|
$count++;
|
||||||
|
/* if (
|
||||||
array_key_exists('attributes', $role) &&
|
array_key_exists('attributes', $role) &&
|
||||||
array_key_exists('role', $role['attributes']) &&
|
array_key_exists('role', $role['attributes']) &&
|
||||||
$role['attributes']['role'] !== NULL
|
$role['attributes']['role'] !== NULL
|
||||||
) {
|
) {
|
||||||
$count++;
|
$count++;
|
||||||
}
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
return $count;
|
return $count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function organizeCast(array $cast): array
|
protected function organizeCast(array $cast): array
|
||||||
{
|
{
|
||||||
$cast = $this->dedupeCast($cast);
|
$cast = $this->dedupeCast($cast);
|
||||||
$output = [];
|
$output = [];
|
||||||
@ -157,8 +180,19 @@ final class Character extends BaseController {
|
|||||||
|
|
||||||
if ($isVA)
|
if ($isVA)
|
||||||
{
|
{
|
||||||
$person = current($role['relationships']['person']['people'])['attributes'];
|
foreach($role['relationships']['person']['people'] as $pid => $peoples)
|
||||||
$name = $person['name'];
|
{
|
||||||
|
$p = $peoples;
|
||||||
|
}
|
||||||
|
|
||||||
|
$person = $p['attributes'];
|
||||||
|
$person['id'] = $pid;
|
||||||
|
$person['image'] = $person['image']['original'];
|
||||||
|
|
||||||
|
uasort($role['relationships']['media']['anime'], function ($a, $b) {
|
||||||
|
return $a['attributes']['canonicalTitle'] <=> $b['attributes']['canonicalTitle'];
|
||||||
|
});
|
||||||
|
|
||||||
$item = [
|
$item = [
|
||||||
'person' => $person,
|
'person' => $person,
|
||||||
'series' => $role['relationships']['media']['anime']
|
'series' => $role['relationships']['media']['anime']
|
||||||
@ -168,7 +202,11 @@ final class Character extends BaseController {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$output[$roleName][] = $role['relationships']['person']['people'];
|
foreach($role['relationships']['person']['people'] as $pid => $person)
|
||||||
|
{
|
||||||
|
$person['id'] = $pid;
|
||||||
|
$output[$roleName][$pid] = $person;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,36 +268,45 @@ final class Index extends BaseController {
|
|||||||
$kitsuUrl = 'https://media.kitsu.io/';
|
$kitsuUrl = 'https://media.kitsu.io/';
|
||||||
$fileName = str_replace('-original', '', $file);
|
$fileName = str_replace('-original', '', $file);
|
||||||
[$id, $ext] = explode('.', basename($fileName));
|
[$id, $ext] = explode('.', basename($fileName));
|
||||||
switch ($type)
|
|
||||||
|
$typeMap = [
|
||||||
|
'anime' => [
|
||||||
|
'kitsuUrl' => "anime/poster_images/{$id}/medium.{$ext}",
|
||||||
|
'width' => 220,
|
||||||
|
],
|
||||||
|
'avatars' => [
|
||||||
|
'kitsuUrl' => "users/avatars/{$id}/original.{$ext}",
|
||||||
|
'width' => null,
|
||||||
|
],
|
||||||
|
'characters' => [
|
||||||
|
'kitsuUrl' => "characters/images/{$id}/original.{$ext}",
|
||||||
|
'width' => 225,
|
||||||
|
],
|
||||||
|
'manga' => [
|
||||||
|
'kitsuUrl' => "manga/poster_images/{$id}/medium.{$ext}",
|
||||||
|
'width' => 220,
|
||||||
|
],
|
||||||
|
'people' => [
|
||||||
|
'kitsuUrl' => "people/images/{$id}/original.{$ext}",
|
||||||
|
'width' => null,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
if ( ! array_key_exists($type, $typeMap))
|
||||||
{
|
{
|
||||||
case 'anime':
|
|
||||||
$kitsuUrl .= "anime/poster_images/{$id}/small.jpg";
|
|
||||||
$width = 220;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'avatars':
|
|
||||||
$kitsuUrl .= "users/avatars/{$id}/original.jpg";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'manga':
|
|
||||||
$kitsuUrl .= "manga/poster_images/{$id}/small.jpg";
|
|
||||||
$width = 220;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'characters':
|
|
||||||
$kitsuUrl .= "characters/images/{$id}/original.jpg";
|
|
||||||
$width = 225;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
$this->notFound();
|
$this->notFound();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$kitsuUrl .= $typeMap[$type]['kitsuUrl'];
|
||||||
|
$width = $typeMap[$type]['width'];
|
||||||
|
|
||||||
$promise = (new HummingbirdClient)->request($kitsuUrl);
|
$promise = (new HummingbirdClient)->request($kitsuUrl);
|
||||||
$response = wait($promise);
|
$response = wait($promise);
|
||||||
$data = wait($response->getBody());
|
$data = wait($response->getBody());
|
||||||
|
|
||||||
|
// echo "Fetching {$kitsuUrl}\n";
|
||||||
|
|
||||||
$baseSavePath = $this->config->get('img_cache_path');
|
$baseSavePath = $this->config->get('img_cache_path');
|
||||||
$filePrefix = "{$baseSavePath}/{$type}/{$id}";
|
$filePrefix = "{$baseSavePath}/{$type}/{$id}";
|
||||||
|
|
||||||
|
@ -280,6 +280,7 @@ final class Manga extends Controller {
|
|||||||
public function details($manga_id): void
|
public function details($manga_id): void
|
||||||
{
|
{
|
||||||
$data = $this->model->getManga($manga_id);
|
$data = $this->model->getManga($manga_id);
|
||||||
|
$staff = [];
|
||||||
$characters = [];
|
$characters = [];
|
||||||
|
|
||||||
if (empty($data))
|
if (empty($data))
|
||||||
@ -293,14 +294,44 @@ final class Manga extends Controller {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($data['included'] as $included)
|
if (array_key_exists('characters', $data['included']))
|
||||||
{
|
{
|
||||||
if ($included['type'] === 'characters')
|
foreach ($data['included']['characters'] as $id => $character)
|
||||||
{
|
{
|
||||||
$characters[$included['id']] = $included['attributes'];
|
$characters[$id] = $character['attributes'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('mediaStaff', $data['included']))
|
||||||
|
{
|
||||||
|
foreach ($data['included']['mediaStaff'] as $id => $person)
|
||||||
|
{
|
||||||
|
$personDetails = [];
|
||||||
|
foreach ($person['relationships']['person']['people'] as $p)
|
||||||
|
{
|
||||||
|
$personDetails = $p['attributes'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$role = $person['attributes']['role'];
|
||||||
|
|
||||||
|
if ( ! array_key_exists($role, $staff))
|
||||||
|
{
|
||||||
|
$staff[$role] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$staff[$role][$id] = [
|
||||||
|
'name' => $personDetails['name'] ?? '??',
|
||||||
|
'image' => $personDetails['image'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uasort($characters, function ($a, $b) {
|
||||||
|
return $a['name'] <=> $b['name'];
|
||||||
|
});
|
||||||
|
|
||||||
|
// dump($staff);
|
||||||
|
|
||||||
$this->outputHTML('manga/details', [
|
$this->outputHTML('manga/details', [
|
||||||
'title' => $this->formatTitle(
|
'title' => $this->formatTitle(
|
||||||
$this->config->get('whose_list') . "'s Manga List",
|
$this->config->get('whose_list') . "'s Manga List",
|
||||||
@ -309,6 +340,7 @@ final class Manga extends Controller {
|
|||||||
),
|
),
|
||||||
'characters' => $characters,
|
'characters' => $characters,
|
||||||
'data' => $data,
|
'data' => $data,
|
||||||
|
'staff' => $staff,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
110
src/Controller/People.php
Normal file
110
src/Controller/People.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?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\Controller;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\Controller as BaseController;
|
||||||
|
use Aviat\AnimeClient\API\JsonAPI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for People pages
|
||||||
|
*/
|
||||||
|
final class People extends BaseController {
|
||||||
|
/**
|
||||||
|
* Show information about a person
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function index(string $id): void
|
||||||
|
{
|
||||||
|
$model = $this->container->get('kitsu-model');
|
||||||
|
|
||||||
|
$rawData = $model->getPerson($id);
|
||||||
|
|
||||||
|
if (( ! array_key_exists('data', $rawData)) || empty($rawData['data']))
|
||||||
|
{
|
||||||
|
$this->notFound(
|
||||||
|
$this->formatTitle(
|
||||||
|
'People',
|
||||||
|
'Person not found'
|
||||||
|
),
|
||||||
|
'Person Not Found'
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = JsonAPI::organizeData($rawData);
|
||||||
|
|
||||||
|
$viewData = [
|
||||||
|
'title' => $this->formatTitle(
|
||||||
|
'People',
|
||||||
|
$data['attributes']['name']
|
||||||
|
),
|
||||||
|
'data' => $data,
|
||||||
|
'castCount' => 0,
|
||||||
|
'castings' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
if (array_key_exists('included', $data) && array_key_exists('castings', $data['included']))
|
||||||
|
{
|
||||||
|
$viewData['castings'] = $this->organizeCast($data['included']['castings']);
|
||||||
|
$viewData['castCount'] = count($viewData['castings']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->outputHTML('person', $viewData);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function organizeCast(array $cast): array
|
||||||
|
{
|
||||||
|
$output = [];
|
||||||
|
|
||||||
|
foreach ($cast as $id => $role)
|
||||||
|
{
|
||||||
|
if (empty($role['attributes']['role']))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$roleName = $role['attributes']['role'];
|
||||||
|
$media = $role['relationships']['media'];
|
||||||
|
|
||||||
|
if (array_key_exists('anime', $media))
|
||||||
|
{
|
||||||
|
foreach($media['anime'] as $sid => $series)
|
||||||
|
{
|
||||||
|
$output[$roleName]['anime'][$sid] = $series;
|
||||||
|
}
|
||||||
|
uasort($output[$roleName]['anime'], function ($a, $b) {
|
||||||
|
return $a['attributes']['canonicalTitle'] <=> $b['attributes']['canonicalTitle'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (array_key_exists('manga', $media))
|
||||||
|
{
|
||||||
|
foreach ($media['manga'] as $sid => $series)
|
||||||
|
{
|
||||||
|
$output[$roleName]['manga'][$sid] = $series;
|
||||||
|
}
|
||||||
|
uasort($output[$roleName]['anime'], function ($a, $b) {
|
||||||
|
return $a['attributes']['canonicalTitle'] <=> $b['attributes']['canonicalTitle'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user