HummingBirdAnimeClient/src/AnimeClient/API/Anilist/Model.php

295 lines
6.6 KiB
PHP
Raw Normal View History

<?php declare(strict_types=1);
/**
* Hummingbird Anime List Client
*
2018-08-22 13:48:27 -04:00
* An API client for Kitsu to manage anime and manga watch lists
*
2021-02-04 11:57:01 -05:00
* PHP version 8
*
2022-03-04 15:50:35 -05:00
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
2020-12-10 17:06:50 -05:00
* @version 5.2
2022-03-04 15:50:35 -05:00
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\API\Anilist;
2020-03-11 16:26:17 -04:00
use Amp\Http\Client\Request;
2020-12-10 15:59:37 -05:00
use Aviat\AnimeClient\Anilist;
2018-08-15 08:51:37 -04:00
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
use Aviat\AnimeClient\Types\FormItem;
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
use Aviat\Ion\Json;
use InvalidArgumentException;
2019-12-09 14:34:23 -05:00
use Throwable;
use function Amp\Promise\wait;
2019-12-09 14:34:23 -05:00
/**
* Anilist API Model
*/
2018-08-15 08:51:37 -04:00
final class Model
{
2020-08-06 09:39:12 -04:00
use RequestBuilderTrait;
2018-08-15 08:51:37 -04:00
/**
* Constructor
*/
public function __construct(private ListItem $listItem)
2018-08-15 08:51:37 -04:00
{
}
// -------------------------------------------------------------------------
// ! Generic API calls
// -------------------------------------------------------------------------
/**
* Attempt to get an auth token
*
* @param string $code - The request token
* @param string $redirectUri - The oauth callback url
2019-12-09 14:34:23 -05:00
* @throws Throwable
* @return mixed[]
*/
public function authenticate(string $code, string $redirectUri): array
{
$config = $this->getContainer()->get('config');
$request = $this->requestBuilder
->newRequest('POST', Anilist::TOKEN_URL)
->setJsonBody([
'grant_type' => 'authorization_code',
'client_id' => $config->get(['anilist', 'client_id']),
'client_secret' => $config->get(['anilist', 'client_secret']),
'redirect_uri' => $redirectUri,
'code' => $code,
])
->getFullRequest();
2020-08-24 13:09:43 -04:00
$response = $this->requestBuilder->getResponseFromRequest($request);
2020-03-11 16:26:17 -04:00
return Json::decode(wait($response->getBody()->buffer()));
}
/**
* Check auth status with simple API call
*/
public function checkAuth(): array
{
return $this->requestBuilder->runQuery('CheckLogin');
}
2018-09-26 22:31:04 -04:00
/**
* Get user list data for syncing with Kitsu
*
2019-12-06 15:46:56 -05:00
* @throws ContainerException
* @throws NotFoundException
2018-09-26 22:31:04 -04:00
*/
public function getSyncList(string $type = 'anime'): array
{
$config = $this->container->get('config');
$anilistUser = $config->get(['anilist', 'username']);
if ( ! (is_string($anilistUser) && $anilistUser !== ''))
2018-09-26 22:31:04 -04:00
{
throw new InvalidArgumentException('Anilist username is not defined in config');
}
return $this->requestBuilder->runQuery('SyncUserList', [
2018-09-26 22:31:04 -04:00
'name' => $anilistUser,
'type' => $type,
]);
}
2018-08-15 08:51:37 -04:00
/**
* Create a list item
*
* @return Request
*/
public function createListItem(array $data, string $type = 'anime'): ?Request
2018-08-15 08:51:37 -04:00
{
2020-01-15 15:22:38 -05:00
if ($data['mal_id'] === NULL)
{
return NULL;
}
2018-08-15 08:51:37 -04:00
2018-09-26 22:31:04 -04:00
$mediaId = $this->getMediaIdFromMalId($data['mal_id'], mb_strtoupper($type));
if ($mediaId === NULL)
2018-09-26 22:31:04 -04:00
{
return NULL;
}
2018-09-26 22:31:04 -04:00
2020-01-15 15:22:38 -05:00
$createData = [];
2018-10-01 13:03:48 -04:00
if ($type === 'ANIME')
2018-09-26 22:31:04 -04:00
{
2018-08-15 08:51:37 -04:00
$createData = [
'id' => $mediaId,
'status' => AnimeWatchingStatus::KITSU_TO_ANILIST[$data['status']],
2018-08-15 08:51:37 -04:00
];
2018-09-26 22:31:04 -04:00
}
2018-10-01 13:03:48 -04:00
elseif ($type === 'MANGA')
2018-09-26 22:31:04 -04:00
{
2018-08-15 08:51:37 -04:00
$createData = [
'id' => $mediaId,
'status' => MangaReadingStatus::KITSU_TO_ANILIST[$data['status']],
2018-08-15 08:51:37 -04:00
];
}
2019-12-06 15:46:56 -05:00
return $this->listItem->create($createData);
2018-08-15 08:51:37 -04:00
}
2018-09-26 22:31:04 -04:00
/**
* Create a list item with all the relevant data
*/
public function createFullListItem(array $data, string $type): Request
2018-09-26 22:31:04 -04:00
{
$createData = $data['data'];
$mediaId = $this->getMediaIdFromMalId($data['mal_id'], strtoupper($type));
2018-10-05 14:32:05 -04:00
if (empty($mediaId))
{
throw new MissingIdException('No id mapping found');
}
2018-09-26 22:31:04 -04:00
$createData['id'] = $mediaId;
2018-10-05 14:32:05 -04:00
2018-09-26 22:31:04 -04:00
return $this->listItem->createFull($createData);
}
2018-08-15 08:51:37 -04:00
/**
* Get the data for a specific list item, generally for editing
*
* @param string $malId - The unique identifier of that list item
2018-11-09 10:38:35 -05:00
* @param string $type - Them media type (anime/manga)
2019-12-09 14:41:04 -05:00
*
* @return mixed[]
2018-08-15 08:51:37 -04:00
*/
2018-09-26 22:31:04 -04:00
public function getListItem(string $malId, string $type): array
2018-08-15 08:51:37 -04:00
{
2018-09-26 22:31:04 -04:00
$id = $this->getListIdFromMalId($malId, $type);
2021-02-16 14:43:51 -05:00
if ($id === NULL)
{
return [];
}
$data = $this->listItem->get($id)['data'];
return ($data !== NULL)
? $data['MediaList']
: [];
}
/**
* Increase the watch count for the current list item
*
2018-11-09 10:38:35 -05:00
* @param string $type - Them media type (anime/manga)
*/
public function incrementListItem(FormItem $data, string $type): ?Request
{
2018-09-26 22:31:04 -04:00
$id = $this->getListIdFromMalId($data['mal_id'], $type);
if ($id === NULL)
{
return NULL;
}
return $this->listItem->increment($id, $data['data']);
2018-08-15 08:51:37 -04:00
}
/**
* Modify a list item
*
2018-11-09 10:38:35 -05:00
* @param string $type - Them media type (anime/manga)
2018-08-15 08:51:37 -04:00
*/
public function updateListItem(FormItem $data, string $type): ?Request
2018-08-15 08:51:37 -04:00
{
2018-09-26 22:31:04 -04:00
$id = $this->getListIdFromMalId($data['mal_id'], mb_strtoupper($type));
if ($id === NULL)
{
return NULL;
}
return $this->listItem->update($id, $data['data']);
2018-08-15 08:51:37 -04:00
}
/**
* Remove a list item
*
* @param string $malId - The id of the list item to remove
* @param string $type - Them media type (anime/manga)
2018-08-15 08:51:37 -04:00
*/
public function deleteListItem(string $malId, string $type): ?Request
2018-08-15 08:51:37 -04:00
{
$id = $this->getListIdFromMalId($malId, $type);
if ($id === NULL)
{
return NULL;
}
return $this->listItem->delete($id);
2018-08-15 08:51:37 -04:00
}
/**
* Get the id of the specific list entry from the malId
*
2018-11-09 10:38:35 -05:00
* @param string $type - The media type (anime/manga)
*/
2018-09-26 22:31:04 -04:00
public function getListIdFromMalId(string $malId, string $type): ?string
{
2018-09-26 22:31:04 -04:00
$mediaId = $this->getMediaIdFromMalId($malId, $type);
if ($mediaId === NULL)
{
return NULL;
}
2018-09-26 22:31:04 -04:00
return $this->getListIdFromMediaId($mediaId);
}
2018-10-05 14:32:05 -04:00
2018-09-26 22:31:04 -04:00
/**
2018-11-09 10:38:35 -05:00
* Get the Anilist list item id from the media id from its MAL id
2018-09-26 22:31:04 -04:00
* this way is more accurate than getting the list item id
* directly from the MAL id
*/
private function getListIdFromMediaId(string $mediaId): ?string
2018-09-26 22:31:04 -04:00
{
$config = $this->container->get('config');
$anilistUser = $config->get(['anilist', 'username']);
2018-10-05 14:32:05 -04:00
$info = $this->requestBuilder->runQuery('ListItemIdByMediaId', [
2018-09-26 22:31:04 -04:00
'id' => $mediaId,
'userName' => $anilistUser,
]);
2018-10-05 14:32:05 -04:00
if ( ! empty($info['errors']))
{
return NULL;
}
return (string) $info['data']['MediaList']['id'];
}
/**
* Get the Anilist media id from the malId
*/
private function getMediaIdFromMalId(string $malId, string $type = 'ANIME'): ?string
{
if ($malId === '')
{
return NULL;
}
$info = $this->requestBuilder->runQuery('MediaIdByMalId', [
'id' => $malId,
2018-09-26 22:31:04 -04:00
'type' => mb_strtoupper($type),
]);
2018-10-05 14:32:05 -04:00
if (array_key_exists('errors', $info))
{
return NULL;
}
return (string) $info['data']['Media']['id'];
}
}