Merge remote-tracking branch 'origin/develop'
This commit is contained in:
commit
6df059fe75
@ -3,8 +3,6 @@
|
|||||||
Update your anime/manga list on Kitsu.io and MyAnimeList.net
|
Update your anime/manga list on Kitsu.io and MyAnimeList.net
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/timw4mail/HummingBirdAnimeClient.svg?branch=master)](https://travis-ci.org/timw4mail/HummingBirdAnimeClient)
|
[![Build Status](https://travis-ci.org/timw4mail/HummingBirdAnimeClient.svg?branch=master)](https://travis-ci.org/timw4mail/HummingBirdAnimeClient)
|
||||||
[![build status](https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient/badges/develop/build.svg)](https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient/commits/develop)
|
|
||||||
[![coverage report](https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient/badges/develop/coverage.svg)](https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient/commits/develop)
|
|
||||||
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/timw4mail/HummingBirdAnimeClient/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/timw4mail/HummingBirdAnimeClient/?branch=master)
|
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/timw4mail/HummingBirdAnimeClient/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/timw4mail/HummingBirdAnimeClient/?branch=master)
|
||||||
|
|
||||||
[[Hosted Example](https://list.timshomepage.net)]
|
[[Hosted Example](https://list.timshomepage.net)]
|
||||||
@ -52,12 +50,8 @@ Update your anime/manga list on Kitsu.io and MyAnimeList.net
|
|||||||
* public/images/manga
|
* public/images/manga
|
||||||
5. Make sure the `console` script is executable
|
5. Make sure the `console` script is executable
|
||||||
|
|
||||||
### Using MAL API
|
|
||||||
1. Update `app/config/mal.toml` with your username and password
|
|
||||||
2. Enable MAL api in `app/config/config.toml`
|
|
||||||
|
|
||||||
### Server Setup
|
### Server Setup
|
||||||
|
|
||||||
See the [wiki](https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient/wikis/home)
|
See the [wiki](https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient/wiki)
|
||||||
for more in-depth information
|
for more in-depth information
|
||||||
|
|
||||||
|
@ -8,13 +8,12 @@
|
|||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2017 Timothy J. Warren
|
* @copyright 2015 - 2018 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://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
use const Aviat\AnimeClient\{
|
use const Aviat\AnimeClient\{
|
||||||
DEFAULT_CONTROLLER_METHOD,
|
DEFAULT_CONTROLLER_METHOD,
|
||||||
DEFAULT_CONTROLLER
|
DEFAULT_CONTROLLER
|
||||||
@ -184,6 +183,16 @@ return [
|
|||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Default / Shared routes
|
// Default / Shared routes
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
'anilist-redirect' => [
|
||||||
|
'path' => '/anilist-redirect',
|
||||||
|
'action' => 'anilistRedirect',
|
||||||
|
'controller' => DEFAULT_CONTROLLER,
|
||||||
|
],
|
||||||
|
'anilist-oauth' => [
|
||||||
|
'path' => '/anilist-oauth',
|
||||||
|
'action' => 'anilistCallback',
|
||||||
|
'controller' => DEFAULT_CONTROLLER,
|
||||||
|
],
|
||||||
'image_proxy' => [
|
'image_proxy' => [
|
||||||
'path' => '/public/images/{type}/{file}',
|
'path' => '/public/images/{type}/{file}',
|
||||||
'action' => 'images',
|
'action' => 'images',
|
||||||
|
@ -20,6 +20,7 @@ use Aura\Html\HelperLocatorFactory;
|
|||||||
use Aura\Router\RouterContainer;
|
use Aura\Router\RouterContainer;
|
||||||
use Aura\Session\SessionFactory;
|
use Aura\Session\SessionFactory;
|
||||||
use Aviat\AnimeClient\API\{
|
use Aviat\AnimeClient\API\{
|
||||||
|
Anilist,
|
||||||
Kitsu,
|
Kitsu,
|
||||||
MAL,
|
MAL,
|
||||||
Kitsu\KitsuRequestBuilder,
|
Kitsu\KitsuRequestBuilder,
|
||||||
@ -45,11 +46,14 @@ return function (array $configArray = []) {
|
|||||||
|
|
||||||
$appLogger = new Logger('animeclient');
|
$appLogger = new Logger('animeclient');
|
||||||
$appLogger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/app.log', Logger::NOTICE));
|
$appLogger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/app.log', Logger::NOTICE));
|
||||||
|
$anilistRequestLogger = new Logger('anilist-request');
|
||||||
|
$anilistRequestLogger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/anilist_request.log', Logger::NOTICE));
|
||||||
$kitsuRequestLogger = new Logger('kitsu-request');
|
$kitsuRequestLogger = new Logger('kitsu-request');
|
||||||
$kitsuRequestLogger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/kitsu_request.log', Logger::NOTICE));
|
$kitsuRequestLogger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/kitsu_request.log', Logger::NOTICE));
|
||||||
$malRequestLogger = new Logger('mal-request');
|
$malRequestLogger = new Logger('mal-request');
|
||||||
$malRequestLogger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/mal_request.log', Logger::NOTICE));
|
$malRequestLogger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/mal_request.log', Logger::NOTICE));
|
||||||
$container->setLogger($appLogger);
|
$container->setLogger($appLogger);
|
||||||
|
$container->setLogger($anilistRequestLogger, 'anilist-request');
|
||||||
$container->setLogger($kitsuRequestLogger, 'kitsu-request');
|
$container->setLogger($kitsuRequestLogger, 'kitsu-request');
|
||||||
$container->setLogger($malRequestLogger, 'mal-request');
|
$container->setLogger($malRequestLogger, 'mal-request');
|
||||||
|
|
||||||
|
@ -11,8 +11,5 @@ whose_list = "Tim"
|
|||||||
# do you wish to show the anime collection?
|
# do you wish to show the anime collection?
|
||||||
show_anime_collection = true
|
show_anime_collection = true
|
||||||
|
|
||||||
# do you have a My Anime List account set up in mal.toml?
|
|
||||||
use_mal_api = false
|
|
||||||
|
|
||||||
# path to public directory on the server
|
# path to public directory on the server
|
||||||
asset_dir = "/../../public"
|
asset_dir = "/../../public"
|
@ -1,6 +0,0 @@
|
|||||||
################################################################################
|
|
||||||
# My Anime LIst Integration Config #
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
username = "timw4mail"
|
|
||||||
password = "mysecretpassword"
|
|
@ -13,7 +13,7 @@
|
|||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<br />
|
<br />
|
||||||
<table class="form">
|
<table class="invisible form">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="status">Watching Status</label></td>
|
<td><label for="status">Watching Status</label></td>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<main>
|
<main class="media-list">
|
||||||
<?php if ($auth->isAuthenticated()): ?>
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
<a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a>
|
<a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
@ -24,27 +24,13 @@
|
|||||||
<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['anime']['id']}.jpg") ?>" alt="" />
|
<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['anime']['id']}.jpg") ?>" alt="" />
|
||||||
<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']]); ?>">
|
||||||
<?= array_shift($item['anime']['titles']) ?>
|
<span class="canonical"><?= $item['anime']['title'] ?></span>
|
||||||
<?php foreach ($item['anime']['titles'] as $title): ?>
|
<?php foreach ($item['anime']['titles'] as $title): ?>
|
||||||
<br /><small><?= $title ?></small>
|
<br /><small><?= $title ?></small>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="table">
|
<div class="table">
|
||||||
<?php if ($auth->isAuthenticated()): ?>
|
|
||||||
<div class="row">
|
|
||||||
<span class="edit">
|
|
||||||
<a class="bracketed" title="Edit information about this anime" href="<?=
|
|
||||||
$url->generate('edit', [
|
|
||||||
'controller' => 'anime',
|
|
||||||
'id' => $item['id'],
|
|
||||||
'status' => $item['watching_status']
|
|
||||||
]);
|
|
||||||
?>">Edit</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
<?php if ($item['private'] || $item['rewatching']): ?>
|
<?php if ($item['private'] || $item['rewatching']): ?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<?php foreach(['private', 'rewatching'] as $attr): ?>
|
<?php foreach(['private', 'rewatching'] as $attr): ?>
|
||||||
@ -77,6 +63,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
|
<div class="row">
|
||||||
|
<span class="edit">
|
||||||
|
<a class="bracketed" title="Edit information about this anime" href="<?=
|
||||||
|
$url->generate('edit', [
|
||||||
|
'controller' => 'anime',
|
||||||
|
'id' => $item['id'],
|
||||||
|
'status' => $item['watching_status']
|
||||||
|
]);
|
||||||
|
?>">Edit</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<?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 class="completion">Episodes:
|
<div class="completion">Episodes:
|
||||||
@ -85,7 +85,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="media_type"><?= $escape->html($item['anime']['type']) ?></div>
|
<div class="media_type"><?= $escape->html($item['anime']['show_type']) ?></div>
|
||||||
<div class="airing_status"><?= $escape->html($item['airing']['status']) ?></div>
|
<div class="airing_status"><?= $escape->html($item['airing']['status']) ?></div>
|
||||||
<div class="age_rating"><?= $escape->html($item['anime']['age_rating']) ?></div>
|
<div class="age_rating"><?= $escape->html($item['anime']['age_rating']) ?></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2><a rel="external" href="<?= $show_data['url'] ?>"><?= array_shift($show_data['titles']) ?></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>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
@ -2,23 +2,25 @@
|
|||||||
<main>
|
<main>
|
||||||
<h2>Edit Anime List Item</h2>
|
<h2>Edit Anime List Item</h2>
|
||||||
<form action="<?= $action ?>" method="post">
|
<form action="<?= $action ?>" method="post">
|
||||||
<table class="form">
|
<table class="invisible form">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
<h3><?= $escape->html(array_shift($item['anime']['titles'])) ?></h3>
|
<h3><?= $escape->html($item['anime']['title']) ?></h3>
|
||||||
<?php foreach($item['anime']['titles'] as $title): ?>
|
<?php foreach($item['anime']['titles'] as $title): ?>
|
||||||
<h4><?= $escape->html($title) ?></h4>
|
<h4><?= $escape->html($title) ?></h4>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
|
||||||
<article class="media">
|
|
||||||
<?= $helper->img($urlGenerator->assetUrl('images/anime', "{$item['anime']['id']}.jpg")) ?>
|
|
||||||
</article>
|
|
||||||
</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="9">
|
||||||
|
<article class="media">
|
||||||
|
<?= $helper->img($urlGenerator->assetUrl('images/anime', "{$item['anime']['id']}.jpg")) ?>
|
||||||
|
</article>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="private">Is Private?</label></td>
|
<td><label for="private">Is Private?</label></td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<main>
|
<main class="media-list">
|
||||||
<?php if ($auth->isAuthenticated()): ?>
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
<a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a>
|
<a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
<?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']]) ?>">
|
||||||
<?= array_shift($item['anime']['titles']) ?>
|
<?= $item['anime']['title'] ?>
|
||||||
</a>
|
</a>
|
||||||
<?php foreach ($item['anime']['titles'] as $title): ?>
|
<?php foreach ($item['anime']['titles'] as $title): ?>
|
||||||
<br/><?= $title ?>
|
<br/><?= $title ?>
|
||||||
@ -50,7 +50,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td><?= $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']['show_type'] ?></td>
|
||||||
<td 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>
|
||||||
@ -83,8 +83,8 @@
|
|||||||
<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) ?>
|
||||||
<?= implode(', ', $item['anime']['genres']) ?>
|
<?= implode(', ', $item['anime']->genres) ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<br />
|
<br />
|
||||||
<table class="form">
|
<table class="invisible form">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="media_id">Media</label></td>
|
<td><label for="media_id">Media</label></td>
|
||||||
|
27
app/views/collection/cover-item.php
Normal file
27
app/views/collection/cover-item.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<article class="media" id="a-<?= $item['hummingbird_id'] ?>">
|
||||||
|
<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.jpg") ?>"
|
||||||
|
alt="<?= $item['title'] ?> cover image"/>
|
||||||
|
<div class="name">
|
||||||
|
<a href="<?= $url->generate('anime.details', ['id' => $item['slug']]) ?>">
|
||||||
|
<?= $item['title'] ?>
|
||||||
|
<?= ($item['alternate_title'] != "") ? "<small><br />{$item['alternate_title']}</small>" : ""; ?>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="table">
|
||||||
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
|
<div class="row">
|
||||||
|
<span class="edit">
|
||||||
|
<a class="bracketed"
|
||||||
|
href="<?= $url->generate($collection_type . '.collection.edit.get', [
|
||||||
|
'id' => $item['hummingbird_id']
|
||||||
|
]) ?>">Edit</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
|
<div class="row">
|
||||||
|
<div class="completion">Episodes: <?= $item['episode_count'] ?></div>
|
||||||
|
<div class="media_type"><?= $item['show_type'] ?></div>
|
||||||
|
<div class="age_rating"><?= $item['age_rating'] ?></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
@ -1,44 +1,25 @@
|
|||||||
<main>
|
<main class="media-list">
|
||||||
<?php if ($auth->isAuthenticated()): ?>
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
<a class="bracketed" href="<?= $url->generate($collection_type . '.collection.add.get') ?>">Add Item</a>
|
<a class="bracketed" href="<?= $url->generate($collection_type . '.collection.add.get') ?>">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: ?>
|
||||||
|
<div class="tabs">
|
||||||
|
<?php $i = 0; ?>
|
||||||
<?php foreach ($sections as $name => $items): ?>
|
<?php foreach ($sections as $name => $items): ?>
|
||||||
<section class="status">
|
<input <?= $i === 0 ? 'checked="checked"' : '' ?> type="radio" id="collection-tab-<?= $i ?>" name="collection-tabs" />
|
||||||
|
<label for="collection-tab-<?= $i ?>"><?= $name ?></label>
|
||||||
|
<div class="content">
|
||||||
<h2><?= $name ?></h2>
|
<h2><?= $name ?></h2>
|
||||||
<section class="media-wrap">
|
<section class="media-wrap">
|
||||||
<?php foreach ($items as $item): ?>
|
<?php foreach ($items as $item): ?>
|
||||||
<article class="media" id="a-<?= $item['hummingbird_id'] ?>">
|
<?php include __DIR__ . '/cover-item.php'; ?>
|
||||||
<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.jpg") ?>"
|
|
||||||
alt="<?= $item['title'] ?> cover image" />
|
|
||||||
<div class="name">
|
|
||||||
<a href="<?= $url->generate('anime.details', ['id' => $item['slug']]) ?>">
|
|
||||||
<?= $item['title'] ?>
|
|
||||||
<?= ($item['alternate_title'] != "") ? "<small><br />{$item['alternate_title']}</small>" : ""; ?>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="table">
|
|
||||||
<?php if ($auth->isAuthenticated()): ?>
|
|
||||||
<div class="row">
|
|
||||||
<span class="edit">
|
|
||||||
<a class="bracketed" href="<?= $url->generate($collection_type . '.collection.edit.get', [
|
|
||||||
'id' => $item['hummingbird_id']
|
|
||||||
]) ?>">Edit</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<?php endif ?>
|
|
||||||
<div class="row">
|
|
||||||
<div class="completion">Episodes: <?= $item['episode_count'] ?></div>
|
|
||||||
<div class="media_type"><?= $item['show_type'] ?></div>
|
|
||||||
<div class="age_rating"><?= $item['age_rating'] ?></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</div>
|
||||||
|
<?php $i++; ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
</div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</main>
|
</main>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<main>
|
<main>
|
||||||
<h2>Edit Anime Collection Item</h2>
|
<h2>Edit Anime Collection Item</h2>
|
||||||
<form action="<?= $action_url ?>" method="post">
|
<form action="<?= $action_url ?>" method="post">
|
||||||
<table class="form">
|
<table class="invisible form" style="border:0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
@ -11,17 +11,19 @@
|
|||||||
<h4><?= $item['alternate_title'] ?></h4>
|
<h4><?= $item['alternate_title'] ?></h4>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
|
||||||
<article class="media">
|
|
||||||
<?= $helper->img($urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.jpg")); ?>
|
|
||||||
</article>
|
|
||||||
</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="media_id">Media</label></td>
|
<td rowspan="4" class="align_center">
|
||||||
<td>
|
<article class="media">
|
||||||
|
<?= $helper->img($urlGenerator->assetUrl("images/anime/{$item['hummingbird_id']}.jpg")); ?>
|
||||||
|
</article>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="align_right"><label for="media_id">Media</label></td>
|
||||||
|
<td class="align_left">
|
||||||
<select name="media_id" id="media_id">
|
<select name="media_id" id="media_id">
|
||||||
<?php foreach($media_items as $id => $name): ?>
|
<?php foreach($media_items as $id => $name): ?>
|
||||||
<option <?= $item['media_id'] == $id ? 'selected="selected"' : '' ?> value="<?= $id ?>"><?= $name ?></option>
|
<option <?= $item['media_id'] == $id ? 'selected="selected"' : '' ?> value="<?= $id ?>"><?= $name ?></option>
|
||||||
|
19
app/views/collection/list-item.php
Normal file
19
app/views/collection/list-item.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<tr>
|
||||||
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
|
<td>
|
||||||
|
<a class="bracketed"
|
||||||
|
href="<?= $url->generate($collection_type . '.collection.edit.get', ['id' => $item['hummingbird_id']]) ?>">Edit</a>
|
||||||
|
</td>
|
||||||
|
<?php endif ?>
|
||||||
|
<td class="align_left">
|
||||||
|
<a href="<?= $url->generate('anime.details', ['id' => $item['slug']]) ?>">
|
||||||
|
<?= $item['title'] ?>
|
||||||
|
</a>
|
||||||
|
<?= (!empty($item['alternate_title'])) ? " <br /><small> " . $item['alternate_title'] . "</small>" : "" ?>
|
||||||
|
</td>
|
||||||
|
<td><?= $item['episode_count'] ?></td>
|
||||||
|
<td><?= $item['episode_length'] ?></td>
|
||||||
|
<td><?= $item['show_type'] ?></td>
|
||||||
|
<td><?= $item['age_rating'] ?></td>
|
||||||
|
<td class="align_left"><?= $item['notes'] ?></td>
|
||||||
|
</tr>
|
@ -5,13 +5,19 @@
|
|||||||
<?php if (empty($sections)): ?>
|
<?php if (empty($sections)): ?>
|
||||||
<h3>There's nothing here!</h3>
|
<h3>There's nothing here!</h3>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
|
<?php $i = 0; ?>
|
||||||
|
<div class="tabs">
|
||||||
<?php foreach ($sections as $name => $items): ?>
|
<?php foreach ($sections as $name => $items): ?>
|
||||||
|
<input <?= $i === 0 ? 'checked="checked"' : '' ?> type="radio" id="collection-tab-<?= $i ?>"
|
||||||
|
name="collection-tabs"/>
|
||||||
|
<label for="collection-tab-<?= $i ?>"><?= $name ?></label>
|
||||||
|
<div class="content">
|
||||||
<h2><?= $name ?></h2>
|
<h2><?= $name ?></h2>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<?php if ($auth->isAuthenticated()): ?>
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
<th>Actions</th>
|
<td>Actions</td>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<th>Title</th>
|
<th>Title</th>
|
||||||
<th>Episode Count</th>
|
<th>Episode Count</th>
|
||||||
@ -23,29 +29,14 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($items as $item): ?>
|
<?php foreach ($items as $item): ?>
|
||||||
<tr>
|
<?php include __DIR__ . '/list-item.php' ?>
|
||||||
<?php if($auth->isAuthenticated()): ?>
|
|
||||||
<td>
|
|
||||||
<a class="bracketed" href="<?= $url->generate($collection_type . '.collection.edit.get', ['id' => $item['hummingbird_id']]) ?>">Edit</a>
|
|
||||||
</td>
|
|
||||||
<?php endif ?>
|
|
||||||
<td class="align_left">
|
|
||||||
<a href="<?= $url->generate('anime.details', ['id' => $item['slug']]) ?>">
|
|
||||||
<?= $item['title'] ?>
|
|
||||||
</a>
|
|
||||||
<?= ( ! empty($item['alternate_title'])) ? " <br /><small> " . $item['alternate_title'] . "</small>" : "" ?>
|
|
||||||
</td>
|
|
||||||
<td><?= $item['episode_count'] ?></td>
|
|
||||||
<td><?= $item['episode_length'] ?></td>
|
|
||||||
<td><?= $item['show_type'] ?></td>
|
|
||||||
<td><?= $item['age_rating'] ?></td>
|
|
||||||
<td class="align_left"><?= $item['notes'] ?></td>
|
|
||||||
</tr>
|
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<br />
|
</div>
|
||||||
|
<?php $i++ ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
</div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</main>
|
</main>
|
||||||
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/table') ?>"></script>
|
<script defer="defer" src="<?= $urlGenerator->assetUrl('js.php/g/table') ?>"></script>
|
@ -1,11 +1,11 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title><?= $title ?></title>
|
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
|
<title><?= $title ?></title>
|
||||||
<meta http-equiv="cache-control" content="no-store" />
|
<meta http-equiv="cache-control" content="no-store" />
|
||||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self'" />
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self'" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=1" />
|
||||||
<link rel="stylesheet" href="<?= $urlGenerator->assetUrl('css/app.min.css') ?>" />
|
<link rel="stylesheet" href="<?= $urlGenerator->assetUrl('css/app.min.css') ?>" />
|
||||||
<link rel="icon" href="<?= $urlGenerator->assetUrl('images/icons/favicon.ico') ?>" />
|
<link rel="icon" href="<?= $urlGenerator->assetUrl('images/icons/favicon.ico') ?>" />
|
||||||
<link rel="apple-touch-icon" sizes="57x57" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-57x57.png') ?>">
|
<link rel="apple-touch-icon" sizes="57x57" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-57x57.png') ?>">
|
||||||
|
@ -7,7 +7,7 @@ $lastSegment = $urlGenerator->lastSegment();
|
|||||||
$extraSegment = $lastSegment === 'list' ? '/list' : '';
|
$extraSegment = $lastSegment === 'list' ? '/list' : '';
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<h1 class="flex flex-align-end flex-wrap">
|
<div id="main-nav" class="flex flex-align-end flex-wrap">
|
||||||
<span class="flex-no-wrap grow-1">
|
<span class="flex-no-wrap grow-1">
|
||||||
<?php if(strpos($route_path, 'collection') === FALSE): ?>
|
<?php if(strpos($route_path, 'collection') === FALSE): ?>
|
||||||
<?= $helper->a(
|
<?= $helper->a(
|
||||||
@ -67,7 +67,7 @@ $extraSegment = $lastSegment === 'list' ? '/list' : '';
|
|||||||
[<?= $helper->a($url->generate('login'), "{$whose} Login") ?>]
|
[<?= $helper->a($url->generate('login'), "{$whose} Login") ?>]
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</span>
|
</span>
|
||||||
</h1>
|
</div>
|
||||||
<nav>
|
<nav>
|
||||||
<?php if ($container->get('util')->isViewPage()): ?>
|
<?php if ($container->get('util')->isViewPage()): ?>
|
||||||
<?= $helper->menu($menu_name) ?>
|
<?= $helper->menu($menu_name) ?>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<br />
|
<br />
|
||||||
<table class="form">
|
<table class="invisible form">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="status">Reading Status</label></td>
|
<td><label for="status">Reading Status</label></td>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<main>
|
<main class="media-list">
|
||||||
<?php if ($auth->isAuthenticated()): ?>
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
<a class="bracketed" href="<?= $url->generate('manga.add.get') ?>">Add Item</a>
|
<a class="bracketed" href="<?= $url->generate('manga.add.get') ?>">Add Item</a>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
@ -26,7 +26,7 @@
|
|||||||
<img src="<?= $urlGenerator->assetUrl('images/manga', "{$item['manga']['id']}.jpg") ?>" />
|
<img src="<?= $urlGenerator->assetUrl('images/manga', "{$item['manga']['id']}.jpg") ?>" />
|
||||||
<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(array_shift($item['manga']['titles'])) ?>
|
<?= $escape->html($item['manga']['title']) ?>
|
||||||
<?php foreach($item['manga']['titles'] as $title): ?>
|
<?php foreach($item['manga']['titles'] as $title): ?>
|
||||||
<br /><small><?= $title ?></small>
|
<br /><small><?= $title ?></small>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
@ -73,8 +73,8 @@
|
|||||||
Chapters: <span class="chapters_read"><?= $item['chapters']['read'] ?></span> /
|
Chapters: <span class="chapters_read"><?= $item['chapters']['read'] ?></span> /
|
||||||
<span class="chapter_count"><?= $item['chapters']['total'] ?></span>
|
<span class="chapter_count"><?= $item['chapters']['total'] ?></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<?php /* </div>
|
||||||
<div class="row">
|
<div class="row"> */ ?>
|
||||||
<div class="volume_completion">
|
<div class="volume_completion">
|
||||||
Volumes: <span class="volume_count"><?= $item['volumes']['total'] ?></span>
|
Volumes: <span class="volume_count"><?= $item['volumes']['total'] ?></span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,26 +1,28 @@
|
|||||||
<?php if ($auth->isAuthenticated()): ?>
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
<main>
|
<main>
|
||||||
<h1>
|
<h2>
|
||||||
Edit <?= $item['manga']['titles'][0] ?>
|
Edit Manga List Item
|
||||||
</h1>
|
</h2>
|
||||||
<form action="<?= $action ?>" method="post">
|
<form action="<?= $action ?>" method="post">
|
||||||
<table class="form">
|
<table class="invisible form">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
<h3><?= $escape->html(array_shift($item['manga']['titles'])) ?></h3>
|
<h3><?= $escape->html($item['manga']['title']) ?></h3>
|
||||||
<?php foreach ($item['manga']['titles'] as $title): ?>
|
<?php foreach ($item['manga']['titles'] as $title): ?>
|
||||||
<h4><?= $escape->html($title) ?></h4>
|
<h4><?= $escape->html($title) ?></h4>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<article class="media">
|
|
||||||
<?= $helper->img($urlGenerator->assetUrl('images/manga', "{$item['manga']['id']}.jpg")); ?>
|
|
||||||
</article>
|
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="9">
|
||||||
|
<article class="media">
|
||||||
|
<?= $helper->img($urlGenerator->assetUrl('images/manga', "{$item['manga']['id']}.jpg")); ?>
|
||||||
|
</article>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="status">Reading Status</label></td>
|
<td><label for="status">Reading Status</label></td>
|
||||||
<td>
|
<td>
|
||||||
@ -35,21 +37,24 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><label for="series_rating">Rating</label></td>
|
<td><label for="series_rating">Rating</label></td>
|
||||||
<td>
|
<td>
|
||||||
<input type="number" min="0" max="10" maxlength="2" name="new_rating" value="<?= $item['user_rating'] ?>" id="series_rating" size="2" /> / 10
|
<input type="number" min="0" max="10" maxlength="2" name="new_rating"
|
||||||
|
value="<?= $item['user_rating'] ?>" id="series_rating" size="2"/> / 10
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="chapters_read">Chapters Read</label></td>
|
<td><label for="chapters_read">Chapters Read</label></td>
|
||||||
<td>
|
<td>
|
||||||
<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'] ?>
|
<?php /*<input type="number" disabled="disabled" min="0" name="volumes_read" id="volumes_read" value="" /> */ ?>
|
||||||
|
- / <?= $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>
|
||||||
@ -61,7 +66,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><label for="reread_count">Reread Count</label></td>
|
<td><label for="reread_count">Reread Count</label></td>
|
||||||
<td>
|
<td>
|
||||||
<input type="number" min="0" id="reread_count" name="reread_count" value="<?= $item['reread'] ?>" />
|
<input type="number" min="0" id="reread_count" name="reread_count"
|
||||||
|
value="<?= $item['reread'] ?>"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<main>
|
<main class="media-list">
|
||||||
<?php if ($auth->isAuthenticated()): ?>
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
<a class="bracketed" href="<?= $url->generate('manga.add.get') ?>">Add Item</a>
|
<a class="bracketed" href="<?= $url->generate('manga.add.get') ?>">Add Item</a>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<?php if ($auth->isAuthenticated()): ?>
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
<th> </th>
|
<td> </td>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<th>Title</th>
|
<th>Title</th>
|
||||||
<th>Rating</th>
|
<th>Rating</th>
|
||||||
@ -39,7 +39,7 @@
|
|||||||
<?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']]) ?>">
|
||||||
<?= array_shift($item['manga']['titles']) ?>
|
<?= $item['manga']['title'] ?>
|
||||||
</a>
|
</a>
|
||||||
<?php foreach($item['manga']['titles'] as $title): ?>
|
<?php foreach($item['manga']['titles'] as $title): ?>
|
||||||
<br /><?= $title ?>
|
<br /><?= $title ?>
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
"phpmd/phpmd": "^2.4",
|
"phpmd/phpmd": "^2.4",
|
||||||
"phpstan/phpstan": "^0.9.1",
|
"phpstan/phpstan": "^0.9.1",
|
||||||
"phpunit/phpunit": "^6.0",
|
"phpunit/phpunit": "^6.0",
|
||||||
|
"roave/security-advisories": "dev-master",
|
||||||
"robmorgan/phinx": "^0.9.1",
|
"robmorgan/phinx": "^0.9.1",
|
||||||
"sebastian/phpcpd": "^3.0",
|
"sebastian/phpcpd": "^3.0",
|
||||||
"spatie/phpunit-snapshot-assertions": "^1.2.0",
|
"spatie/phpunit-snapshot-assertions": "^1.2.0",
|
||||||
|
@ -28,9 +28,12 @@ if ($timezone === '' || $timezone === FALSE)
|
|||||||
// Load composer autoloader
|
// Load composer autoloader
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
// if (array_key_exists('ENV', $_ENV) && $_ENV['ENV'] === 'development')
|
||||||
|
{
|
||||||
$whoops = new \Whoops\Run;
|
$whoops = new \Whoops\Run;
|
||||||
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
|
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
|
||||||
$whoops->register();
|
$whoops->register();
|
||||||
|
}
|
||||||
|
|
||||||
// Define base directories
|
// Define base directories
|
||||||
$APP_DIR = _dir(__DIR__, 'app');
|
$APP_DIR = _dir(__DIR__, 'app');
|
||||||
|
@ -7,7 +7,7 @@ const atImport = require('postcss-import');
|
|||||||
const cssNext = require('postcss-cssnext');
|
const cssNext = require('postcss-cssnext');
|
||||||
const cssNano = require('cssnano');
|
const cssNano = require('cssnano');
|
||||||
|
|
||||||
const css = fs.readFileSync('css/base.css', 'utf8');
|
const css = fs.readFileSync('css/base.css', 'utf-8');
|
||||||
|
|
||||||
postcss()
|
postcss()
|
||||||
.use(atImport())
|
.use(atImport())
|
||||||
|
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
@ -1,8 +1,10 @@
|
|||||||
@import "./marx.css";
|
@import "./marx.css";
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
--blue-link: rgb(18, 113, 219);
|
||||||
--link-shadow: 1px 1px 1px #000;
|
--link-shadow: 1px 1px 1px #000;
|
||||||
--shadow: 1px 2px 1px rgba(0, 0, 0, 0.85);
|
--white-link-shadow: 1px 1px 1px #fff;
|
||||||
|
--shadow: 2px 2px 2px #000;
|
||||||
--title-overlay: rgba(0, 0, 0, 0.45);
|
--title-overlay: rgba(0, 0, 0, 0.45);
|
||||||
--title-overlay-fallback: #000;
|
--title-overlay-fallback: #000;
|
||||||
--text-color: #ffffff;
|
--text-color: #ffffff;
|
||||||
@ -13,9 +15,13 @@
|
|||||||
--radius: 5px;
|
--radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
template, [hidden="hidden"], .media[hidden] {display:none}
|
template, [hidden="hidden"], .media[hidden] {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
|
||||||
body {margin: 0.5em;}
|
body {
|
||||||
|
margin: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
background: rgba(255, 255, 255, 0.65);
|
background: rgba(255, 255, 255, 0.65);
|
||||||
@ -23,7 +29,7 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
min-width:85%;
|
/* min-width: 85%; */
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,40 +62,87 @@ a:hover, a:active {
|
|||||||
.bracketed {
|
.bracketed {
|
||||||
color: var(--edit-link-color);
|
color: var(--edit-link-color);
|
||||||
}
|
}
|
||||||
.bracketed, h1 a {
|
|
||||||
|
.bracketed, #main-nav a {
|
||||||
text-shadow: var(--link-shadow);
|
text-shadow: var(--link-shadow);
|
||||||
}
|
}
|
||||||
.bracketed:before {content: '[\00a0'}
|
|
||||||
.bracketed:after {content: '\00a0]'}
|
.bracketed:before {
|
||||||
|
content: '[\00a0'
|
||||||
|
}
|
||||||
|
|
||||||
|
.bracketed:after {
|
||||||
|
content: '\00a0]'
|
||||||
|
}
|
||||||
|
|
||||||
.bracketed:hover, .bracketed:active {
|
.bracketed:hover, .bracketed:active {
|
||||||
color: var(--edit-link-hover-color)
|
color: var(--edit-link-hover-color)
|
||||||
}
|
}
|
||||||
|
|
||||||
.grow-1 {flex-grow: 1}
|
.grow-1 {
|
||||||
.flex-wrap {flex-wrap: wrap}
|
flex-grow: 1
|
||||||
.flex-no-wrap {flex-wrap: nowrap}
|
}
|
||||||
.flex-align-end {align-items: flex-end}
|
|
||||||
.flex-align-space-around {align-content: space-around}
|
.flex-wrap {
|
||||||
.flex-justify-space-around {justify-content: space-around}
|
flex-wrap: wrap
|
||||||
.flex-self-center {align-self:center}
|
}
|
||||||
.flex {display: flex}
|
|
||||||
|
.flex-no-wrap {
|
||||||
|
flex-wrap: nowrap
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-align-end {
|
||||||
|
align-items: flex-end
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-align-space-around {
|
||||||
|
align-content: space-around
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-justify-space-around {
|
||||||
|
justify-content: space-around
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-self-center {
|
||||||
|
align-self: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex
|
||||||
|
}
|
||||||
|
|
||||||
.small-font {
|
.small-font {
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.justify {text-align:justify}
|
.justify {
|
||||||
.align_center {text-align:center !important}
|
text-align: justify
|
||||||
.align_left {text-align:left !important}
|
}
|
||||||
.align_right {text-align:right !important}
|
|
||||||
|
|
||||||
.valign_top {vertical-align:top}
|
.align_center {
|
||||||
|
text-align: center !important
|
||||||
|
}
|
||||||
|
|
||||||
.no_border {border:none}
|
.align_left {
|
||||||
|
text-align: left !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.align_right {
|
||||||
|
text-align: right !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.valign_top {
|
||||||
|
vertical-align: top
|
||||||
|
}
|
||||||
|
|
||||||
|
.no_border {
|
||||||
|
border: none
|
||||||
|
}
|
||||||
|
|
||||||
.media-wrap {
|
.media-wrap {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.danger {
|
.danger {
|
||||||
@ -111,6 +164,7 @@ a:hover, a:active {
|
|||||||
padding: 0 0.5em;
|
padding: 0 0.5em;
|
||||||
padding: 0 0.5rem;
|
padding: 0 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-btn:hover, .user-btn:active {
|
.user-btn:hover, .user-btn:active {
|
||||||
border-color: var(--edit-link-hover-color);
|
border-color: var(--edit-link-hover-color);
|
||||||
background-color: var(--edit-link-hover-color);
|
background-color: var(--edit-link-hover-color);
|
||||||
@ -120,6 +174,20 @@ a:hover, a:active {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
Main Nav
|
||||||
|
------------------------------------------------------------------------------*/
|
||||||
|
#main-nav {
|
||||||
|
font-family: var(--default-font-list);
|
||||||
|
margin: 2em 0 1.6em;
|
||||||
|
margin: 2rem 0 1.6rem;
|
||||||
|
border-bottom: .1rem solid rgba(0, 0, 0, 0.2);
|
||||||
|
font-size: 3.6em;
|
||||||
|
font-size: 3.6rem;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
CSS loading icon
|
CSS loading icon
|
||||||
------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------*/
|
||||||
@ -197,17 +265,22 @@ a:hover, a:active {
|
|||||||
.sorting_desc {
|
.sorting_desc {
|
||||||
vertical-align: text-bottom;
|
vertical-align: text-bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sorting::before {
|
.sorting::before {
|
||||||
content: " ↕\00a0";
|
content: " ↕\00a0";
|
||||||
}
|
}
|
||||||
|
|
||||||
.sorting_asc::before {
|
.sorting_asc::before {
|
||||||
content: " ↑\00a0";
|
content: " ↑\00a0";
|
||||||
}
|
}
|
||||||
|
|
||||||
.sorting_desc::before {
|
.sorting_desc::before {
|
||||||
content: " ↓\00a0";
|
content: " ↓\00a0";
|
||||||
}
|
}
|
||||||
|
|
||||||
.form { width:100%; }
|
.form {
|
||||||
|
/* width: 100%; */
|
||||||
|
}
|
||||||
|
|
||||||
.form thead th, .form thead tr {
|
.form thead th, .form thead tr {
|
||||||
background: inherit;
|
background: inherit;
|
||||||
@ -219,14 +292,16 @@ a:hover, a:active {
|
|||||||
min-width: 25px;
|
min-width: 25px;
|
||||||
max-width: 30%;
|
max-width: 30%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form tr > td:nth-child(even) {
|
.form tr > td:nth-child(even) {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
width:70%;
|
/* width: 70%; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.invisible tbody > tr:nth-child(odd) {
|
.invisible tbody > tr:nth-child(odd) {
|
||||||
background: inherit;
|
background: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.invisible tr, .invisible td, .invisible th {
|
.invisible tr, .invisible td, .invisible th {
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
@ -280,6 +355,7 @@ a:hover, a:active {
|
|||||||
border: 1px solid #1f8454;
|
border: 1px solid #1f8454;
|
||||||
background: #70dda9;
|
background: #70dda9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message.success .icon::after {
|
.message.success .icon::after {
|
||||||
content: '✔'
|
content: '✔'
|
||||||
}
|
}
|
||||||
@ -305,6 +381,7 @@ a:hover, a:active {
|
|||||||
width: 220px;
|
width: 220px;
|
||||||
height: 311px;
|
height: 311px;
|
||||||
margin: var(--normal-padding);
|
margin: var(--normal-padding);
|
||||||
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media > img,
|
.media > img,
|
||||||
@ -322,11 +399,10 @@ a:hover, a:active {
|
|||||||
.medium_metadata > div,
|
.medium_metadata > div,
|
||||||
.row {
|
.row {
|
||||||
text-shadow: var(--shadow);
|
text-shadow: var(--shadow);
|
||||||
background: var(--title-overlay-fallback);
|
|
||||||
background: var(--title-overlay);
|
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
padding: var(--normal-padding);
|
padding: var(--normal-padding);
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media_type, .age_rating {
|
.media_type, .age_rating {
|
||||||
@ -349,42 +425,74 @@ a:hover, a:active {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
.small_character:hover > .name,
|
|
||||||
.character:hover > .name,
|
.media > .name a {
|
||||||
.media:hover > .name,
|
transition: none;
|
||||||
.media:hover > .media_metadata > div,
|
}
|
||||||
.media:hover > .medium_metadata > div,
|
|
||||||
.media:hover > .table .row
|
.media .name a::before {
|
||||||
{
|
/* background: var(--title-overlay-fallback);
|
||||||
transition: .25s ease;
|
background: var(--title-overlay); */
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
height: 311px;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 220px;
|
||||||
|
z-index: -1; /* Put the pseudo-element behind its parent */
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-list .media:hover .name a::before {
|
||||||
|
/* transition: .25s ease; */
|
||||||
background: rgba(0, 0, 0, 0.75);
|
background: rgba(0, 0, 0, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.media > .name span.canonical {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media > .name small {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media:hover .name {
|
||||||
|
background: rgba(0, 0, 0, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-list .media > .name a:hover,
|
||||||
|
.media-list .media > .name a:hover small {
|
||||||
|
color: var(--blue-link);
|
||||||
|
}
|
||||||
|
|
||||||
.media:hover > button[hidden],
|
.media:hover > button[hidden],
|
||||||
.media:hover > .edit_buttons[hidden]
|
.media:hover > .edit_buttons[hidden] {
|
||||||
{
|
|
||||||
transition: .25s ease;
|
transition: .25s ease;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.media:hover {
|
||||||
|
transition: .25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
.small_character > .name a,
|
.small_character > .name a,
|
||||||
.small_character > .name a small,
|
.small_character > .name a small,
|
||||||
.character > .name a,
|
.character > .name a,
|
||||||
.character > .name a small,
|
.character > .name a small,
|
||||||
.media > .name a,
|
.media > .name a,
|
||||||
.media > .name a small
|
.media > .name a small {
|
||||||
{
|
|
||||||
background: none;
|
background: none;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
text-shadow: var(--shadow);
|
text-shadow: var(--shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
Anime-list-specific styles
|
Anime-list-specific styles
|
||||||
------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------*/
|
||||||
.anime .name, .manga .name {
|
.anime .name, .manga .name {
|
||||||
|
background: var(--title-overlay-fallback);
|
||||||
|
background: var(--title-overlay);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.5em 0.25em;
|
padding: 0.5em 0.25em;
|
||||||
@ -401,7 +509,6 @@ a:hover, a:active {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.anime .table, .manga .table {
|
.anime .table, .manga .table {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@ -411,8 +518,6 @@ a:hover, a:active {
|
|||||||
|
|
||||||
.anime .row, .manga .row {
|
.anime .row, .manga .row {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: var(--title-overlay-fallback);
|
|
||||||
background: var(--title-overlay);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-content: space-around;
|
align-content: space-around;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
@ -422,6 +527,7 @@ a:hover, a:active {
|
|||||||
|
|
||||||
.anime .row > span, .manga .row > span {
|
.anime .row > span, .manga .row > span {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.anime .row > div, .manga .row > div {
|
.anime .row > div, .manga .row > div {
|
||||||
@ -430,14 +536,26 @@ a:hover, a:active {
|
|||||||
align-self: center;
|
align-self: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.anime .media > button.plus_one {
|
.anime .media > button.plus_one {
|
||||||
|
border-color: hsla(0, 0%, 100%, .65);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 138px;
|
top: 138px;
|
||||||
top: calc(50% - 21.5px);
|
top: calc(50% - 21.5px);
|
||||||
left: 44px;
|
left: 44px;
|
||||||
left: calc(50% - 66.5px);
|
left: calc(50% - 66.5px);
|
||||||
|
z-index: 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.anime .media > button.plus_one:hover {
|
||||||
|
color: hsla(0, 0%, 100%, .65);
|
||||||
|
background: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.anime .media > button.plus_one:active {
|
||||||
|
background: #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
@ -448,7 +566,7 @@ a:hover, a:active {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.manga .media {
|
.manga .media {
|
||||||
border:1px solid #ddd;
|
/* border: 1px solid #ddd; */
|
||||||
height: 310px;
|
height: 310px;
|
||||||
margin: 0.25em;
|
margin: 0.25em;
|
||||||
}
|
}
|
||||||
@ -456,11 +574,25 @@ a:hover, a:active {
|
|||||||
.manga .media > .edit_buttons {
|
.manga .media > .edit_buttons {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 86px;
|
top: 86px;
|
||||||
top: calc(50% - 58.5px);
|
/* top: calc(50% - 58.5px); */
|
||||||
|
top: calc(50% - 22.4px);
|
||||||
left: 43.5px;
|
left: 43.5px;
|
||||||
left: calc(50% - 66.5px);
|
left: calc(50% - 66.5px);
|
||||||
|
z-index: 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.manga .media > .edit_buttons button {
|
||||||
|
border-color: hsla(0, 0%, 100%, .65);
|
||||||
|
}
|
||||||
|
|
||||||
|
.manga .media > .edit_buttons:hover button {
|
||||||
|
color: hsla(0, 0%, 100%, .65);
|
||||||
|
background: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manga .media > .edit_buttons button:active {
|
||||||
|
background: #444;
|
||||||
|
}
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
Search page styles
|
Search page styles
|
||||||
@ -493,11 +625,13 @@ a:hover, a:active {
|
|||||||
left: 0;
|
left: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
z-index: 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
#series_list article.media {
|
#series_list article.media {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#series_list .name, #series_list .name label {
|
#series_list .name, #series_list .name label {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: block;
|
display: block;
|
||||||
@ -508,6 +642,7 @@ a:hover, a:active {
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
line-height: 1.25em;
|
line-height: 1.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#series_list .name small {
|
#series_list .name small {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
@ -546,6 +681,7 @@ a:hover, a:active {
|
|||||||
.details .media_details {
|
.details .media_details {
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.details .media_details td {
|
.details .media_details td {
|
||||||
padding: 0 1.5rem;
|
padding: 0 1.5rem;
|
||||||
}
|
}
|
||||||
@ -559,18 +695,25 @@ a:hover, a:active {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.details .media_details td:nth-child(even) {
|
.details .media_details td:nth-child(even) {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.character,
|
.character,
|
||||||
.small_character {
|
.small_character {
|
||||||
background: rgba(0,0,0,0.5);
|
/* background: rgba(0,0,0,0.5); */
|
||||||
width: 225px;
|
width: 225px;
|
||||||
height: 350px;
|
height: 350px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.character:hover .name,
|
||||||
|
.small_character:hover .name {
|
||||||
|
background: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
.small_character a {
|
.small_character a {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -646,9 +789,19 @@ a:hover, a:active {
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cover_streaming_link {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media:hover .cover_streaming_link {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.cover_streaming_link .streaming-logo {
|
.cover_streaming_link .streaming-logo {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
-webkit-filter: drop-shadow(0 -1px 4px #fff);
|
||||||
|
filter: drop-shadow(0 -1px 4px #fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
@ -686,3 +839,75 @@ a:hover, a:active {
|
|||||||
.loading-content .cssload-inner.cssload-three {
|
.loading-content .cssload-inner.cssload-three {
|
||||||
border-color: #fff
|
border-color: #fff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
CSS Tabs
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
background: #efefef;
|
||||||
|
box-shadow: 0 48px 80px -32px rgba(0, 0, 0, 0.3);
|
||||||
|
margin-top: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs label {
|
||||||
|
border: 1px solid #e5e5e5;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px 30px;
|
||||||
|
background: #e5e5e5;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #7f7f7f;
|
||||||
|
transition: background 0.1s, color 0.1s;
|
||||||
|
/* margin-left: 4em; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs label:hover {
|
||||||
|
background: #d8d8d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs label:active {
|
||||||
|
background: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs [type=radio]:focus + label {
|
||||||
|
box-shadow: inset 0px 0px 0px 3px #2aa1c0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs [type=radio] {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs [type=radio]:checked + label {
|
||||||
|
border-bottom: 1px solid #fff;
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs [type=radio]:checked + label + .content {
|
||||||
|
border: 1px solid #e5e5e5;
|
||||||
|
border-top: 0;
|
||||||
|
display: block;
|
||||||
|
padding: 20px 30px 30px;
|
||||||
|
background: #fff;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs .content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
.tabs label {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs .content {
|
||||||
|
order: 99;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ use Aviat\AnimeClient\API\HummingbirdClient;
|
|||||||
use Aviat\Ion\{Json, JsonException};
|
use Aviat\Ion\{Json, JsonException};
|
||||||
|
|
||||||
// Include Amp and Artax
|
// Include Amp and Artax
|
||||||
require_once('../vendor/autoload.php');
|
require_once '../vendor/autoload.php';
|
||||||
|
|
||||||
//Creative rewriting of /g/groupname to ?g=groupname
|
//Creative rewriting of /g/groupname to ?g=groupname
|
||||||
$pi = $_SERVER['PATH_INFO'];
|
$pi = $_SERVER['PATH_INFO'];
|
||||||
@ -318,10 +318,11 @@ class JSMin {
|
|||||||
$lastModifiedDate = gmdate('D, d M Y H:i:s', $lastModified);
|
$lastModifiedDate = gmdate('D, d M Y H:i:s', $lastModified);
|
||||||
$expiresDate = gmdate('D, d M Y H:i:s', $expires);
|
$expiresDate = gmdate('D, d M Y H:i:s', $expires);
|
||||||
|
|
||||||
header("Content-Type: {$mimeType}; charset=utf8");
|
header("Content-Type: {$mimeType}; charset=utf-8");
|
||||||
header("Cache-control: public, max-age=691200, must-revalidate");
|
header('Cache-control: public, max-age=691200, must-revalidate');
|
||||||
header("Last-Modified: {$lastModifiedDate} GMT");
|
|
||||||
header("Expires: {$expiresDate} GMT");
|
header("Expires: {$expiresDate} GMT");
|
||||||
|
header("Last-Modified: {$lastModifiedDate} GMT");
|
||||||
|
header('X-Content-Type-Options: no-sniff');
|
||||||
|
|
||||||
echo $content;
|
echo $content;
|
||||||
|
|
||||||
@ -335,7 +336,7 @@ class JSMin {
|
|||||||
*/
|
*/
|
||||||
public static function send304()
|
public static function send304()
|
||||||
{
|
{
|
||||||
header("status: 304 Not Modified", true, 304);
|
header('status: 304 Not Modified', true, 304);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,8 +39,17 @@
|
|||||||
data,
|
data,
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
success: () => {
|
success: (res) => {
|
||||||
if (data.data.status === 'completed') {
|
const resData = JSON.parse(res);
|
||||||
|
|
||||||
|
if (resData.errors) {
|
||||||
|
_.hide(_.$('#loading-shadow')[ 0 ]);
|
||||||
|
_.showMessage('error', `Failed to update ${title}. `);
|
||||||
|
_.scrollToTop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resData.data.attributes.status === 'completed') {
|
||||||
_.hide(parentSel);
|
_.hide(parentSel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +273,7 @@ var AnimeClient = (function(w) {
|
|||||||
responseText = request.responseText;
|
responseText = request.responseText;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.status > 400) {
|
if (request.status > 299) {
|
||||||
config.error.call(null, request.status, responseText, request.response);
|
config.error.call(null, request.status, responseText, request.response);
|
||||||
} else {
|
} else {
|
||||||
config.success.call(null, responseText, request.status);
|
config.success.call(null, responseText, request.status);
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
const LightTableSorter = (function() {
|
'use strict';
|
||||||
let _cellIndex, _onClickEvent, _order, _reset, _sort, _text, _th, _toggle;
|
const LightTableSorter = (() => {
|
||||||
_th = null;
|
let th = null;
|
||||||
_cellIndex = null;
|
let cellIndex = null;
|
||||||
_order = '';
|
let order = '';
|
||||||
_text = function(row) {
|
const text = (row) => {
|
||||||
return row.cells.item(_cellIndex).textContent.toLowerCase();
|
return row.cells.item(cellIndex).textContent.toLowerCase();
|
||||||
};
|
};
|
||||||
_sort = function(a, b) {
|
const sort = (a, b) => {
|
||||||
let n, textA, textB;
|
let textA = text(a);
|
||||||
textA = _text(a);
|
let textB = text(b);
|
||||||
textB = _text(b);
|
const n = parseInt(textA, 10);
|
||||||
n = parseInt(textA, 10);
|
|
||||||
if (n) {
|
if (n) {
|
||||||
textA = n;
|
textA = n;
|
||||||
textB = parseInt(textB, 10);
|
textB = parseInt(textB, 10);
|
||||||
@ -23,51 +22,49 @@ const LightTableSorter = (function() {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
_toggle = function() {
|
const toggle = () => {
|
||||||
let c;
|
const c = order !== 'sorting_asc' ? 'sorting_asc' : 'sorting_desc';
|
||||||
c = _order !== 'sorting_asc' ? 'sorting_asc' : 'sorting_desc';
|
th.className = (th.className.replace(order, '') + ' ' + c).trim();
|
||||||
_th.className = (_th.className.replace(_order, '') + ' ' + c).trim();
|
return order = c;
|
||||||
return _order = c;
|
|
||||||
};
|
};
|
||||||
_reset = function() {
|
const reset = () => {
|
||||||
_th.className = _th.className.replace('sorting_asc', 'sorting').replace('sorting_desc', 'sorting');
|
th.classList.remove('sorting_asc', 'sorting_desc');
|
||||||
return _order = '';
|
th.classList.add('sorting');
|
||||||
|
return order = '';
|
||||||
};
|
};
|
||||||
_onClickEvent = function(e) {
|
const onClickEvent = (e) => {
|
||||||
let row, rows, tbody, _i, _len;
|
if (th && (cellIndex !== e.target.cellIndex)) {
|
||||||
if (_th && (_cellIndex !== e.target.cellIndex)) {
|
reset();
|
||||||
_reset();
|
|
||||||
}
|
}
|
||||||
_th = e.target;
|
th = e.target;
|
||||||
if (_th.nodeName.toLowerCase() === 'th') {
|
if (th.nodeName.toLowerCase() === 'th') {
|
||||||
_cellIndex = _th.cellIndex;
|
cellIndex = th.cellIndex;
|
||||||
tbody = _th.offsetParent.getElementsByTagName('tbody')[0];
|
const tbody = th.offsetParent.getElementsByTagName('tbody')[0];
|
||||||
rows = tbody.rows;
|
let rows = Array.from(tbody.rows);
|
||||||
if (rows) {
|
if (rows) {
|
||||||
rows = Array.prototype.slice.call(rows, 0);
|
rows.sort(sort);
|
||||||
rows = Array.prototype.sort.call(rows, _sort);
|
if (order === 'sorting_asc') {
|
||||||
if (_order === 'sorting_asc') {
|
rows.reverse();
|
||||||
Array.prototype.reverse.call(rows);
|
|
||||||
}
|
}
|
||||||
_toggle();
|
toggle();
|
||||||
tbody.innerHtml = '';
|
tbody.innerHtml = '';
|
||||||
for (_i = 0, _len = rows.length; _i < _len; _i++) {
|
|
||||||
row = rows[_i];
|
rows.forEach(row => {
|
||||||
tbody.appendChild(row);
|
tbody.appendChild(row);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
init: function() {
|
init: () => {
|
||||||
let ths = document.getElementsByTagName('th');
|
let ths = document.getElementsByTagName('th');
|
||||||
let _results = [];
|
let results = [];
|
||||||
for (let _i = 0, _len = ths.length; _i < _len; _i++) {
|
for (let i = 0, len = ths.length; i < len; i++) {
|
||||||
let th = ths[_i];
|
let th = ths[i];
|
||||||
th.className = 'sorting';
|
th.classList.add('sorting');
|
||||||
_results.push(th.onclick = _onClickEvent);
|
results.push(th.onclick = onClickEvent);
|
||||||
}
|
}
|
||||||
return _results;
|
return results;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
0
public/js/cache/.gitkeep
vendored
Normal file → Executable file
0
public/js/cache/.gitkeep
vendored
Normal file → Executable file
@ -4,10 +4,10 @@
|
|||||||
"watch": "watch 'npm run build' --filter=./cssfilter.js"
|
"watch": "watch 'npm run build' --filter=./cssfilter.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"cssnano": "^3.10.0",
|
"cssnano": "^4.0.5",
|
||||||
"postcss-cachify": "^1.3.1",
|
"postcss-cachify": "^1.3.1",
|
||||||
"postcss-cssnext": "^3.0.0",
|
"postcss-cssnext": "^3.0.0",
|
||||||
"postcss-import": "^10.0.0",
|
"postcss-import": "^12.0.0",
|
||||||
"watch": "^1.0.2"
|
"watch": "^1.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1177
public/yarn.lock
1177
public/yarn.lock
File diff suppressed because it is too large
Load Diff
73
src/API/Anilist.php
Normal file
73
src/API/Anilist.php
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\API;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\API\Enum\{
|
||||||
|
AnimeWatchingStatus\Kitsu as KAWS,
|
||||||
|
MangaReadingStatus\Kitsu as KMRS
|
||||||
|
};
|
||||||
|
use Aviat\AnimeClient\API\Enum\{
|
||||||
|
AnimeWatchingStatus\Anilist as AnimeWatchingStatus,
|
||||||
|
MangaReadingStatus\Anilist as MangaReadingStatus
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants and mappings for the Anilist API
|
||||||
|
*/
|
||||||
|
final class Anilist {
|
||||||
|
const AUTH_URL = 'https://anilist.co/api/v2/oauth/authorize';
|
||||||
|
const BASE_URL = 'https://graphql.anilist.co';
|
||||||
|
|
||||||
|
const KITSU_ANILIST_WATCHING_STATUS_MAP = [
|
||||||
|
KAWS::WATCHING => AnimeWatchingStatus::WATCHING,
|
||||||
|
KAWS::COMPLETED => AnimeWatchingStatus::COMPLETED,
|
||||||
|
KAWS::ON_HOLD => AnimeWatchingStatus::ON_HOLD,
|
||||||
|
KAWS::DROPPED => AnimeWatchingStatus::DROPPED,
|
||||||
|
KAWS::PLAN_TO_WATCH => AnimeWatchingStatus::PLAN_TO_WATCH,
|
||||||
|
];
|
||||||
|
|
||||||
|
const ANILIST_KITSU_WATCHING_STATUS_MAP = [
|
||||||
|
'CURRENT' => KAWS::WATCHING,
|
||||||
|
'COMPLETED' => KAWS::COMPLETED,
|
||||||
|
'PAUSED' => KAWS::ON_HOLD,
|
||||||
|
'DROPPED' => KAWS::DROPPED,
|
||||||
|
'PLANNING' => KAWS::PLAN_TO_WATCH,
|
||||||
|
];
|
||||||
|
|
||||||
|
public static function getIdToWatchingStatusMap()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'CURRENT' => AnimeWatchingStatus::WATCHING,
|
||||||
|
'COMPLETED' => AnimeWatchingStatus::COMPLETED,
|
||||||
|
'PAUSED' => AnimeWatchingStatus::ON_HOLD,
|
||||||
|
'DROPPED' => AnimeWatchingStatus::DROPPED,
|
||||||
|
'PLANNING' => AnimeWatchingStatus::PLAN_TO_WATCH,
|
||||||
|
'REPEATING' => AnimeWatchingStatus::WATCHING,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getIdToReadingStatusMap()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'CURRENT' => MangaReadingStatus::READING,
|
||||||
|
'COMPLETED' => MangaReadingStatus::COMPLETED,
|
||||||
|
'PAUSED' => MangaReadingStatus::ON_HOLD,
|
||||||
|
'DROPPED' => MangaReadingStatus::DROPPED,
|
||||||
|
'PLANNING' => MangaReadingStatus::PLAN_TO_READ
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
49
src/API/Anilist/AnilistRequestBuilder.php
Normal file
49
src/API/Anilist/AnilistRequestBuilder.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\API\Anilist;
|
||||||
|
|
||||||
|
use const Aviat\AnimeClient\USER_AGENT;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\API\APIRequestBuilder;
|
||||||
|
|
||||||
|
final class AnilistRequestBuilder extends APIRequestBuilder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base url for api requests
|
||||||
|
* @var string $base_url
|
||||||
|
*/
|
||||||
|
protected $baseUrl = 'https://kitsu.io/api/edge/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Valid HTTP request methods
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $validMethods = ['POST'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP headers to send with every request
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $defaultHeaders = [
|
||||||
|
'User-Agent' => USER_AGENT,
|
||||||
|
'Accept' => 'application/vnd.api+json',
|
||||||
|
'Content-Type' => 'application/vnd.api+json',
|
||||||
|
'CLIENT_ID' => 'dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd',
|
||||||
|
'CLIENT_SECRET' => '54d7307928f63414defd96399fc31ba847961ceaecef3a5fd93144e960c0e151',
|
||||||
|
];
|
||||||
|
}
|
179
src/API/Anilist/AnilistTrait.php
Normal file
179
src/API/Anilist/AnilistTrait.php
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\API\MAL;
|
||||||
|
|
||||||
|
use function Amp\Promise\wait;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\API\{
|
||||||
|
Anilist,
|
||||||
|
HummingbirdClient
|
||||||
|
};
|
||||||
|
|
||||||
|
trait AnilistTrait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The request builder for the MAL API
|
||||||
|
* @var AnilistRequestBuilder
|
||||||
|
*/
|
||||||
|
protected $requestBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base url for api requests
|
||||||
|
* @var string $base_url
|
||||||
|
*/
|
||||||
|
protected $baseUrl = Anilist::BASE_URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP headers to send with every request
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $defaultHeaders = [
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
'Accept-Encoding' => 'gzip',
|
||||||
|
'Content-type' => 'application/json',
|
||||||
|
'User-Agent' => "Tim's Anime Client/4.0"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the request builder object
|
||||||
|
*
|
||||||
|
* @param MALRequestBuilder $requestBuilder
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setRequestBuilder($requestBuilder): self
|
||||||
|
{
|
||||||
|
$this->requestBuilder = $requestBuilder;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a request object
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @param string $url
|
||||||
|
* @param array $options
|
||||||
|
* @return \Amp\Artax\Response
|
||||||
|
*/
|
||||||
|
public function setUpRequest(string $type, string $url, array $options = [])
|
||||||
|
{
|
||||||
|
$config = $this->container->get('config');
|
||||||
|
|
||||||
|
$request = $this->requestBuilder
|
||||||
|
->newRequest($type, $url)
|
||||||
|
->setBasicAuth($config->get(['mal','username']), $config->get(['mal','password']));
|
||||||
|
|
||||||
|
if (array_key_exists('query', $options))
|
||||||
|
{
|
||||||
|
$request = $request->setQuery($options['query']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('body', $options))
|
||||||
|
{
|
||||||
|
$request = $request->setBody($options['body']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $request->getFullRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a request
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @param string $url
|
||||||
|
* @param array $options
|
||||||
|
* @return \Amp\Artax\Response
|
||||||
|
*/
|
||||||
|
private function getResponse(string $type, string $url, array $options = [])
|
||||||
|
{
|
||||||
|
$logger = NULL;
|
||||||
|
if ($this->getContainer())
|
||||||
|
{
|
||||||
|
$logger = $this->container->getLogger('mal-request');
|
||||||
|
}
|
||||||
|
|
||||||
|
$request = $this->setUpRequest($type, $url, $options);
|
||||||
|
$response = wait((new HummingbirdClient)->request($request));
|
||||||
|
|
||||||
|
$logger->debug('MAL api response', [
|
||||||
|
'status' => $response->getStatus(),
|
||||||
|
'reason' => $response->getReason(),
|
||||||
|
'body' => $response->getBody(),
|
||||||
|
'headers' => $response->getHeaders(),
|
||||||
|
'requestHeaders' => $request->getHeaders(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a request
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @param string $url
|
||||||
|
* @param array $options
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function request(string $type, string $url, array $options = []): array
|
||||||
|
{
|
||||||
|
$logger = NULL;
|
||||||
|
if ($this->getContainer())
|
||||||
|
{
|
||||||
|
$logger = $this->container->getLogger('anilist-request');
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->getResponse($type, $url, $options);
|
||||||
|
|
||||||
|
if ((int) $response->getStatus() > 299 OR (int) $response->getStatus() < 200)
|
||||||
|
{
|
||||||
|
if ($logger)
|
||||||
|
{
|
||||||
|
$logger->warning('Non 200 response for api call', (array)$response->getBody());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return XML::toArray(wait($response->getBody()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove some boilerplate for post requests
|
||||||
|
*
|
||||||
|
* @param mixed ...$args
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function postRequest(...$args): array
|
||||||
|
{
|
||||||
|
$logger = NULL;
|
||||||
|
if ($this->getContainer())
|
||||||
|
{
|
||||||
|
$logger = $this->container->getLogger('anilist-request');
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->getResponse('POST', ...$args);
|
||||||
|
$validResponseCodes = [200, 201];
|
||||||
|
|
||||||
|
if ( ! \in_array((int) $response->getStatus(), $validResponseCodes, TRUE))
|
||||||
|
{
|
||||||
|
if ($logger)
|
||||||
|
{
|
||||||
|
$logger->warning('Non 201 response for POST api call', (array)$response->getBody());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return XML::toArray($response->getBody());
|
||||||
|
}
|
||||||
|
}
|
109
src/API/Anilist/ListItem.php
Normal file
109
src/API/Anilist/ListItem.php
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\API\Anilist;
|
||||||
|
|
||||||
|
use Amp\Artax\{FormBody, Request};
|
||||||
|
use Aviat\AnimeClient\API\{
|
||||||
|
XML
|
||||||
|
};
|
||||||
|
use Aviat\AnimeClient\Types\AbstractType;
|
||||||
|
use Aviat\Ion\Di\ContainerAware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CRUD operations for MAL list items
|
||||||
|
*/
|
||||||
|
final class ListItem {
|
||||||
|
use ContainerAware;
|
||||||
|
use AnilistTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a list item
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @param string $type
|
||||||
|
* @return Request
|
||||||
|
*/
|
||||||
|
public function create(array $data, string $type = 'anime'): Request
|
||||||
|
{
|
||||||
|
$id = $data['id'];
|
||||||
|
$createData = [
|
||||||
|
'id' => $id,
|
||||||
|
'data' => XML::toXML([
|
||||||
|
'entry' => $data['data']
|
||||||
|
])
|
||||||
|
];
|
||||||
|
|
||||||
|
$config = $this->container->get('config');
|
||||||
|
|
||||||
|
return $this->requestBuilder->newRequest('POST', "{$type}list/add/{$id}.xml")
|
||||||
|
->setFormFields($createData)
|
||||||
|
->setBasicAuth($config->get(['mal','username']), $config->get(['mal', 'password']))
|
||||||
|
->getFullRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a list item
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param string $type
|
||||||
|
* @return Request
|
||||||
|
*/
|
||||||
|
public function delete(string $id, string $type = 'anime'): Request
|
||||||
|
{
|
||||||
|
$config = $this->container->get('config');
|
||||||
|
|
||||||
|
return $this->requestBuilder->newRequest('DELETE', "{$type}list/delete/{$id}.xml")
|
||||||
|
->setFormFields([
|
||||||
|
'id' => $id
|
||||||
|
])
|
||||||
|
->setBasicAuth($config->get(['mal','username']), $config->get(['mal', 'password']))
|
||||||
|
->getFullRequest();
|
||||||
|
|
||||||
|
// return $response->getBody() === 'Deleted'
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $id): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a list item
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param AbstractType $data
|
||||||
|
* @param string $type
|
||||||
|
* @return Request
|
||||||
|
*/
|
||||||
|
public function update(string $id, AbstractType $data, string $type = 'anime'): Request
|
||||||
|
{
|
||||||
|
$config = $this->container->get('config');
|
||||||
|
|
||||||
|
$xml = XML::toXML(['entry' => $data]);
|
||||||
|
$body = new FormBody();
|
||||||
|
$body->addField('id', $id);
|
||||||
|
$body->addField('data', $xml);
|
||||||
|
|
||||||
|
return $this->requestBuilder->newRequest('POST', "{$type}list/update/{$id}.xml")
|
||||||
|
->setFormFields([
|
||||||
|
'id' => $id,
|
||||||
|
'data' => $xml
|
||||||
|
])
|
||||||
|
->setBasicAuth($config->get(['mal','username']), $config->get(['mal', 'password']))
|
||||||
|
->getFullRequest();
|
||||||
|
}
|
||||||
|
}
|
23
src/API/Anilist/Model.php
Normal file
23
src/API/Anilist/Model.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\API\Anilist;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anilist API Model
|
||||||
|
*/
|
||||||
|
final class Model {
|
||||||
|
}
|
31
src/API/Enum/AnimeWatchingStatus/Anilist.php
Normal file
31
src/API/Enum/AnimeWatchingStatus/Anilist.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\API\Enum\AnimeWatchingStatus;
|
||||||
|
|
||||||
|
use Aviat\Ion\Enum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible values for watching status for the current anime
|
||||||
|
*/
|
||||||
|
final class Anilist extends Enum {
|
||||||
|
const WATCHING = 'CURRENT';
|
||||||
|
const COMPLETED = 'COMPLETED';
|
||||||
|
const ON_HOLD = 'PAUSED';
|
||||||
|
const DROPPED = 'DROPPED';
|
||||||
|
const PLAN_TO_WATCH = 'PLANNING';
|
||||||
|
const REPEATING = 'REPEATING';
|
||||||
|
}
|
@ -21,7 +21,7 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for watching status for the current anime
|
* Possible values for watching status for the current anime
|
||||||
*/
|
*/
|
||||||
class Kitsu extends Enum {
|
final class Kitsu extends Enum {
|
||||||
const WATCHING = 'current';
|
const WATCHING = 'current';
|
||||||
const PLAN_TO_WATCH = 'planned';
|
const PLAN_TO_WATCH = 'planned';
|
||||||
const ON_HOLD = 'on_hold';
|
const ON_HOLD = 'on_hold';
|
||||||
|
@ -21,7 +21,7 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for watching status for the current anime
|
* Possible values for watching status for the current anime
|
||||||
*/
|
*/
|
||||||
class MAL extends Enum {
|
final class MAL extends Enum {
|
||||||
const WATCHING = 1;
|
const WATCHING = 1;
|
||||||
const COMPLETED = 2;
|
const COMPLETED = 2;
|
||||||
const ON_HOLD = 3;
|
const ON_HOLD = 3;
|
||||||
|
@ -21,7 +21,7 @@ use Aviat\Ion\Enum as Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for current watching status of anime
|
* Possible values for current watching status of anime
|
||||||
*/
|
*/
|
||||||
class Route extends Enum {
|
final class Route extends Enum {
|
||||||
const ALL = 'all';
|
const ALL = 'all';
|
||||||
const WATCHING = 'watching';
|
const WATCHING = 'watching';
|
||||||
const PLAN_TO_WATCH = 'plan_to_watch';
|
const PLAN_TO_WATCH = 'plan_to_watch';
|
||||||
|
@ -21,7 +21,7 @@ use Aviat\Ion\Enum as Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for current watching status of anime
|
* Possible values for current watching status of anime
|
||||||
*/
|
*/
|
||||||
class Title extends Enum {
|
final class Title extends Enum {
|
||||||
const ALL = 'All';
|
const ALL = 'All';
|
||||||
const WATCHING = 'Currently Watching';
|
const WATCHING = 'Currently Watching';
|
||||||
const PLAN_TO_WATCH = 'Plan to Watch';
|
const PLAN_TO_WATCH = 'Plan to Watch';
|
||||||
|
31
src/API/Enum/MangaReadingStatus/Anilist.php
Normal file
31
src/API/Enum/MangaReadingStatus/Anilist.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
||||||
|
|
||||||
|
use Aviat\Ion\Enum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible values for watching status for the current anime
|
||||||
|
*/
|
||||||
|
final class Anilist extends Enum {
|
||||||
|
const WATCHING = 'CURRENT';
|
||||||
|
const COMPLETED = 'COMPLETED';
|
||||||
|
const ON_HOLD = 'PAUSED';
|
||||||
|
const DROPPED = 'DROPPED';
|
||||||
|
const PLAN_TO_WATCH = 'PLANNING';
|
||||||
|
const REPEATING = 'REPEATING';
|
||||||
|
}
|
@ -21,7 +21,7 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for current reading status of manga
|
* Possible values for current reading status of manga
|
||||||
*/
|
*/
|
||||||
class Kitsu extends Enum {
|
final class Kitsu extends Enum {
|
||||||
const READING = 'current';
|
const READING = 'current';
|
||||||
const PLAN_TO_READ = 'planned';
|
const PLAN_TO_READ = 'planned';
|
||||||
const DROPPED = 'dropped';
|
const DROPPED = 'dropped';
|
||||||
|
@ -21,7 +21,7 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for watching status for the current anime
|
* Possible values for watching status for the current anime
|
||||||
*/
|
*/
|
||||||
class MAL extends Enum {
|
final class MAL extends Enum {
|
||||||
const READING = 'reading';
|
const READING = 'reading';
|
||||||
const COMPLETED = 'completed';
|
const COMPLETED = 'completed';
|
||||||
const ON_HOLD = 'onhold';
|
const ON_HOLD = 'onhold';
|
||||||
|
@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
||||||
|
|
||||||
use Aviat\Ion\Enum as Enum;
|
use Aviat\Ion\Enum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Possible values for current reading status of manga
|
* Possible values for current reading status of manga
|
||||||
*/
|
*/
|
||||||
class Route extends Enum {
|
final class Route extends Enum {
|
||||||
const ALL = 'all';
|
const ALL = 'all';
|
||||||
const READING = 'reading';
|
const READING = 'reading';
|
||||||
const PLAN_TO_READ = 'plan_to_read';
|
const PLAN_TO_READ = 'plan_to_read';
|
||||||
|
@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
||||||
|
|
||||||
use Aviat\Ion\Enum as Enum;
|
use Aviat\Ion\Enum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Possible values for current reading status of manga
|
* Possible values for current reading status of manga
|
||||||
*/
|
*/
|
||||||
class Title extends Enum {
|
final class Title extends Enum {
|
||||||
const ALL = 'All';
|
const ALL = 'All';
|
||||||
const READING = 'Currently Reading';
|
const READING = 'Currently Reading';
|
||||||
const PLAN_TO_READ = 'Plan to Read';
|
const PLAN_TO_READ = 'Plan to Read';
|
||||||
|
@ -19,7 +19,7 @@ namespace Aviat\AnimeClient\API;
|
|||||||
/**
|
/**
|
||||||
* Class encapsulating Json API data structure for a request or response
|
* Class encapsulating Json API data structure for a request or response
|
||||||
*/
|
*/
|
||||||
class JsonAPI {
|
final class JsonAPI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The full data array
|
* The full data array
|
||||||
|
@ -22,7 +22,7 @@ use DateTimeImmutable;
|
|||||||
/**
|
/**
|
||||||
* Data massaging helpers for the Kitsu API
|
* Data massaging helpers for the Kitsu API
|
||||||
*/
|
*/
|
||||||
class Kitsu {
|
final class Kitsu {
|
||||||
const AUTH_URL = 'https://kitsu.io/api/oauth/token';
|
const AUTH_URL = 'https://kitsu.io/api/oauth/token';
|
||||||
const AUTH_USER_ID_KEY = 'kitsu-auth-userid';
|
const AUTH_USER_ID_KEY = 'kitsu-auth-userid';
|
||||||
const AUTH_TOKEN_CACHE_KEY = 'kitsu-auth-token';
|
const AUTH_TOKEN_CACHE_KEY = 'kitsu-auth-token';
|
||||||
@ -143,7 +143,10 @@ class Kitsu {
|
|||||||
*/
|
*/
|
||||||
public static function parseStreamingLinks(array $included): array
|
public static function parseStreamingLinks(array $included): array
|
||||||
{
|
{
|
||||||
if ( ! array_key_exists('streamingLinks', $included))
|
if (
|
||||||
|
( ! array_key_exists('streamingLinks', $included)) ||
|
||||||
|
count($included['streamingLinks']) === 0
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -152,7 +155,16 @@ class Kitsu {
|
|||||||
|
|
||||||
foreach ($included['streamingLinks'] as $streamingLink)
|
foreach ($included['streamingLinks'] as $streamingLink)
|
||||||
{
|
{
|
||||||
$host = parse_url($streamingLink['url'], \PHP_URL_HOST);
|
$url = $streamingLink['url'];
|
||||||
|
|
||||||
|
// 'Fix' links that start with the hostname,
|
||||||
|
// rather than a protocol
|
||||||
|
if (strpos($url, '//') === FALSE)
|
||||||
|
{
|
||||||
|
$url = '//' . $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$host = parse_url($url, \PHP_URL_HOST);
|
||||||
|
|
||||||
$links[] = [
|
$links[] = [
|
||||||
'meta' => static::getServiceMetaData($host),
|
'meta' => static::getServiceMetaData($host),
|
||||||
@ -182,17 +194,7 @@ class Kitsu {
|
|||||||
|
|
||||||
if (count($anime['relationships']['streamingLinks']) > 0)
|
if (count($anime['relationships']['streamingLinks']) > 0)
|
||||||
{
|
{
|
||||||
foreach ($anime['relationships']['streamingLinks'] as $streamingLink)
|
return static::parseStreamingLinks($anime['relationships']);
|
||||||
{
|
|
||||||
$host = parse_url($streamingLink['url'], \PHP_URL_HOST);
|
|
||||||
|
|
||||||
$links[] = [
|
|
||||||
'meta' => static::getServiceMetaData($host),
|
|
||||||
'link' => $streamingLink['url'],
|
|
||||||
'subs' => $streamingLink['subs'],
|
|
||||||
'dubs' => $streamingLink['dubs']
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $links;
|
return $links;
|
||||||
@ -243,10 +245,9 @@ class Kitsu {
|
|||||||
foreach($existingTitles as $existing)
|
foreach($existingTitles as $existing)
|
||||||
{
|
{
|
||||||
$isSubset = mb_substr_count($existing, $title) > 0;
|
$isSubset = mb_substr_count($existing, $title) > 0;
|
||||||
$diff = levenshtein($existing, $title);
|
$diff = levenshtein(mb_strtolower($existing), mb_strtolower($title));
|
||||||
$onlydifferentCase = (mb_strtolower($existing) === mb_strtolower($title));
|
|
||||||
|
|
||||||
if ($diff <= 3 OR $isSubset OR $onlydifferentCase OR mb_strlen($title) > 55 OR mb_strlen($existing) > 60)
|
if ($diff <= 4 || $isSubset || mb_strlen($title) > 45 || mb_strlen($existing) > 50)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ use Exception;
|
|||||||
/**
|
/**
|
||||||
* Kitsu API Authentication
|
* Kitsu API Authentication
|
||||||
*/
|
*/
|
||||||
class Auth {
|
final class Auth {
|
||||||
use CacheTrait;
|
use CacheTrait;
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
|
|
||||||
@ -37,14 +37,14 @@ class Auth {
|
|||||||
*
|
*
|
||||||
* @var Model
|
* @var Model
|
||||||
*/
|
*/
|
||||||
protected $model;
|
private $model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Session object
|
* Session object
|
||||||
*
|
*
|
||||||
* @var \Aura\Session\Segment
|
* @var \Aura\Session\Segment
|
||||||
*/
|
*/
|
||||||
protected $segment;
|
private $segment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -21,7 +21,7 @@ use Aviat\Ion\Enum as BaseEnum;
|
|||||||
/**
|
/**
|
||||||
* Status of when anime is being/was/will be aired
|
* Status of when anime is being/was/will be aired
|
||||||
*/
|
*/
|
||||||
class AnimeAiringStatus extends BaseEnum {
|
final class AnimeAiringStatus extends BaseEnum {
|
||||||
const NOT_YET_AIRED = 'Not Yet Aired';
|
const NOT_YET_AIRED = 'Not Yet Aired';
|
||||||
const AIRING = 'Currently Airing';
|
const AIRING = 'Currently Airing';
|
||||||
const FINISHED_AIRING = 'Finished Airing';
|
const FINISHED_AIRING = 'Finished Airing';
|
||||||
|
@ -18,7 +18,7 @@ namespace Aviat\AnimeClient\API\Kitsu;
|
|||||||
|
|
||||||
use Aviat\AnimeClient\API\APIRequestBuilder;
|
use Aviat\AnimeClient\API\APIRequestBuilder;
|
||||||
|
|
||||||
class KitsuRequestBuilder extends APIRequestBuilder {
|
final class KitsuRequestBuilder extends APIRequestBuilder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base url for api requests
|
* The base url for api requests
|
||||||
|
@ -25,39 +25,17 @@ use Aviat\AnimeClient\API\{
|
|||||||
HummingbirdClient,
|
HummingbirdClient,
|
||||||
ListItemInterface
|
ListItemInterface
|
||||||
};
|
};
|
||||||
|
use Aviat\AnimeClient\Types\FormItemData;
|
||||||
use Aviat\Ion\Di\ContainerAware;
|
use Aviat\Ion\Di\ContainerAware;
|
||||||
use Aviat\Ion\Json;
|
use Aviat\Ion\Json;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CRUD operations for Kitsu list items
|
* CRUD operations for Kitsu list items
|
||||||
*/
|
*/
|
||||||
class ListItem implements ListItemInterface {
|
final class ListItem implements ListItemInterface {
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
use KitsuTrait;
|
use KitsuTrait;
|
||||||
|
|
||||||
private function getAuthHeader()
|
|
||||||
{
|
|
||||||
$cache = $this->getContainer()->get('cache');
|
|
||||||
$cacheItem = $cache->getItem('kitsu-auth-token');
|
|
||||||
$sessionSegment = $this->getContainer()
|
|
||||||
->get('session')
|
|
||||||
->getSegment(SESSION_SEGMENT);
|
|
||||||
|
|
||||||
if ($sessionSegment->get('auth_token') !== NULL)
|
|
||||||
{
|
|
||||||
$token = $sessionSegment->get('auth_token');
|
|
||||||
return "bearer {$token}";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cacheItem->isHit())
|
|
||||||
{
|
|
||||||
$token = $cacheItem->get();
|
|
||||||
return "bearer {$token}";
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function create(array $data): Request
|
public function create(array $data): Request
|
||||||
{
|
{
|
||||||
$body = [
|
$body = [
|
||||||
@ -134,7 +112,7 @@ class ListItem implements ListItemInterface {
|
|||||||
return Json::decode(wait($response->getBody()));
|
return Json::decode(wait($response->getBody()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(string $id, array $data): Request
|
public function update(string $id, FormItemData $data): Request
|
||||||
{
|
{
|
||||||
$authHeader = $this->getAuthHeader();
|
$authHeader = $this->getAuthHeader();
|
||||||
$requestData = [
|
$requestData = [
|
||||||
@ -155,4 +133,25 @@ class ListItem implements ListItemInterface {
|
|||||||
|
|
||||||
return $request->getFullRequest();
|
return $request->getFullRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getAuthHeader()
|
||||||
|
{
|
||||||
|
$cache = $this->getContainer()->get('cache');
|
||||||
|
$cacheItem = $cache->getItem('kitsu-auth-token');
|
||||||
|
$sessionSegment = $this->getContainer()
|
||||||
|
->get('session')
|
||||||
|
->getSegment(SESSION_SEGMENT);
|
||||||
|
|
||||||
|
if ($sessionSegment->get('auth_token') !== NULL) {
|
||||||
|
$token = $sessionSegment->get('auth_token');
|
||||||
|
return "bearer {$token}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cacheItem->isHit()) {
|
||||||
|
$token = $cacheItem->get();
|
||||||
|
return "bearer {$token}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
@ -26,7 +26,6 @@ use Aviat\AnimeClient\API\{
|
|||||||
ParallelAPIRequest
|
ParallelAPIRequest
|
||||||
};
|
};
|
||||||
use Aviat\AnimeClient\API\Enum\{
|
use Aviat\AnimeClient\API\Enum\{
|
||||||
AnimeWatchingStatus\Title,
|
|
||||||
AnimeWatchingStatus\Kitsu as KitsuWatchingStatus,
|
AnimeWatchingStatus\Kitsu as KitsuWatchingStatus,
|
||||||
MangaReadingStatus\Kitsu as KitsuReadingStatus
|
MangaReadingStatus\Kitsu as KitsuReadingStatus
|
||||||
};
|
};
|
||||||
@ -37,17 +36,25 @@ use Aviat\AnimeClient\API\Kitsu\Transformer\{
|
|||||||
MangaTransformer,
|
MangaTransformer,
|
||||||
MangaListTransformer
|
MangaListTransformer
|
||||||
};
|
};
|
||||||
|
use Aviat\AnimeClient\Types\{
|
||||||
|
AbstractType,
|
||||||
|
Anime,
|
||||||
|
FormItem,
|
||||||
|
FormItemData,
|
||||||
|
AnimeListItem,
|
||||||
|
MangaPage
|
||||||
|
};
|
||||||
use Aviat\Ion\{Di\ContainerAware, Json};
|
use Aviat\Ion\{Di\ContainerAware, Json};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kitsu API Model
|
* Kitsu API Model
|
||||||
*/
|
*/
|
||||||
class Model {
|
final class Model {
|
||||||
use CacheTrait;
|
use CacheTrait;
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
use KitsuTrait;
|
use KitsuTrait;
|
||||||
|
|
||||||
const LIST_PAGE_SIZE = 100;
|
private const LIST_PAGE_SIZE = 100;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to map anime list items
|
* Class to map anime list items
|
||||||
@ -56,27 +63,27 @@ class Model {
|
|||||||
*
|
*
|
||||||
* @var AnimeListTransformer
|
* @var AnimeListTransformer
|
||||||
*/
|
*/
|
||||||
protected $animeListTransformer;
|
private $animeListTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var AnimeTransformer
|
* @var AnimeTransformer
|
||||||
*/
|
*/
|
||||||
protected $animeTransformer;
|
private $animeTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ListItem
|
* @var ListItem
|
||||||
*/
|
*/
|
||||||
protected $listItem;
|
private $listItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var MangaTransformer
|
* @var MangaTransformer
|
||||||
*/
|
*/
|
||||||
protected $mangaTransformer;
|
private $mangaTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var MangaListTransformer
|
* @var MangaListTransformer
|
||||||
*/
|
*/
|
||||||
protected $mangaListTransformer;
|
private $mangaListTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -314,15 +321,15 @@ class Model {
|
|||||||
* Get information about a particular anime
|
* Get information about a particular anime
|
||||||
*
|
*
|
||||||
* @param string $slug
|
* @param string $slug
|
||||||
* @return array
|
* @return Anime
|
||||||
*/
|
*/
|
||||||
public function getAnime(string $slug): array
|
public function getAnime(string $slug): Anime
|
||||||
{
|
{
|
||||||
$baseData = $this->getRawMediaData('anime', $slug);
|
$baseData = $this->getRawMediaData('anime', $slug);
|
||||||
|
|
||||||
if (empty($baseData))
|
if (empty($baseData))
|
||||||
{
|
{
|
||||||
return [];
|
return new Anime();
|
||||||
}
|
}
|
||||||
|
|
||||||
$transformed = $this->animeTransformer->transform($baseData);
|
$transformed = $this->animeTransformer->transform($baseData);
|
||||||
@ -417,7 +424,7 @@ class Model {
|
|||||||
* @param array $options
|
* @param array $options
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getFullAnimeList(array $options = [
|
public function getFullRawAnimeList(array $options = [
|
||||||
'include' => 'anime.mappings'
|
'include' => 'anime.mappings'
|
||||||
]): array
|
]): array
|
||||||
{
|
{
|
||||||
@ -441,10 +448,10 @@ class Model {
|
|||||||
foreach($responses as $response)
|
foreach($responses as $response)
|
||||||
{
|
{
|
||||||
$data = Json::decode($response);
|
$data = Json::decode($response);
|
||||||
$output = array_merge_recursive($output, $data);
|
$output[] = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $output;
|
return array_merge_recursive(...$output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -547,7 +554,7 @@ class Model {
|
|||||||
'sort' => '-updated_at'
|
'sort' => '-updated_at'
|
||||||
];
|
];
|
||||||
|
|
||||||
return $this->getFullAnimeList($options);
|
return $this->getFullRawAnimeList($options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
@ -558,15 +565,15 @@ class Model {
|
|||||||
* Get information about a particular manga
|
* Get information about a particular manga
|
||||||
*
|
*
|
||||||
* @param string $slug
|
* @param string $slug
|
||||||
* @return array
|
* @return MangaPage
|
||||||
*/
|
*/
|
||||||
public function getManga(string $slug): array
|
public function getManga(string $slug): MangaPage
|
||||||
{
|
{
|
||||||
$baseData = $this->getRawMediaData('manga', $slug);
|
$baseData = $this->getRawMediaData('manga', $slug);
|
||||||
|
|
||||||
if (empty($baseData))
|
if (empty($baseData))
|
||||||
{
|
{
|
||||||
return [];
|
return new MangaPage([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$transformed = $this->mangaTransformer->transform($baseData);
|
$transformed = $this->mangaTransformer->transform($baseData);
|
||||||
@ -580,7 +587,7 @@ class Model {
|
|||||||
* @param string $mangaId
|
* @param string $mangaId
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getMangaById(string $mangaId): array
|
public function getMangaById(string $mangaId): MangaPage
|
||||||
{
|
{
|
||||||
$baseData = $this->getRawMediaDataById('manga', $mangaId);
|
$baseData = $this->getRawMediaDataById('manga', $mangaId);
|
||||||
return $this->mangaTransformer->transform($baseData);
|
return $this->mangaTransformer->transform($baseData);
|
||||||
@ -680,7 +687,7 @@ class Model {
|
|||||||
* @param array $options
|
* @param array $options
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getFullMangaList(array $options = [
|
public function getFullRawMangaList(array $options = [
|
||||||
'include' => 'manga.mappings'
|
'include' => 'manga.mappings'
|
||||||
]): array
|
]): array
|
||||||
{
|
{
|
||||||
@ -704,10 +711,10 @@ class Model {
|
|||||||
foreach($responses as $response)
|
foreach($responses as $response)
|
||||||
{
|
{
|
||||||
$data = Json::decode($response);
|
$data = Json::decode($response);
|
||||||
$output = array_merge_recursive($output, $data);
|
$output[] = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $output;
|
return array_merge_recursive(...$output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -804,9 +811,9 @@ class Model {
|
|||||||
* Get the data for a specific list item, generally for editing
|
* Get the data for a specific list item, generally for editing
|
||||||
*
|
*
|
||||||
* @param string $listId - The unique identifier of that list item
|
* @param string $listId - The unique identifier of that list item
|
||||||
* @return array
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getListItem(string $listId): array
|
public function getListItem(string $listId)
|
||||||
{
|
{
|
||||||
$baseData = $this->listItem->get($listId);
|
$baseData = $this->listItem->get($listId);
|
||||||
$included = JsonAPI::organizeIncludes($baseData['included']);
|
$included = JsonAPI::organizeIncludes($baseData['included']);
|
||||||
@ -814,12 +821,12 @@ class Model {
|
|||||||
|
|
||||||
switch (TRUE)
|
switch (TRUE)
|
||||||
{
|
{
|
||||||
case in_array('anime', array_keys($included)):
|
case array_key_exists('anime', $included): // in_array('anime', array_keys($included)):
|
||||||
$included = JsonAPI::inlineIncludedRelationships($included, 'anime');
|
$included = JsonAPI::inlineIncludedRelationships($included, 'anime');
|
||||||
$baseData['data']['included'] = $included;
|
$baseData['data']['included'] = $included;
|
||||||
return $this->animeListTransformer->transform($baseData['data']);
|
return $this->animeListTransformer->transform($baseData['data']);
|
||||||
|
|
||||||
case in_array('manga', array_keys($included)):
|
case array_key_exists('manga', $included): // in_array('manga', array_keys($included)):
|
||||||
$included = JsonAPI::inlineIncludedRelationships($included, 'manga');
|
$included = JsonAPI::inlineIncludedRelationships($included, 'manga');
|
||||||
$baseData['data']['included'] = $included;
|
$baseData['data']['included'] = $included;
|
||||||
$baseData['data']['manga'] = $baseData['included'][0];
|
$baseData['data']['manga'] = $baseData['included'][0];
|
||||||
@ -833,10 +840,10 @@ class Model {
|
|||||||
/**
|
/**
|
||||||
* Modify a list item
|
* Modify a list item
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param FormItem $data
|
||||||
* @return Request
|
* @return Request
|
||||||
*/
|
*/
|
||||||
public function updateListItem(array $data): Request
|
public function updateListItem(FormItem $data): Request
|
||||||
{
|
{
|
||||||
return $this->listItem->update($data['id'], $data['data']);
|
return $this->listItem->update($data['id'], $data['data']);
|
||||||
}
|
}
|
||||||
|
@ -17,21 +17,27 @@
|
|||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Kitsu;
|
use Aviat\AnimeClient\API\Kitsu;
|
||||||
|
use Aviat\AnimeClient\Types\{
|
||||||
|
Anime,
|
||||||
|
AnimeFormItem,
|
||||||
|
AnimeFormItemData,
|
||||||
|
AnimeListItem
|
||||||
|
};
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transformer for anime list
|
* Transformer for anime list
|
||||||
*/
|
*/
|
||||||
class AnimeListTransformer extends AbstractTransformer {
|
final class AnimeListTransformer extends AbstractTransformer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert raw api response to a more
|
* Convert raw api response to a more
|
||||||
* logical and workable structure
|
* logical and workable structure
|
||||||
*
|
*
|
||||||
* @param array $item API library item
|
* @param array $item API library item
|
||||||
* @return array
|
* @return AnimeListItem
|
||||||
*/
|
*/
|
||||||
public function transform($item): array
|
public function transform($item): AnimeListItem
|
||||||
{
|
{
|
||||||
$included = $item['included'];
|
$included = $item['included'];
|
||||||
$animeId = $item['relationships']['media']['data']['id'];
|
$animeId = $item['relationships']['media']['data']['id'];
|
||||||
@ -66,7 +72,10 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
? Kitsu::parseListItemStreamingLinks($included, $animeId)
|
? Kitsu::parseListItemStreamingLinks($included, $animeId)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return [
|
$titles = Kitsu::filterTitles($anime);
|
||||||
|
$title = array_shift($titles);
|
||||||
|
|
||||||
|
return new AnimeListItem([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
'mal_id' => $MALid,
|
'mal_id' => $MALid,
|
||||||
'episodes' => [
|
'episodes' => [
|
||||||
@ -81,24 +90,24 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
'started' => $anime['startDate'],
|
'started' => $anime['startDate'],
|
||||||
'ended' => $anime['endDate']
|
'ended' => $anime['endDate']
|
||||||
],
|
],
|
||||||
'anime' => [
|
'anime' => new Anime([
|
||||||
'id' => $animeId,
|
'id' => $animeId,
|
||||||
'age_rating' => $anime['ageRating'],
|
'age_rating' => $anime['ageRating'],
|
||||||
'title' => $anime['canonicalTitle'],
|
'title' => $title,
|
||||||
'titles' => Kitsu::filterTitles($anime),
|
'titles' => $titles,
|
||||||
'slug' => $anime['slug'],
|
'slug' => $anime['slug'],
|
||||||
'type' => $this->string($anime['showType'])->upperCaseFirst()->__toString(),
|
'show_type' => $this->string($anime['showType'])->upperCaseFirst()->__toString(),
|
||||||
'image' => $anime['posterImage']['small'],
|
'cover_image' => $anime['posterImage']['small'],
|
||||||
'genres' => $genres,
|
'genres' => $genres,
|
||||||
'streaming_links' => $streamingLinks,
|
'streaming_links' => $streamingLinks,
|
||||||
],
|
]),
|
||||||
'watching_status' => $item['attributes']['status'],
|
'watching_status' => $item['attributes']['status'],
|
||||||
'notes' => $item['attributes']['notes'],
|
'notes' => $item['attributes']['notes'],
|
||||||
'rewatching' => (bool) $item['attributes']['reconsuming'],
|
'rewatching' => (bool) $item['attributes']['reconsuming'],
|
||||||
'rewatched' => (int) $item['attributes']['reconsumeCount'],
|
'rewatched' => (int) $item['attributes']['reconsumeCount'],
|
||||||
'user_rating' => $rating,
|
'user_rating' => $rating,
|
||||||
'private' => $item['attributes']['private'] ?? FALSE,
|
'private' => $item['attributes']['private'] ?? FALSE,
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,14 +115,14 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
* api response format
|
* api response format
|
||||||
*
|
*
|
||||||
* @param array $item Transformed library item
|
* @param array $item Transformed library item
|
||||||
* @return array API library item
|
* @return AnimeFormItem API library item
|
||||||
*/
|
*/
|
||||||
public function untransform($item): array
|
public function untransform($item): AnimeFormItem
|
||||||
{
|
{
|
||||||
$privacy = (array_key_exists('private', $item) && $item['private']);
|
$privacy = (array_key_exists('private', $item) && $item['private']);
|
||||||
$rewatching = (array_key_exists('rewatching', $item) && $item['rewatching']);
|
$rewatching = (array_key_exists('rewatching', $item) && $item['rewatching']);
|
||||||
|
|
||||||
$untransformed = [
|
$untransformed = new AnimeFormItem([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
'mal_id' => $item['mal_id'] ?? NULL,
|
'mal_id' => $item['mal_id'] ?? NULL,
|
||||||
'data' => [
|
'data' => [
|
||||||
@ -123,7 +132,7 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
'notes' => $item['notes'],
|
'notes' => $item['notes'],
|
||||||
'private' => $privacy
|
'private' => $privacy
|
||||||
]
|
]
|
||||||
];
|
]);
|
||||||
|
|
||||||
if (is_numeric($item['episodes_watched']) && $item['episodes_watched'] > 0)
|
if (is_numeric($item['episodes_watched']) && $item['episodes_watched'] > 0)
|
||||||
{
|
{
|
||||||
|
@ -17,31 +17,32 @@
|
|||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\{JsonAPI, Kitsu};
|
use Aviat\AnimeClient\API\{JsonAPI, Kitsu};
|
||||||
|
use Aviat\AnimeClient\Types\Anime;
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transformer for anime description page
|
* Transformer for anime description page
|
||||||
*/
|
*/
|
||||||
class AnimeTransformer extends AbstractTransformer {
|
final class AnimeTransformer extends AbstractTransformer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert raw api response to a more
|
* Convert raw api response to a more
|
||||||
* logical and workable structure
|
* logical and workable structure
|
||||||
*
|
*
|
||||||
* @param array $item API library item
|
* @param array $item API library item
|
||||||
* @return array
|
* @return Anime
|
||||||
*/
|
*/
|
||||||
public function transform($item): array
|
public function transform($item): Anime
|
||||||
{
|
{
|
||||||
|
|
||||||
$item['included'] = JsonAPI::organizeIncludes($item['included']);
|
$item['included'] = JsonAPI::organizeIncludes($item['included']);
|
||||||
$genres = $item['included']['categories'] ?? [];
|
$genres = $item['included']['categories'] ?? [];
|
||||||
$item['genres'] = array_column($genres, 'title') ?? [];
|
$item['genres'] = array_column($genres, 'title') ?? [];
|
||||||
sort($item['genres']);
|
sort($item['genres']);
|
||||||
|
|
||||||
$titles = Kitsu::filterTitles($item);
|
$title = $item['canonicalTitle'];
|
||||||
|
$titles = array_diff($item['titles'], [$title]);
|
||||||
|
|
||||||
return [
|
return new Anime([
|
||||||
'age_rating' => $item['ageRating'],
|
'age_rating' => $item['ageRating'],
|
||||||
'age_rating_guide' => $item['ageRatingGuide'],
|
'age_rating_guide' => $item['ageRatingGuide'],
|
||||||
'cover_image' => $item['posterImage']['small'],
|
'cover_image' => $item['posterImage']['small'],
|
||||||
@ -54,10 +55,10 @@ class AnimeTransformer extends AbstractTransformer {
|
|||||||
'status' => Kitsu::getAiringStatus($item['startDate'], $item['endDate']),
|
'status' => Kitsu::getAiringStatus($item['startDate'], $item['endDate']),
|
||||||
'streaming_links' => Kitsu::parseStreamingLinks($item['included']),
|
'streaming_links' => Kitsu::parseStreamingLinks($item['included']),
|
||||||
'synopsis' => $item['synopsis'],
|
'synopsis' => $item['synopsis'],
|
||||||
'title' => $titles[0],
|
'title' => $title,
|
||||||
'titles' => $titles,
|
'titles' => $titles,
|
||||||
'trailer_id' => $item['youtubeVideoId'],
|
'trailer_id' => $item['youtubeVideoId'],
|
||||||
'url' => "https://kitsu.io/anime/{$item['slug']}",
|
'url' => "https://kitsu.io/anime/{$item['slug']}",
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,13 +17,17 @@
|
|||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Kitsu;
|
use Aviat\AnimeClient\API\Kitsu;
|
||||||
|
use Aviat\AnimeClient\Types\{
|
||||||
|
MangaFormItem, MangaFormItemData,
|
||||||
|
MangaListItem, MangaListItemDetail
|
||||||
|
};
|
||||||
use Aviat\Ion\StringWrapper;
|
use Aviat\Ion\StringWrapper;
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data transformation class for zippered Hummingbird manga
|
* Data transformation class for zippered Hummingbird manga
|
||||||
*/
|
*/
|
||||||
class MangaListTransformer extends AbstractTransformer {
|
final class MangaListTransformer extends AbstractTransformer {
|
||||||
|
|
||||||
use StringWrapper;
|
use StringWrapper;
|
||||||
|
|
||||||
@ -31,9 +35,9 @@ class MangaListTransformer extends AbstractTransformer {
|
|||||||
* Remap zipped anime data to a more logical form
|
* Remap zipped anime data to a more logical form
|
||||||
*
|
*
|
||||||
* @param array $item manga entry item
|
* @param array $item manga entry item
|
||||||
* @return array
|
* @return MangaListItem
|
||||||
*/
|
*/
|
||||||
public function transform($item): array
|
public function transform($item): MangaListItem
|
||||||
{
|
{
|
||||||
$included = $item['included'];
|
$included = $item['included'];
|
||||||
$mangaId = $item['relationships']['media']['data']['id'];
|
$mangaId = $item['relationships']['media']['data']['id'];
|
||||||
@ -72,7 +76,10 @@ class MangaListTransformer extends AbstractTransformer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$map = [
|
$titles = Kitsu::filterTitles($manga);
|
||||||
|
$title = array_shift($titles);
|
||||||
|
|
||||||
|
$map = new MangaListItem([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
'mal_id' => $MALid,
|
'mal_id' => $MALid,
|
||||||
'chapters' => [
|
'chapters' => [
|
||||||
@ -83,22 +90,22 @@ class MangaListTransformer extends AbstractTransformer {
|
|||||||
'read' => '-', //$item['attributes']['volumes_read'],
|
'read' => '-', //$item['attributes']['volumes_read'],
|
||||||
'total' => $totalVolumes
|
'total' => $totalVolumes
|
||||||
],
|
],
|
||||||
'manga' => [
|
'manga' => new MangaListItemDetail([
|
||||||
'id' => $mangaId,
|
|
||||||
'titles' => Kitsu::filterTitles($manga),
|
|
||||||
'alternate_title' => NULL,
|
|
||||||
'slug' => $manga['slug'],
|
|
||||||
'url' => 'https://kitsu.io/manga/' . $manga['slug'],
|
|
||||||
'type' => $manga['mangaType'],
|
|
||||||
'image' => $manga['posterImage']['small'],
|
|
||||||
'genres' => $genres,
|
'genres' => $genres,
|
||||||
],
|
'id' => $mangaId,
|
||||||
|
'image' => $manga['posterImage']['small'],
|
||||||
|
'slug' => $manga['slug'],
|
||||||
|
'title' => $title,
|
||||||
|
'titles' => $titles,
|
||||||
|
'type' => $manga['mangaType'],
|
||||||
|
'url' => 'https://kitsu.io/manga/' . $manga['slug'],
|
||||||
|
]),
|
||||||
'reading_status' => $item['attributes']['status'],
|
'reading_status' => $item['attributes']['status'],
|
||||||
'notes' => $item['attributes']['notes'],
|
'notes' => $item['attributes']['notes'],
|
||||||
'rereading' => (bool)$item['attributes']['reconsuming'],
|
'rereading' => (bool)$item['attributes']['reconsuming'],
|
||||||
'reread' => $item['attributes']['reconsumeCount'],
|
'reread' => $item['attributes']['reconsumeCount'],
|
||||||
'user_rating' => $rating,
|
'user_rating' => $rating,
|
||||||
];
|
]);
|
||||||
|
|
||||||
return $map;
|
return $map;
|
||||||
}
|
}
|
||||||
@ -107,22 +114,22 @@ class MangaListTransformer extends AbstractTransformer {
|
|||||||
* Untransform data to update the api
|
* Untransform data to update the api
|
||||||
*
|
*
|
||||||
* @param array $item
|
* @param array $item
|
||||||
* @return array
|
* @return MangaFormItem
|
||||||
*/
|
*/
|
||||||
public function untransform($item): array
|
public function untransform($item): MangaFormItem
|
||||||
{
|
{
|
||||||
$rereading = array_key_exists('rereading', $item) && (bool)$item['rereading'];
|
$rereading = array_key_exists('rereading', $item) && (bool)$item['rereading'];
|
||||||
|
|
||||||
$map = [
|
$map = new MangaFormItem([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
'mal_id' => $item['mal_id'],
|
'mal_id' => $item['mal_id'],
|
||||||
'data' => [
|
'data' => new MangaFormItemData([
|
||||||
'status' => $item['status'],
|
'status' => $item['status'],
|
||||||
'reconsuming' => $rereading,
|
'reconsuming' => $rereading,
|
||||||
'reconsumeCount' => (int)$item['reread_count'],
|
'reconsumeCount' => (int)$item['reread_count'],
|
||||||
'notes' => $item['notes'],
|
'notes' => $item['notes'],
|
||||||
],
|
]),
|
||||||
];
|
]);
|
||||||
|
|
||||||
if (is_numeric($item['chapters_read']) && $item['chapters_read'] > 0)
|
if (is_numeric($item['chapters_read']) && $item['chapters_read'] > 0)
|
||||||
{
|
{
|
||||||
|
@ -16,35 +16,37 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\Types\MangaPage;
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transformer for anime description page
|
* Transformer for anime description page
|
||||||
*/
|
*/
|
||||||
class MangaTransformer extends AbstractTransformer {
|
final class MangaTransformer extends AbstractTransformer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert raw api response to a more
|
* Convert raw api response to a more
|
||||||
* logical and workable structure
|
* logical and workable structure
|
||||||
*
|
*
|
||||||
* @param array $item API library item
|
* @param array $item API library item
|
||||||
* @return array
|
* @return MangaPage
|
||||||
*/
|
*/
|
||||||
public function transform($item)
|
public function transform($item): MangaPage
|
||||||
{
|
{
|
||||||
|
// \dump($item);
|
||||||
$genres = [];
|
$genres = [];
|
||||||
|
|
||||||
foreach($item['included'] as $included)
|
foreach($item['included'] as $included)
|
||||||
{
|
{
|
||||||
if ($included['type'] === 'genres')
|
if ($included['type'] === 'categories')
|
||||||
{
|
{
|
||||||
$genres[] = $included['attributes']['name'];
|
$genres[] = $included['attributes']['title'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort($genres);
|
sort($genres);
|
||||||
|
|
||||||
return [
|
return new MangaPage([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
'title' => $item['canonicalTitle'],
|
'title' => $item['canonicalTitle'],
|
||||||
'en_title' => $item['titles']['en'],
|
'en_title' => $item['titles']['en'],
|
||||||
@ -56,7 +58,7 @@ class MangaTransformer extends AbstractTransformer {
|
|||||||
'synopsis' => $item['synopsis'],
|
'synopsis' => $item['synopsis'],
|
||||||
'url' => "https://kitsu.io/manga/{$item['slug']}",
|
'url' => "https://kitsu.io/manga/{$item['slug']}",
|
||||||
'genres' => $genres,
|
'genres' => $genres,
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function count(int $value = NULL)
|
private function count(int $value = NULL)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
namespace Aviat\AnimeClient\API;
|
namespace Aviat\AnimeClient\API;
|
||||||
|
|
||||||
use Amp\Artax\Request;
|
use Amp\Artax\Request;
|
||||||
|
use Aviat\AnimeClient\Types\FormItemData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common interface for anime and manga list item CRUD
|
* Common interface for anime and manga list item CRUD
|
||||||
@ -43,10 +44,10 @@ interface ListItemInterface {
|
|||||||
* Update a list item
|
* Update a list item
|
||||||
*
|
*
|
||||||
* @param string $id - The id of the list item to update
|
* @param string $id - The id of the list item to update
|
||||||
* @param array $data - The data with which to update the list item
|
* @param FormItemData $data - The data with which to update the list item
|
||||||
* @return Request
|
* @return Request
|
||||||
*/
|
*/
|
||||||
public function update(string $id, array $data): Request;
|
public function update(string $id, FormItemData $data): Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a list item
|
* Delete a list item
|
||||||
|
@ -28,7 +28,7 @@ use Aviat\AnimeClient\API\Enum\{
|
|||||||
/**
|
/**
|
||||||
* Constants and mappings for the My Anime List API
|
* Constants and mappings for the My Anime List API
|
||||||
*/
|
*/
|
||||||
class MAL {
|
final class MAL {
|
||||||
const AUTH_URL = 'https://myanimelist.net/api/account/verify_credentials.xml';
|
const AUTH_URL = 'https://myanimelist.net/api/account/verify_credentials.xml';
|
||||||
const BASE_URL = 'https://myanimelist.net/api/';
|
const BASE_URL = 'https://myanimelist.net/api/';
|
||||||
|
|
||||||
|
@ -20,12 +20,13 @@ use Amp\Artax\{FormBody, Request};
|
|||||||
use Aviat\AnimeClient\API\{
|
use Aviat\AnimeClient\API\{
|
||||||
XML
|
XML
|
||||||
};
|
};
|
||||||
|
use Aviat\AnimeClient\Types\AbstractType;
|
||||||
use Aviat\Ion\Di\ContainerAware;
|
use Aviat\Ion\Di\ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CRUD operations for MAL list items
|
* CRUD operations for MAL list items
|
||||||
*/
|
*/
|
||||||
class ListItem {
|
final class ListItem {
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
use MALTrait;
|
use MALTrait;
|
||||||
|
|
||||||
@ -84,11 +85,11 @@ class ListItem {
|
|||||||
* Update a list item
|
* Update a list item
|
||||||
*
|
*
|
||||||
* @param string $id
|
* @param string $id
|
||||||
* @param array $data
|
* @param AbstractType $data
|
||||||
* @param string $type
|
* @param string $type
|
||||||
* @return Request
|
* @return Request
|
||||||
*/
|
*/
|
||||||
public function update(string $id, array $data, string $type = 'anime'): Request
|
public function update(string $id, AbstractType $data, string $type = 'anime'): Request
|
||||||
{
|
{
|
||||||
$config = $this->container->get('config');
|
$config = $this->container->get('config');
|
||||||
|
|
||||||
|
@ -16,12 +16,14 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API\MAL;
|
namespace Aviat\AnimeClient\API\MAL;
|
||||||
|
|
||||||
|
use const Aviat\AnimeClient\USER_AGENT;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\{
|
use Aviat\AnimeClient\API\{
|
||||||
APIRequestBuilder,
|
APIRequestBuilder,
|
||||||
MAL as M
|
MAL as M
|
||||||
};
|
};
|
||||||
|
|
||||||
class MALRequestBuilder extends APIRequestBuilder {
|
final class MALRequestBuilder extends APIRequestBuilder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base url for api requests
|
* The base url for api requests
|
||||||
@ -38,7 +40,7 @@ class MALRequestBuilder extends APIRequestBuilder {
|
|||||||
'Accept' => 'text/xml',
|
'Accept' => 'text/xml',
|
||||||
'Accept-Encoding' => 'gzip',
|
'Accept-Encoding' => 'gzip',
|
||||||
'Content-type' => 'application/x-www-form-urlencoded',
|
'Content-type' => 'application/x-www-form-urlencoded',
|
||||||
'User-Agent' => "Tim's Anime Client/4.0"
|
'User-Agent' => USER_AGENT,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,12 +24,13 @@ use Aviat\AnimeClient\API\MAL\{
|
|||||||
};
|
};
|
||||||
use Aviat\AnimeClient\API\XML;
|
use Aviat\AnimeClient\API\XML;
|
||||||
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
|
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
|
||||||
|
use Aviat\AnimeClient\Types\{Anime, FormItem};
|
||||||
use Aviat\Ion\Di\ContainerAware;
|
use Aviat\Ion\Di\ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MyAnimeList API Model
|
* MyAnimeList API Model
|
||||||
*/
|
*/
|
||||||
class Model {
|
final class Model {
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
use MALTrait;
|
use MALTrait;
|
||||||
|
|
||||||
@ -147,11 +148,11 @@ class Model {
|
|||||||
/**
|
/**
|
||||||
* Update a list item
|
* Update a list item
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param FormItem $data
|
||||||
* @param string $type "anime" or "manga"
|
* @param string $type "anime" or "manga"
|
||||||
* @return Request
|
* @return Request
|
||||||
*/
|
*/
|
||||||
public function updateListItem(array $data, string $type = 'anime'): Request
|
public function updateListItem(FormItem $data, string $type = 'anime'): Request
|
||||||
{
|
{
|
||||||
$updateData = [];
|
$updateData = [];
|
||||||
|
|
||||||
|
@ -17,12 +17,13 @@
|
|||||||
namespace Aviat\AnimeClient\API\MAL\Transformer;
|
namespace Aviat\AnimeClient\API\MAL\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
||||||
|
use Aviat\AnimeClient\Types\{AnimeFormItem, AnimeFormItemData};
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transformer for updating MAL List
|
* Transformer for updating MAL List
|
||||||
*/
|
*/
|
||||||
class AnimeListTransformer extends AbstractTransformer {
|
final class AnimeListTransformer extends AbstractTransformer {
|
||||||
/**
|
/**
|
||||||
* Identity transformation
|
* Identity transformation
|
||||||
*
|
*
|
||||||
@ -38,16 +39,14 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
* Transform Kitsu episode data to MAL episode data
|
* Transform Kitsu episode data to MAL episode data
|
||||||
*
|
*
|
||||||
* @param array $item
|
* @param array $item
|
||||||
* @return array
|
* @return AnimeFormItem
|
||||||
*/
|
*/
|
||||||
public function untransform(array $item): array
|
public function untransform(array $item): AnimeFormItem
|
||||||
{
|
{
|
||||||
$map = [
|
$map = new AnimeFormItem([
|
||||||
'id' => $item['mal_id'],
|
'id' => $item['mal_id'],
|
||||||
'data' => []
|
'data' => new AnimeFormItemData([]),
|
||||||
];
|
]);
|
||||||
|
|
||||||
$data =& $item['data'];
|
|
||||||
|
|
||||||
foreach($item['data'] as $key => $value)
|
foreach($item['data'] as $key => $value)
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ use Aviat\Ion\Transformer\AbstractTransformer;
|
|||||||
/**
|
/**
|
||||||
* Transformer for updating MAL List
|
* Transformer for updating MAL List
|
||||||
*/
|
*/
|
||||||
class MangaListTransformer extends AbstractTransformer {
|
final class MangaListTransformer extends AbstractTransformer {
|
||||||
/**
|
/**
|
||||||
* Identity transformation
|
* Identity transformation
|
||||||
*
|
*
|
||||||
|
@ -16,14 +16,30 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Mapping;
|
namespace Aviat\AnimeClient\API\Mapping;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\{Kitsu, MAL, Route, Title};
|
use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\{Anilist, Kitsu, MAL, Route, Title};
|
||||||
use Aviat\Ion\Enum;
|
use Aviat\Ion\Enum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Anime watching status mappings, among Kitsu, MAL, Page titles
|
* Anime watching status mappings, among Kitsu, MAL, Page titles
|
||||||
* and url route segments
|
* and url route segments
|
||||||
*/
|
*/
|
||||||
class AnimeWatchingStatus extends Enum {
|
final class AnimeWatchingStatus extends Enum {
|
||||||
|
const ANILIST_TO_KITSU = [
|
||||||
|
Anilist::WATCHING => Kitsu::WATCHING,
|
||||||
|
Anilist::PLAN_TO_WATCH => Kitsu::PLAN_TO_WATCH,
|
||||||
|
Anilist::COMPLETED => Kitsu::COMPLETED,
|
||||||
|
Anilist::ON_HOLD => Kitsu::ON_HOLD,
|
||||||
|
Anilist::DROPPED => Kitsu::DROPPED
|
||||||
|
];
|
||||||
|
|
||||||
|
const KITSU_TO_ANILIST = [
|
||||||
|
Kitsu::WATCHING => Anilist::WATCHING,
|
||||||
|
Kitsu::PLAN_TO_WATCH => Anilist::PLAN_TO_WATCH,
|
||||||
|
Kitsu::COMPLETED => Anilist::COMPLETED,
|
||||||
|
Kitsu::ON_HOLD => Anilist::ON_HOLD,
|
||||||
|
Kitsu::DROPPED => Anilist::DROPPED
|
||||||
|
];
|
||||||
|
|
||||||
const KITSU_TO_MAL = [
|
const KITSU_TO_MAL = [
|
||||||
Kitsu::WATCHING => MAL::WATCHING,
|
Kitsu::WATCHING => MAL::WATCHING,
|
||||||
Kitsu::PLAN_TO_WATCH => MAL::PLAN_TO_WATCH,
|
Kitsu::PLAN_TO_WATCH => MAL::PLAN_TO_WATCH,
|
||||||
|
@ -16,14 +16,31 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Mapping;
|
namespace Aviat\AnimeClient\API\Mapping;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Enum\MangaReadingStatus\{Kitsu, MAL, Title, Route};
|
use Aviat\AnimeClient\API\Enum\MangaReadingStatus\{Anilist, Kitsu, MAL, Title, Route};
|
||||||
use Aviat\Ion\Enum;
|
use Aviat\Ion\Enum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manga reading status mappings, among Kitsu, MAL, Page titles
|
* Manga reading status mappings, among Kitsu, MAL, Page titles
|
||||||
* and url route segments
|
* and url route segments
|
||||||
*/
|
*/
|
||||||
class MangaReadingStatus extends Enum {
|
final class MangaReadingStatus extends Enum {
|
||||||
|
const ANILIST_TO_KITSU = [
|
||||||
|
Anilist::READING => Kitsu::READING,
|
||||||
|
Anilist::PLAN_TO_READ => Kitsu::PLAN_TO_READ,
|
||||||
|
Anilist::COMPLETED => Kitsu::COMPLETED,
|
||||||
|
Anilist::ON_HOLD => Kitsu::ON_HOLD,
|
||||||
|
Anilist::DROPPED => Kitsu::DROPPED
|
||||||
|
];
|
||||||
|
|
||||||
|
const KITSU_TO_ANILIST = [
|
||||||
|
Kitsu::READING => Anilist::READING,
|
||||||
|
Kitsu::PLAN_TO_READ => Anilist::PLAN_TO_READ,
|
||||||
|
Kitsu::COMPLETED => Anilist::COMPLETED,
|
||||||
|
Kitsu::ON_HOLD => Anilist::ON_HOLD,
|
||||||
|
Kitsu::DROPPED => Anilist::DROPPED
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
const KITSU_TO_MAL = [
|
const KITSU_TO_MAL = [
|
||||||
Kitsu::READING => MAL::READING,
|
Kitsu::READING => MAL::READING,
|
||||||
Kitsu::PLAN_TO_READ => MAL::PLAN_TO_READ,
|
Kitsu::PLAN_TO_READ => MAL::PLAN_TO_READ,
|
||||||
|
@ -22,14 +22,14 @@ use function Amp\Promise\{all, wait};
|
|||||||
/**
|
/**
|
||||||
* Class to simplify making and validating simultaneous requests
|
* Class to simplify making and validating simultaneous requests
|
||||||
*/
|
*/
|
||||||
class ParallelAPIRequest {
|
final class ParallelAPIRequest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of requests to make in parallel
|
* Set of requests to make in parallel
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $requests = [];
|
private $requests = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a request
|
* Add a request
|
||||||
@ -76,9 +76,7 @@ class ParallelAPIRequest {
|
|||||||
{
|
{
|
||||||
$promises[$key] = call(function () use ($client, $url) {
|
$promises[$key] = call(function () use ($client, $url) {
|
||||||
$response = yield $client->request($url);
|
$response = yield $client->request($url);
|
||||||
$body = yield $response->getBody();
|
return yield $response->getBody();
|
||||||
|
|
||||||
return $body;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ use DOMDocument, DOMNode, DOMNodeList, InvalidArgumentException;
|
|||||||
/**
|
/**
|
||||||
* XML <=> PHP Array codec
|
* XML <=> PHP Array codec
|
||||||
*/
|
*/
|
||||||
class XML {
|
final class XML {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XML representation of the data
|
* XML representation of the data
|
||||||
|
@ -19,7 +19,7 @@ namespace Aviat\AnimeClient\Command;
|
|||||||
/**
|
/**
|
||||||
* Clears the API Cache
|
* Clears the API Cache
|
||||||
*/
|
*/
|
||||||
class CacheClear extends BaseCommand {
|
final class CacheClear extends BaseCommand {
|
||||||
/**
|
/**
|
||||||
* Clear the API cache
|
* Clear the API cache
|
||||||
*
|
*
|
||||||
|
@ -19,7 +19,7 @@ namespace Aviat\AnimeClient\Command;
|
|||||||
/**
|
/**
|
||||||
* Clears the API Cache
|
* Clears the API Cache
|
||||||
*/
|
*/
|
||||||
class CachePrime extends BaseCommand {
|
final class CachePrime extends BaseCommand {
|
||||||
/**
|
/**
|
||||||
* Clear, then prime the API cache
|
* Clear, then prime the API cache
|
||||||
*
|
*
|
||||||
|
@ -32,7 +32,7 @@ use DateTime;
|
|||||||
/**
|
/**
|
||||||
* Clears the API Cache
|
* Clears the API Cache
|
||||||
*/
|
*/
|
||||||
class SyncLists extends BaseCommand {
|
final class SyncLists extends BaseCommand {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for making requests to Kitsu API
|
* Model for making requests to Kitsu API
|
||||||
|
@ -20,6 +20,7 @@ use Aviat\AnimeClient\Controller as BaseController;
|
|||||||
use Aviat\AnimeClient\API\Kitsu\Transformer\AnimeListTransformer;
|
use Aviat\AnimeClient\API\Kitsu\Transformer\AnimeListTransformer;
|
||||||
use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Kitsu as KitsuWatchingStatus;
|
use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Kitsu as KitsuWatchingStatus;
|
||||||
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
||||||
|
use Aviat\AnimeClient\Types\AnimeFormItem;
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Json;
|
use Aviat\Ion\Json;
|
||||||
use Aviat\Ion\StringWrapper;
|
use Aviat\Ion\StringWrapper;
|
||||||
@ -27,7 +28,7 @@ use Aviat\Ion\StringWrapper;
|
|||||||
/**
|
/**
|
||||||
* Controller for Anime-related pages
|
* Controller for Anime-related pages
|
||||||
*/
|
*/
|
||||||
class Anime extends BaseController {
|
final class Anime extends BaseController {
|
||||||
|
|
||||||
use StringWrapper;
|
use StringWrapper;
|
||||||
|
|
||||||
@ -201,7 +202,7 @@ class Anime extends BaseController {
|
|||||||
// large form-based updates
|
// large form-based updates
|
||||||
$transformer = new AnimeListTransformer();
|
$transformer = new AnimeListTransformer();
|
||||||
$postData = $transformer->untransform($data);
|
$postData = $transformer->untransform($data);
|
||||||
$fullResult = $this->model->updateLibraryItem($postData);
|
$fullResult = $this->model->updateLibraryItem(new AnimeFormItem($postData));
|
||||||
|
|
||||||
if ($fullResult['statusCode'] === 200)
|
if ($fullResult['statusCode'] === 200)
|
||||||
{
|
{
|
||||||
@ -232,7 +233,7 @@ class Anime extends BaseController {
|
|||||||
$data = $this->request->getParsedBody();
|
$data = $this->request->getParsedBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $this->model->updateLibraryItem($data);
|
$response = $this->model->updateLibraryItem(new AnimeFormItem($data));
|
||||||
|
|
||||||
$this->cache->clear();
|
$this->cache->clear();
|
||||||
$this->outputJSON($response['body'], $response['statusCode']);
|
$this->outputJSON($response['body'], $response['statusCode']);
|
||||||
@ -277,7 +278,7 @@ class Anime extends BaseController {
|
|||||||
$show_data = $this->model->getAnime($animeId);
|
$show_data = $this->model->getAnime($animeId);
|
||||||
$characters = [];
|
$characters = [];
|
||||||
|
|
||||||
if (empty($show_data))
|
if ($show_data->title === '')
|
||||||
{
|
{
|
||||||
$this->notFound(
|
$this->notFound(
|
||||||
$this->config->get('whose_list') .
|
$this->config->get('whose_list') .
|
||||||
@ -301,7 +302,7 @@ class Anime extends BaseController {
|
|||||||
'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['titles'][0]
|
$show_data->title
|
||||||
),
|
),
|
||||||
'characters' => $characters,
|
'characters' => $characters,
|
||||||
'show_data' => $show_data,
|
'show_data' => $show_data,
|
||||||
|
@ -26,7 +26,7 @@ use Aviat\Ion\Di\ContainerInterface;
|
|||||||
/**
|
/**
|
||||||
* Controller for Anime collection pages
|
* Controller for Anime collection pages
|
||||||
*/
|
*/
|
||||||
class AnimeCollection extends BaseController {
|
final class AnimeCollection extends BaseController {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The anime collection model
|
* The anime collection model
|
||||||
|
@ -23,7 +23,7 @@ use Aviat\Ion\ArrayWrapper;
|
|||||||
/**
|
/**
|
||||||
* Controller for character description pages
|
* Controller for character description pages
|
||||||
*/
|
*/
|
||||||
class Character extends BaseController {
|
final class Character extends BaseController {
|
||||||
|
|
||||||
use ArrayWrapper;
|
use ArrayWrapper;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ use Aviat\Ion\View\HtmlView;
|
|||||||
/**
|
/**
|
||||||
* Controller for handling routes that don't fit elsewhere
|
* Controller for handling routes that don't fit elsewhere
|
||||||
*/
|
*/
|
||||||
class Index extends BaseController {
|
final class Index extends BaseController {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Purges the API cache
|
* Purges the API cache
|
||||||
@ -72,6 +72,24 @@ class Index extends BaseController {
|
|||||||
], $view);
|
], $view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect to Anilist to start Oauth flow
|
||||||
|
*/
|
||||||
|
public function anilistRedirect()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Oauth callback for Anilist API
|
||||||
|
*/
|
||||||
|
public function anilistCallback()
|
||||||
|
{
|
||||||
|
$this->outputHTML('blank', [
|
||||||
|
'title' => 'Oauth!'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt login authentication
|
* Attempt login authentication
|
||||||
*
|
*
|
||||||
|
@ -20,13 +20,14 @@ use Aviat\AnimeClient\Controller;
|
|||||||
use Aviat\AnimeClient\API\Kitsu\Transformer\MangaListTransformer;
|
use Aviat\AnimeClient\API\Kitsu\Transformer\MangaListTransformer;
|
||||||
use Aviat\AnimeClient\API\Mapping\MangaReadingStatus;
|
use Aviat\AnimeClient\API\Mapping\MangaReadingStatus;
|
||||||
use Aviat\AnimeClient\Model\Manga as MangaModel;
|
use Aviat\AnimeClient\Model\Manga as MangaModel;
|
||||||
|
use Aviat\AnimeClient\Types\MangaFormItem;
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\{Json, StringWrapper};
|
use Aviat\Ion\{Json, StringWrapper};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for manga list
|
* Controller for manga list
|
||||||
*/
|
*/
|
||||||
class Manga extends Controller {
|
final class Manga extends Controller {
|
||||||
|
|
||||||
use StringWrapper;
|
use StringWrapper;
|
||||||
|
|
||||||
@ -200,7 +201,7 @@ class Manga extends Controller {
|
|||||||
// large form-based updates
|
// large form-based updates
|
||||||
$transformer = new MangaListTransformer();
|
$transformer = new MangaListTransformer();
|
||||||
$post_data = $transformer->untransform($data);
|
$post_data = $transformer->untransform($data);
|
||||||
$full_result = $this->model->updateLibraryItem($post_data);
|
$full_result = $this->model->updateLibraryItem(new MangaFormItem($post_data));
|
||||||
|
|
||||||
if ($full_result['statusCode'] === 200)
|
if ($full_result['statusCode'] === 200)
|
||||||
{
|
{
|
||||||
@ -234,7 +235,7 @@ class Manga extends Controller {
|
|||||||
$data = $this->request->getParsedBody();
|
$data = $this->request->getParsedBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $this->model->updateLibraryItem($data);
|
$response = $this->model->updateLibraryItem(new MangaFormItem($data));
|
||||||
|
|
||||||
$this->cache->clear();
|
$this->cache->clear();
|
||||||
$this->outputJSON($response['body'], $response['statusCode']);
|
$this->outputJSON($response['body'], $response['statusCode']);
|
||||||
|
@ -26,7 +26,7 @@ use Aviat\Ion\Di\ContainerInterface;
|
|||||||
/**
|
/**
|
||||||
* Controller for manga collection pages
|
* Controller for manga collection pages
|
||||||
*/
|
*/
|
||||||
class MangaCollection extends BaseController {
|
final class MangaCollection extends BaseController {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The manga collection model
|
* The manga collection model
|
||||||
|
@ -28,7 +28,7 @@ use Aviat\Ion\StringWrapper;
|
|||||||
/**
|
/**
|
||||||
* Basic routing/ dispatch
|
* Basic routing/ dispatch
|
||||||
*/
|
*/
|
||||||
class Dispatcher extends RoutingBase {
|
final class Dispatcher extends RoutingBase {
|
||||||
|
|
||||||
use StringWrapper;
|
use StringWrapper;
|
||||||
|
|
||||||
|
@ -17,13 +17,14 @@
|
|||||||
namespace Aviat\AnimeClient\Helper;
|
namespace Aviat\AnimeClient\Helper;
|
||||||
|
|
||||||
use Aviat\AnimeClient\MenuGenerator;
|
use Aviat\AnimeClient\MenuGenerator;
|
||||||
|
use Aviat\Ion\Di\ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MenuGenerator helper wrapper
|
* MenuGenerator helper wrapper
|
||||||
*/
|
*/
|
||||||
class Menu {
|
final class Menu {
|
||||||
|
|
||||||
use \Aviat\Ion\Di\ContainerAware;
|
use ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the html for the selected menu
|
* Create the html for the selected menu
|
||||||
|
@ -25,7 +25,7 @@ use Aviat\Ion\Exception\ConfigException;
|
|||||||
/**
|
/**
|
||||||
* Helper object to manage menu creation and selection
|
* Helper object to manage menu creation and selection
|
||||||
*/
|
*/
|
||||||
class MenuGenerator extends UrlGenerator {
|
final class MenuGenerator extends UrlGenerator {
|
||||||
|
|
||||||
use ArrayWrapper;
|
use ArrayWrapper;
|
||||||
use StringWrapper;
|
use StringWrapper;
|
||||||
|
@ -44,7 +44,7 @@ class API {
|
|||||||
|
|
||||||
foreach ($array as $key => $item)
|
foreach ($array as $key => $item)
|
||||||
{
|
{
|
||||||
$sort[$key] = $item[$sortKey]['titles'][0];
|
$sort[$key] = $item[$sortKey]['title'];
|
||||||
}
|
}
|
||||||
|
|
||||||
array_multisort($sort, SORT_ASC, $array);
|
array_multisort($sort, SORT_ASC, $array);
|
||||||
|
@ -18,6 +18,11 @@ namespace Aviat\AnimeClient\Model;
|
|||||||
|
|
||||||
use Aviat\AnimeClient\API\ParallelAPIRequest;
|
use Aviat\AnimeClient\API\ParallelAPIRequest;
|
||||||
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
||||||
|
use Aviat\AnimeClient\Types\{
|
||||||
|
Anime as AnimeType,
|
||||||
|
AnimeFormItem,
|
||||||
|
AnimeListItem
|
||||||
|
};
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Json;
|
use Aviat\Ion\Json;
|
||||||
|
|
||||||
@ -93,9 +98,9 @@ class Anime extends API {
|
|||||||
* Get information about an anime from its slug
|
* Get information about an anime from its slug
|
||||||
*
|
*
|
||||||
* @param string $slug
|
* @param string $slug
|
||||||
* @return array
|
* @return AnimeType
|
||||||
*/
|
*/
|
||||||
public function getAnime(string $slug): array
|
public function getAnime(string $slug): AnimeType
|
||||||
{
|
{
|
||||||
return $this->kitsuModel->getAnime($slug);
|
return $this->kitsuModel->getAnime($slug);
|
||||||
}
|
}
|
||||||
@ -127,9 +132,9 @@ class Anime extends API {
|
|||||||
* for editing/updating that item
|
* for editing/updating that item
|
||||||
*
|
*
|
||||||
* @param string $itemId
|
* @param string $itemId
|
||||||
* @return array
|
* @return AnimeListItem
|
||||||
*/
|
*/
|
||||||
public function getLibraryItem(string $itemId): array
|
public function getLibraryItem(string $itemId): AnimeListItem
|
||||||
{
|
{
|
||||||
return $this->kitsuModel->getListItem($itemId);
|
return $this->kitsuModel->getListItem($itemId);
|
||||||
}
|
}
|
||||||
@ -166,10 +171,10 @@ class Anime extends API {
|
|||||||
/**
|
/**
|
||||||
* Update a list entry
|
* Update a list entry
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param AnimeFormItem $data
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function updateLibraryItem(array $data): array
|
public function updateLibraryItem(AnimeFormItem $data): array
|
||||||
{
|
{
|
||||||
$requester = new ParallelAPIRequest();
|
$requester = new ParallelAPIRequest();
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ use PDO;
|
|||||||
/**
|
/**
|
||||||
* Model for getting anime collection data
|
* Model for getting anime collection data
|
||||||
*/
|
*/
|
||||||
class AnimeCollection extends Collection {
|
final class AnimeCollection extends Collection {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Anime API Model
|
* Anime API Model
|
||||||
|
@ -21,14 +21,18 @@ use Aviat\AnimeClient\API\{
|
|||||||
Mapping\MangaReadingStatus,
|
Mapping\MangaReadingStatus,
|
||||||
ParallelAPIRequest
|
ParallelAPIRequest
|
||||||
};
|
};
|
||||||
|
use Aviat\AnimeClient\Types\{
|
||||||
|
MangaFormItem,
|
||||||
|
MangaListItem,
|
||||||
|
MangaPage
|
||||||
|
};
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Json;
|
use Aviat\Ion\Json;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for handling requests dealing with the manga list
|
* Model for handling requests dealing with the manga list
|
||||||
*/
|
*/
|
||||||
class Manga extends API
|
class Manga extends API {
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* Model for making requests to Kitsu API
|
* Model for making requests to Kitsu API
|
||||||
* @var \Aviat\AnimeClient\API\Kitsu\Model
|
* @var \Aviat\AnimeClient\API\Kitsu\Model
|
||||||
@ -67,21 +71,28 @@ class Manga extends API
|
|||||||
{
|
{
|
||||||
if ($status === 'All')
|
if ($status === 'All')
|
||||||
{
|
{
|
||||||
return $this->kitsuModel->getFullOrganizedMangaList();
|
$data = $this->kitsuModel->getFullOrganizedMangaList();
|
||||||
|
foreach($data as &$section)
|
||||||
|
{
|
||||||
|
$this->sortByName($section, 'manga');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
$APIstatus = MangaReadingStatus::TITLE_TO_KITSU[$status];
|
$APIstatus = MangaReadingStatus::TITLE_TO_KITSU[$status];
|
||||||
$data = $this->kitsuModel->getMangaList($APIstatus);
|
$data = $this->mapByStatus($this->kitsuModel->getMangaList($APIstatus));
|
||||||
return $this->mapByStatus($data)[$status];
|
$this->sortByName($data[$status], 'manga');
|
||||||
|
return $data[$status];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the details of a manga
|
* Get the details of a manga
|
||||||
*
|
*
|
||||||
* @param string $manga_id
|
* @param string $manga_id
|
||||||
* @return array
|
* @return MangaPage
|
||||||
*/
|
*/
|
||||||
public function getManga($manga_id): array
|
public function getManga($manga_id): MangaPage
|
||||||
{
|
{
|
||||||
return $this->kitsuModel->getManga($manga_id);
|
return $this->kitsuModel->getManga($manga_id);
|
||||||
}
|
}
|
||||||
@ -90,9 +101,9 @@ class Manga extends API
|
|||||||
* Get anime by its kitsu id
|
* Get anime by its kitsu id
|
||||||
*
|
*
|
||||||
* @param string $animeId
|
* @param string $animeId
|
||||||
* @return array
|
* @return MangaPage
|
||||||
*/
|
*/
|
||||||
public function getMangaById(string $animeId): array
|
public function getMangaById(string $animeId): MangaPage
|
||||||
{
|
{
|
||||||
return $this->kitsuModel->getMangaById($animeId);
|
return $this->kitsuModel->getMangaById($animeId);
|
||||||
}
|
}
|
||||||
@ -102,9 +113,9 @@ class Manga extends API
|
|||||||
* for editing/updating that item
|
* for editing/updating that item
|
||||||
*
|
*
|
||||||
* @param string $itemId
|
* @param string $itemId
|
||||||
* @return array
|
* @return MangaListItem
|
||||||
*/
|
*/
|
||||||
public function getLibraryItem(string $itemId): array
|
public function getLibraryItem(string $itemId): MangaListItem
|
||||||
{
|
{
|
||||||
return $this->kitsuModel->getListItem($itemId);
|
return $this->kitsuModel->getListItem($itemId);
|
||||||
}
|
}
|
||||||
@ -141,10 +152,10 @@ class Manga extends API
|
|||||||
/**
|
/**
|
||||||
* Update a list entry
|
* Update a list entry
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param MangaFormItem $data
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function updateLibraryItem(array $data): array
|
public function updateLibraryItem(MangaFormItem $data): array
|
||||||
{
|
{
|
||||||
$requester = new ParallelAPIRequest();
|
$requester = new ParallelAPIRequest();
|
||||||
|
|
||||||
@ -221,9 +232,7 @@ class Manga extends API
|
|||||||
$output[$key][] = $entry;
|
$output[$key][] = $entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($output as &$val) {
|
unset($entry);
|
||||||
$this->sortByName($val, 'manga');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ use PDO;
|
|||||||
/**
|
/**
|
||||||
* Model for getting anime collection data
|
* Model for getting anime collection data
|
||||||
*/
|
*/
|
||||||
class MangaCollection extends Collection {
|
final class MangaCollection extends Collection {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manga API Model
|
* Manga API Model
|
||||||
|
157
src/Types/AbstractType.php
Normal file
157
src/Types/AbstractType.php
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
use ArrayAccess;
|
||||||
|
use LogicException;
|
||||||
|
|
||||||
|
abstract class AbstractType implements ArrayAccess {
|
||||||
|
/**
|
||||||
|
* Populate values for unserializing data
|
||||||
|
*
|
||||||
|
* @param $properties
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public static function __set_state($properties)
|
||||||
|
{
|
||||||
|
return new static($properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the properties by using the constructor
|
||||||
|
*
|
||||||
|
* @param mixed $data
|
||||||
|
*/
|
||||||
|
public function __construct($data = [])
|
||||||
|
{
|
||||||
|
$typeKeys = array_keys((array)$this);
|
||||||
|
$dataKeys = array_keys((array)$data);
|
||||||
|
|
||||||
|
$unsetKeys = array_diff($typeKeys, $dataKeys);
|
||||||
|
|
||||||
|
foreach ($data as $key => $value)
|
||||||
|
{
|
||||||
|
$this->__set($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove unset keys so that they aren't serialized
|
||||||
|
foreach ($unsetKeys as $k)
|
||||||
|
{
|
||||||
|
unset($this->$k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if a property is set
|
||||||
|
*
|
||||||
|
* @param $name
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function __isset($name): bool
|
||||||
|
{
|
||||||
|
return property_exists($this, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a property on the type object
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param mixed $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __set($name, $value): void
|
||||||
|
{
|
||||||
|
$setterMethod = 'set' . ucfirst($name);
|
||||||
|
|
||||||
|
if (method_exists($this, $setterMethod))
|
||||||
|
{
|
||||||
|
$this->$setterMethod($value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!property_exists($this, $name))
|
||||||
|
{
|
||||||
|
$existing = json_encode($this);
|
||||||
|
|
||||||
|
throw new LogicException("Trying to set non-existent property: '$name'. Existing properties: $existing");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->$name = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a property from the type object
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function __get($name)
|
||||||
|
{
|
||||||
|
if (property_exists($this, $name))
|
||||||
|
{
|
||||||
|
return $this->$name;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new LogicException("Trying to get non-existent property: '$name'");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementing ArrayAccess
|
||||||
|
*
|
||||||
|
* @param $offset
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function offsetExists($offset): bool
|
||||||
|
{
|
||||||
|
return $this->__isset($offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementing ArrayAccess
|
||||||
|
*
|
||||||
|
* @param $offset
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function offsetGet($offset)
|
||||||
|
{
|
||||||
|
return $this->__get($offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementing ArrayAccess
|
||||||
|
*
|
||||||
|
* @param $offset
|
||||||
|
* @param $value
|
||||||
|
*/
|
||||||
|
public function offsetSet($offset, $value): void
|
||||||
|
{
|
||||||
|
$this->__set($offset, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementing ArrayAccess
|
||||||
|
*
|
||||||
|
* @param $offset
|
||||||
|
*/
|
||||||
|
public function offsetUnset($offset): void
|
||||||
|
{
|
||||||
|
if ($this->offsetExists($offset))
|
||||||
|
{
|
||||||
|
unset($this->$offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
src/Types/Anime.php
Normal file
40
src/Types/Anime.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing an Anime object for display
|
||||||
|
*/
|
||||||
|
final class Anime extends AbstractType {
|
||||||
|
public $age_rating;
|
||||||
|
public $age_rating_guide;
|
||||||
|
public $cover_image;
|
||||||
|
public $episode_count;
|
||||||
|
public $episode_length;
|
||||||
|
public $genres;
|
||||||
|
public $id;
|
||||||
|
public $included;
|
||||||
|
public $show_type;
|
||||||
|
public $slug;
|
||||||
|
public $status;
|
||||||
|
public $streaming_links;
|
||||||
|
public $synopsis;
|
||||||
|
public $title;
|
||||||
|
public $titles;
|
||||||
|
public $trailer_id;
|
||||||
|
public $url;
|
||||||
|
}
|
27
src/Types/AnimeFormItem.php
Normal file
27
src/Types/AnimeFormItem.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing an Anime object for display
|
||||||
|
*/
|
||||||
|
final class AnimeFormItem extends FormItem {
|
||||||
|
public function setData($value): void
|
||||||
|
{
|
||||||
|
$this->data = new AnimeFormItemData($value);
|
||||||
|
}
|
||||||
|
}
|
22
src/Types/AnimeFormItemData.php
Normal file
22
src/Types/AnimeFormItemData.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing an Anime object for display
|
||||||
|
*/
|
||||||
|
final class AnimeFormItemData extends FormItemData {}
|
42
src/Types/AnimeListItem.php
Normal file
42
src/Types/AnimeListItem.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing an Anime object for display
|
||||||
|
*/
|
||||||
|
final class AnimeListItem extends AbstractType {
|
||||||
|
public $id;
|
||||||
|
public $mal_id;
|
||||||
|
public $episodes = [
|
||||||
|
'length' => 0,
|
||||||
|
'total' => 0,
|
||||||
|
'watched' => '',
|
||||||
|
];
|
||||||
|
public $airing = [
|
||||||
|
'status' => '',
|
||||||
|
'started' => '',
|
||||||
|
'ended' => '',
|
||||||
|
];
|
||||||
|
public $anime;
|
||||||
|
public $watching_status;
|
||||||
|
public $notes;
|
||||||
|
public $rewatching;
|
||||||
|
public $rewatched;
|
||||||
|
public $user_rating;
|
||||||
|
public $private;
|
||||||
|
}
|
29
src/Types/FormItem.php
Normal file
29
src/Types/FormItem.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing an Anime object for display
|
||||||
|
*/
|
||||||
|
abstract class FormItem extends AbstractType {
|
||||||
|
public $id;
|
||||||
|
public $mal_id;
|
||||||
|
public $data;
|
||||||
|
|
||||||
|
abstract public function setData($value): void;
|
||||||
|
}
|
||||||
|
|
30
src/Types/FormItemData.php
Normal file
30
src/Types/FormItemData.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing an Anime object for display
|
||||||
|
*/
|
||||||
|
abstract class FormItemData extends AbstractType {
|
||||||
|
public $notes;
|
||||||
|
public $private;
|
||||||
|
public $progress;
|
||||||
|
public $rating;
|
||||||
|
public $reconsumeCount;
|
||||||
|
public $reconsuming;
|
||||||
|
public $status;
|
||||||
|
}
|
28
src/Types/MangaFormItem.php
Normal file
28
src/Types/MangaFormItem.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form data for updating a Manga List item
|
||||||
|
*/
|
||||||
|
final class MangaFormItem extends FormItem {
|
||||||
|
public function setData($value): void
|
||||||
|
{
|
||||||
|
$this->data = new MangaFormItemData($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
19
src/Types/MangaFormItemData.php
Normal file
19
src/Types/MangaFormItemData.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
final class MangaFormItemData extends FormItemData {}
|
40
src/Types/MangaListItem.php
Normal file
40
src/Types/MangaListItem.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing an Anime object for display
|
||||||
|
*/
|
||||||
|
final class MangaListItem extends AbstractType {
|
||||||
|
public $id;
|
||||||
|
public $mal_id;
|
||||||
|
public $chapters = [
|
||||||
|
'read' => 0,
|
||||||
|
'total' => 0,
|
||||||
|
];
|
||||||
|
public $volumes = [
|
||||||
|
'read' => '-',
|
||||||
|
'total' => 0,
|
||||||
|
];
|
||||||
|
public $manga;
|
||||||
|
public $reading_status;
|
||||||
|
public $notes;
|
||||||
|
public $rereading;
|
||||||
|
public $reread;
|
||||||
|
public $user_rating;
|
||||||
|
}
|
||||||
|
|
31
src/Types/MangaListItemDetail.php
Normal file
31
src/Types/MangaListItemDetail.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing the manga represented by the list item
|
||||||
|
*/
|
||||||
|
final class MangaListItemDetail extends AbstractType {
|
||||||
|
public $genres;
|
||||||
|
public $id;
|
||||||
|
public $image;
|
||||||
|
public $slug;
|
||||||
|
public $title;
|
||||||
|
public $titles;
|
||||||
|
public $type;
|
||||||
|
public $url;
|
||||||
|
}
|
35
src/Types/MangaPage.php
Normal file
35
src/Types/MangaPage.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Hummingbird Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @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.0
|
||||||
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing an Anime object for display
|
||||||
|
*/
|
||||||
|
final class MangaPage extends AbstractType {
|
||||||
|
public $chapter_count;
|
||||||
|
public $cover_image;
|
||||||
|
public $en_title;
|
||||||
|
public $genres;
|
||||||
|
public $id;
|
||||||
|
public $included;
|
||||||
|
public $jp_title;
|
||||||
|
public $manga_type;
|
||||||
|
public $synopsis;
|
||||||
|
public $title;
|
||||||
|
public $url;
|
||||||
|
public $volume_count;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user