Refactor list sync to be easier to follow
All checks were successful
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good
All checks were successful
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good
This commit is contained in:
parent
fa89df567d
commit
77ee6ae50e
@ -79,6 +79,8 @@ abstract class APIRequestBuilder {
|
|||||||
{
|
{
|
||||||
$request = (new Request($uri));
|
$request = (new Request($uri));
|
||||||
$request->setHeader('User-Agent', USER_AGENT);
|
$request->setHeader('User-Agent', USER_AGENT);
|
||||||
|
$request->setTcpConnectTimeout(300000);
|
||||||
|
$request->setTransferTimeout(300000);
|
||||||
|
|
||||||
return $request;
|
return $request;
|
||||||
}
|
}
|
||||||
@ -269,7 +271,7 @@ abstract class APIRequestBuilder {
|
|||||||
*/
|
*/
|
||||||
public function newRequest(string $type, string $uri): self
|
public function newRequest(string $type, string $uri): self
|
||||||
{
|
{
|
||||||
if ( ! \in_array($type, $this->validMethods, TRUE))
|
if ( ! in_array($type, $this->validMethods, TRUE))
|
||||||
{
|
{
|
||||||
throw new InvalidArgumentException('Invalid HTTP method');
|
throw new InvalidArgumentException('Invalid HTTP method');
|
||||||
}
|
}
|
||||||
@ -327,6 +329,8 @@ abstract class APIRequestBuilder {
|
|||||||
$this->path = '';
|
$this->path = '';
|
||||||
$this->query = '';
|
$this->query = '';
|
||||||
$this->request = new Request($requestUrl, $type);
|
$this->request = new Request($requestUrl, $type);
|
||||||
|
$this->request->setInactivityTimeout(300000);
|
||||||
|
$this->request->setTlsHandshakeTimeout(300000);
|
||||||
$this->request->setTcpConnectTimeout(300000);
|
$this->request->setTcpConnectTimeout(300000);
|
||||||
$this->request->setTransferTimeout(300000);
|
$this->request->setTransferTimeout(300000);
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ use Aviat\AnimeClient\API\Kitsu\Transformer\{
|
|||||||
MangaTransformer,
|
MangaTransformer,
|
||||||
MangaListTransformer
|
MangaListTransformer
|
||||||
};
|
};
|
||||||
|
use Aviat\AnimeClient\Enum\ListType;
|
||||||
use Aviat\AnimeClient\Types\{
|
use Aviat\AnimeClient\Types\{
|
||||||
Anime,
|
Anime,
|
||||||
FormItem,
|
FormItem,
|
||||||
@ -175,38 +176,6 @@ final class Model {
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the data for the anime watch history page
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @throws Throwable
|
|
||||||
*/
|
|
||||||
public function getAnimeHistory(): array
|
|
||||||
{
|
|
||||||
$raw = $this->getRawHistoryList('anime');
|
|
||||||
$organized = JsonAPI::organizeData($raw);
|
|
||||||
$organized = array_filter($organized, fn ($item) => array_key_exists('relationships', $item));
|
|
||||||
|
|
||||||
return (new AnimeHistoryTransformer())->transform($organized);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the data for the manga read history page
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @throws Throwable
|
|
||||||
*/
|
|
||||||
public function getMangaHistory(): array
|
|
||||||
{
|
|
||||||
$raw = $this->getRawHistoryList('manga');
|
|
||||||
$organized = JsonAPI::organizeData($raw);
|
|
||||||
$organized = array_filter($organized, fn ($item) => array_key_exists('relationships', $item));
|
|
||||||
|
|
||||||
return (new MangaHistoryTransformer())->transform($organized);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the userid for a username from Kitsu
|
* Get the userid for a username from Kitsu
|
||||||
*
|
*
|
||||||
@ -420,6 +389,22 @@ final class Model {
|
|||||||
return $this->animeTransformer->transform($baseData);
|
return $this->animeTransformer->transform($baseData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the data for the anime watch history page
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function getAnimeHistory(): array
|
||||||
|
{
|
||||||
|
$raw = $this->getRawHistoryList('anime');
|
||||||
|
$organized = JsonAPI::organizeData($raw);
|
||||||
|
$organized = array_filter($organized, fn ($item) => array_key_exists('relationships', $item));
|
||||||
|
|
||||||
|
return (new AnimeHistoryTransformer())->transform($organized);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about a particular anime
|
* Get information about a particular anime
|
||||||
*
|
*
|
||||||
@ -485,27 +470,7 @@ final class Model {
|
|||||||
*/
|
*/
|
||||||
public function getAnimeListCount(string $status = '') : int
|
public function getAnimeListCount(string $status = '') : int
|
||||||
{
|
{
|
||||||
$options = [
|
return $this->getListCount(ListType::ANIME, $status);
|
||||||
'query' => [
|
|
||||||
'filter' => [
|
|
||||||
'user_id' => $this->getUserIdByUsername(),
|
|
||||||
'kind' => 'anime'
|
|
||||||
],
|
|
||||||
'page' => [
|
|
||||||
'limit' => 1
|
|
||||||
],
|
|
||||||
'sort' => '-updated_at'
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
if ( ! empty($status))
|
|
||||||
{
|
|
||||||
$options['query']['filter']['status'] = $status;
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = $this->getRequest('library-entries', $options);
|
|
||||||
|
|
||||||
return $response['meta']['count'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -676,6 +641,22 @@ final class Model {
|
|||||||
return $this->mangaTransformer->transform($baseData);
|
return $this->mangaTransformer->transform($baseData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the data for the manga read history page
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function getMangaHistory(): array
|
||||||
|
{
|
||||||
|
$raw = $this->getRawHistoryList('manga');
|
||||||
|
$organized = JsonAPI::organizeData($raw);
|
||||||
|
$organized = array_filter($organized, fn ($item) => array_key_exists('relationships', $item));
|
||||||
|
|
||||||
|
return (new MangaHistoryTransformer())->transform($organized);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about a particular manga
|
* Get information about a particular manga
|
||||||
*
|
*
|
||||||
@ -754,27 +735,7 @@ final class Model {
|
|||||||
*/
|
*/
|
||||||
public function getMangaListCount(string $status = '') : int
|
public function getMangaListCount(string $status = '') : int
|
||||||
{
|
{
|
||||||
$options = [
|
return $this->getListCount(ListType::MANGA, $status);
|
||||||
'query' => [
|
|
||||||
'filter' => [
|
|
||||||
'user_id' => $this->getUserIdByUsername(),
|
|
||||||
'kind' => 'manga'
|
|
||||||
],
|
|
||||||
'page' => [
|
|
||||||
'limit' => 1
|
|
||||||
],
|
|
||||||
'sort' => '-updated_at'
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
if ( ! empty($status))
|
|
||||||
{
|
|
||||||
$options['query']['filter']['status'] = $status;
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = $this->getRequest('library-entries', $options);
|
|
||||||
|
|
||||||
return $response['meta']['count'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -976,6 +937,20 @@ final class Model {
|
|||||||
return $this->listItem->delete($id);
|
return $this->listItem->delete($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSyncList(string $type): array
|
||||||
|
{
|
||||||
|
$options = [
|
||||||
|
'filter' => [
|
||||||
|
'user_id' => $this->getUserIdByUsername($this->getUsername()),
|
||||||
|
'kind' => $type,
|
||||||
|
],
|
||||||
|
'include' => "{$type},{$type}.mappings",
|
||||||
|
'sort' => '-updated_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->getRawSyncList($type, $options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the aggregated pages of anime or manga history
|
* Get the aggregated pages of anime or manga history
|
||||||
*
|
*
|
||||||
@ -1124,4 +1099,93 @@ final class Model {
|
|||||||
$baseData['included'] = $data['included'];
|
$baseData['included'] = $data['included'];
|
||||||
return $baseData;
|
return $baseData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getListCount(string $type, string $status = ''): int
|
||||||
|
{
|
||||||
|
$options = [
|
||||||
|
'query' => [
|
||||||
|
'filter' => [
|
||||||
|
'user_id' => $this->getUserIdByUsername(),
|
||||||
|
'kind' => $type,
|
||||||
|
],
|
||||||
|
'page' => [
|
||||||
|
'limit' => 1
|
||||||
|
],
|
||||||
|
'sort' => '-updated_at'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
if ( ! empty($status))
|
||||||
|
{
|
||||||
|
$options['query']['filter']['status'] = $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->getRequest('library-entries', $options);
|
||||||
|
|
||||||
|
return $response['meta']['count'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the full anime list
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @param array $options
|
||||||
|
* @return array
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
private function getRawSyncList(string $type, array $options): array
|
||||||
|
{
|
||||||
|
$count = $this->getListCount($type);
|
||||||
|
$size = static::LIST_PAGE_SIZE;
|
||||||
|
$pages = ceil($count / $size);
|
||||||
|
|
||||||
|
$requester = new ParallelAPIRequest();
|
||||||
|
|
||||||
|
// Set up requests
|
||||||
|
for ($i = 0; $i < $pages; $i++)
|
||||||
|
{
|
||||||
|
$offset = $i * $size;
|
||||||
|
$requester->addRequest($this->getRawSyncListPage($type, $size, $offset, $options));
|
||||||
|
}
|
||||||
|
|
||||||
|
$responses = $requester->makeRequests();
|
||||||
|
$output = [];
|
||||||
|
|
||||||
|
foreach($responses as $response)
|
||||||
|
{
|
||||||
|
$data = Json::decode($response);
|
||||||
|
$output[] = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge_recursive(...$output);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the full anime list in paginated form
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @param int $limit
|
||||||
|
* @param int $offset
|
||||||
|
* @param array $options
|
||||||
|
* @return Request
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
private function getRawSyncListPage(string $type, int $limit, int $offset = 0, array $options = []): Request
|
||||||
|
{
|
||||||
|
$defaultOptions = [
|
||||||
|
'filter' => [
|
||||||
|
'user_id' => $this->getUserIdByUsername($this->getUsername()),
|
||||||
|
'kind' => $type,
|
||||||
|
],
|
||||||
|
'page' => [
|
||||||
|
'offset' => $offset,
|
||||||
|
'limit' => $limit
|
||||||
|
],
|
||||||
|
'sort' => '-updated_at'
|
||||||
|
];
|
||||||
|
$options = array_merge($defaultOptions, $options);
|
||||||
|
|
||||||
|
return $this->setUpRequest('GET', 'library-entries', ['query' => $options]);
|
||||||
|
}
|
||||||
}
|
}
|
@ -43,29 +43,26 @@ abstract class BaseCommand extends Command {
|
|||||||
/**
|
/**
|
||||||
* Echo text in a box
|
* Echo text in a box
|
||||||
*
|
*
|
||||||
* @param string $message
|
* @param string|array $message
|
||||||
* @param string|int|null $fgColor
|
* @param string|int|null $fgColor
|
||||||
* @param string|int|null $bgColor
|
* @param string|int|null $bgColor
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function echoBox(string $message, $fgColor = NULL, $bgColor = NULL): void
|
public function echoBox($message, $fgColor = NULL, $bgColor = NULL): void
|
||||||
{
|
{
|
||||||
|
if (is_array($message))
|
||||||
|
{
|
||||||
|
$message = implode("\n", $message);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$len = strlen($message);
|
|
||||||
|
|
||||||
// color message
|
// color message
|
||||||
$message = Colors::colorize($message, $fgColor, $bgColor);
|
$message = Colors::colorize($message, $fgColor, $bgColor);
|
||||||
$colorLen = strlen($message);
|
|
||||||
|
|
||||||
// create the box
|
// create the box
|
||||||
$box = new Box($this->getConsole(), $message);
|
$box = new Box($this->getConsole(), $message);
|
||||||
|
|
||||||
if ($len !== $colorLen)
|
|
||||||
{
|
|
||||||
$box->setPadding((($colorLen - $len) / 2) + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
$box->write();
|
$box->write();
|
||||||
|
|
||||||
echo "\n";
|
echo "\n";
|
||||||
@ -106,6 +103,11 @@ abstract class BaseCommand extends Command {
|
|||||||
$this->echoBox($message, Colors::RED | Colors::BOLD, Colors::BLACK);
|
$this->echoBox($message, Colors::RED | Colors::BOLD, Colors::BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function clearLine(): void
|
||||||
|
{
|
||||||
|
$this->getConsole()->write("\r\e[2K");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup the Di container
|
* Setup the Di container
|
||||||
*
|
*
|
||||||
|
@ -16,19 +16,18 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\Command;
|
namespace Aviat\AnimeClient\Command;
|
||||||
|
|
||||||
|
use ConsoleKit\Widgets;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\{
|
use Aviat\AnimeClient\API\{
|
||||||
Anilist\MissingIdException,
|
Anilist\MissingIdException,
|
||||||
FailedResponseException,
|
FailedResponseException,
|
||||||
JsonAPI,
|
JsonAPI,
|
||||||
ParallelAPIRequest
|
ParallelAPIRequest
|
||||||
};
|
};
|
||||||
use Aviat\AnimeClient\API\Anilist\Transformer\{
|
use Aviat\AnimeClient\API\Anilist;
|
||||||
AnimeListTransformer as AALT,
|
use Aviat\AnimeClient\API\Kitsu;
|
||||||
MangaListTransformer as AMLT
|
|
||||||
};
|
|
||||||
use Aviat\AnimeClient\API\Anilist\Model as AnilistModel;
|
|
||||||
use Aviat\AnimeClient\API\Kitsu\Model as KitsuModel;
|
|
||||||
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
|
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
|
||||||
|
use Aviat\AnimeClient\Enum\{APISource, ListType, SyncAction};
|
||||||
use Aviat\AnimeClient\Types\FormItem;
|
use Aviat\AnimeClient\Types\FormItem;
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use Aviat\Ion\Di\Exception\ContainerException;
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
use Aviat\Ion\Di\Exception\NotFoundException;
|
||||||
@ -44,18 +43,24 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for making requests to Anilist API
|
* Model for making requests to Anilist API
|
||||||
* @var AnilistModel
|
* @var Anilist\Model
|
||||||
*/
|
*/
|
||||||
protected AnilistModel $anilistModel;
|
private Anilist\Model $anilistModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for making requests to Kitsu API
|
* Model for making requests to Kitsu API
|
||||||
* @var KitsuModel
|
* @var Kitsu\Model
|
||||||
*/
|
*/
|
||||||
protected KitsuModel $kitsuModel;
|
private Kitsu\Model $kitsuModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the Kitsu <=> Anilist sync script
|
* Does the Kitsu API have valid authentication?
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private bool $isKitsuAuthenticated = FALSE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync Kitsu <=> Anilist
|
||||||
*
|
*
|
||||||
* @param array $args
|
* @param array $args
|
||||||
* @param array $options
|
* @param array $options
|
||||||
@ -64,6 +69,45 @@ final class SyncLists extends BaseCommand {
|
|||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function execute(array $args, array $options = []): void
|
public function execute(array $args, array $options = []): void
|
||||||
|
{
|
||||||
|
$this->init();
|
||||||
|
|
||||||
|
foreach ([ListType::ANIME, ListType::MANGA] as $type)
|
||||||
|
{
|
||||||
|
$this->fetchCount($type);
|
||||||
|
$rawData = $this->fetch($type);
|
||||||
|
$normalized = $this->transform($type, $rawData);
|
||||||
|
$compared = $this->compare($type, $normalized);
|
||||||
|
|
||||||
|
/* $toUpdateCounts = [
|
||||||
|
'addToAnilist' => count($compared['addToAnilist']),
|
||||||
|
'updateAnilist' => count($compared['updateAnilist']),
|
||||||
|
'addToKitsu' => count($compared['addToKitsu']),
|
||||||
|
'updateKitsu' => count($compared['updateKitsu']),
|
||||||
|
];
|
||||||
|
|
||||||
|
dump($toUpdateCounts); */
|
||||||
|
|
||||||
|
$this->update($type, $compared);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* $this->sync(ListType::ANIME);
|
||||||
|
$this->sync(ListType::MANGA);
|
||||||
|
|
||||||
|
$this->echoBox('Finished syncing lists'); */
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Main sync flow methods
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up dependencies
|
||||||
|
*
|
||||||
|
* @throws ContainerException
|
||||||
|
* @throws NotFoundException
|
||||||
|
*/
|
||||||
|
protected function init(): void
|
||||||
{
|
{
|
||||||
$this->setContainer($this->setupContainer());
|
$this->setContainer($this->setupContainer());
|
||||||
$this->setCache($this->container->get('cache'));
|
$this->setCache($this->container->get('cache'));
|
||||||
@ -71,28 +115,171 @@ final class SyncLists extends BaseCommand {
|
|||||||
$config = $this->container->get('config');
|
$config = $this->container->get('config');
|
||||||
$anilistEnabled = $config->get(['anilist', 'enabled']);
|
$anilistEnabled = $config->get(['anilist', 'enabled']);
|
||||||
|
|
||||||
|
// We can't sync kitsu against itself!
|
||||||
if ( ! $anilistEnabled)
|
if ( ! $anilistEnabled)
|
||||||
{
|
{
|
||||||
$this->echoBox('Anlist API is not enabled. Can not sync.');
|
$this->echoErrorBox('Anlist API is not enabled. Can not sync.');
|
||||||
return;
|
die();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authentication is required to update Kitsu
|
||||||
|
$this->isKitsuAuthenticated = $this->container->get('auth')->isAuthenticated();
|
||||||
|
if ( ! $this->isKitsuAuthenticated)
|
||||||
|
{
|
||||||
|
$this->echoWarningBox('Kitsu is not authenticated. Kitsu list can not be updated.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->anilistModel = $this->container->get('anilist-model');
|
$this->anilistModel = $this->container->get('anilist-model');
|
||||||
$this->kitsuModel = $this->container->get('kitsu-model');
|
$this->kitsuModel = $this->container->get('kitsu-model');
|
||||||
|
|
||||||
$this->sync('anime');
|
|
||||||
$this->sync('manga');
|
|
||||||
|
|
||||||
$this->echoBox('Finished syncing lists');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to synchronize external APIs
|
* Get and display the count of items for each API
|
||||||
*
|
*
|
||||||
* @param string $type
|
* @param string $type
|
||||||
* @throws Throwable
|
|
||||||
*/
|
*/
|
||||||
protected function sync(string $type): void
|
protected function fetchCount(string $type): void
|
||||||
|
{
|
||||||
|
$this->echo('Fetching List Counts');
|
||||||
|
$progress = new Widgets\ProgressBar($this->getConsole(), 2, 50, FALSE);
|
||||||
|
|
||||||
|
$displayLines = [];
|
||||||
|
|
||||||
|
$kitsuCount = $this->fetchKitsuCount($type);
|
||||||
|
$displayLines[] = "Number of Kitsu {$type} list items: {$kitsuCount}";
|
||||||
|
$progress->incr();
|
||||||
|
|
||||||
|
$anilistCount = $this->fetchAnilistCount($type);
|
||||||
|
$displayLines[] = "Number of Anilist {$type} list items: {$anilistCount}";
|
||||||
|
$progress->incr();
|
||||||
|
|
||||||
|
$this->clearLine();
|
||||||
|
|
||||||
|
$this->echoBox($displayLines);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function fetch(string $type): array
|
||||||
|
{
|
||||||
|
$this->echo('Fetching List Data');
|
||||||
|
$progress = new Widgets\ProgressBar($this->getConsole(), 2, 50, FALSE);
|
||||||
|
|
||||||
|
$anilist = $this->fetchAnilist($type);
|
||||||
|
$progress->incr();
|
||||||
|
|
||||||
|
$kitsu = $this->fetchKitsu($type);
|
||||||
|
$progress->incr();
|
||||||
|
|
||||||
|
$this->clearLine();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'anilist' => $anilist,
|
||||||
|
'kitsu' => $kitsu,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function transform(string $type, array $data): array
|
||||||
|
{
|
||||||
|
$this->echo('Normalizing List Data');
|
||||||
|
$progress = new Widgets\ProgressBar($this->getConsole(), 2, 50, FALSE);
|
||||||
|
|
||||||
|
$kitsu = $this->transformKitsu($type, $data['kitsu']);
|
||||||
|
$progress->incr();
|
||||||
|
|
||||||
|
$anilist = $this->transformAnilist($type, $data['anilist']);
|
||||||
|
$progress->incr();
|
||||||
|
|
||||||
|
$this->clearLine();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'anilist' => $anilist,
|
||||||
|
'kitsu' => $kitsu,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function compare(string $type, array $data): array
|
||||||
|
{
|
||||||
|
$this->echo('Comparing List Items');
|
||||||
|
|
||||||
|
return $this->compareLists($type, $data['anilist'], $data['kitsu']);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function update(string $type, array $data)
|
||||||
|
{
|
||||||
|
if ( ! empty($data['addToAnilist']))
|
||||||
|
{
|
||||||
|
$count = count($data['addToAnilist']);
|
||||||
|
$this->echoBox("Adding {$count} missing {$type} list items to Anilist");
|
||||||
|
$this->updateAnilistListItems($data['addToAnilist'], SyncAction::CREATE, $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty($data['updateAnilist']))
|
||||||
|
{
|
||||||
|
$count = count($data['updateAnilist']);
|
||||||
|
$this->echoBox("Updating {$count} outdated Anilist {$type} list items");
|
||||||
|
$this->updateAnilistListItems($data['updateAnilist'], SyncAction::UPDATE, $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isKitsuAuthenticated)
|
||||||
|
{
|
||||||
|
if ( ! empty($data['addToKitsu']))
|
||||||
|
{
|
||||||
|
$count = count($data['addToKitsu']);
|
||||||
|
$this->echoBox("Adding {$count} missing {$type} list items to Kitsu");
|
||||||
|
$this->updateKitsuListItems($data['addToKitsu'], SyncAction::CREATE, $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty($data['updateKitsu']))
|
||||||
|
{
|
||||||
|
$count = count($data['updateKitsu']);
|
||||||
|
$this->echoBox("Updating {$count} outdated Kitsu {$type} list items");
|
||||||
|
$this->updateKitsuListItems($data['updateKitsu'], SyncAction::UPDATE, $type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->echoErrorBox('Kitsu is not authenticated, so lists can not be updated');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Fetch helpers
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
private function fetchAnilistCount(string $type)
|
||||||
|
{
|
||||||
|
$list = $this->fetchAnilist($type);
|
||||||
|
|
||||||
|
if ( ! isset($list['data']['MediaListCollection']['lists']))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = 0;
|
||||||
|
|
||||||
|
foreach ($list['data']['MediaListCollection']['lists'] as $subList)
|
||||||
|
{
|
||||||
|
$count += array_reduce($subList, fn ($carry, $item) => $carry + count(array_values($item)), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fetchAnilist(string $type): array
|
||||||
|
{
|
||||||
|
static $list = [
|
||||||
|
ListType::ANIME => NULL,
|
||||||
|
ListType::MANGA => NULL,
|
||||||
|
];
|
||||||
|
|
||||||
|
// This uses a static so I don't have to fetch this list twice for a count
|
||||||
|
if ($list[$type] === NULL)
|
||||||
|
{
|
||||||
|
$list[$type] = $this->anilistModel->getSyncList(strtoupper($type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list[$type];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fetchKitsuCount(string $type): int
|
||||||
{
|
{
|
||||||
$uType = ucfirst($type);
|
$uType = ucfirst($type);
|
||||||
|
|
||||||
@ -106,157 +293,31 @@ final class SyncLists extends BaseCommand {
|
|||||||
dump($e);
|
dump($e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $kitsuCount;
|
||||||
$this->echoBox("Number of Kitsu {$type} list items: {$kitsuCount}");
|
|
||||||
|
|
||||||
$data = $this->diffLists($type);
|
|
||||||
|
|
||||||
if ( ! empty($data['addToAnilist']))
|
|
||||||
{
|
|
||||||
$count = count($data['addToAnilist']);
|
|
||||||
$this->echoBox("Adding {$count} missing {$type} list items to Anilist");
|
|
||||||
$this->updateAnilistListItems($data['addToAnilist'], 'create', $type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! empty($data['updateAnilist']))
|
|
||||||
{
|
|
||||||
$count = count($data['updateAnilist']);
|
|
||||||
$this->echoBox("Updating {$count} outdated Anilist {$type} list items");
|
|
||||||
$this->updateAnilistListItems($data['updateAnilist'], 'update', $type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! empty($data['addToKitsu']))
|
|
||||||
{
|
|
||||||
$count = count($data['addToKitsu']);
|
|
||||||
$this->echoBox("Adding {$count} missing {$type} list items to Kitsu");
|
|
||||||
$this->updateKitsuListItems($data['addToKitsu'], 'create', $type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! empty($data['updateKitsu']))
|
|
||||||
{
|
|
||||||
$count = count($data['updateKitsu']);
|
|
||||||
$this->echoBox("Updating {$count} outdated Kitsu {$type} list items");
|
|
||||||
$this->updateKitsuListItems($data['updateKitsu'], 'update', $type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function fetchKitsu(string $type): array
|
||||||
* Filter Kitsu mappings for the specified type
|
|
||||||
*
|
|
||||||
* @param array $includes
|
|
||||||
* @param string $type
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function filterMappings(array $includes, string $type = 'anime'): array
|
|
||||||
{
|
{
|
||||||
$output = [];
|
return $this->kitsuModel->getSyncList($type);
|
||||||
|
|
||||||
foreach($includes as $id => $mapping)
|
|
||||||
{
|
|
||||||
if ($mapping['externalSite'] === "myanimelist/{$type}")
|
|
||||||
{
|
|
||||||
$output[$id] = $mapping;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// ------------------------------------------------------------------------
|
||||||
* Format an Anilist list for comparison
|
// Transform Helpers
|
||||||
*
|
// ------------------------------------------------------------------------
|
||||||
* @param string $type
|
|
||||||
* @return array
|
private function transformKitsu(string $type, array $data): array
|
||||||
*/
|
|
||||||
protected function formatAnilistList(string $type): array
|
|
||||||
{
|
{
|
||||||
$type = ucfirst($type);
|
|
||||||
$method = "formatAnilist{$type}List";
|
|
||||||
return $this->$method();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format an Anilist anime list for comparison
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* @throws ContainerException
|
|
||||||
* @throws NotFoundException
|
|
||||||
*/
|
|
||||||
protected function formatAnilistAnimeList(): array
|
|
||||||
{
|
|
||||||
$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 = [];
|
|
||||||
foreach ($transformedAnilist as $item)
|
|
||||||
{
|
|
||||||
$output[$item['mal_id']] = $item->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
$count = count($output);
|
|
||||||
$this->echoBox("Number of Anilist anime list items: {$count}");
|
|
||||||
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format an Anilist manga list for comparison
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* @throws ContainerException
|
|
||||||
* @throws NotFoundException
|
|
||||||
*/
|
|
||||||
protected function formatAnilistMangaList(): array
|
|
||||||
{
|
|
||||||
$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 = [];
|
|
||||||
foreach ($transformedAnilist as $item)
|
|
||||||
{
|
|
||||||
$output[$item['mal_id']] = $item->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
$count = count($output);
|
|
||||||
$this->echoBox("Number of Anilist manga list items: {$count}");
|
|
||||||
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a kitsu list for the sake of comparision
|
|
||||||
*
|
|
||||||
* @param string $type
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function formatKitsuList(string $type = 'anime'): array
|
|
||||||
{
|
|
||||||
$method = 'getFullRaw' . ucfirst($type) . 'List';
|
|
||||||
$data = $this->kitsuModel->$method();
|
|
||||||
|
|
||||||
if (empty($data))
|
if (empty($data))
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! array_key_exists('included', $data))
|
||||||
|
{
|
||||||
|
dump($data);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
$includes = JsonAPI::organizeIncludes($data['included']);
|
$includes = JsonAPI::organizeIncludes($data['included']);
|
||||||
$includes['mappings'] = $this->filterMappings($includes['mappings'], $type);
|
$includes['mappings'] = $this->filterMappings($includes['mappings'], $type);
|
||||||
|
|
||||||
@ -271,7 +332,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
foreach ($potentialMappings as $mappingId)
|
foreach ($potentialMappings as $mappingId)
|
||||||
{
|
{
|
||||||
if (\is_array($mappingId))
|
if (is_array($mappingId))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -298,21 +359,37 @@ final class SyncLists extends BaseCommand {
|
|||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function transformAnilist(string $type, array $data): array
|
||||||
* Go through lists of the specified type, and determine what kind of action each item needs
|
|
||||||
*
|
|
||||||
* @param string $type
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function diffLists(string $type = 'anime'): array
|
|
||||||
{
|
{
|
||||||
// Get libraryEntries with media.mappings from Kitsu
|
$uType = ucfirst($type);
|
||||||
// Organize mappings, and ignore entries without mappings
|
$className = "\\Aviat\\AnimeClient\\API\\Anilist\\Transformer\\{$uType}ListTransformer";
|
||||||
$kitsuList = $this->formatKitsuList($type);
|
$transformer = new $className;
|
||||||
|
|
||||||
// Get Anilist list data
|
$firstTransformed = [];
|
||||||
$anilistList = $this->formatAnilistList($type);
|
|
||||||
|
|
||||||
|
foreach ($data['data']['MediaListCollection']['lists'] as $list)
|
||||||
|
{
|
||||||
|
$firstTransformed[] = $transformer->untransformCollection($list['entries']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$transformed = array_merge_recursive(...$firstTransformed);
|
||||||
|
|
||||||
|
// Key the array by mal_id
|
||||||
|
$output = [];
|
||||||
|
foreach ($transformed as $item)
|
||||||
|
{
|
||||||
|
$output[$item['mal_id']] = $item->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Compare Helpers
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private function compareLists(string $type, array $anilistList, array $kitsuList): array
|
||||||
|
{
|
||||||
$itemsToAddToAnilist = [];
|
$itemsToAddToAnilist = [];
|
||||||
$itemsToAddToKitsu = [];
|
$itemsToAddToKitsu = [];
|
||||||
$anilistUpdateItems = [];
|
$anilistUpdateItems = [];
|
||||||
@ -320,15 +397,21 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
$malIds = array_keys($anilistList);
|
$malIds = array_keys($anilistList);
|
||||||
$kitsuMalIds = array_map('intval', array_column($kitsuList, 'malId'));
|
$kitsuMalIds = array_map('intval', array_column($kitsuList, 'malId'));
|
||||||
$missingMalIds = array_diff($malIds, $kitsuMalIds);
|
$missingMalIds = array_filter(array_diff($kitsuMalIds, $malIds), fn ($id) => ! in_array($id, $kitsuMalIds));
|
||||||
|
|
||||||
// Add items on Anilist, but not Kitsu to Kitsu
|
// Add items on Anilist, but not Kitsu to Kitsu
|
||||||
foreach($missingMalIds as $mid)
|
foreach($missingMalIds as $mid)
|
||||||
{
|
{
|
||||||
$itemsToAddToKitsu[] = array_merge($anilistList[$mid]['data'], [
|
if ( ! array_key_exists($mid, $anilistList))
|
||||||
'id' => $this->kitsuModel->getKitsuIdFromMALId((string)$mid, $type),
|
{
|
||||||
'type' => $type
|
continue;
|
||||||
]);
|
}
|
||||||
|
|
||||||
|
$data = $anilistList[$mid]['data'];
|
||||||
|
$data['id'] = $this->kitsuModel->getKitsuIdFromMALId((string)$mid, $type);
|
||||||
|
$data['type'] = $type;
|
||||||
|
|
||||||
|
$itemsToAddToKitsu[] = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($kitsuList as $kitsuItem)
|
foreach($kitsuList as $kitsuItem)
|
||||||
@ -359,7 +442,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$statusMap = ($type === 'anime') ? AnimeWatchingStatus::class : MangaReadingStatus::class;
|
$statusMap = ($type === ListType::ANIME) ? AnimeWatchingStatus::class : MangaReadingStatus::class;
|
||||||
|
|
||||||
// Looks like this item only exists on Kitsu
|
// Looks like this item only exists on Kitsu
|
||||||
$kItem = $kitsuItem['data'];
|
$kItem = $kitsuItem['data'];
|
||||||
@ -392,7 +475,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
* @param array $anilistItem
|
* @param array $anilistItem
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
protected function compareListItems(array $kitsuItem, array $anilistItem): ?array
|
private function compareListItems(array $kitsuItem, array $anilistItem): ?array
|
||||||
{
|
{
|
||||||
$compareKeys = [
|
$compareKeys = [
|
||||||
'notes',
|
'notes',
|
||||||
@ -585,6 +668,10 @@ final class SyncLists extends BaseCommand {
|
|||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Update Helpers
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/Update list items on Kitsu
|
* Create/Update list items on Kitsu
|
||||||
*
|
*
|
||||||
@ -593,23 +680,23 @@ final class SyncLists extends BaseCommand {
|
|||||||
* @param string $type
|
* @param string $type
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
protected function updateKitsuListItems(array $itemsToUpdate, string $action = 'update', string $type = 'anime'): void
|
private function updateKitsuListItems(array $itemsToUpdate, string $action = SyncAction::UPDATE, string $type = ListType::ANIME): void
|
||||||
{
|
{
|
||||||
$requester = new ParallelAPIRequest();
|
$requester = new ParallelAPIRequest();
|
||||||
foreach($itemsToUpdate as $item)
|
foreach($itemsToUpdate as $item)
|
||||||
{
|
{
|
||||||
if ($action === 'update')
|
if ($action === SyncAction::UPDATE)
|
||||||
{
|
{
|
||||||
$requester->addRequest(
|
$requester->addRequest(
|
||||||
$this->kitsuModel->updateListItem(FormItem::from($item))
|
$this->kitsuModel->updateListItem(FormItem::from($item))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if ($action === 'create')
|
else if ($action === SyncAction::CREATE)
|
||||||
{
|
{
|
||||||
$maybeRequest = $this->kitsuModel->createListItem($item);
|
$maybeRequest = $this->kitsuModel->createListItem($item);
|
||||||
if ($maybeRequest === NULL)
|
if ($maybeRequest === NULL)
|
||||||
{
|
{
|
||||||
$this->echoBox("Skipped creating Kitsu {$type} due to missing id ¯\_(ツ)_/¯");
|
$this->echoWarning("Skipped creating Kitsu {$type} due to missing id ¯\_(ツ)_/¯");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$requester->addRequest($this->kitsuModel->createListItem($item));
|
$requester->addRequest($this->kitsuModel->createListItem($item));
|
||||||
@ -625,8 +712,8 @@ final class SyncLists extends BaseCommand {
|
|||||||
$id = $itemsToUpdate[$key]['id'];
|
$id = $itemsToUpdate[$key]['id'];
|
||||||
if ( ! array_key_exists('errors', $responseData))
|
if ( ! array_key_exists('errors', $responseData))
|
||||||
{
|
{
|
||||||
$verb = ($action === 'update') ? 'updated' : 'created';
|
$verb = ($action === SyncAction::UPDATE) ? 'updated' : 'created';
|
||||||
$this->echoBox("Successfully {$verb} Kitsu {$type} list item with id: {$id}");
|
$this->echoSuccess("Successfully {$verb} Kitsu {$type} list item with id: {$id}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,14 +724,14 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
if ($errorTitle === 'cannot exceed length of media')
|
if ($errorTitle === 'cannot exceed length of media')
|
||||||
{
|
{
|
||||||
$this->echoBox("Skipped Kitsu {$type} {$id} due to episode count mismatch with other API");
|
$this->echoWarning("Skipped Kitsu {$type} {$id} due to episode count mismatch with other API");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dump($responseData);
|
dump($responseData);
|
||||||
$verb = ($action === 'update') ? 'update' : 'create';
|
$verb = ($action === SyncAction::UPDATE) ? SyncAction::UPDATE : SyncAction::CREATE;
|
||||||
$this->echoBox("Failed to {$verb} Kitsu {$type} list item with id: {$id}");
|
$this->echoError("Failed to {$verb} Kitsu {$type} list item with id: {$id}");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -657,19 +744,19 @@ final class SyncLists extends BaseCommand {
|
|||||||
* @param string $type
|
* @param string $type
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
protected function updateAnilistListItems(array $itemsToUpdate, string $action = 'update', string $type = 'anime'): void
|
private function updateAnilistListItems(array $itemsToUpdate, string $action = SyncAction::UPDATE, string $type = ListType::ANIME): void
|
||||||
{
|
{
|
||||||
$requester = new ParallelAPIRequest();
|
$requester = new ParallelAPIRequest();
|
||||||
|
|
||||||
foreach($itemsToUpdate as $item)
|
foreach($itemsToUpdate as $item)
|
||||||
{
|
{
|
||||||
if ($action === 'update')
|
if ($action === SyncAction::UPDATE)
|
||||||
{
|
{
|
||||||
$requester->addRequest(
|
$requester->addRequest(
|
||||||
$this->anilistModel->updateListItem(FormItem::from($item), $type)
|
$this->anilistModel->updateListItem(FormItem::from($item), $type)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if ($action === 'create')
|
else if ($action === SyncAction::CREATE)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -679,7 +766,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
{
|
{
|
||||||
// Case where there's a MAL mapping from Kitsu, but no equivalent Anlist item
|
// Case where there's a MAL mapping from Kitsu, but no equivalent Anlist item
|
||||||
$id = $item['mal_id'];
|
$id = $item['mal_id'];
|
||||||
$this->echoBox("Skipping Anilist ${type} with mal_id: {$id} due to missing mapping");
|
$this->echoWarning("Skipping Anilist ${type} with MAL id: {$id} due to missing mapping");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -694,15 +781,41 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
if ( ! array_key_exists('errors', $responseData))
|
if ( ! array_key_exists('errors', $responseData))
|
||||||
{
|
{
|
||||||
$verb = ($action === 'update') ? 'updated' : 'created';
|
$verb = ($action === SyncAction::UPDATE) ? 'updated' : 'created';
|
||||||
$this->echoBox("Successfully {$verb} Anilist {$type} list item with id: {$id}");
|
$this->echoSuccess("Successfully {$verb} Anilist {$type} list item with id: {$id}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dump($responseData);
|
dump($responseData);
|
||||||
$verb = ($action === 'update') ? 'update' : 'create';
|
$verb = ($action === SyncAction::UPDATE) ? SyncAction::UPDATE : SyncAction::CREATE;
|
||||||
$this->echoBox("Failed to {$verb} Anilist {$type} list item with id: {$id}");
|
$this->echoError("Failed to {$verb} Anilist {$type} list item with id: {$id}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Other Helpers
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter Kitsu mappings for the specified type
|
||||||
|
*
|
||||||
|
* @param array $includes
|
||||||
|
* @param string $type
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function filterMappings(array $includes, string $type = ListType::ANIME): array
|
||||||
|
{
|
||||||
|
$output = [];
|
||||||
|
|
||||||
|
foreach($includes as $id => $mapping)
|
||||||
|
{
|
||||||
|
if ($mapping['externalSite'] === "myanimelist/{$type}")
|
||||||
|
{
|
||||||
|
$output[$id] = $mapping;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ class FormItemData extends AbstractType {
|
|||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
public bool $private = FALSE;
|
public ?bool $private = FALSE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int
|
* @var int
|
||||||
|
Loading…
Reference in New Issue
Block a user