2016-12-21 12:46:20 -05:00
|
|
|
<?php declare(strict_types=1);
|
|
|
|
/**
|
|
|
|
* Anime List Client
|
|
|
|
*
|
|
|
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
|
|
|
*
|
|
|
|
* PHP version 7
|
|
|
|
*
|
2017-01-06 23:34:56 -05:00
|
|
|
* @package AnimeListClient
|
|
|
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
2017-01-11 10:30:53 -05:00
|
|
|
* @copyright 2015 - 2017 Timothy J. Warren
|
2017-01-06 23:34:56 -05:00
|
|
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
|
|
|
* @version 4.0
|
|
|
|
* @link https://github.com/timw4mail/HummingBirdAnimeClient
|
2017-01-11 10:34:24 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
namespace Aviat\AnimeClient\API\Kitsu;
|
2016-12-21 12:46:20 -05:00
|
|
|
|
2017-01-05 22:24:45 -05:00
|
|
|
use Aviat\AnimeClient\API\Kitsu as K;
|
2017-01-03 21:06:49 -05:00
|
|
|
use Aviat\AnimeClient\API\Kitsu\Transformer\{
|
2017-01-04 13:16:58 -05:00
|
|
|
AnimeTransformer, AnimeListTransformer, MangaTransformer, MangaListTransformer
|
2017-01-03 21:06:49 -05:00
|
|
|
};
|
2017-01-05 13:41:32 -05:00
|
|
|
use Aviat\Ion\Di\ContainerAware;
|
2017-01-06 21:39:01 -05:00
|
|
|
use Aviat\Ion\Json;
|
|
|
|
use GuzzleHttp\Exception\ClientException;
|
2016-12-21 12:46:20 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Kitsu API Model
|
|
|
|
*/
|
|
|
|
class KitsuModel {
|
2017-01-05 13:41:32 -05:00
|
|
|
use ContainerAware;
|
2016-12-21 12:46:20 -05:00
|
|
|
use KitsuTrait;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Class to map anime list items
|
|
|
|
* to a common format used by
|
|
|
|
* templates
|
|
|
|
*
|
|
|
|
* @var AnimeListTransformer
|
|
|
|
*/
|
|
|
|
protected $animeListTransformer;
|
|
|
|
|
2016-12-22 21:36:23 -05:00
|
|
|
/**
|
|
|
|
* @var AnimeTransformer
|
|
|
|
*/
|
|
|
|
protected $animeTransformer;
|
|
|
|
|
2017-01-06 21:39:01 -05:00
|
|
|
/**
|
|
|
|
* @var ListItem
|
|
|
|
*/
|
|
|
|
protected $listItem;
|
|
|
|
|
2017-01-05 13:41:32 -05:00
|
|
|
/**
|
|
|
|
* @var MangaTransformer
|
|
|
|
*/
|
|
|
|
protected $mangaTransformer;
|
|
|
|
|
2017-01-04 13:16:58 -05:00
|
|
|
/**
|
|
|
|
* @var MangaListTransformer
|
|
|
|
*/
|
2017-01-03 21:06:49 -05:00
|
|
|
protected $mangaListTransformer;
|
|
|
|
|
2016-12-22 21:36:23 -05:00
|
|
|
/**
|
|
|
|
* KitsuModel constructor.
|
|
|
|
*/
|
2017-01-06 21:39:01 -05:00
|
|
|
public function __construct(ListItem $listItem)
|
2016-12-21 12:46:20 -05:00
|
|
|
{
|
|
|
|
// Set up Guzzle trait
|
|
|
|
$this->init();
|
|
|
|
|
2016-12-22 21:36:23 -05:00
|
|
|
$this->animeTransformer = new AnimeTransformer();
|
2016-12-21 12:46:20 -05:00
|
|
|
$this->animeListTransformer = new AnimeListTransformer();
|
2017-01-06 21:39:01 -05:00
|
|
|
$this->listItem = $listItem;
|
2017-01-04 13:16:58 -05:00
|
|
|
$this->mangaTransformer = new MangaTransformer();
|
2017-01-03 21:06:49 -05:00
|
|
|
$this->mangaListTransformer = new MangaListTransformer();
|
2016-12-21 12:46:20 -05:00
|
|
|
}
|
|
|
|
|
2017-01-10 12:35:46 -05:00
|
|
|
/**
|
|
|
|
* Get the userid for a username from Kitsu
|
|
|
|
*
|
|
|
|
* @param string $username
|
|
|
|
* @return string
|
|
|
|
*/
|
2017-01-05 13:41:32 -05:00
|
|
|
public function getUserIdByUsername(string $username)
|
|
|
|
{
|
|
|
|
$data = $this->getRequest('users', [
|
|
|
|
'query' => [
|
|
|
|
'filter' => [
|
|
|
|
'name' => $username
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]);
|
|
|
|
|
|
|
|
return $data['data'][0]['id'];
|
|
|
|
}
|
|
|
|
|
2016-12-21 12:46:20 -05:00
|
|
|
/**
|
|
|
|
* Get the access token from the Kitsu API
|
|
|
|
*
|
|
|
|
* @param string $username
|
|
|
|
* @param string $password
|
|
|
|
* @return bool|string
|
|
|
|
*/
|
|
|
|
public function authenticate(string $username, string $password)
|
|
|
|
{
|
2017-01-09 20:36:48 -05:00
|
|
|
$response = $this->getResponse('POST', K::AUTH_URL, [
|
|
|
|
'headers' => [],
|
2017-01-05 13:41:32 -05:00
|
|
|
'form_params' => [
|
2016-12-21 12:46:20 -05:00
|
|
|
'grant_type' => 'password',
|
|
|
|
'username' => $username,
|
2017-01-05 13:41:32 -05:00
|
|
|
'password' => $password
|
|
|
|
]
|
2016-12-21 12:46:20 -05:00
|
|
|
]);
|
|
|
|
|
2017-01-09 20:36:48 -05:00
|
|
|
$data = Json::decode((string)$response->getBody());
|
|
|
|
|
2017-01-05 13:41:32 -05:00
|
|
|
if (array_key_exists('access_token', $data))
|
|
|
|
{
|
|
|
|
return $data['access_token'];
|
2016-12-21 12:46:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-01-05 13:41:32 -05:00
|
|
|
/**
|
|
|
|
* Get information about a particular anime
|
|
|
|
*
|
|
|
|
* @param string $animeId
|
|
|
|
* @return array
|
|
|
|
*/
|
2016-12-22 21:36:23 -05:00
|
|
|
public function getAnime(string $animeId): array
|
|
|
|
{
|
2017-01-05 13:41:32 -05:00
|
|
|
$baseData = $this->getRawMediaData('anime', $animeId);
|
2016-12-22 21:36:23 -05:00
|
|
|
return $this->animeTransformer->transform($baseData);
|
|
|
|
}
|
|
|
|
|
2017-01-05 13:41:32 -05:00
|
|
|
/**
|
|
|
|
* Get information about a particular manga
|
|
|
|
*
|
2017-01-06 21:39:01 -05:00
|
|
|
* @param string $mangaId
|
2017-01-05 13:41:32 -05:00
|
|
|
* @return array
|
|
|
|
*/
|
2017-01-04 13:16:58 -05:00
|
|
|
public function getManga(string $mangaId): array
|
2016-12-22 21:36:23 -05:00
|
|
|
{
|
2017-01-04 13:16:58 -05:00
|
|
|
$baseData = $this->getRawMediaData('manga', $mangaId);
|
|
|
|
return $this->mangaTransformer->transform($baseData);
|
2016-12-22 21:36:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getAnimeList($status): array
|
|
|
|
{
|
|
|
|
$options = [
|
2016-12-21 12:46:20 -05:00
|
|
|
'query' => [
|
|
|
|
'filter' => [
|
2017-01-05 13:41:32 -05:00
|
|
|
'user_id' => $this->getUserIdByUsername($this->getUsername()),
|
2016-12-22 21:36:23 -05:00
|
|
|
'media_type' => 'Anime',
|
|
|
|
'status' => $status,
|
|
|
|
],
|
2017-01-05 22:24:45 -05:00
|
|
|
'include' => 'media,media.genres',
|
2016-12-22 21:36:23 -05:00
|
|
|
'page' => [
|
|
|
|
'offset' => 0,
|
2017-01-10 12:35:46 -05:00
|
|
|
'limit' => 1000
|
2016-12-21 12:46:20 -05:00
|
|
|
],
|
2016-12-22 21:36:23 -05:00
|
|
|
'sort' => '-updated_at'
|
2016-12-21 12:46:20 -05:00
|
|
|
]
|
2016-12-22 21:36:23 -05:00
|
|
|
];
|
2016-12-21 12:46:20 -05:00
|
|
|
|
2016-12-22 21:36:23 -05:00
|
|
|
$data = $this->getRequest('library-entries', $options);
|
2017-01-05 22:24:45 -05:00
|
|
|
$included = K::organizeIncludes($data['included']);
|
2016-12-21 12:46:20 -05:00
|
|
|
|
2017-01-03 20:29:43 -05:00
|
|
|
foreach($data['data'] as $i => &$item)
|
2016-12-21 12:46:20 -05:00
|
|
|
{
|
2017-01-05 22:24:45 -05:00
|
|
|
$item['anime'] = $included['anime'][$item['relationships']['media']['data']['id']];
|
|
|
|
|
|
|
|
$animeGenres = $item['anime']['relationships']['genres'];
|
|
|
|
|
|
|
|
foreach($animeGenres as $id)
|
2017-01-06 21:39:01 -05:00
|
|
|
{
|
|
|
|
$item['genres'][] = $included['genres'][$id]['name'];
|
|
|
|
}
|
2016-12-21 12:46:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
$transformed = $this->animeListTransformer->transformCollection($data['data']);
|
|
|
|
|
|
|
|
return $transformed;
|
|
|
|
}
|
2016-12-22 21:36:23 -05:00
|
|
|
|
2017-01-03 21:06:49 -05:00
|
|
|
public function getMangaList($status): array
|
2017-01-04 13:16:58 -05:00
|
|
|
{
|
|
|
|
$options = [
|
|
|
|
'query' => [
|
|
|
|
'filter' => [
|
2017-01-05 13:41:32 -05:00
|
|
|
'user_id' => $this->getUserIdByUsername($this->getUsername()),
|
2017-01-04 13:16:58 -05:00
|
|
|
'media_type' => 'Manga',
|
|
|
|
'status' => $status,
|
|
|
|
],
|
|
|
|
'include' => 'media',
|
|
|
|
'page' => [
|
|
|
|
'offset' => 0,
|
|
|
|
'limit' => 200
|
|
|
|
],
|
|
|
|
'sort' => '-updated_at'
|
|
|
|
]
|
|
|
|
];
|
|
|
|
|
|
|
|
$data = $this->getRequest('library-entries', $options);
|
|
|
|
|
|
|
|
foreach($data['data'] as $i => &$item)
|
|
|
|
{
|
|
|
|
$item['manga'] = $data['included'][$i];
|
|
|
|
}
|
|
|
|
|
|
|
|
$transformed = $this->mangaListTransformer->transformCollection($data['data']);
|
|
|
|
|
|
|
|
return $transformed;
|
|
|
|
}
|
2017-01-03 21:06:49 -05:00
|
|
|
|
2017-01-05 13:41:32 -05:00
|
|
|
public function search(string $type, string $query): array
|
2016-12-22 21:36:23 -05:00
|
|
|
{
|
2017-01-05 13:41:32 -05:00
|
|
|
$options = [
|
|
|
|
'query' => [
|
|
|
|
'filter' => [
|
|
|
|
'text' => $query
|
2017-01-10 21:13:44 -05:00
|
|
|
],
|
|
|
|
'page' => [
|
|
|
|
'offset' => 0,
|
|
|
|
'limit' => 20
|
|
|
|
],
|
|
|
|
]
|
2017-01-05 13:41:32 -05:00
|
|
|
];
|
|
|
|
|
2017-01-09 20:36:48 -05:00
|
|
|
$raw = $this->getRequest($type, $options);
|
|
|
|
|
|
|
|
foreach ($raw['data'] as &$item)
|
|
|
|
{
|
|
|
|
$item['attributes']['titles'] = K::filterTitles($item['attributes']);
|
|
|
|
array_shift($item['attributes']['titles']);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $raw;
|
2017-01-06 21:39:01 -05:00
|
|
|
}
|
2016-12-22 21:36:23 -05:00
|
|
|
|
2017-01-10 21:13:44 -05:00
|
|
|
public function createListItem(array $data): bool
|
|
|
|
{
|
|
|
|
$data['user_id'] = $this->getUserIdByUsername($this->getUsername());
|
|
|
|
return $this->listItem->create($data);
|
|
|
|
}
|
|
|
|
|
2017-01-06 21:39:01 -05:00
|
|
|
public function getListItem(string $listId): array
|
|
|
|
{
|
|
|
|
$baseData = $this->listItem->get($listId);
|
|
|
|
|
|
|
|
switch ($baseData['included'][0]['type'])
|
|
|
|
{
|
|
|
|
case 'anime':
|
|
|
|
$baseData['data']['anime'] = $baseData['included'][0];
|
|
|
|
return $this->animeListTransformer->transform($baseData['data']);
|
|
|
|
|
|
|
|
case 'manga':
|
|
|
|
$baseData['data']['manga'] = $baseData['included'][0];
|
|
|
|
return $this->mangaListTransformer->transform($baseData['data']);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return $baseData['data']['attributes'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function updateListItem(array $data)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
$response = $this->listItem->update($data['id'], $data['data']);
|
|
|
|
return [
|
|
|
|
'statusCode' => $response->getStatusCode(),
|
|
|
|
'body' => $response->getBody(),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
catch(ClientException $e)
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
'statusCode' => $e->getResponse()->getStatusCode(),
|
|
|
|
'body' => Json::decode((string)$e->getResponse()->getBody())
|
|
|
|
];
|
|
|
|
}
|
2016-12-22 21:36:23 -05:00
|
|
|
}
|
|
|
|
|
2017-01-09 20:36:48 -05:00
|
|
|
public function deleteListItem(string $id): bool
|
|
|
|
{
|
|
|
|
return $this->listItem->delete($id);
|
|
|
|
}
|
|
|
|
|
2017-01-05 13:41:32 -05:00
|
|
|
private function getUsername(): string
|
2016-12-22 21:36:23 -05:00
|
|
|
{
|
2017-01-05 13:41:32 -05:00
|
|
|
return $this->getContainer()
|
|
|
|
->get('config')
|
|
|
|
->get(['kitsu_username']);
|
|
|
|
}
|
2016-12-22 21:36:23 -05:00
|
|
|
|
2017-01-05 13:41:32 -05:00
|
|
|
private function getRawMediaData(string $type, string $slug): array
|
|
|
|
{
|
|
|
|
$options = [
|
|
|
|
'query' => [
|
|
|
|
'filter' => [
|
|
|
|
'slug' => $slug
|
|
|
|
],
|
2017-01-05 22:24:45 -05:00
|
|
|
'include' => ($type === 'anime')
|
|
|
|
? 'genres,mappings,streamingLinks'
|
|
|
|
: 'genres,mappings',
|
2017-01-05 13:41:32 -05:00
|
|
|
]
|
|
|
|
];
|
|
|
|
|
|
|
|
$data = $this->getRequest($type, $options);
|
|
|
|
|
|
|
|
$baseData = $data['data'][0]['attributes'];
|
|
|
|
$rawGenres = array_pluck($data['included'], 'attributes');
|
|
|
|
$genres = array_pluck($rawGenres, 'name');
|
|
|
|
$baseData['genres'] = $genres;
|
|
|
|
$baseData['included'] = $data['included'];
|
2016-12-22 21:36:23 -05:00
|
|
|
return $baseData;
|
|
|
|
}
|
2016-12-21 12:46:20 -05:00
|
|
|
}
|