Lots of Anilist integration, see #5
This commit is contained in:
parent
ede69b6099
commit
2d3295757d
@ -24,6 +24,8 @@
|
||||
"aura/session": "^2.0",
|
||||
"aviat/banker": "^1.0.0",
|
||||
"aviat/ion": "^2.3.0",
|
||||
"ext-gd":"*",
|
||||
"ext-pdo": "*",
|
||||
"maximebf/consolekit": "^1.0",
|
||||
"monolog/monolog": "^1.0",
|
||||
"psr/http-message": "~1.0",
|
||||
|
@ -84,26 +84,30 @@ trait AnilistTrait {
|
||||
->get('session')
|
||||
->getSegment(SESSION_SEGMENT);
|
||||
|
||||
$authenticated = $sessionSegment->get('auth_token') !== NULL;
|
||||
//$authenticated = $sessionSegment->get('auth_token') !== NULL;
|
||||
|
||||
if ($authenticated)
|
||||
//if ($authenticated)
|
||||
{
|
||||
$request = $request->setAuth('bearer', $anilistConfig['access_token']);
|
||||
}
|
||||
|
||||
if (array_key_exists('form_params', $options)) {
|
||||
if (array_key_exists('form_params', $options))
|
||||
{
|
||||
$request = $request->setFormFields($options['form_params']);
|
||||
}
|
||||
|
||||
if (array_key_exists('query', $options)) {
|
||||
if (array_key_exists('query', $options))
|
||||
{
|
||||
$request = $request->setQuery($options['query']);
|
||||
}
|
||||
|
||||
if (array_key_exists('body', $options)) {
|
||||
if (array_key_exists('body', $options))
|
||||
{
|
||||
$request = $request->setJsonBody($options['body']);
|
||||
}
|
||||
|
||||
if (array_key_exists('headers', $options)) {
|
||||
if (array_key_exists('headers', $options))
|
||||
{
|
||||
$request = $request->setHeaders($options['headers']);
|
||||
}
|
||||
|
||||
@ -148,7 +152,8 @@ trait AnilistTrait {
|
||||
public function mutateRequest (string $name, array $variables = []): Request
|
||||
{
|
||||
$file = realpath(__DIR__ . "/GraphQL/Mutations/{$name}.graphql");
|
||||
if (!file_exists($file)) {
|
||||
if (!file_exists($file))
|
||||
{
|
||||
throw new \LogicException('GraphQL mutation file does not exist.');
|
||||
}
|
||||
|
||||
@ -161,7 +166,8 @@ trait AnilistTrait {
|
||||
|
||||
if (!empty($variables)) {
|
||||
$body['variables'] = [];
|
||||
foreach ($variables as $key => $val) {
|
||||
foreach ($variables as $key => $val)
|
||||
{
|
||||
$body['variables'][$key] = $val;
|
||||
}
|
||||
}
|
||||
@ -211,7 +217,8 @@ trait AnilistTrait {
|
||||
private function getResponseFromRequest(Request $request): Response
|
||||
{
|
||||
$logger = NULL;
|
||||
if ($this->getContainer()) {
|
||||
if ($this->getContainer())
|
||||
{
|
||||
$logger = $this->container->getLogger('anilist-request');
|
||||
}
|
||||
|
||||
@ -236,15 +243,22 @@ trait AnilistTrait {
|
||||
*/
|
||||
protected function postRequest(array $options = []): array
|
||||
{
|
||||
$response = $this->getResponse(Anilist::BASE_URL, $options);
|
||||
$validResponseCodes = [200, 201];
|
||||
|
||||
$logger = NULL;
|
||||
if ($this->getContainer())
|
||||
{
|
||||
$logger = $this->container->getLogger('anilist-request');
|
||||
$logger->debug('Anilist response', [
|
||||
'status' => $response->getStatus(),
|
||||
'reason' => $response->getReason(),
|
||||
'body' => $response->getBody(),
|
||||
'headers' => $response->getHeaders(),
|
||||
//'requestHeaders' => $request->getHeaders(),
|
||||
]);
|
||||
}
|
||||
|
||||
$response = $this->getResponse(Anilist::BASE_URL, $options);
|
||||
$validResponseCodes = [200, 201];
|
||||
|
||||
if ( ! \in_array($response->getStatus(), $validResponseCodes, TRUE))
|
||||
{
|
||||
if ($logger)
|
||||
|
@ -0,0 +1,27 @@
|
||||
mutation (
|
||||
$id: Int,
|
||||
$notes: String,
|
||||
$private: Boolean,
|
||||
$progress: Int,
|
||||
$repeat: Int,
|
||||
$status: MediaListStatus,
|
||||
$score: Int,
|
||||
) {
|
||||
SaveMediaListEntry (
|
||||
mediaId: $id,
|
||||
notes: $notes,
|
||||
private: $private,
|
||||
progress: $progress,
|
||||
repeat: $repeat,
|
||||
scoreRaw: $score,
|
||||
status: $status
|
||||
) {
|
||||
mediaId
|
||||
notes
|
||||
private
|
||||
progress
|
||||
repeat
|
||||
score(format: POINT_10)
|
||||
status
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
query ($id: Int) {
|
||||
Media (idMal: $id) {
|
||||
query ($id: Int, $type: MediaType) {
|
||||
Media (idMal: $id, type: $type) {
|
||||
mediaListEntry {
|
||||
id
|
||||
userId
|
||||
|
@ -0,0 +1,7 @@
|
||||
query ($id: Int, $userName: String) {
|
||||
MediaList (mediaId: $id, userName: $userName) {
|
||||
id
|
||||
userId
|
||||
mediaId
|
||||
}
|
||||
}
|
27
src/API/Anilist/GraphQL/Queries/SyncUserList.graphql
Normal file
27
src/API/Anilist/GraphQL/Queries/SyncUserList.graphql
Normal file
@ -0,0 +1,27 @@
|
||||
query ($name: String, $type: MediaType) {
|
||||
MediaListCollection(userName: $name, type: $type) {
|
||||
lists {
|
||||
entries {
|
||||
id
|
||||
mediaId
|
||||
score
|
||||
progress
|
||||
progressVolumes
|
||||
repeat
|
||||
private
|
||||
notes
|
||||
status
|
||||
media {
|
||||
id
|
||||
idMal
|
||||
title {
|
||||
romaji
|
||||
english
|
||||
native
|
||||
userPreferred
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -24,7 +24,6 @@ query ($name: String) {
|
||||
status
|
||||
episodes
|
||||
season
|
||||
seasonYear
|
||||
genres
|
||||
synonyms
|
||||
countryOfOrigin
|
||||
|
@ -19,6 +19,7 @@ namespace Aviat\AnimeClient\API\Anilist;
|
||||
use Amp\Artax\Request;
|
||||
|
||||
use Aviat\AnimeClient\API\ListItemInterface;
|
||||
use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Anilist as AnilistStatus;
|
||||
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
||||
use Aviat\AnimeClient\Types\FormItemData;
|
||||
|
||||
@ -29,7 +30,7 @@ final class ListItem implements ListItemInterface{
|
||||
use AnilistTrait;
|
||||
|
||||
/**
|
||||
* Create a list item
|
||||
* Create a minimal list item
|
||||
*
|
||||
* @param array $data
|
||||
* @return Request
|
||||
@ -39,6 +40,17 @@ final class ListItem implements ListItemInterface{
|
||||
return $this->mutateRequest('CreateMediaListEntry', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a fleshed-out list item
|
||||
*
|
||||
* @param array $data
|
||||
* @return Request
|
||||
*/
|
||||
public function createFull(array $data): Request
|
||||
{
|
||||
return $this->mutateRequest('CreateFullMediaListEntry', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a list item
|
||||
*
|
||||
@ -90,18 +102,20 @@ final class ListItem implements ListItemInterface{
|
||||
|
||||
$notes = $data['notes'] ?? '';
|
||||
$progress = array_key_exists('progress', $array) ? $data['progress'] : 0;
|
||||
$private = array_key_exists('private', $array) ? (bool)$data['private'] : false;
|
||||
$rating = array_key_exists('rating', $array) ? $data['rating'] : NULL;
|
||||
$status = $data['status'];
|
||||
$status = ($data['reconsuming'] === true) ? AnilistStatus::REPEATING : AnimeWatchingStatus::KITSU_TO_ANILIST[$data['status']];
|
||||
|
||||
// @TODO Handle weirdness with reWatching
|
||||
return $this->mutateRequest('UpdateMediaListEntry', [
|
||||
'id' => $id,
|
||||
'status' => AnimeWatchingStatus::KITSU_TO_ANILIST[$status],
|
||||
'score' => $rating * 20,
|
||||
$updateData = [
|
||||
'id' => (int)$id,
|
||||
'status' => $status,
|
||||
'score' => $rating * 10,
|
||||
'progress' => $progress,
|
||||
'repeat' => (int)$data['reconsumeCount'],
|
||||
'private' => (bool)$data['private'],
|
||||
'private' => $private,
|
||||
'notes' => $notes,
|
||||
]);
|
||||
];
|
||||
|
||||
return $this->mutateRequest('UpdateMediaListEntry', $updateData);
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@
|
||||
|
||||
namespace Aviat\AnimeClient\API\Anilist;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
use Amp\Artax\Request;
|
||||
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
|
||||
use Aviat\AnimeClient\Types\FormItem;
|
||||
@ -45,6 +47,30 @@ final class Model
|
||||
// ! Generic API calls
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get user list data for syncing with Kitsu
|
||||
*
|
||||
* @param string $type
|
||||
* @return array
|
||||
* @throws \Aviat\Ion\Di\Exception\ContainerException
|
||||
* @throws \Aviat\Ion\Di\Exception\NotFoundException
|
||||
*/
|
||||
public function getSyncList(string $type = 'anime'): array
|
||||
{
|
||||
$config = $this->container->get('config');
|
||||
$anilistUser = $config->get(['anilist', 'username']);
|
||||
|
||||
if ( ! is_string($anilistUser))
|
||||
{
|
||||
throw new InvalidArgumentException('Anilist username is not defined in config');
|
||||
}
|
||||
|
||||
return $this->runQuery('SyncUserList', [
|
||||
'name' => $anilistUser,
|
||||
'type' => $type,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list item
|
||||
*
|
||||
@ -56,14 +82,22 @@ final class Model
|
||||
{
|
||||
$createData = [];
|
||||
|
||||
$mediaId = $this->getMediaIdFromMalId($data['mal_id'], strtoupper($type));
|
||||
$mediaId = $this->getMediaIdFromMalId($data['mal_id'], mb_strtoupper($type));
|
||||
|
||||
if ($type === 'anime') {
|
||||
if (empty($mediaId))
|
||||
{
|
||||
throw new InvalidArgumentException('Media id missing');
|
||||
}
|
||||
|
||||
if ($type === 'anime')
|
||||
{
|
||||
$createData = [
|
||||
'id' => $mediaId,
|
||||
'status' => AnimeWatchingStatus::KITSU_TO_ANILIST[$data['status']],
|
||||
];
|
||||
} elseif ($type === 'manga') {
|
||||
}
|
||||
elseif ($type === 'manga')
|
||||
{
|
||||
$createData = [
|
||||
'id' => $mediaId,
|
||||
'status' => MangaReadingStatus::KITSU_TO_ANILIST[$data['status']],
|
||||
@ -73,15 +107,32 @@ final class Model
|
||||
return $this->listItem->create($createData, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list item with all the relevant data
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $type
|
||||
* @return Request
|
||||
*/
|
||||
public function createFullListItem(array $data, string $type = 'anime'): Request
|
||||
{
|
||||
$createData = $data['data'];
|
||||
$mediaId = $this->getMediaIdFromMalId($data['mal_id']);
|
||||
|
||||
$createData['id'] = $mediaId;
|
||||
|
||||
return $this->listItem->createFull($createData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data for a specific list item, generally for editing
|
||||
*
|
||||
* @param string $malId - The unique identifier of that list item
|
||||
* @return mixed
|
||||
*/
|
||||
public function getListItem(string $malId): array
|
||||
public function getListItem(string $malId, string $type): array
|
||||
{
|
||||
$id = $this->getListIdFromMalId($malId);
|
||||
$id = $this->getListIdFromMalId($malId, $type);
|
||||
|
||||
$data = $this->listItem->get($id)['data'];
|
||||
|
||||
@ -96,9 +147,9 @@ final class Model
|
||||
* @param FormItem $data
|
||||
* @return Request
|
||||
*/
|
||||
public function incrementListItem(FormItem $data): Request
|
||||
public function incrementListItem(FormItem $data, string $type): Request
|
||||
{
|
||||
$id = $this->getListIdFromMalId($data['mal_id']);
|
||||
$id = $this->getListIdFromMalId($data['mal_id'], $type);
|
||||
|
||||
return $this->listItem->increment($id, $data['data']);
|
||||
}
|
||||
@ -107,11 +158,12 @@ final class Model
|
||||
* Modify a list item
|
||||
*
|
||||
* @param FormItem $data
|
||||
* @param int [$id]
|
||||
* @return Request
|
||||
*/
|
||||
public function updateListItem(FormItem $data): Request
|
||||
public function updateListItem(FormItem $data, string $type): Request
|
||||
{
|
||||
$id = $this->getListIdFromMalId($data['mal_id']);
|
||||
$id = $this->getListIdFromMalId($data['mal_id'], mb_strtoupper($type));
|
||||
|
||||
return $this->listItem->update($id, $data['data']);
|
||||
}
|
||||
@ -122,9 +174,9 @@ final class Model
|
||||
* @param string $malId - The id of the list item to remove
|
||||
* @return Request
|
||||
*/
|
||||
public function deleteListItem(string $malId): Request
|
||||
public function deleteListItem(string $malId, string $type): Request
|
||||
{
|
||||
$item_id = $this->getListIdFromMalId($malId);
|
||||
$item_id = $this->getListIdFromMalId($malId, $type);
|
||||
|
||||
return $this->listItem->delete($item_id);
|
||||
}
|
||||
@ -135,10 +187,35 @@ final class Model
|
||||
* @param string $malId
|
||||
* @return string
|
||||
*/
|
||||
public function getListIdFromMalId(string $malId): ?string
|
||||
public function getListIdFromMalId(string $malId, string $type): ?string
|
||||
{
|
||||
$info = $this->runQuery('ListItemIdByMalId', ['id' => $malId]);
|
||||
return (string)$info['data']['Media']['mediaListEntry']['id'] ?? NULL;
|
||||
$mediaId = $this->getMediaIdFromMalId($malId, $type);
|
||||
return $this->getListIdFromMediaId($mediaId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Anilist media id from its MAL id
|
||||
* this way is more accurate than getting the list item id
|
||||
* directly from the MAL id
|
||||
*/
|
||||
private function getListIdFromMediaId(string $mediaId)
|
||||
{
|
||||
$config = $this->container->get('config');
|
||||
$anilistUser = $config->get(['anilist', 'username']);
|
||||
|
||||
$info = $this->runQuery('ListItemIdByMediaId', [
|
||||
'id' => $mediaId,
|
||||
'userName' => $anilistUser,
|
||||
]);
|
||||
|
||||
/* dump([
|
||||
'media_id' => $mediaId,
|
||||
'userName' => $anilistUser,
|
||||
'response' => $info,
|
||||
]);
|
||||
die(); */
|
||||
|
||||
return (string)$info['data']['MediaList']['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -152,9 +229,15 @@ final class Model
|
||||
{
|
||||
$info = $this->runQuery('MediaIdByMalId', [
|
||||
'id' => $malId,
|
||||
'type' => $type
|
||||
'type' => mb_strtoupper($type),
|
||||
]);
|
||||
|
||||
/* dump([
|
||||
'mal_id' => $malId,
|
||||
'response' => $info,
|
||||
]);
|
||||
die(); */
|
||||
|
||||
return (string)$info['data']['Media']['id'];
|
||||
}
|
||||
}
|
@ -16,22 +16,51 @@
|
||||
|
||||
namespace Aviat\AnimeClient\API\Anilist\Transformer;
|
||||
|
||||
use Aviat\AnimeClient\Types\{AnimeListItem, AnimeFormItem};
|
||||
use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Anilist as AnilistStatus;
|
||||
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
||||
use Aviat\AnimeClient\Types\{Anime, AnimeListItem, AnimeFormItem};
|
||||
|
||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||
|
||||
class AnimeListTransformer extends AbstractTransformer {
|
||||
|
||||
public function transform($item): AnimeListItem
|
||||
{
|
||||
dump($item); die();
|
||||
|
||||
return new AnimeListItem([
|
||||
return new AnimeListItem([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform Anilist list item to Kitsu form update format
|
||||
*
|
||||
* @param array $item
|
||||
* @return AnimeFormItem
|
||||
*/
|
||||
public function untransform(array $item): AnimeFormItem
|
||||
{
|
||||
return new AnimeFormItem([
|
||||
'id' => $item['id'],
|
||||
'mal_id' => $item['media']['idMal'],
|
||||
'data' => [
|
||||
'notes' => $item['notes'] ?? '',
|
||||
'private' => $item['private'],
|
||||
'progress' => $item['progress'],
|
||||
'rating' => $item['score'],
|
||||
'reconsumeCount' => $item['repeat'],
|
||||
'reconsuming' => $item['status'] === AnilistStatus::REPEATING,
|
||||
'status' => AnimeWatchingStatus::ANILIST_TO_KITSU[$item['status']],
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function untransform(array $item): AnimeFormItem
|
||||
/**
|
||||
* Transform a set of structures
|
||||
*
|
||||
* @param array|object $collection
|
||||
* @return array
|
||||
*/
|
||||
public function untransformCollection($collection): array
|
||||
{
|
||||
return new AnimeFormItem($item);
|
||||
$list = (array)$collection;
|
||||
return array_map([$this, 'untransform'], $list);
|
||||
}
|
||||
}
|
@ -16,7 +16,10 @@
|
||||
|
||||
namespace Aviat\AnimeClient\API\Anilist\Transformer;
|
||||
|
||||
use Aviat\AnimeClient\API\Enum\MangaReadingStatus\Anilist as AnilistStatus;
|
||||
use Aviat\AnimeClient\API\Mapping\MangaReadingStatus;
|
||||
use Aviat\AnimeClient\Types\MangaFormItem;
|
||||
|
||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||
|
||||
class MangaListTransformer extends AbstractTransformer {
|
||||
@ -26,8 +29,38 @@ class MangaListTransformer extends AbstractTransformer {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform Anilist list item to Kitsu form update format
|
||||
*
|
||||
* @param array $item
|
||||
* @return MangaFormItem
|
||||
*/
|
||||
public function untransform(array $item): MangaFormItem
|
||||
{
|
||||
return new MangaFormItem($item);
|
||||
return new MangaFormItem([
|
||||
'id' => $item['id'],
|
||||
'mal_id' => $item['media']['idMal'],
|
||||
'data' => [
|
||||
'notes' => $item['notes'] ?? '',
|
||||
'private' => $item['private'],
|
||||
'progress' => $item['progress'],
|
||||
'rating' => $item['score'],
|
||||
'reconsumeCount' => $item['repeat'],
|
||||
'reconsuming' => $item['status'] === AnilistStatus::REPEATING,
|
||||
'status' => MangaReadingStatus::ANILIST_TO_KITSU[$item['status']],
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a set of structures
|
||||
*
|
||||
* @param array|object $collection
|
||||
* @return array
|
||||
*/
|
||||
public function untransformCollection($collection): array
|
||||
{
|
||||
$list = (array)$collection;
|
||||
return array_map([$this, 'untransform'], $list);
|
||||
}
|
||||
}
|
@ -62,6 +62,11 @@ final class ListItem implements ListItemInterface {
|
||||
]
|
||||
];
|
||||
|
||||
if (array_key_exists('notes', $data))
|
||||
{
|
||||
$body['data']['attributes']['notes'] = $data['notes'];
|
||||
}
|
||||
|
||||
$authHeader = $this->getAuthHeader();
|
||||
|
||||
$request = $this->requestBuilder->newRequest('POST', 'library-entries');
|
||||
|
@ -37,11 +37,8 @@ use Aviat\AnimeClient\API\Kitsu\Transformer\{
|
||||
MangaListTransformer
|
||||
};
|
||||
use Aviat\AnimeClient\Types\{
|
||||
AbstractType,
|
||||
Anime,
|
||||
FormItem,
|
||||
FormItemData,
|
||||
AnimeListItem,
|
||||
MangaPage
|
||||
};
|
||||
use Aviat\Ion\{Di\ContainerAware, Json};
|
||||
|
@ -45,8 +45,8 @@ final class AnimeListTransformer extends AbstractTransformer {
|
||||
$genres = array_column($anime['relationships']['genres'], 'name') ?? [];
|
||||
sort($genres);
|
||||
|
||||
$rating = (int) $item['attributes']['rating'] !== 0
|
||||
? 2 * $item['attributes']['rating']
|
||||
$rating = (int) $item['attributes']['ratingTwenty'] !== 0
|
||||
? $item['attributes']['ratingTwenty'] / 2
|
||||
: '-';
|
||||
|
||||
$total_episodes = array_key_exists('episodeCount', $anime) && (int) $anime['episodeCount'] !== 0
|
||||
@ -141,7 +141,7 @@ final class AnimeListTransformer extends AbstractTransformer {
|
||||
|
||||
if (is_numeric($item['user_rating']) && $item['user_rating'] > 0)
|
||||
{
|
||||
$untransformed['data']['rating'] = $item['user_rating'] / 2;
|
||||
$untransformed['data']['ratingTwenty'] = $item['user_rating'] * 2;
|
||||
}
|
||||
|
||||
return $untransformed;
|
||||
|
@ -46,8 +46,8 @@ final class MangaListTransformer extends AbstractTransformer {
|
||||
$genres = array_column($manga['relationships']['genres'], 'name') ?? [];
|
||||
sort($genres);
|
||||
|
||||
$rating = (int) $item['attributes']['rating'] !== 0
|
||||
? 2 * $item['attributes']['rating']
|
||||
$rating = (int) $item['attributes']['ratingTwenty'] !== 0
|
||||
? $item['attributes']['ratingTwenty'] / 2
|
||||
: '-';
|
||||
|
||||
$totalChapters = ((int) $manga['chapterCount'] !== 0)
|
||||
@ -138,7 +138,7 @@ final class MangaListTransformer extends AbstractTransformer {
|
||||
|
||||
if (is_numeric($item['new_rating']) && $item['new_rating'] > 0)
|
||||
{
|
||||
$map['data']['rating'] = $item['new_rating'] / 2;
|
||||
$map['data']['ratingTwenty'] = $item['new_rating'] * 2;
|
||||
}
|
||||
|
||||
return $map;
|
||||
|
@ -66,6 +66,7 @@ final class ParallelAPIRequest {
|
||||
* Actually make the requests
|
||||
*
|
||||
* @return array
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function makeRequests(): array
|
||||
{
|
||||
|
@ -21,6 +21,7 @@ use function Aviat\AnimeClient\loadToml;
|
||||
use Aura\Session\SessionFactory;
|
||||
use Aviat\AnimeClient\Util;
|
||||
use Aviat\AnimeClient\API\CacheTrait;
|
||||
use Aviat\AnimeClient\API\Anilist;
|
||||
use Aviat\AnimeClient\API\Kitsu;
|
||||
use Aviat\AnimeClient\API\Kitsu\KitsuRequestBuilder;
|
||||
use Aviat\Banker\Pool;
|
||||
@ -85,7 +86,10 @@ class BaseCommand extends Command {
|
||||
$app_logger->pushHandler(new RotatingFileHandler($APP_DIR . '/logs/app-cli.log', Logger::NOTICE));
|
||||
$kitsu_request_logger = new Logger('kitsu-request');
|
||||
$kitsu_request_logger->pushHandler(new RotatingFileHandler($APP_DIR . '/logs/kitsu_request-cli.log', Logger::NOTICE));
|
||||
$anilistRequestLogger = new Logger('anilist-request');
|
||||
$anilistRequestLogger->pushHandler(new RotatingFileHandler($APP_DIR . '/logs/anilist_request-cli.log', Logger::NOTICE));
|
||||
$container->setLogger($app_logger);
|
||||
$container->setLogger($anilistRequestLogger, 'anilist-request');
|
||||
$container->setLogger($kitsu_request_logger, 'kitsu-request');
|
||||
|
||||
// Create Config Object
|
||||
@ -122,6 +126,20 @@ class BaseCommand extends Command {
|
||||
$model->setCache($cache);
|
||||
return $model;
|
||||
});
|
||||
$container->set('anilist-model', function ($container) {
|
||||
$requestBuilder = new Anilist\AnilistRequestBuilder();
|
||||
$requestBuilder->setLogger($container->getLogger('anilist-request'));
|
||||
|
||||
$listItem = new Anilist\ListItem();
|
||||
$listItem->setContainer($container);
|
||||
$listItem->setRequestBuilder($requestBuilder);
|
||||
|
||||
$model = new Anilist\Model($listItem);
|
||||
$model->setContainer($container);
|
||||
$model->setRequestBuilder($requestBuilder);
|
||||
|
||||
return $model;
|
||||
});
|
||||
|
||||
$container->set('util', function($container) {
|
||||
return new Util($container);
|
||||
|
@ -16,19 +16,28 @@
|
||||
|
||||
namespace Aviat\AnimeClient\Command;
|
||||
|
||||
use Aviat\AnimeClient\API\{
|
||||
FailedResponseException,
|
||||
JsonAPI,
|
||||
ParallelAPIRequest
|
||||
use Aviat\AnimeClient\API\
|
||||
{FailedResponseException, JsonAPI, Kitsu\Transformer\MangaListTransformer, ParallelAPIRequest};
|
||||
use Aviat\AnimeClient\API\Anilist\Transformer\{
|
||||
AnimeListTransformer as AALT,
|
||||
MangaListTransformer as AMLT,
|
||||
};
|
||||
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
|
||||
use Aviat\AnimeClient\Types\{AnimeFormItem, MangaFormItem};
|
||||
use Aviat\Ion\Json;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* Clears the API Cache
|
||||
* Syncs list data between Anilist and Kitsu
|
||||
*/
|
||||
final class SyncLists extends BaseCommand {
|
||||
|
||||
/**
|
||||
* Model for making requests to Anilist API
|
||||
* @var \Aviat\AnimeClient\API\Anilist\Model
|
||||
*/
|
||||
protected $anilistModel;
|
||||
|
||||
/**
|
||||
* Model for making requests to Kitsu API
|
||||
* @var \Aviat\AnimeClient\API\Kitsu\Model
|
||||
@ -36,7 +45,7 @@ final class SyncLists extends BaseCommand {
|
||||
protected $kitsuModel;
|
||||
|
||||
/**
|
||||
* Run the Kitsu <=> MAL sync script
|
||||
* Run the Kitsu <=> Anilist sync script
|
||||
*
|
||||
* @param array $args
|
||||
* @param array $options
|
||||
@ -48,6 +57,7 @@ final class SyncLists extends BaseCommand {
|
||||
{
|
||||
$this->setContainer($this->setupContainer());
|
||||
$this->setCache($this->container->get('cache'));
|
||||
$this->anilistModel = $this->container->get('anilist-model');
|
||||
$this->kitsuModel = $this->container->get('kitsu-model');
|
||||
|
||||
$this->sync('anime');
|
||||
@ -64,18 +74,6 @@ final class SyncLists extends BaseCommand {
|
||||
{
|
||||
$uType = ucfirst($type);
|
||||
|
||||
// Do a little check to make sure you don't have immediate issues
|
||||
// if you have 0 or 1 items in a list on MAL.
|
||||
/* $malList = $this->malModel->getList($type);
|
||||
$malCount = 0;
|
||||
if ( ! empty($malList))
|
||||
{
|
||||
$malCount = count(array_key_exists(0, $malList)
|
||||
? $malList
|
||||
: [$malList]
|
||||
);
|
||||
} */
|
||||
|
||||
$kitsuCount = 0;
|
||||
try
|
||||
{
|
||||
@ -87,24 +85,23 @@ final class SyncLists extends BaseCommand {
|
||||
}
|
||||
|
||||
|
||||
// $this->echoBox("Number of MAL {$type} list items: {$malCount}");
|
||||
$this->echoBox("Number of Kitsu {$type} list items: {$kitsuCount}");
|
||||
|
||||
$data = $this->diffLists($type);
|
||||
|
||||
/* if ( ! empty($data['addToMAL']))
|
||||
if ( ! empty($data['addToAnilist']))
|
||||
{
|
||||
$count = count($data['addToMAL']);
|
||||
$this->echoBox("Adding {$count} missing {$type} list items to MAL");
|
||||
$this->updateMALListItems($data['addToMAL'], 'create', $type);
|
||||
$count = count($data['addToAnilist']);
|
||||
$this->echoBox("Adding {$count} missing {$type} list items to Anilist");
|
||||
$this->updateAnilistListItems($data['addToAnilist'], 'create', $type);
|
||||
}
|
||||
|
||||
if ( ! empty($data['updateMAL']))
|
||||
if ( ! empty($data['updateAnilist']))
|
||||
{
|
||||
$count = count($data['updateMAL']);
|
||||
$this->echoBox("Updating {$count} outdated MAL {$type} list items");
|
||||
$this->updateMALListItems($data['updateMAL'], 'update', $type);
|
||||
} */
|
||||
$count = count($data['updateAnilist']);
|
||||
$this->echoBox("Updating {$count} outdated Anilist {$type} list items");
|
||||
$this->updateAnilistListItems($data['updateAnilist'], 'update', $type);
|
||||
}
|
||||
|
||||
if ( ! empty($data['addToKitsu']))
|
||||
{
|
||||
@ -144,107 +141,79 @@ final class SyncLists extends BaseCommand {
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a MAL list for comparison
|
||||
* Format an Anilist list for comparison
|
||||
*
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
/* protected function formatMALList(string $type): array
|
||||
protected function formatAnilistList(string $type): array
|
||||
{
|
||||
$type = ucfirst($type);
|
||||
$method = "formatMAL{$type}List";
|
||||
$method = "formatAnilist{$type}List";
|
||||
return $this->$method();
|
||||
} */
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a MAL anime list for comparison
|
||||
* Format an Anilist anime list for comparison
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
/* protected function formatMALAnimeList(): array
|
||||
protected function formatAnilistAnimeList(): array
|
||||
{
|
||||
$orig = $this->malModel->getList('anime');
|
||||
$anilistList = $this->anilistModel->getSyncList('ANIME');
|
||||
$anilistTransformer = new AALT();
|
||||
|
||||
$transformedAnilist = [];
|
||||
|
||||
foreach ($anilistList['data']['MediaListCollection']['lists'] as $list)
|
||||
{
|
||||
$newTransformed = $anilistTransformer->untransformCollection($list['entries']);
|
||||
$transformedAnilist = array_merge($transformedAnilist, $newTransformed);
|
||||
}
|
||||
|
||||
// Key the array by the mal_id for easier reference in the next comparision step
|
||||
$output = [];
|
||||
|
||||
// Bail early on empty list
|
||||
if (empty($orig))
|
||||
foreach ($transformedAnilist as $item)
|
||||
{
|
||||
return [];
|
||||
$output[$item['mal_id']] = $item->toArray();
|
||||
}
|
||||
|
||||
// Due to xml parsing differences,
|
||||
// 1 item has no wrapping array.
|
||||
// In this case, just re-create the
|
||||
// wrapper array
|
||||
if ( ! array_key_exists(0, $orig))
|
||||
{
|
||||
$orig = [$orig];
|
||||
}
|
||||
|
||||
foreach($orig as $item)
|
||||
{
|
||||
$output[$item['series_animedb_id']] = [
|
||||
'id' => $item['series_animedb_id'],
|
||||
'data' => [
|
||||
'status' => AnimeWatchingStatus::MAL_TO_KITSU[$item['my_status']],
|
||||
'progress' => $item['my_watched_episodes'],
|
||||
'reconsuming' => (bool) $item['my_rewatching'],
|
||||
'rating' => $item['my_score'] / 2,
|
||||
'updatedAt' => (new \DateTime())
|
||||
->setTimestamp((int)$item['my_last_updated'])
|
||||
->format(\DateTime::W3C),
|
||||
]
|
||||
];
|
||||
}
|
||||
$count = count($output);
|
||||
$this->echoBox("Number of Anilist anime list items: {$count}");
|
||||
|
||||
return $output;
|
||||
} */
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a MAL manga list for comparison
|
||||
* Format an Anilist manga list for comparison
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
/* protected function formatMALMangaList(): array
|
||||
protected function formatAnilistMangaList(): array
|
||||
{
|
||||
$orig = $this->malModel->getList('manga');
|
||||
$anilistList = $this->anilistModel->getSyncList('MANGA');
|
||||
$anilistTransformer = new AMLT();
|
||||
|
||||
$transformedAnilist = [];
|
||||
|
||||
foreach ($anilistList['data']['MediaListCollection']['lists'] as $list)
|
||||
{
|
||||
$newTransformed = $anilistTransformer->untransformCollection($list['entries']);
|
||||
$transformedAnilist = array_merge($transformedAnilist, $newTransformed);
|
||||
}
|
||||
|
||||
// Key the array by the mal_id for easier reference in the next comparision step
|
||||
$output = [];
|
||||
|
||||
// Bail early on empty list
|
||||
if (empty($orig))
|
||||
foreach ($transformedAnilist as $item)
|
||||
{
|
||||
return [];
|
||||
$output[$item['mal_id']] = $item->toArray();
|
||||
}
|
||||
|
||||
// Due to xml parsing differences,
|
||||
// 1 item has no wrapping array.
|
||||
// In this case, just re-create the
|
||||
// wrapper array
|
||||
if ( ! array_key_exists(0, $orig))
|
||||
{
|
||||
$orig = [$orig];
|
||||
}
|
||||
|
||||
foreach($orig as $item)
|
||||
{
|
||||
$output[$item['series_mangadb_id']] = [
|
||||
'id' => $item['series_mangadb_id'],
|
||||
'data' => [
|
||||
'my_status' => $item['my_status'],
|
||||
'status' => MangaReadingStatus::MAL_TO_KITSU[$item['my_status']],
|
||||
'progress' => $item['my_read_chapters'],
|
||||
'volumes' => $item['my_read_volumes'],
|
||||
'reconsuming' => (bool) $item['my_rereadingg'],
|
||||
'rating' => $item['my_score'] / 2,
|
||||
'updatedAt' => (new \DateTime())
|
||||
->setTimestamp((int)$item['my_last_updated'])
|
||||
->format(\DateTime::W3C),
|
||||
]
|
||||
];
|
||||
}
|
||||
$count = count($output);
|
||||
$this->echoBox("Number of Anilist manga list items: {$count}");
|
||||
|
||||
return $output;
|
||||
} */
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a kitsu list for the sake of comparision
|
||||
@ -254,7 +223,7 @@ final class SyncLists extends BaseCommand {
|
||||
*/
|
||||
protected function formatKitsuList(string $type = 'anime'): array
|
||||
{
|
||||
$data = $this->kitsuModel->{'getFull' . ucfirst($type) . 'List'}();
|
||||
$data = $this->kitsuModel->{'getFullRaw' . ucfirst($type) . 'List'}();
|
||||
|
||||
if (empty($data))
|
||||
{
|
||||
@ -281,7 +250,7 @@ final class SyncLists extends BaseCommand {
|
||||
}
|
||||
}
|
||||
|
||||
// Skip to the next item if there isn't a MAL ID
|
||||
// Skip to the next item if there isn't a Anilist ID
|
||||
if ($malId === NULL)
|
||||
{
|
||||
continue;
|
||||
@ -309,31 +278,51 @@ final class SyncLists extends BaseCommand {
|
||||
// Organize mappings, and ignore entries without mappings
|
||||
$kitsuList = $this->formatKitsuList($type);
|
||||
|
||||
// Get MAL list data
|
||||
// $malList = $this->formatMALList($type);
|
||||
// Get Anilist list data
|
||||
$anilistList = $this->formatAnilistList($type);
|
||||
|
||||
$itemsToAddToMAL = [];
|
||||
$itemsToAddToAnilist = [];
|
||||
$itemsToAddToKitsu = [];
|
||||
$malUpdateItems = [];
|
||||
$anilistUpdateItems = [];
|
||||
$kitsuUpdateItems = [];
|
||||
|
||||
// $malIds = array_column($malList, 'id');
|
||||
// $kitsuMalIds = array_column($kitsuList, 'malId');
|
||||
// $missingMalIds = array_diff($malIds, $kitsuMalIds);
|
||||
$malBlackList = ($type === 'anime')
|
||||
? [
|
||||
27821, // Fate/stay night: Unlimited Blade Works - Prologue
|
||||
29317, // Saekano: How to Raise a Boring Girlfriend Prologue
|
||||
30514, // Nisekoinogatari
|
||||
] : [
|
||||
114638, // Cells at Work: Black
|
||||
];
|
||||
|
||||
/* foreach($missingMalIds as $mid)
|
||||
$malIds = array_keys($anilistList);
|
||||
$kitsuMalIds = array_map('intval', array_column($kitsuList, 'malId'));
|
||||
$missingMalIds = array_diff($malIds, $kitsuMalIds);
|
||||
$missingMalIds = array_diff($missingMalIds, $malBlackList);
|
||||
|
||||
foreach($missingMalIds as $mid)
|
||||
{
|
||||
$itemsToAddToKitsu[] = array_merge($malList[$mid]['data'], [
|
||||
'id' => $this->kitsuModel->getKitsuIdFromMALId($mid, $type),
|
||||
$itemsToAddToKitsu[] = array_merge($anilistList[$mid]['data'], [
|
||||
'id' => $this->kitsuModel->getKitsuIdFromMALId((string)$mid, $type),
|
||||
'type' => $type
|
||||
]);
|
||||
} */
|
||||
}
|
||||
|
||||
/* foreach($kitsuList as $kitsuItem)
|
||||
foreach($kitsuList as $kitsuItem)
|
||||
{
|
||||
if (\in_array($kitsuItem['malId'], $malIds, TRUE))
|
||||
$malId = $kitsuItem['malId'];
|
||||
|
||||
if (in_array($malId, $malBlackList))
|
||||
{
|
||||
$item = $this->compareListItems($kitsuItem, $malList[$kitsuItem['malId']]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (array_key_exists($malId, $anilistList))
|
||||
{
|
||||
$anilistItem = $anilistList[$malId];
|
||||
// dump($anilistItem);
|
||||
|
||||
$item = $this->compareListItems($kitsuItem, $anilistItem);
|
||||
|
||||
if ($item === NULL)
|
||||
{
|
||||
@ -345,25 +334,39 @@ final class SyncLists extends BaseCommand {
|
||||
$kitsuUpdateItems[] = $item['data'];
|
||||
}
|
||||
|
||||
if (\in_array('mal', $item['updateType'], TRUE))
|
||||
if (\in_array('anilist', $item['updateType'], TRUE))
|
||||
{
|
||||
$malUpdateItems[] = $item['data'];
|
||||
$anilistUpdateItems[] = $item['data'];
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$statusMap = ($type === 'anime') ? AnimeWatchingStatus::class : MangaReadingStatus::class;
|
||||
|
||||
// Looks like this item only exists on Kitsu
|
||||
$itemsToAddToMAL[] = [
|
||||
'mal_id' => $kitsuItem['malId'],
|
||||
'data' => $kitsuItem['data']
|
||||
$kItem = $kitsuItem['data'];
|
||||
$newItemStatus = ($kItem['reconsuming'] === true) ? 'REPEATING' : $statusMap::KITSU_TO_ANILIST[$kItem['status']];
|
||||
$itemsToAddToAnilist[] = [
|
||||
'mal_id' => $malId,
|
||||
'data' => [
|
||||
'notes' => $kItem['notes'],
|
||||
'private' => $kItem['private'],
|
||||
'progress' => $kItem['progress'],
|
||||
'repeat' => $kItem['reconsumeCount'],
|
||||
'score' => $kItem['ratingTwenty'] / 2,
|
||||
'status' => $newItemStatus,
|
||||
], // $kitsuItem['data']
|
||||
];
|
||||
|
||||
} */
|
||||
}
|
||||
|
||||
//dump($itemsToAddToAnilist);
|
||||
//die();
|
||||
|
||||
return [
|
||||
// 'addToMAL' => $itemsToAddToMAL,
|
||||
// 'updateMAL' => $malUpdateItems,
|
||||
'addToAnilist' => $itemsToAddToAnilist,
|
||||
'updateAnilist' => $anilistUpdateItems,
|
||||
'addToKitsu' => $itemsToAddToKitsu,
|
||||
'updateKitsu' => $kitsuUpdateItems
|
||||
];
|
||||
@ -373,18 +376,27 @@ final class SyncLists extends BaseCommand {
|
||||
* Compare two list items, and return the out of date one, if one exists
|
||||
*
|
||||
* @param array $kitsuItem
|
||||
* @param array $malItem
|
||||
* @param array $anilistItem
|
||||
* @return array|null
|
||||
*/
|
||||
protected function compareListItems(array $kitsuItem, array $malItem): ?array
|
||||
protected function compareListItems(array $kitsuItem, array $anilistItem): ?array
|
||||
{
|
||||
$compareKeys = ['status', 'progress', 'rating', 'reconsuming'];
|
||||
$compareKeys = [
|
||||
'notes',
|
||||
'progress',
|
||||
'rating',
|
||||
'reconsumeCount',
|
||||
'reconsuming',
|
||||
'status',
|
||||
];
|
||||
$diff = [];
|
||||
$dateDiff = new DateTime($kitsuItem['data']['updatedAt']) <=> new DateTime($malItem['data']['updatedAt']);
|
||||
|
||||
// Correct differences in notation
|
||||
$kitsuItem['data']['rating'] = $kitsuItem['data']['ratingTwenty'] / 2;
|
||||
|
||||
foreach($compareKeys as $key)
|
||||
{
|
||||
$diff[$key] = $kitsuItem['data'][$key] <=> $malItem['data'][$key];
|
||||
$diff[$key] = $kitsuItem['data'][$key] <=> $anilistItem['data'][$key];
|
||||
}
|
||||
|
||||
// No difference? Bail out early
|
||||
@ -404,9 +416,18 @@ final class SyncLists extends BaseCommand {
|
||||
'updateType' => []
|
||||
];
|
||||
|
||||
$sameNotes = $diff['notes'] === 0;
|
||||
$sameStatus = $diff['status'] === 0;
|
||||
$sameProgress = $diff['progress'] === 0;
|
||||
$sameRating = $diff['rating'] === 0;
|
||||
$sameRewatchCount = $diff['reconsumeCount'] === 0;
|
||||
|
||||
// If an item is completed, make sure the 'reconsuming' flag is false
|
||||
if ($kitsuItem['data']['status'] === 'completed' && $kitsuItem['data']['reconsuming'] === TRUE)
|
||||
{
|
||||
$update['data']['reconsuming'] = FALSE;
|
||||
$return['updateType'][] = 'kitsu';
|
||||
}
|
||||
|
||||
|
||||
// If status is the same, and progress count is different, use greater progress
|
||||
@ -415,18 +436,25 @@ final class SyncLists extends BaseCommand {
|
||||
if ($diff['progress'] === 1)
|
||||
{
|
||||
$update['data']['progress'] = $kitsuItem['data']['progress'];
|
||||
$return['updateType'][] = 'mal';
|
||||
$return['updateType'][] = 'anilist';
|
||||
}
|
||||
else if($diff['progress'] === -1)
|
||||
{
|
||||
$update['data']['progress'] = $malItem['data']['progress'];
|
||||
$update['data']['progress'] = $anilistItem['data']['progress'];
|
||||
$return['updateType'][] = 'kitsu';
|
||||
}
|
||||
}
|
||||
|
||||
// If status is different, go with Kitsu
|
||||
if ( ! $sameStatus)
|
||||
{
|
||||
$update['data']['status'] = $kitsuItem['data']['status'];
|
||||
$return['updateType'][] = 'anilist';
|
||||
}
|
||||
|
||||
// If status and progress are different, it's a bit more complicated...
|
||||
// But, at least for now, assume newer record is correct
|
||||
if ( ! ($sameStatus || $sameProgress))
|
||||
/* if ( ! ($sameStatus || $sameProgress))
|
||||
{
|
||||
if ($dateDiff === 1)
|
||||
{
|
||||
@ -437,59 +465,111 @@ final class SyncLists extends BaseCommand {
|
||||
$update['data']['progress'] = $kitsuItem['data']['progress'];
|
||||
}
|
||||
|
||||
$return['updateType'][] = 'mal';
|
||||
$return['updateType'][] = 'anilist';
|
||||
}
|
||||
else if($dateDiff === -1)
|
||||
{
|
||||
$update['data']['status'] = $malItem['data']['status'];
|
||||
$update['data']['status'] = $anilistItem['data']['status'];
|
||||
|
||||
if ((int)$malItem['data']['progress'] !== 0)
|
||||
if ((int)$anilistItem['data']['progress'] !== 0)
|
||||
{
|
||||
$update['data']['progress'] = $kitsuItem['data']['progress'];
|
||||
}
|
||||
|
||||
$return['updateType'][] = 'kitsu';
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// If rating is different, use the rating from the item most recently updated
|
||||
// If rating is different, use the kitsu rating, unless the other rating
|
||||
// is set, and the kitsu rating is not set
|
||||
if ( ! $sameRating)
|
||||
{
|
||||
if ($dateDiff === 1)
|
||||
if ($kitsuItem['data']['rating'] !== 0)
|
||||
{
|
||||
$update['data']['rating'] = $kitsuItem['data']['rating'];
|
||||
$return['updateType'][] = 'mal';
|
||||
$return['updateType'][] = 'anilist';
|
||||
}
|
||||
else if ($dateDiff === -1)
|
||||
else
|
||||
{
|
||||
$update['data']['rating'] = $malItem['data']['rating'];
|
||||
$update['data']['rating'] = $anilistItem['data']['rating'];
|
||||
$return['updateType'][] = 'kitsu';
|
||||
}
|
||||
}
|
||||
|
||||
// If notes are set, use kitsu, otherwise, set kitsu from anilist
|
||||
if ( ! $sameNotes)
|
||||
{
|
||||
if ($kitsuItem['data']['notes'] !== '')
|
||||
{
|
||||
$update['data']['notes'] = $kitsuItem['data']['notes'];
|
||||
$return['updateType'][] = 'anilist';
|
||||
}
|
||||
else
|
||||
{
|
||||
$update['data']['notes'] = $anilistItem['data']['notes'];
|
||||
$return['updateType'][] = 'kitsu';
|
||||
}
|
||||
}
|
||||
|
||||
// Assume the larger reconsumeCount is correct
|
||||
if ( ! $sameRewatchCount)
|
||||
{
|
||||
if ($diff['reconsumeCount'] === 1)
|
||||
{
|
||||
$update['data']['reconsumeCount'] = $kitsuItem['data']['reconsumeCount'];
|
||||
$return['updateType'][] = 'anilist';
|
||||
}
|
||||
else if ($diff['reconsumeCount'] === -1)
|
||||
{
|
||||
$update['data']['reconsumeCount'] = $anilistItem['data']['reconsumeCount'];
|
||||
$return['updateType'][] = 'kitsu';
|
||||
}
|
||||
}
|
||||
|
||||
// If status is different, use the status of the more recently updated item
|
||||
if ( ! $sameStatus)
|
||||
/* if ( ! $sameStatus)
|
||||
{
|
||||
if ($dateDiff === 1)
|
||||
{
|
||||
$update['data']['status'] = $kitsuItem['data']['status'];
|
||||
$return['updateType'][] = 'mal';
|
||||
$return['updateType'][] = 'anilist';
|
||||
}
|
||||
else if ($dateDiff === -1)
|
||||
{
|
||||
$update['data']['status'] = $malItem['data']['status'];
|
||||
$update['data']['status'] = $anilistItem['data']['status'];
|
||||
$return['updateType'][] = 'kitsu';
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
$return['meta'] = [
|
||||
'kitsu' => $kitsuItem['data'],
|
||||
'mal' => $malItem['data'],
|
||||
'dateDiff' => $dateDiff,
|
||||
'anilist' => $anilistItem['data'],
|
||||
// 'dateDiff' => $dateDiff,
|
||||
'diff' => $diff,
|
||||
];
|
||||
$return['data'] = $update;
|
||||
$return['updateType'] = array_unique($return['updateType']);
|
||||
|
||||
// Fill in missing data values for update on Anlist
|
||||
// so I don't have to create a really complex graphql query
|
||||
// to handle each combination of fields
|
||||
if ($return['updateType'][0] === 'anilist')
|
||||
{
|
||||
$prevData = [
|
||||
'notes' => $kitsuItem['data']['notes'],
|
||||
'private' => $kitsuItem['data']['private'],
|
||||
'progress' => $kitsuItem['data']['progress'],
|
||||
'rating' => $kitsuItem['data']['rating'],
|
||||
'reconsumeCount' => $kitsuItem['data']['reconsumeCount'],
|
||||
'reconsuming' => $kitsuItem['data']['reconsuming'],
|
||||
'status' => $kitsuItem['data']['status'],
|
||||
];
|
||||
|
||||
$return['data']['data'] = array_merge($prevData, $return['data']['data']);
|
||||
}
|
||||
|
||||
dump($return);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
@ -505,9 +585,13 @@ final class SyncLists extends BaseCommand {
|
||||
$requester = new ParallelAPIRequest();
|
||||
foreach($itemsToUpdate as $item)
|
||||
{
|
||||
$typeClass = '\\Aviat\\AnimeClient\\Types\\' . ucFirst($type) . 'FormItem';
|
||||
|
||||
if ($action === 'update')
|
||||
{
|
||||
$requester->addRequest($this->kitsuModel->updateListItem($item));
|
||||
$requester->addRequest(
|
||||
$this->kitsuModel->updateListItem(new $typeClass($item))
|
||||
);
|
||||
}
|
||||
else if ($action === 'create')
|
||||
{
|
||||
@ -537,27 +621,29 @@ final class SyncLists extends BaseCommand {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create/Update list items on MAL
|
||||
* Create/Update list items on Anilist
|
||||
*
|
||||
* @param array $itemsToUpdate
|
||||
* @param string $action
|
||||
* @param string $type
|
||||
*/
|
||||
/* protected function updateMALListItems(array$itemsToUpdate, string $action = 'update', string $type = 'anime'): void
|
||||
protected function updateAnilistListItems(array$itemsToUpdate, string $action = 'update', string $type = 'anime'): void
|
||||
{
|
||||
$transformer = new ALT();
|
||||
$requester = new ParallelAPIRequest();
|
||||
|
||||
$typeClass = '\\Aviat\\AnimeClient\\Types\\' . ucFirst($type) . 'FormItem';
|
||||
|
||||
foreach($itemsToUpdate as $item)
|
||||
{
|
||||
if ($action === 'update')
|
||||
{
|
||||
$requester->addRequest($this->malModel->updateListItem($item, $type));
|
||||
$requester->addRequest(
|
||||
$this->anilistModel->updateListItem(new $typeClass($item), $type)
|
||||
);
|
||||
}
|
||||
else if ($action === 'create')
|
||||
{
|
||||
$data = $transformer->untransform($item);
|
||||
$requester->addRequest($this->malModel->createFullListItem($data, $type));
|
||||
$requester->addRequest($this->anilistModel->createFullListItem($item, $type));
|
||||
}
|
||||
}
|
||||
|
||||
@ -566,20 +652,21 @@ final class SyncLists extends BaseCommand {
|
||||
foreach($responses as $key => $response)
|
||||
{
|
||||
$id = $itemsToUpdate[$key]['mal_id'];
|
||||
$goodResponse = (
|
||||
($action === 'update' && $response === 'Updated') ||
|
||||
($action === 'create' && $response === 'Created')
|
||||
);
|
||||
if ($goodResponse)
|
||||
|
||||
$responseData = Json::decode($response);
|
||||
|
||||
// $id = $itemsToUpdate[$key]['id'];
|
||||
if ( ! array_key_exists('errors', $responseData))
|
||||
{
|
||||
$verb = ($action === 'update') ? 'updated' : 'created';
|
||||
$this->echoBox("Successfully {$verb} MAL {$type} list item with id: {$id}");
|
||||
$this->echoBox("Successfully {$verb} Anilist {$type} list item with id: {$id}");
|
||||
}
|
||||
else
|
||||
{
|
||||
dump($responseData);
|
||||
$verb = ($action === 'update') ? 'update' : 'create';
|
||||
$this->echoBox("Failed to {$verb} MAL {$type} list item with id: {$id}");
|
||||
$this->echoBox("Failed to {$verb} Anilist {$type} list item with id: {$id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
@ -130,6 +130,11 @@ final class Manga extends Controller {
|
||||
$this->redirect('manga/add', 303);
|
||||
}
|
||||
|
||||
if (empty($data['mal_id']))
|
||||
{
|
||||
unset($data['mal_id']);
|
||||
}
|
||||
|
||||
$result = $this->model->createLibraryItem($data);
|
||||
|
||||
if ($result)
|
||||
@ -182,8 +187,9 @@ final class Manga extends Controller {
|
||||
*/
|
||||
public function search(): void
|
||||
{
|
||||
$query_data = $this->request->getQueryParams();
|
||||
$this->outputJSON($this->model->search($query_data['query']));
|
||||
$queryParams = $this->request->getQueryParams();
|
||||
$query = $queryParams['query'];
|
||||
$this->outputJSON($this->model->search($query));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -218,13 +224,9 @@ final class Manga extends Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a manga item
|
||||
*
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
* @return void
|
||||
* Increment the progress of a manga item
|
||||
*/
|
||||
public function update(): void
|
||||
public function increment(): void
|
||||
{
|
||||
if (stripos($this->request->getHeader('content-type')[0], 'application/json') !== FALSE)
|
||||
{
|
||||
@ -235,7 +237,7 @@ final class Manga extends Controller {
|
||||
$data = $this->request->getParsedBody();
|
||||
}
|
||||
|
||||
$response = $this->model->updateLibraryItem(new MangaFormItem($data));
|
||||
$response = $this->model->incrementLibraryItem(new MangaFormItem($data));
|
||||
|
||||
$this->cache->clear();
|
||||
$this->outputJSON($response['body'], $response['statusCode']);
|
||||
@ -251,13 +253,11 @@ final class Manga extends Controller {
|
||||
public function delete(): void
|
||||
{
|
||||
$body = $this->request->getParsedBody();
|
||||
$id = $body['id'];
|
||||
$malId = $body['mal_id'];
|
||||
$response = $this->model->deleteLibraryItem($id, $malId);
|
||||
$response = $this->model->deleteLibraryItem($body['id'], $body['mal_id']);
|
||||
|
||||
if ($response)
|
||||
{
|
||||
$this->setFlashMessage("Successfully deleted manga.", 'success');
|
||||
$this->setFlashMessage('Successfully deleted manga.', 'success');
|
||||
$this->cache->clear();
|
||||
}
|
||||
else
|
||||
|
@ -31,6 +31,13 @@ use Aviat\Ion\Json;
|
||||
*/
|
||||
class Anime extends API {
|
||||
|
||||
/**
|
||||
* Is the Anilist API enabled?
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $anilistEnabled;
|
||||
|
||||
/**
|
||||
* Model for making requests to Anilist API
|
||||
*
|
||||
@ -54,6 +61,9 @@ class Anime extends API {
|
||||
{
|
||||
$this->anilistModel = $container->get('anilist-model');
|
||||
$this->kitsuModel = $container->get('kitsu-model');
|
||||
|
||||
$config = $container->get('config');
|
||||
$this->anilistEnabled = (bool) $config->get(['anilist', 'enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,18 +147,6 @@ class Anime extends API {
|
||||
$item = $this->kitsuModel->getListItem($itemId);
|
||||
$array = $item->toArray();
|
||||
|
||||
if ( ! empty($item->mal_id))
|
||||
{
|
||||
$anilistInfo = $this->anilistModel->getListItem($item['mal_id']);
|
||||
|
||||
if (empty($anilistInfo))
|
||||
{
|
||||
return $item;
|
||||
}
|
||||
|
||||
$array['anilist_item_id'] = $anilistInfo['id'];
|
||||
}
|
||||
|
||||
if (is_array($array['notes']))
|
||||
{
|
||||
$array['notes'] = '';
|
||||
@ -168,9 +166,9 @@ class Anime extends API {
|
||||
$requester = new ParallelAPIRequest();
|
||||
$requester->addRequest($this->kitsuModel->createListItem($data), 'kitsu');
|
||||
|
||||
// @TODO Make sure Anilist integration is optional
|
||||
if (array_key_exists('mal_id', $data)) {
|
||||
$requester->addRequest($this->anilistModel->createListItem($data), 'anilist');
|
||||
if (array_key_exists('mal_id', $data) && $this->anilistEnabled)
|
||||
{
|
||||
$requester->addRequest($this->anilistModel->createListItem($data, 'ANIME'), 'anilist');
|
||||
}
|
||||
|
||||
$results = $requester->makeRequests();
|
||||
@ -199,9 +197,9 @@ class Anime extends API {
|
||||
|
||||
$array = $data->toArray();
|
||||
|
||||
// @TODO Make sure Anilist integration is optional
|
||||
if (array_key_exists('mal_id', $array)) {
|
||||
$requester->addRequest($this->anilistModel->incrementListItem($data), 'anilist');
|
||||
if (array_key_exists('mal_id', $array) && $this->anilistEnabled)
|
||||
{
|
||||
$requester->addRequest($this->anilistModel->incrementListItem($data, 'ANIME'), 'anilist');
|
||||
}
|
||||
|
||||
$results = $requester->makeRequests();
|
||||
@ -228,10 +226,9 @@ class Anime extends API {
|
||||
|
||||
$array = $data->toArray();
|
||||
|
||||
// @TODO Make sure Anilist integration is optional
|
||||
if (array_key_exists('mal_id', $array))
|
||||
if (array_key_exists('mal_id', $array) && $this->anilistEnabled)
|
||||
{
|
||||
$requester->addRequest($this->anilistModel->updateListItem($data), 'anilist');
|
||||
$requester->addRequest($this->anilistModel->updateListItem($data, 'ANIME'), 'anilist');
|
||||
}
|
||||
|
||||
$results = $requester->makeRequests();
|
||||
@ -257,9 +254,9 @@ class Anime extends API {
|
||||
$requester = new ParallelAPIRequest();
|
||||
$requester->addRequest($this->kitsuModel->deleteListItem($id), 'kitsu');
|
||||
|
||||
// @TODO Make sure Anilist integration is optional
|
||||
if ($malId !== null) {
|
||||
$requester->addRequest($this->anilistModel->deleteListItem($malId), 'anilist');
|
||||
if ($malId !== null && $this->anilistEnabled)
|
||||
{
|
||||
$requester->addRequest($this->anilistModel->deleteListItem($malId, 'ANIME'), 'anilist');
|
||||
}
|
||||
|
||||
$results = $requester->makeRequests();
|
||||
|
@ -33,6 +33,19 @@ use Aviat\Ion\Json;
|
||||
* Model for handling requests dealing with the manga list
|
||||
*/
|
||||
class Manga extends API {
|
||||
/**
|
||||
* Is the Anilist API enabled?
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $anilistEnabled;
|
||||
|
||||
/**
|
||||
* Model for making requests to the Anilist API
|
||||
* @var \Aviat\AnimeClient\API\Anilist\Model
|
||||
*/
|
||||
protected $anilistModel;
|
||||
|
||||
/**
|
||||
* Model for making requests to Kitsu API
|
||||
* @var \Aviat\AnimeClient\API\Kitsu\Model
|
||||
@ -43,12 +56,14 @@ class Manga extends API {
|
||||
* Constructor
|
||||
*
|
||||
* @param ContainerInterface $container
|
||||
* @throws \Aviat\Ion\Di\ContainerException
|
||||
* @throws \Aviat\Ion\Di\NotFoundException
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->anilistModel = $container->get('anilist-model');
|
||||
$this->kitsuModel = $container->get('kitsu-model');
|
||||
|
||||
$config = $container->get('config');
|
||||
$this->anilistEnabled = (bool)$config->get(['anilist', 'enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -121,6 +136,11 @@ class Manga extends API {
|
||||
$requester = new ParallelAPIRequest();
|
||||
$requester->addRequest($this->kitsuModel->createListItem($data), 'kitsu');
|
||||
|
||||
if (array_key_exists('mal_id', $data) && $this->anilistEnabled)
|
||||
{
|
||||
$requester->addRequest($this->anilistModel->createListItem($data, 'MANGA'), 'anilist');
|
||||
}
|
||||
|
||||
$results = $requester->makeRequests();
|
||||
|
||||
return count($results) > 0;
|
||||
@ -137,6 +157,41 @@ class Manga extends API {
|
||||
$requester = new ParallelAPIRequest();
|
||||
$requester->addRequest($this->kitsuModel->updateListItem($data), 'kitsu');
|
||||
|
||||
$array = $data->toArray();
|
||||
|
||||
if (array_key_exists('mal_id', $array) && $this->anilistEnabled)
|
||||
{
|
||||
$requester->addRequest($this->anilistModel->updateListItem($data, 'MANGA'), 'anilist');
|
||||
}
|
||||
|
||||
$results = $requester->makeRequests();
|
||||
$body = Json::decode($results['kitsu']);
|
||||
$statusCode = array_key_exists('error', $body) ? 400: 200;
|
||||
|
||||
return [
|
||||
'body' => Json::decode($results['kitsu']),
|
||||
'statusCode' => $statusCode
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the progress of a list entry
|
||||
*
|
||||
* @param MangaFormItem $data
|
||||
* @return array
|
||||
*/
|
||||
public function incrementLibraryItem(MangaFormItem $data): array
|
||||
{
|
||||
$requester = new ParallelAPIRequest();
|
||||
$requester->addRequest($this->kitsuModel->incrementListItem($data), 'kitsu');
|
||||
|
||||
$array = $data->toArray();
|
||||
|
||||
if (array_key_exists('mal_id', $array) && $this->anilistEnabled)
|
||||
{
|
||||
$requester->addRequest($this->anilistModel->incrementListItem($data, 'MANGA'), 'anilist');
|
||||
}
|
||||
|
||||
$results = $requester->makeRequests();
|
||||
$body = Json::decode($results['kitsu']);
|
||||
$statusCode = array_key_exists('error', $body) ? 400 : 200;
|
||||
@ -159,6 +214,11 @@ class Manga extends API {
|
||||
$requester = new ParallelAPIRequest();
|
||||
$requester->addRequest($this->kitsuModel->deleteListItem($id), 'kitsu');
|
||||
|
||||
if ($malId !== null && $this->anilistEnabled)
|
||||
{
|
||||
$requester->addRequest($this->anilistModel->deleteListItem($malId, 'MANGA'), 'anilist');
|
||||
}
|
||||
|
||||
$results = $requester->makeRequests();
|
||||
|
||||
return count($results) > 0;
|
||||
|
Loading…
Reference in New Issue
Block a user