Better handling of alternate titles, Airing Status and genres for anime list views
This commit is contained in:
parent
9eda005399
commit
4c75701c0d
@ -18,8 +18,10 @@
|
|||||||
<?= $helper->img($item['anime']['image']); ?>
|
<?= $helper->img($item['anime']['image']); ?>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]); ?>">
|
<a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]); ?>">
|
||||||
<?= $escape->html($item['anime']['title']) ?>
|
<?= array_shift($item['anime']['titles']) ?>
|
||||||
<?= ($item['anime']['alternate_title'] != "") ? "<br />({$item['anime']['alternate_title']})" : ""; ?>
|
<?php foreach ($item['anime']['titles'] as $title): ?>
|
||||||
|
<br /><small><?= $title ?></small>
|
||||||
|
<?php endforeach ?>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="table">
|
<div class="table">
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<table>
|
<table>
|
||||||
<?php /*<tr>
|
<tr>
|
||||||
<td class="align_right">Airing Status</td>
|
<td class="align_right">Airing Status</td>
|
||||||
<td><?= $data['status'] ?></td>
|
<td><?= $data['status'] ?></td>
|
||||||
</tr>*/ ?>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Show Type</td>
|
<td>Show Type</td>
|
||||||
<td><?= $data['show_type'] ?></td>
|
<td><?= $data['show_type'] ?></td>
|
||||||
@ -34,14 +34,10 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2><a rel="external" href="<?= $data['url'] ?>"><?= $data['title'] ?></a></h2>
|
<h2><a rel="external" href="<?= $data['url'] ?>"><?= array_shift($data['titles']) ?></a></h2>
|
||||||
<?php if ( ! empty($data['jp_title'])): ?>
|
<?php foreach ($data['titles'] as $title): ?>
|
||||||
<h3><?= $data['jp_title'] ?></h3>
|
<h3><?= $title ?></h3>
|
||||||
<?php endif ?>
|
<?php endforeach ?>
|
||||||
<?php if( ! empty($data['en_title'] && $data['en_title'] !== $data['title'])): ?>
|
|
||||||
<h3><?= $data['en_title'] ?></h3>
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<p><?= nl2br($data['synopsis']) ?></p>
|
<p><?= nl2br($data['synopsis']) ?></p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
<h3><?= $escape->html($item['anime']['title']) ?></h3>
|
<h3><?= $escape->html(array_shift($item['anime']['titles'])) ?></h3>
|
||||||
<?php if($item['anime']['alternate_title'] != ""): ?>
|
<?php foreach($item['anime']['titles'] as $title): ?>
|
||||||
<h4><?= $escape->html($item['anime']['alternate_title']) ?></h4>
|
<h4><?= $escape->html($title) ?></h4>
|
||||||
<?php endif ?>
|
<?php endforeach ?>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<article class="media">
|
<article class="media">
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach($items as $item): ?>
|
<?php foreach($items as $item): ?>
|
||||||
<?php if ($item['private']) && ! $auth->is_authenticated()) continue; ?>
|
<?php if ($item['private'] && ! $auth->is_authenticated()) continue; ?>
|
||||||
<tr id="a-<?= $item['id'] ?>">
|
<tr id="a-<?= $item['id'] ?>">
|
||||||
<?php if ($auth->is_authenticated()): ?>
|
<?php if ($auth->is_authenticated()): ?>
|
||||||
<td>
|
<td>
|
||||||
@ -35,36 +35,38 @@
|
|||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<td class="justify">
|
<td class="justify">
|
||||||
<a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]) ?>">
|
<a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]) ?>">
|
||||||
<?= $item['anime']['title'] ?>
|
<?= array_shift($item['anime']['titles']) ?>
|
||||||
</a>
|
</a>
|
||||||
<?= ( ! empty($item['anime']['alternate_title'])) ? " <br /> " . $item['anime']['alternate_title'] : "" ?>
|
<?php foreach($item['anime']['titles'] as $title): ?>
|
||||||
|
<br /><?= $title ?>
|
||||||
|
<?php endforeach ?>
|
||||||
</td>
|
</td>
|
||||||
<td class="align_left"><?= $item['airing']['status'] ?></td>
|
<td><?= $item['airing']['status'] ?></td>
|
||||||
<td><?= $item['user_rating'] ?> / 10 </td>
|
<td><?= $item['user_rating'] ?> / 10 </td>
|
||||||
<td><?= $item['anime']['type'] ?></td>
|
<td><?= $item['anime']['type'] ?></td>
|
||||||
<td class="align_left" id="<?= $item['anime']['slug'] ?>">
|
<td id="<?= $item['anime']['slug'] ?>">
|
||||||
Episodes: <br />
|
Episodes: <br />
|
||||||
<span class="completed_number"><?= $item['episodes']['watched'] ?></span> / <span class="total_number"><?= $item['episodes']['total'] ?></span>
|
<span class="completed_number"><?= $item['episodes']['watched'] ?></span> / <span class="total_number"><?= $item['episodes']['total'] ?></span>
|
||||||
</td>
|
</td>
|
||||||
<td><?= $item['anime']['age_rating'] ?></td>
|
<td><?= $item['anime']['age_rating'] ?></td>
|
||||||
<td>
|
<td>
|
||||||
|
<ul>
|
||||||
<?php if ($item['rewatched'] > 0): ?>
|
<?php if ($item['rewatched'] > 0): ?>
|
||||||
Rewatched <?= $item['rewatched'] ?> time(s)<br />
|
<li>Rewatched <?= $item['rewatched'] ?> time(s)</li>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php $attr_list = []; ?>
|
|
||||||
<?php foreach(['private','rewatching'] as $attr): ?>
|
<?php foreach(['private','rewatching'] as $attr): ?>
|
||||||
<?php if($item[$attr]): ?>
|
<?php if($item[$attr]): ?>
|
||||||
<?php $attr_list[] = ucfirst($attr); ?>
|
<li><?= ucfirst($attr); ?></li>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<?= implode(', ', $attr_list); ?>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<p><?= $escape->html($item['notes']) ?></p>
|
<p><?= $escape->html($item['notes']) ?></p>
|
||||||
</td>
|
</td>
|
||||||
<td class="align_left">
|
<td class="align_left">
|
||||||
<?php sort($item['anime']['genres']) ?>
|
<?php sort($item['anime']['genres']) ?>
|
||||||
<?= join(', ', $item['anime']['genres']) ?>
|
<?= implode(', ', $item['anime']['genres']) ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<main>
|
<main>
|
||||||
<?php /* if ($auth->is_authenticated()): ?>
|
<?php if ($auth->is_authenticated()): ?>
|
||||||
<a class="bracketed" href="<?= $urlGenerator->url('manga/add') ?>">Add Item</a>
|
<a class="bracketed" href="<?= $urlGenerator->url('manga/add') ?>">Add Item</a>
|
||||||
<?php endif */ ?>
|
<?php endif ?>
|
||||||
<?php if (empty($sections)): ?>
|
<?php if (empty($sections)): ?>
|
||||||
<h3>There's nothing here!</h3>
|
<h3>There's nothing here!</h3>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
@ -11,26 +11,28 @@
|
|||||||
<section class="media-wrap">
|
<section class="media-wrap">
|
||||||
<?php foreach($items as $item): ?>
|
<?php foreach($items as $item): ?>
|
||||||
<article class="media" id="manga-<?= $item['id'] ?>">
|
<article class="media" id="manga-<?= $item['id'] ?>">
|
||||||
<?php /*if ($auth->is_authenticated()): ?>
|
<?php if ($auth->is_authenticated()): ?>
|
||||||
<div class="edit_buttons" hidden>
|
<div class="edit_buttons" hidden>
|
||||||
<button class="plus_one_chapter">+1 Chapter</button>
|
<button class="plus_one_chapter">+1 Chapter</button>
|
||||||
</div>
|
</div>
|
||||||
<?php endif */ ?>
|
<?php endif ?>
|
||||||
<img src="<?= $escape->attr($item['manga']['image']) ?>" />
|
<img src="<?= $escape->attr($item['manga']['image']) ?>" />
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<a href="<?= $url->generate('manga.details', ['id' => $item['manga']['slug']]) ?>">
|
<a href="<?= $url->generate('manga.details', ['id' => $item['manga']['slug']]) ?>">
|
||||||
<?= $escape->html($item['manga']['title']) ?>
|
<?= $escape->html(array_shift($item['manga']['titles'])) ?>
|
||||||
<?= (isset($item['manga']['alternate_title'])) ? "<br />({$item['manga']['alternate_title']})" : ""; ?>
|
<?php foreach($item['manga']['titles'] as $title): ?>
|
||||||
|
<br /><small><?= $title ?></small>
|
||||||
|
<?php endforeach ?>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="table">
|
<div class="table">
|
||||||
<?php /*if ($auth->is_authenticated()): ?>
|
<?php if ($auth->is_authenticated()): ?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="edit">
|
<span class="edit">
|
||||||
<a class="bracketed" title="Edit information about this manga" href="<?= $urlGenerator->url("manga/edit/{$item['id']}/{$name}") ?>">Edit</a>
|
<a class="bracketed" title="Edit information about this manga" href="<?= $urlGenerator->url("manga/edit/{$item['id']}/{$name}") ?>">Edit</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<?php endif */ ?>
|
<?php endif ?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="user_rating">Rating: <?= $item['user_rating'] ?> / 10</div>
|
<div class="user_rating">Rating: <?= $item['user_rating'] ?> / 10</div>
|
||||||
</div>
|
</div>
|
||||||
@ -53,6 +55,6 @@
|
|||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</main>
|
</main>
|
||||||
<?php /*if ($auth->is_authenticated()): ?>
|
<?php if ($auth->is_authenticated()): ?>
|
||||||
<script src="<?= $urlGenerator->asset_url('js.php/g/edit') ?>"></script>
|
<script src="<?= $urlGenerator->asset_url('js.php/g/edit') ?>"></script>
|
||||||
<?php endif*/ ?>
|
<?php endif ?>
|
@ -1,19 +1,18 @@
|
|||||||
<?php if ($auth->is_authenticated()): ?>
|
<?php if ($auth->is_authenticated()): ?>
|
||||||
<main>
|
<main>
|
||||||
<h1>
|
<h1>
|
||||||
Edit <?= $item['manga']['title'] ?>
|
Edit <?= $item['manga']['titles'][0] ?>
|
||||||
<?= ($item['manga']['alternate_title'] != "") ? "({$item['manga']['alternate_title']})" : ""; ?>
|
|
||||||
</h1>
|
</h1>
|
||||||
<form action="<?= $action ?>" method="post">
|
<form action="<?= $action ?>" method="post">
|
||||||
<table class="form">
|
<table class="form">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
<h3><?= $escape->html($item['manga']['title']) ?></h3>
|
<h3><?= $escape->html(array_shift($item['manga']['titles'])) ?></h3>
|
||||||
<?php if($item['manga']['alternate_title'] != ""): ?>
|
<?php foreach($item['manga']['titles'] as $title): ?>
|
||||||
<h4><?= $escape->html($item['manga']['alternate_title']) ?></h4>
|
<h4><?= $escape->html($title) ?></h4>
|
||||||
<?php endif ?>
|
<?php endforeach ?>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<article class="media">
|
<article class="media">
|
||||||
<?= $helper->img($item['manga']['image']); ?>
|
<?= $helper->img($item['manga']['image']); ?>
|
||||||
@ -45,12 +44,12 @@
|
|||||||
<input type="number" min="0" name="chapters_read" id="chapters_read" value="<?= $item['chapters']['read'] ?>" /> / <?= $item['chapters']['total'] ?>
|
<input type="number" min="0" name="chapters_read" id="chapters_read" value="<?= $item['chapters']['read'] ?>" /> / <?= $item['chapters']['total'] ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<? /*<tr>
|
||||||
<td><label for="volumes_read">Volumes Read</label></td>
|
<td><label for="volumes_read">Volumes Read</label></td>
|
||||||
<td>
|
<td>
|
||||||
<input type="number" min="0" name="volumes_read" id="volumes_read" value="<?= $item['volumes']['read'] ?>" /> / <?= $item['volumes']['total'] ?>
|
<input type="number" min="0" name="volumes_read" id="volumes_read" value="<?= $item['volumes']['read'] ?>" /> / <?= $item['volumes']['total'] ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr> */ ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="rereading_flag">Rereading?</label></td>
|
<td><label for="rereading_flag">Rereading?</label></td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -10,9 +10,9 @@
|
|||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<?php /*if ($auth->is_authenticated()): ?>
|
<?php if ($auth->is_authenticated()): ?>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<?php endif*/ ?>
|
<?php endif ?>
|
||||||
<th>Title</th>
|
<th>Title</th>
|
||||||
<th>Rating</th>
|
<th>Rating</th>
|
||||||
<th>Completed Chapters</th>
|
<th>Completed Chapters</th>
|
||||||
@ -23,16 +23,18 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach($items as $item): ?>
|
<?php foreach($items as $item): ?>
|
||||||
<tr id="manga-<?= $item['id'] ?>">
|
<tr id="manga-<?= $item['id'] ?>">
|
||||||
<?php /*if($auth->is_authenticated()): ?>
|
<?php if($auth->is_authenticated()): ?>
|
||||||
<td>
|
<td>
|
||||||
<a class="bracketed" href="<?= $urlGenerator->url("manga/edit/{$item['id']}/{$name}") ?>">Edit</a>
|
<a class="bracketed" href="<?= $urlGenerator->url("manga/edit/{$item['id']}/{$name}") ?>">Edit</a>
|
||||||
</td>
|
</td>
|
||||||
<?php endif*/ ?>
|
<?php endif ?>
|
||||||
<td class="align_left">
|
<td class="align_left">
|
||||||
<a href="<?= $url->generate('manga.details', ['id' => $item['manga']['slug']]) ?>">
|
<a href="<?= $url->generate('manga.details', ['id' => $item['manga']['slug']]) ?>">
|
||||||
<?= $item['manga']['title'] ?>
|
<?= array_shift($item['manga']['titles']) ?>
|
||||||
</a>
|
</a>
|
||||||
<?= ( ! is_null($item['manga']['alternate_title'])) ? " · " . $item['manga']['alternate_title'] : "" ?>
|
<?php foreach($item['manga']['titles'] as $title): ?>
|
||||||
|
<br /><?= $title ?>
|
||||||
|
<?php endforeach ?>
|
||||||
</td>
|
</td>
|
||||||
<td><?= $item['user_rating'] ?> / 10</td>
|
<td><?= $item['user_rating'] ?> / 10</td>
|
||||||
<td><?= $item['chapters']['read'] ?> / <?= $item['chapters']['total'] ?></td>
|
<td><?= $item['chapters']['read'] ?> / <?= $item['chapters']['total'] ?></td>
|
||||||
|
@ -53,12 +53,11 @@ $whoops = new Run();
|
|||||||
$defaultHandler = new PrettyPageHandler();
|
$defaultHandler = new PrettyPageHandler();
|
||||||
$whoops->pushHandler($defaultHandler);
|
$whoops->pushHandler($defaultHandler);
|
||||||
|
|
||||||
// Set up json handler for ajax errors
|
|
||||||
//$jsonHandler = new JsonResponseHandler();
|
|
||||||
//$whoops->pushHandler($jsonHandler);
|
|
||||||
|
|
||||||
// Register as the error handler
|
// Register as the error handler
|
||||||
$whoops->register();
|
if (array_key_exists('whoops', $_GET))
|
||||||
|
{
|
||||||
|
$whoops->register();
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Dependency Injection setup
|
// Dependency Injection setup
|
||||||
|
@ -1085,7 +1085,9 @@ a:hover, a:active {
|
|||||||
display:block;
|
display:block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media > .name > a {
|
.media > .name a,
|
||||||
|
.media > .name a small
|
||||||
|
{
|
||||||
background:none;
|
background:none;
|
||||||
color:#fff;
|
color:#fff;
|
||||||
text-shadow:1px 2px 1px rgba(0, 0, 0, .85);
|
text-shadow:1px 2px 1px rgba(0, 0, 0, .85);
|
||||||
|
@ -354,7 +354,9 @@ a:hover, a:active {
|
|||||||
display:block;
|
display:block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media > .name > a {
|
.media > .name a,
|
||||||
|
.media > .name a small
|
||||||
|
{
|
||||||
background:none;
|
background:none;
|
||||||
color:#fff;
|
color:#fff;
|
||||||
text-shadow: var(--shadow);
|
text-shadow: var(--shadow);
|
||||||
|
@ -16,13 +16,20 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API;
|
namespace Aviat\AnimeClient\API;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Kitsu\Enum\AnimeWatchingStatus;
|
use Aviat\AnimeClient\API\Kitsu\Enum\{AnimeAiringStatus, AnimeWatchingStatus};
|
||||||
|
use DateTimeImmutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constants and mappings for the Kitsu API
|
* Constants and mappings for the Kitsu API
|
||||||
*/
|
*/
|
||||||
class Kitsu {
|
class Kitsu {
|
||||||
|
const AUTH_URL = 'https://kitsu.io/api/oauth/token';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of Kitsu status to label for select menus
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public static function getStatusToSelectMap()
|
public static function getStatusToSelectMap()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@ -33,4 +40,147 @@ class Kitsu {
|
|||||||
AnimeWatchingStatus::DROPPED => 'Dropped'
|
AnimeWatchingStatus::DROPPED => 'Dropped'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether an anime is airing, finished airing, or has not yet aired
|
||||||
|
*
|
||||||
|
* @param string $startDate
|
||||||
|
* @param string $endDate
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getAiringStatus(string $startDate = null, string $endDate = null): string
|
||||||
|
{
|
||||||
|
$startAirDate = new DateTimeImmutable($startDate ?? 'tomorrow');
|
||||||
|
$endAirDate = new DateTimeImmutable($endDate ?? 'tomorrow');
|
||||||
|
$now = new DateTimeImmutable();
|
||||||
|
|
||||||
|
$isDoneAiring = $now > $endAirDate;
|
||||||
|
$isCurrentlyAiring = ($now > $startAirDate) && ! $isDoneAiring;
|
||||||
|
|
||||||
|
switch (true)
|
||||||
|
{
|
||||||
|
case $isCurrentlyAiring:
|
||||||
|
return AnimeAiringStatus::AIRING;
|
||||||
|
|
||||||
|
case $isDoneAiring:
|
||||||
|
return AnimeAiringStatus::FINISHED_AIRING;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return AnimeAiringStatus::NOT_YET_AIRED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter out duplicate and very similar names from
|
||||||
|
*
|
||||||
|
* @param array $data The 'attributes' section of the api data response
|
||||||
|
* @return array List of alternate titles
|
||||||
|
*/
|
||||||
|
public static function filterTitles(array $data): array
|
||||||
|
{
|
||||||
|
// The 'canonical' title is always returned
|
||||||
|
$valid = [$data['canonicalTitle']];
|
||||||
|
|
||||||
|
if (array_key_exists('titles', $data))
|
||||||
|
{
|
||||||
|
foreach($data['titles'] as $alternateTitle)
|
||||||
|
{
|
||||||
|
if (self::titleIsUnique($alternateTitle, $valid))
|
||||||
|
{
|
||||||
|
$valid[] = $alternateTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorganizes 'included' data to be keyed by
|
||||||
|
* type => [
|
||||||
|
* id => data/attributes,
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* @param array $includes
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function organizeIncludes(array $includes): array
|
||||||
|
{
|
||||||
|
$organized = [];
|
||||||
|
|
||||||
|
foreach ($includes as $item)
|
||||||
|
{
|
||||||
|
$type = $item['type'];
|
||||||
|
$id = $item['id'];
|
||||||
|
$organized[$type] = $organized[$type] ?? [];
|
||||||
|
$organized[$type][$id] = $item['attributes'];
|
||||||
|
|
||||||
|
if (array_key_exists('relationships', $item))
|
||||||
|
{
|
||||||
|
$organized[$type][$id]['relationships'] = self::organizeRelationships($item['relationships']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $organized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorganize relationship mappings to make them simpler to use
|
||||||
|
*
|
||||||
|
* Remove verbose structure, and just map:
|
||||||
|
* type => [ idArray ]
|
||||||
|
*
|
||||||
|
* @param array $relationships
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function organizeRelationships(array $relationships): array
|
||||||
|
{
|
||||||
|
$organized = [];
|
||||||
|
|
||||||
|
foreach($relationships as $key => $data)
|
||||||
|
{
|
||||||
|
if ( ! array_key_exists('data', $data))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$organized[$key] = $organized[$key] ?? [];
|
||||||
|
|
||||||
|
foreach ($data['data'] as $item)
|
||||||
|
{
|
||||||
|
$organized[$key][] = $item['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $organized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if an alternate title is unique enough to list
|
||||||
|
*
|
||||||
|
* @param string $title
|
||||||
|
* @param array $existingTitles
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private static function titleIsUnique(string $title = null, array $existingTitles): bool
|
||||||
|
{
|
||||||
|
if (empty($title))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($existingTitles as $existing)
|
||||||
|
{
|
||||||
|
$isSubset = stripos($existing, $title) !== FALSE;
|
||||||
|
$diff = levenshtein($existing, $title);
|
||||||
|
$onlydifferentCase = (mb_strtolower($existing) === mb_strtolower($title));
|
||||||
|
|
||||||
|
if ($diff < 3 || $isSubset || $onlydifferentCase)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,108 +1,108 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
/**
|
/**
|
||||||
* Anime List Client
|
* Anime List Client
|
||||||
*
|
*
|
||||||
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7
|
* PHP version 7
|
||||||
*
|
*
|
||||||
* @package AnimeListClient
|
* @package AnimeListClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2016 Timothy J. Warren
|
* @copyright 2015 - 2016 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.0
|
* @version 4.0
|
||||||
* @link https://github.com/timw4mail/HummingBirdAnimeClient
|
* @link https://github.com/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu;
|
namespace Aviat\AnimeClient\API\Kitsu;
|
||||||
|
|
||||||
use Aviat\AnimeClient\AnimeClient;
|
use Aviat\AnimeClient\AnimeClient;
|
||||||
use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
|
use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kitsu API Authentication
|
* Kitsu API Authentication
|
||||||
*/
|
*/
|
||||||
class Auth {
|
class Auth {
|
||||||
|
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Anime API Model
|
* Anime API Model
|
||||||
*
|
*
|
||||||
* @var \Aviat\AnimeClient\API\Kitsu\Model
|
* @var \Aviat\AnimeClient\API\Kitsu\Model
|
||||||
*/
|
*/
|
||||||
protected $model;
|
protected $model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Session object
|
* Session object
|
||||||
*
|
*
|
||||||
* @var Aura\Session\Segment
|
* @var Aura\Session\Segment
|
||||||
*/
|
*/
|
||||||
protected $segment;
|
protected $segment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container
|
* @param ContainerInterface $container
|
||||||
*/
|
*/
|
||||||
public function __construct(ContainerInterface $container)
|
public function __construct(ContainerInterface $container)
|
||||||
{
|
{
|
||||||
$this->setContainer($container);
|
$this->setContainer($container);
|
||||||
$this->segment = $container->get('session')
|
$this->segment = $container->get('session')
|
||||||
->getSegment(AnimeClient::SESSION_SEGMENT);
|
->getSegment(AnimeClient::SESSION_SEGMENT);
|
||||||
$this->model = $container->get('kitsu-model');
|
$this->model = $container->get('kitsu-model');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the appropriate authentication call,
|
* Make the appropriate authentication call,
|
||||||
* and save the resulting auth token if successful
|
* and save the resulting auth token if successful
|
||||||
*
|
*
|
||||||
* @param string $password
|
* @param string $password
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function authenticate($password)
|
public function authenticate($password)
|
||||||
{
|
{
|
||||||
$config = $this->container->get('config');
|
$config = $this->container->get('config');
|
||||||
$username = $config->get(['kitsu_username']);
|
$username = $config->get(['kitsu_username']);
|
||||||
$auth_token = $this->model->authenticate($username, $password);
|
$auth_token = $this->model->authenticate($username, $password);
|
||||||
|
|
||||||
if (FALSE !== $auth_token)
|
if (FALSE !== $auth_token)
|
||||||
{
|
{
|
||||||
$this->segment->set('auth_token', $auth_token);
|
$this->segment->set('auth_token', $auth_token);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the current user is authenticated
|
* Check whether the current user is authenticated
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function is_authenticated()
|
public function is_authenticated()
|
||||||
{
|
{
|
||||||
return ($this->get_auth_token() !== FALSE);
|
return ($this->get_auth_token() !== FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear authentication values
|
* Clear authentication values
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function logout()
|
public function logout()
|
||||||
{
|
{
|
||||||
$this->segment->clear();
|
$this->segment->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the authentication token from the session
|
* Retrieve the authentication token from the session
|
||||||
*
|
*
|
||||||
* @return string|false
|
* @return string|false
|
||||||
*/
|
*/
|
||||||
public function get_auth_token()
|
public function get_auth_token()
|
||||||
{
|
{
|
||||||
return $this->segment->get('auth_token', FALSE);
|
return $this->segment->get('auth_token', FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// End of KitsuAuth.php
|
// End of KitsuAuth.php
|
@ -17,6 +17,7 @@
|
|||||||
namespace Aviat\AnimeClient\API\Kitsu;
|
namespace Aviat\AnimeClient\API\Kitsu;
|
||||||
|
|
||||||
use Aviat\AnimeClient\AnimeClient;
|
use Aviat\AnimeClient\AnimeClient;
|
||||||
|
use Aviat\AnimeClient\API\Kitsu as K;
|
||||||
use Aviat\AnimeClient\API\Kitsu\Transformer\{
|
use Aviat\AnimeClient\API\Kitsu\Transformer\{
|
||||||
AnimeTransformer, AnimeListTransformer, MangaTransformer, MangaListTransformer
|
AnimeTransformer, AnimeListTransformer, MangaTransformer, MangaListTransformer
|
||||||
};
|
};
|
||||||
@ -92,7 +93,7 @@ class KitsuModel {
|
|||||||
*/
|
*/
|
||||||
public function authenticate(string $username, string $password)
|
public function authenticate(string $username, string $password)
|
||||||
{
|
{
|
||||||
$data = $this->postRequest(AnimeClient::KITSU_AUTH_URL, [
|
$data = $this->postRequest(K::AUTH_URL, [
|
||||||
'form_params' => [
|
'form_params' => [
|
||||||
'grant_type' => 'password',
|
'grant_type' => 'password',
|
||||||
'username' => $username,
|
'username' => $username,
|
||||||
@ -164,7 +165,7 @@ class KitsuModel {
|
|||||||
'media_type' => 'Anime',
|
'media_type' => 'Anime',
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
],
|
],
|
||||||
'include' => 'media',
|
'include' => 'media,media.genres',
|
||||||
'page' => [
|
'page' => [
|
||||||
'offset' => 0,
|
'offset' => 0,
|
||||||
'limit' => 200
|
'limit' => 200
|
||||||
@ -174,10 +175,21 @@ class KitsuModel {
|
|||||||
];
|
];
|
||||||
|
|
||||||
$data = $this->getRequest('library-entries', $options);
|
$data = $this->getRequest('library-entries', $options);
|
||||||
|
$included = K::organizeIncludes($data['included']);
|
||||||
|
/*?><pre><?= print_r($included, TRUE) ?></pre><?php*/
|
||||||
|
|
||||||
foreach($data['data'] as $i => &$item)
|
foreach($data['data'] as $i => &$item)
|
||||||
{
|
{
|
||||||
$item['anime'] = $data['included'][$i];
|
$item['anime'] = $included['anime'][$item['relationships']['media']['data']['id']];
|
||||||
|
|
||||||
|
$animeGenres = $item['anime']['relationships']['genres'];
|
||||||
|
|
||||||
|
foreach($animeGenres as $id)
|
||||||
|
{
|
||||||
|
$item['genres'][] = $included['genres'][$id]['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// $item['genres'] = array_pluck($genres, 'name');
|
||||||
}
|
}
|
||||||
|
|
||||||
$transformed = $this->animeListTransformer->transformCollection($data['data']);
|
$transformed = $this->animeListTransformer->transformCollection($data['data']);
|
||||||
@ -246,7 +258,9 @@ class KitsuModel {
|
|||||||
'filter' => [
|
'filter' => [
|
||||||
'slug' => $slug
|
'slug' => $slug
|
||||||
],
|
],
|
||||||
'include' => 'genres,mappings,streamingLinks',
|
'include' => ($type === 'anime')
|
||||||
|
? 'genres,mappings,streamingLinks'
|
||||||
|
: 'genres,mappings',
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ namespace Aviat\AnimeClient\API\Kitsu;
|
|||||||
|
|
||||||
use Aviat\AnimeClient\AnimeClient;
|
use Aviat\AnimeClient\AnimeClient;
|
||||||
use Aviat\AnimeClient\API\GuzzleTrait;
|
use Aviat\AnimeClient\API\GuzzleTrait;
|
||||||
use Aviat\Ion\Di\ContainerAware;
|
|
||||||
use Aviat\Ion\Json;
|
use Aviat\Ion\Json;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
use GuzzleHttp\Cookie\CookieJar;
|
use GuzzleHttp\Cookie\CookieJar;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\API\Kitsu;
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,49 +35,34 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
{
|
{
|
||||||
/* ?><pre><?= print_r($item, TRUE) ?></pre><?php
|
/* ?><pre><?= print_r($item, TRUE) ?></pre><?php
|
||||||
// die(); */
|
// die(); */
|
||||||
$anime =& $item['anime'];
|
$anime = $item['anime']['attributes'] ?? $item['anime'];
|
||||||
$genres = $item['anime']['genres'] ?? [];
|
$genres = $item['genres'] ?? [];
|
||||||
|
|
||||||
$rating = (int) 2 * $item['attributes']['rating'];
|
$rating = (int) 2 * $item['attributes']['rating'];
|
||||||
|
|
||||||
$total_episodes = array_key_exists('episodeCount', $item['anime']['attributes'])
|
$total_episodes = array_key_exists('episodeCount', $anime)
|
||||||
? (int) $anime['attributes']['episodeCount']
|
? (int) $anime['episodeCount']
|
||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
$alternate_title = NULL;
|
|
||||||
if (array_key_exists('titles', $item['anime']) && array_key_exists('en_jp', $anime['titles']))
|
|
||||||
{
|
|
||||||
// If the alternate title is very similar, or
|
|
||||||
// a subset of the main title, don't list the
|
|
||||||
// alternate title
|
|
||||||
$not_subset = stripos($anime['canonicalTitle'], $anime['titles']['en_jp']) === FALSE;
|
|
||||||
$diff = levenshtein($anime['canonicalTitle'], $anime['titles']['en_jp'] ?? '');
|
|
||||||
if ($not_subset && $diff >= 5)
|
|
||||||
{
|
|
||||||
$alternate_title = $anime['titles']['en_jp'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
'episodes' => [
|
'episodes' => [
|
||||||
'watched' => $item['attributes']['progress'],
|
'watched' => $item['attributes']['progress'],
|
||||||
'total' => $total_episodes,
|
'total' => $total_episodes,
|
||||||
'length' => $anime['attributes']['episodeLength'],
|
'length' => $anime['episodeLength'],
|
||||||
],
|
],
|
||||||
'airing' => [
|
'airing' => [
|
||||||
'status' => $anime['status'] ?? '',
|
'status' => Kitsu::getAiringStatus($anime['startDate'], $anime['endDate']),
|
||||||
'started' => $anime['attributes']['startDate'],
|
'started' => $anime['startDate'],
|
||||||
'ended' => $anime['attributes']['endDate']
|
'ended' => $anime['endDate']
|
||||||
],
|
],
|
||||||
'anime' => [
|
'anime' => [
|
||||||
'age_rating' => $anime['attributes']['ageRating'],
|
'age_rating' => $anime['ageRating'],
|
||||||
'title' => $anime['attributes']['canonicalTitle'],
|
'titles' => Kitsu::filterTitles($anime),
|
||||||
'alternate_title' => $alternate_title,
|
'slug' => $anime['slug'],
|
||||||
'slug' => $anime['attributes']['slug'],
|
'url' => $anime['url'] ?? '',
|
||||||
'url' => $anime['attributes']['url'] ?? '',
|
'type' => $this->string($anime['showType'])->upperCaseFirst()->__toString(),
|
||||||
'type' => $anime['attributes']['showType'],
|
'image' => $anime['posterImage']['small'],
|
||||||
'image' => $anime['attributes']['posterImage']['small'],
|
|
||||||
'genres' => $genres,
|
'genres' => $genres,
|
||||||
],
|
],
|
||||||
'watching_status' => $item['attributes']['status'],
|
'watching_status' => $item['attributes']['status'],
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\API\Kitsu;
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,15 +33,12 @@ class AnimeTransformer extends AbstractTransformer {
|
|||||||
*/
|
*/
|
||||||
public function transform($item)
|
public function transform($item)
|
||||||
{
|
{
|
||||||
?><pre><?= print_r($item, TRUE) ?></pre><?php
|
|
||||||
|
|
||||||
$item['genres'] = $item['genres'] ?? [];
|
$item['genres'] = $item['genres'] ?? [];
|
||||||
sort($item['genres']);
|
sort($item['genres']);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'title' => $item['canonicalTitle'],
|
'titles' => Kitsu::filterTitles($item),
|
||||||
'en_title' => $item['titles']['en_jp'],
|
'status' => Kitsu::getAiringStatus($item['startDate'], $item['endDate']),
|
||||||
'jp_title' => $item['titles']['ja_jp'],
|
|
||||||
'cover_image' => $item['posterImage']['small'],
|
'cover_image' => $item['posterImage']['small'],
|
||||||
'show_type' => $item['showType'],
|
'show_type' => $item['showType'],
|
||||||
'episode_count' => $item['episodeCount'],
|
'episode_count' => $item['episodeCount'],
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\API\Kitsu;
|
||||||
use Aviat\Ion\StringWrapper;
|
use Aviat\Ion\StringWrapper;
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ class MangaListTransformer extends AbstractTransformer {
|
|||||||
*/
|
*/
|
||||||
public function transform($item)
|
public function transform($item)
|
||||||
{
|
{
|
||||||
|
/*?><pre><?= print_r($item, TRUE) ?></pre><?php*/
|
||||||
$manga =& $item['manga'];
|
$manga =& $item['manga'];
|
||||||
|
|
||||||
$rating = (is_numeric($item['attributes']['rating']))
|
$rating = (is_numeric($item['attributes']['rating']))
|
||||||
@ -59,10 +61,10 @@ class MangaListTransformer extends AbstractTransformer {
|
|||||||
'total' => $total_volumes
|
'total' => $total_volumes
|
||||||
],
|
],
|
||||||
'manga' => [
|
'manga' => [
|
||||||
'title' => $manga['attributes']['canonicalTitle'],
|
'titles' => Kitsu::filterTitles($manga['attributes']),
|
||||||
'alternate_title' => NULL,
|
'alternate_title' => NULL,
|
||||||
'slug' => $manga['id'],
|
'slug' => $manga['attributes']['slug'],
|
||||||
'url' => 'https://kitsu.io/manga/' . $manga['id'],
|
'url' => 'https://kitsu.io/manga/' . $manga['attributes']['slug'],
|
||||||
'type' => $manga['attributes']['mangaType'],
|
'type' => $manga['attributes']['mangaType'],
|
||||||
'image' => $manga['attributes']['posterImage']['small'],
|
'image' => $manga['attributes']['posterImage']['small'],
|
||||||
'genres' => [], //$manga['genres'],
|
'genres' => [], //$manga['genres'],
|
||||||
|
@ -25,7 +25,6 @@ define('SRC_DIR', realpath(__DIR__));
|
|||||||
*/
|
*/
|
||||||
class AnimeClient {
|
class AnimeClient {
|
||||||
|
|
||||||
const KITSU_AUTH_URL = 'https://kitsu.io/api/oauth/token';
|
|
||||||
const SESSION_SEGMENT = 'Aviat\AnimeClient\Auth';
|
const SESSION_SEGMENT = 'Aviat\AnimeClient\Auth';
|
||||||
const DEFAULT_CONTROLLER_NAMESPACE = 'Aviat\AnimeClient\Controller';
|
const DEFAULT_CONTROLLER_NAMESPACE = 'Aviat\AnimeClient\Controller';
|
||||||
const DEFAULT_CONTROLLER = 'Aviat\AnimeClient\Controller\Anime';
|
const DEFAULT_CONTROLLER = 'Aviat\AnimeClient\Controller\Anime';
|
||||||
|
@ -293,7 +293,7 @@ class Anime extends BaseController {
|
|||||||
$data = $this->model->getAnime($anime_id);
|
$data = $this->model->getAnime($anime_id);
|
||||||
|
|
||||||
$this->outputHTML('anime/details', [
|
$this->outputHTML('anime/details', [
|
||||||
'title' => 'Anime · ' . $data['title'],
|
'title' => 'Anime · ' . $data['titles'][0],
|
||||||
'data' => $data,
|
'data' => $data,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ class Manga extends Controller {
|
|||||||
public function edit($id, $status = "All")
|
public function edit($id, $status = "All")
|
||||||
{
|
{
|
||||||
$this->set_session_redirect();
|
$this->set_session_redirect();
|
||||||
$item = $this->model->get_library_item($id, $status);
|
$item = $this->model->getLibraryItem($id);
|
||||||
$title = $this->config->get('whose_list') . "'s Manga List · Edit";
|
$title = $this->config->get('whose_list') . "'s Manga List · Edit";
|
||||||
|
|
||||||
$this->outputHTML('manga/edit', [
|
$this->outputHTML('manga/edit', [
|
||||||
|
@ -69,7 +69,7 @@ class API extends Model {
|
|||||||
|
|
||||||
foreach ($array as $key => $item)
|
foreach ($array as $key => $item)
|
||||||
{
|
{
|
||||||
$sort[$key] = $item[$sort_key]['title'];
|
$sort[$key] = $item[$sort_key]['titles'][0];
|
||||||
}
|
}
|
||||||
|
|
||||||
array_multisort($sort, SORT_ASC, $array);
|
array_multisort($sort, SORT_ASC, $array);
|
||||||
|
@ -83,6 +83,18 @@ class Manga extends API
|
|||||||
return $this->kitsuModel->getManga($manga_id);
|
return $this->kitsuModel->getManga($manga_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get information about a specific list item
|
||||||
|
* for editing/updating that item
|
||||||
|
*
|
||||||
|
* @param string $itemId
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getLibraryItem(string $itemId): array
|
||||||
|
{
|
||||||
|
return $this->kitsuModel->getListItem($itemId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map transformed anime data to be organized by reading status
|
* Map transformed anime data to be organized by reading status
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user