Version 5.1 - All the GraphQL #32
@ -10,6 +10,3 @@ 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
|
||||||
|
|
||||||
# path to public directory on the server
|
|
||||||
asset_dir = "/../../public"
|
|
@ -29,10 +29,10 @@ use Aviat\AnimeClient\API\Enum\{
|
|||||||
* Constants and mappings for the Anilist API
|
* Constants and mappings for the Anilist API
|
||||||
*/
|
*/
|
||||||
final class Anilist {
|
final class Anilist {
|
||||||
const AUTH_URL = 'https://anilist.co/api/v2/oauth/authorize';
|
public const AUTH_URL = 'https://anilist.co/api/v2/oauth/authorize';
|
||||||
const BASE_URL = 'https://graphql.anilist.co';
|
public const BASE_URL = 'https://graphql.anilist.co';
|
||||||
|
|
||||||
const KITSU_ANILIST_WATCHING_STATUS_MAP = [
|
public const KITSU_ANILIST_WATCHING_STATUS_MAP = [
|
||||||
KAWS::WATCHING => AnimeWatchingStatus::WATCHING,
|
KAWS::WATCHING => AnimeWatchingStatus::WATCHING,
|
||||||
KAWS::COMPLETED => AnimeWatchingStatus::COMPLETED,
|
KAWS::COMPLETED => AnimeWatchingStatus::COMPLETED,
|
||||||
KAWS::ON_HOLD => AnimeWatchingStatus::ON_HOLD,
|
KAWS::ON_HOLD => AnimeWatchingStatus::ON_HOLD,
|
||||||
@ -40,7 +40,7 @@ final class Anilist {
|
|||||||
KAWS::PLAN_TO_WATCH => AnimeWatchingStatus::PLAN_TO_WATCH,
|
KAWS::PLAN_TO_WATCH => AnimeWatchingStatus::PLAN_TO_WATCH,
|
||||||
];
|
];
|
||||||
|
|
||||||
const ANILIST_KITSU_WATCHING_STATUS_MAP = [
|
public const ANILIST_KITSU_WATCHING_STATUS_MAP = [
|
||||||
AnimeWatchingStatus::WATCHING => KAWS::WATCHING,
|
AnimeWatchingStatus::WATCHING => KAWS::WATCHING,
|
||||||
AnimeWatchingStatus::COMPLETED => KAWS::COMPLETED,
|
AnimeWatchingStatus::COMPLETED => KAWS::COMPLETED,
|
||||||
AnimeWatchingStatus::ON_HOLD => KAWS::ON_HOLD,
|
AnimeWatchingStatus::ON_HOLD => KAWS::ON_HOLD,
|
||||||
@ -48,7 +48,7 @@ final class Anilist {
|
|||||||
AnimeWatchingStatus::PLAN_TO_WATCH => KAWS::PLAN_TO_WATCH,
|
AnimeWatchingStatus::PLAN_TO_WATCH => KAWS::PLAN_TO_WATCH,
|
||||||
];
|
];
|
||||||
|
|
||||||
const KITSU_ANILIST_READING_STATUS_MAP = [
|
public const KITSU_ANILIST_READING_STATUS_MAP = [
|
||||||
KMRS::READING => MangaReadingStatus::READING,
|
KMRS::READING => MangaReadingStatus::READING,
|
||||||
KMRS::COMPLETED => MangaReadingStatus::COMPLETED,
|
KMRS::COMPLETED => MangaReadingStatus::COMPLETED,
|
||||||
KMRS::ON_HOLD => MangaReadingStatus::ON_HOLD,
|
KMRS::ON_HOLD => MangaReadingStatus::ON_HOLD,
|
||||||
@ -56,7 +56,7 @@ final class Anilist {
|
|||||||
KMRS::PLAN_TO_READ => MangaReadingStatus::PLAN_TO_READ,
|
KMRS::PLAN_TO_READ => MangaReadingStatus::PLAN_TO_READ,
|
||||||
];
|
];
|
||||||
|
|
||||||
const ANILIST_KITSU_READING_STATUS_MAP = [
|
public const ANILIST_KITSU_READING_STATUS_MAP = [
|
||||||
MangaReadingStatus::READING => KMRS::READING,
|
MangaReadingStatus::READING => KMRS::READING,
|
||||||
MangaReadingStatus::COMPLETED => KMRS::COMPLETED,
|
MangaReadingStatus::COMPLETED => KMRS::COMPLETED,
|
||||||
MangaReadingStatus::ON_HOLD => KMRS::ON_HOLD,
|
MangaReadingStatus::ON_HOLD => KMRS::ON_HOLD,
|
||||||
|
@ -341,9 +341,9 @@ final class Model {
|
|||||||
* Get information about a particular anime
|
* Get information about a particular anime
|
||||||
*
|
*
|
||||||
* @param string $animeId
|
* @param string $animeId
|
||||||
* @return array
|
* @return Anime
|
||||||
*/
|
*/
|
||||||
public function getAnimeById(string $animeId): array
|
public function getAnimeById(string $animeId): Anime
|
||||||
{
|
{
|
||||||
$baseData = $this->getRawMediaDataById('anime', $animeId);
|
$baseData = $this->getRawMediaDataById('anime', $animeId);
|
||||||
return $this->animeTransformer->transform($baseData);
|
return $this->animeTransformer->transform($baseData);
|
||||||
@ -455,7 +455,7 @@ final class Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the anine entries, that are organized for output to html
|
* Get all the anime entries, that are organized for output to html
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
|
@ -40,7 +40,7 @@ final class AnimeTransformer extends AbstractTransformer {
|
|||||||
sort($item['genres']);
|
sort($item['genres']);
|
||||||
|
|
||||||
$title = $item['canonicalTitle'];
|
$title = $item['canonicalTitle'];
|
||||||
$titles = array_diff($item['titles'], [$title]);
|
$titles = array_unique(array_diff($item['titles'], [$title]));
|
||||||
|
|
||||||
return new Anime([
|
return new Anime([
|
||||||
'age_rating' => $item['ageRating'],
|
'age_rating' => $item['ageRating'],
|
||||||
|
@ -33,7 +33,6 @@ final class MangaTransformer extends AbstractTransformer {
|
|||||||
*/
|
*/
|
||||||
public function transform($item): MangaPage
|
public function transform($item): MangaPage
|
||||||
{
|
{
|
||||||
// \dump($item);
|
|
||||||
$genres = [];
|
$genres = [];
|
||||||
|
|
||||||
foreach($item['included'] as $included)
|
foreach($item['included'] as $included)
|
||||||
@ -46,11 +45,13 @@ final class MangaTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
sort($genres);
|
sort($genres);
|
||||||
|
|
||||||
|
$title = $item['canonicalTitle'];
|
||||||
|
$titles = array_unique(array_diff($item['titles'], [$title]));
|
||||||
|
|
||||||
return new MangaPage([
|
return new MangaPage([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
'title' => $item['canonicalTitle'],
|
'title' => $title,
|
||||||
'en_title' => $item['titles']['en'],
|
'titles' => $titles,
|
||||||
'jp_title' => $item['titles']['en_jp'],
|
|
||||||
'cover_image' => $item['posterImage']['small'],
|
'cover_image' => $item['posterImage']['small'],
|
||||||
'manga_type' => $item['mangaType'],
|
'manga_type' => $item['mangaType'],
|
||||||
'chapter_count' => $this->count($item['chapterCount']),
|
'chapter_count' => $this->count($item['chapterCount']),
|
||||||
|
@ -85,11 +85,11 @@ final class ListItem {
|
|||||||
* Update a list item
|
* Update a list item
|
||||||
*
|
*
|
||||||
* @param string $id
|
* @param string $id
|
||||||
* @param AbstractType $data
|
* @param array $data
|
||||||
* @param string $type
|
* @param string $type
|
||||||
* @return Request
|
* @return Request
|
||||||
*/
|
*/
|
||||||
public function update(string $id, AbstractType $data, string $type = 'anime'): Request
|
public function update(string $id, array $data, string $type = 'anime'): Request
|
||||||
{
|
{
|
||||||
$config = $this->container->get('config');
|
$config = $this->container->get('config');
|
||||||
|
|
||||||
|
@ -148,11 +148,11 @@ final class Model {
|
|||||||
/**
|
/**
|
||||||
* Update a list item
|
* Update a list item
|
||||||
*
|
*
|
||||||
* @param FormItem $data
|
* @param array $data
|
||||||
* @param string $type "anime" or "manga"
|
* @param string $type "anime" or "manga"
|
||||||
* @return Request
|
* @return Request
|
||||||
*/
|
*/
|
||||||
public function updateListItem(FormItem $data, string $type = 'anime'): Request
|
public function updateListItem($data, string $type = 'anime'): Request
|
||||||
{
|
{
|
||||||
$updateData = [];
|
$updateData = [];
|
||||||
|
|
||||||
|
@ -38,10 +38,10 @@ final class AnimeListTransformer extends AbstractTransformer {
|
|||||||
/**
|
/**
|
||||||
* Transform Kitsu episode data to MAL episode data
|
* Transform Kitsu episode data to MAL episode data
|
||||||
*
|
*
|
||||||
* @param array $item
|
* @param mixed $item
|
||||||
* @return AnimeFormItem
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function untransform(array $item): AnimeFormItem
|
public function untransform($item): array
|
||||||
{
|
{
|
||||||
$map = [
|
$map = [
|
||||||
'id' => $item['mal_id'],
|
'id' => $item['mal_id'],
|
||||||
@ -81,6 +81,6 @@ final class AnimeListTransformer extends AbstractTransformer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AnimeFormItem($map);
|
return $map;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -37,18 +37,16 @@ final class MangaListTransformer extends AbstractTransformer {
|
|||||||
/**
|
/**
|
||||||
* Transform Kitsu data to MAL data
|
* Transform Kitsu data to MAL data
|
||||||
*
|
*
|
||||||
* @param array $item
|
* @param mixed $item
|
||||||
* @return array
|
* @return
|
||||||
*/
|
*/
|
||||||
public function untransform(array $item): array
|
public function untransform($item): array
|
||||||
{
|
{
|
||||||
$map = [
|
$map = [
|
||||||
'id' => $item['mal_id'],
|
'id' => $item['mal_id'] ?? $item['malId'],
|
||||||
'data' => []
|
'data' => []
|
||||||
];
|
];
|
||||||
|
|
||||||
$data =& $item['data'];
|
|
||||||
|
|
||||||
foreach($item['data'] as $key => $value)
|
foreach($item['data'] as $key => $value)
|
||||||
{
|
{
|
||||||
switch($key)
|
switch($key)
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
namespace Aviat\AnimeClient;
|
namespace Aviat\AnimeClient;
|
||||||
|
|
||||||
use Aviat\Ion\ConfigInterface;
|
use Aviat\Ion\ConfigInterface;
|
||||||
use Yosymfony\Toml\Toml;
|
use Yosymfony\Toml\{Toml, TomlBuilder};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load configuration options from .toml files
|
* Load configuration options from .toml files
|
||||||
@ -51,6 +51,86 @@ function loadToml(string $path): array
|
|||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the array sequential, not associative?
|
||||||
|
*
|
||||||
|
* @param mixed $array
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function isSequentialArray($array): bool
|
||||||
|
{
|
||||||
|
if ( ! is_array($array))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$i = 0;
|
||||||
|
foreach ($array as $k => $v)
|
||||||
|
{
|
||||||
|
if ($k !== $i++)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _iterateToml(TomlBuilder $builder, $data, $parentKey = NULL): void
|
||||||
|
{
|
||||||
|
foreach ($data as $key => $value)
|
||||||
|
{
|
||||||
|
if ($value === NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (is_scalar($value) || isSequentialArray($value))
|
||||||
|
{
|
||||||
|
// $builder->addTable('');
|
||||||
|
$builder->addValue($key, $value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newKey = ($parentKey !== NULL)
|
||||||
|
? "{$parentKey}.{$key}"
|
||||||
|
: $key;
|
||||||
|
|
||||||
|
if ( ! isSequentialArray($value))
|
||||||
|
{
|
||||||
|
$builder->addTable($newKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
_iterateToml($builder, $value, $newKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize config data into a Toml file
|
||||||
|
*
|
||||||
|
* @param mixed $data
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function arrayToToml($data): string
|
||||||
|
{
|
||||||
|
$builder = new TomlBuilder();
|
||||||
|
|
||||||
|
_iterateToml($builder, $data);
|
||||||
|
|
||||||
|
return $builder->getTomlString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize toml back to an array
|
||||||
|
*
|
||||||
|
* @param string $toml
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function tomlToArray(string $toml): array
|
||||||
|
{
|
||||||
|
return Toml::parse($toml);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that folder permissions are correct for proper operation
|
* Check that folder permissions are correct for proper operation
|
||||||
*
|
*
|
||||||
@ -64,7 +144,6 @@ function checkFolderPermissions(ConfigInterface $config): array
|
|||||||
|
|
||||||
$pathMap = [
|
$pathMap = [
|
||||||
'app/logs' => realpath(__DIR__ . '/../app/logs'),
|
'app/logs' => realpath(__DIR__ . '/../app/logs'),
|
||||||
'public/js/cache' => "{$publicDir}/js/cache",
|
|
||||||
'public/images/avatars' => "{$publicDir}/images/avatars",
|
'public/images/avatars' => "{$publicDir}/images/avatars",
|
||||||
'public/images/anime' => "{$publicDir}/images/anime",
|
'public/images/anime' => "{$publicDir}/images/anime",
|
||||||
'public/images/characters' => "{$publicDir}/images/characters",
|
'public/images/characters' => "{$publicDir}/images/characters",
|
||||||
|
@ -170,9 +170,8 @@ final class Index extends BaseController {
|
|||||||
$auth = $this->container->get('auth');
|
$auth = $this->container->get('auth');
|
||||||
$this->outputHTML('settings', [
|
$this->outputHTML('settings', [
|
||||||
'auth' => $auth,
|
'auth' => $auth,
|
||||||
|
'config' => $this->config,
|
||||||
'title' => $this->config->get('whose_list') . "'s Settings",
|
'title' => $this->config->get('whose_list') . "'s Settings",
|
||||||
'base_settings' => $this->config->get('default_config'),
|
|
||||||
'user_settings' => $this->config->get('user_config_settings'),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,9 +109,9 @@ class Anime extends API {
|
|||||||
* Get anime by its kitsu id
|
* Get anime by its kitsu id
|
||||||
*
|
*
|
||||||
* @param string $animeId
|
* @param string $animeId
|
||||||
* @return array
|
* @return AnimeType
|
||||||
*/
|
*/
|
||||||
public function getAnimeById(string $animeId): array
|
public function getAnimeById(string $animeId): AnimeType
|
||||||
{
|
{
|
||||||
return $this->kitsuModel->getAnimeById($animeId);
|
return $this->kitsuModel->getAnimeById($animeId);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ namespace Aviat\AnimeClient\Types;
|
|||||||
use ArrayAccess;
|
use ArrayAccess;
|
||||||
use LogicException;
|
use LogicException;
|
||||||
|
|
||||||
abstract class AbstractType implements ArrayAccess {
|
class AbstractType implements ArrayAccess {
|
||||||
/**
|
/**
|
||||||
* Populate values for unserializing data
|
* Populate values for unserializing data
|
||||||
*
|
*
|
||||||
|
@ -22,14 +22,13 @@ namespace Aviat\AnimeClient\Types;
|
|||||||
final class MangaPage extends AbstractType {
|
final class MangaPage extends AbstractType {
|
||||||
public $chapter_count;
|
public $chapter_count;
|
||||||
public $cover_image;
|
public $cover_image;
|
||||||
public $en_title;
|
|
||||||
public $genres;
|
public $genres;
|
||||||
public $id;
|
public $id;
|
||||||
public $included;
|
public $included;
|
||||||
public $jp_title;
|
|
||||||
public $manga_type;
|
public $manga_type;
|
||||||
public $synopsis;
|
public $synopsis;
|
||||||
public $title;
|
public $title;
|
||||||
|
public $titles;
|
||||||
public $url;
|
public $url;
|
||||||
public $volume_count;
|
public $volume_count;
|
||||||
}
|
}
|
||||||
|
60
tests/AnimeClientTest.php
Normal file
60
tests/AnimeClientTest.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?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\Tests;
|
||||||
|
|
||||||
|
use function Aviat\AnimeClient\arrayToToml;
|
||||||
|
use function Aviat\AnimeClient\tomlToArray;
|
||||||
|
|
||||||
|
class AnimeClientTest extends AnimeClientTestCase
|
||||||
|
{
|
||||||
|
public function testArrayToToml ()
|
||||||
|
{
|
||||||
|
$arr = [
|
||||||
|
'cat' => false,
|
||||||
|
'foo' => 'bar',
|
||||||
|
'dateTime' => (array) new \DateTime(),
|
||||||
|
'bar' => [
|
||||||
|
'a' => 1,
|
||||||
|
'b' => 2,
|
||||||
|
'c' => 3,
|
||||||
|
],
|
||||||
|
'baz' => [
|
||||||
|
'x' => [1, 2, 3],
|
||||||
|
'y' => [2, 4, 6],
|
||||||
|
'z' => [3, 6, 9],
|
||||||
|
],
|
||||||
|
'foobar' => [
|
||||||
|
'z' => 22/7,
|
||||||
|
'a' => [
|
||||||
|
'aa' => -8,
|
||||||
|
'b' => [
|
||||||
|
'aaa' => 4028,
|
||||||
|
'c' => [1, 2, 3],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$toml = arrayToToml($arr);
|
||||||
|
|
||||||
|
echo $toml . "\n";
|
||||||
|
|
||||||
|
$parsedArray = tomlToArray($toml);
|
||||||
|
|
||||||
|
$this->assertEquals($arr, $parsedArray);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user