Actually update MAL if enabled
This commit is contained in:
parent
47bfe810fc
commit
a48c3e5f8e
@ -48,10 +48,13 @@ return function(array $config_array = []) {
|
|||||||
|
|
||||||
$app_logger = new Logger('animeclient');
|
$app_logger = new Logger('animeclient');
|
||||||
$app_logger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/app.log', Logger::NOTICE));
|
$app_logger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/app.log', Logger::NOTICE));
|
||||||
$request_logger = new Logger('request');
|
$kitsu_request_logger = new Logger('kitsu_request');
|
||||||
$request_logger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/request.log', Logger::NOTICE));
|
$kitsu_request_logger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/kitsu_request.log', Logger::NOTICE));
|
||||||
|
$mal_request_logger = new Logger('mal_request');
|
||||||
|
$mal_request_logger->pushHandler(new RotatingFileHandler(__DIR__ . '/logs/mal_request.log', Logger::NOTICE));
|
||||||
$container->setLogger($app_logger, 'default');
|
$container->setLogger($app_logger, 'default');
|
||||||
$container->setLogger($request_logger, 'request');
|
$container->setLogger($kitsu_request_logger, 'kitsu_request');
|
||||||
|
$container->setLogger($mal_request_logger, 'mal_request');
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Injected Objects
|
// Injected Objects
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<?php if ($auth->is_authenticated()): ?>
|
<?php if ($auth->is_authenticated()): ?>
|
||||||
<?php /* <pre><?= json_encode($item, \JSON_PRETTY_PRINT); ?></pre> */ ?>
|
|
||||||
<main>
|
<main>
|
||||||
<h2>Edit Anime List Item</h2>
|
<h2>Edit Anime List Item</h2>
|
||||||
<form action="<?= $action ?>" method="post">
|
<form action="<?= $action ?>" method="post">
|
||||||
@ -86,15 +85,20 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Danger Zone</legend>
|
<legend>Danger Zone</legend>
|
||||||
<form class="js-delete" action="<?= $url->generate('anime.delete') ?>" method="post">
|
<form class="js-delete" action="<?= $url->generate('anime.delete') ?>" method="post">
|
||||||
<table class="form invisible">
|
<table class="form invisible">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td>
|
||||||
|
<strong>Permanently</strong> remove this list item and <strong>all</strong> its data?
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="hidden" value="<?= $item['id'] ?>" name="id" />
|
<input type="hidden" value="<?= $item['id'] ?>" name="id" />
|
||||||
|
<input type="hidden" value="<?= $item['mal_id'] ?>" name="mal_id" />
|
||||||
<button type="submit" class="danger">Delete Entry</button>
|
<button type="submit" class="danger">Delete Entry</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -28,4 +28,3 @@ class AnimeWatchingStatus extends BaseEnum {
|
|||||||
const ON_HOLD = 'on_hold';
|
const ON_HOLD = 'on_hold';
|
||||||
const DROPPED = 'dropped';
|
const DROPPED = 'dropped';
|
||||||
}
|
}
|
||||||
// End of AnimeWatchingStatus.php
|
|
@ -93,7 +93,7 @@ trait KitsuTrait {
|
|||||||
'headers' => $this->defaultHeaders
|
'headers' => $this->defaultHeaders
|
||||||
];
|
];
|
||||||
|
|
||||||
$logger = $this->container->getLogger('request');
|
$logger = $this->container->getLogger('kitsu_request');
|
||||||
$sessionSegment = $this->getContainer()
|
$sessionSegment = $this->getContainer()
|
||||||
->get('session')
|
->get('session')
|
||||||
->getSegment(AnimeClient::SESSION_SEGMENT);
|
->getSegment(AnimeClient::SESSION_SEGMENT);
|
||||||
@ -106,10 +106,19 @@ trait KitsuTrait {
|
|||||||
|
|
||||||
$options = array_merge($defaultOptions, $options);
|
$options = array_merge($defaultOptions, $options);
|
||||||
|
|
||||||
$logger->debug(Json::encode([$type, $url]));
|
$response = $this->client->request($type, $url, $options);
|
||||||
$logger->debug(Json::encode($options));
|
|
||||||
|
|
||||||
return $this->client->request($type, $url, $options);
|
$logger->debug('Kitsu API request', [
|
||||||
|
'requestParams' => [
|
||||||
|
'type' => $type,
|
||||||
|
'url' => $url,
|
||||||
|
],
|
||||||
|
'responseValues' => [
|
||||||
|
'status' => $response->getStatusCode()
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -125,7 +134,7 @@ trait KitsuTrait {
|
|||||||
$logger = null;
|
$logger = null;
|
||||||
if ($this->getContainer())
|
if ($this->getContainer())
|
||||||
{
|
{
|
||||||
$logger = $this->container->getLogger('request');
|
$logger = $this->container->getLogger('kitsu_request');
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $this->getResponse($type, $url, $options);
|
$response = $this->getResponse($type, $url, $options);
|
||||||
@ -134,11 +143,8 @@ trait KitsuTrait {
|
|||||||
{
|
{
|
||||||
if ($logger)
|
if ($logger)
|
||||||
{
|
{
|
||||||
$logger->warning('Non 200 response for api call');
|
$logger->warning('Non 200 response for api call', $response->getBody());
|
||||||
$logger->warning($response->getBody());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// throw new RuntimeException($response->getBody());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSON::decode($response->getBody(), TRUE);
|
return JSON::decode($response->getBody(), TRUE);
|
||||||
@ -177,7 +183,7 @@ trait KitsuTrait {
|
|||||||
$logger = null;
|
$logger = null;
|
||||||
if ($this->getContainer())
|
if ($this->getContainer())
|
||||||
{
|
{
|
||||||
$logger = $this->container->getLogger('request');
|
$logger = $this->container->getLogger('kitsu_request');
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $this->getResponse('POST', ...$args);
|
$response = $this->getResponse('POST', ...$args);
|
||||||
@ -187,11 +193,8 @@ trait KitsuTrait {
|
|||||||
{
|
{
|
||||||
if ($logger)
|
if ($logger)
|
||||||
{
|
{
|
||||||
$logger->warning('Non 201 response for POST api call');
|
$logger->warning('Non 201 response for POST api call', $response->getBody());
|
||||||
$logger->warning($response->getBody());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// throw new RuntimeException($response->getBody());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSON::decode($response->getBody(), TRUE);
|
return JSON::decode($response->getBody(), TRUE);
|
||||||
|
@ -167,6 +167,34 @@ class Model {
|
|||||||
return $this->animeTransformer->transform($baseData);
|
return $this->animeTransformer->transform($baseData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mal id for the anime represented by the kitsu id
|
||||||
|
* to enable updating MyAnimeList
|
||||||
|
*
|
||||||
|
* @param string $kitsuAnimeId The id of the anime on Kitsu
|
||||||
|
* @return string|null Returns the mal id if it exists, otherwise null
|
||||||
|
*/
|
||||||
|
public function getMalIdForAnime(string $kitsuAnimeId)
|
||||||
|
{
|
||||||
|
$options = [
|
||||||
|
'query' => [
|
||||||
|
'include' => 'mappings'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
$data = $this->getRequest("anime/{$kitsuAnimeId}", $options);
|
||||||
|
$mappings = array_column($data['included'], 'attributes');
|
||||||
|
|
||||||
|
foreach($mappings as $map)
|
||||||
|
{
|
||||||
|
if ($map['externalSite'] === 'myanimelist/anime')
|
||||||
|
{
|
||||||
|
return $map['externalId'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about a particular manga
|
* Get information about a particular manga
|
||||||
*
|
*
|
||||||
@ -179,6 +207,16 @@ class Model {
|
|||||||
return $this->mangaTransformer->transform($baseData);
|
return $this->mangaTransformer->transform($baseData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get and transform the entirety of the user's anime list
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getFullAnimeList(): array
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the raw (unorganized) anime list for the configured user
|
* Get the raw (unorganized) anime list for the configured user
|
||||||
*
|
*
|
||||||
|
@ -113,6 +113,7 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
$untransformed = [
|
$untransformed = [
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
|
'mal_id' => $item['mal_id'] ?? null,
|
||||||
'data' => [
|
'data' => [
|
||||||
'status' => $item['watching_status'],
|
'status' => $item['watching_status'],
|
||||||
'rating' => $item['user_rating'] / 2,
|
'rating' => $item['user_rating'] / 2,
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API;
|
namespace Aviat\AnimeClient\API;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\API\Kitsu\Enum\{
|
||||||
|
AnimeWatchingStatus as KAWS,
|
||||||
|
MangaReadingStatus as KMRS
|
||||||
|
};
|
||||||
use Aviat\AnimeClient\API\MAL\Enum\{AnimeWatchingStatus, MangaReadingStatus};
|
use Aviat\AnimeClient\API\MAL\Enum\{AnimeWatchingStatus, MangaReadingStatus};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,6 +29,14 @@ class MAL {
|
|||||||
const AUTH_URL = 'https://myanimelist.net/api/account/verify_credentials.xml';
|
const AUTH_URL = 'https://myanimelist.net/api/account/verify_credentials.xml';
|
||||||
const BASE_URL = 'https://myanimelist.net/api/';
|
const BASE_URL = 'https://myanimelist.net/api/';
|
||||||
|
|
||||||
|
const KITSU_MAL_WATCHING_STATUS_MAP = [
|
||||||
|
KAWS::WATCHING => AnimeWatchingStatus::WATCHING,
|
||||||
|
KAWS::COMPLETED => AnimeWatchingStatus::COMPLETED,
|
||||||
|
KAWS::ON_HOLD => AnimeWatchingStatus::ON_HOLD,
|
||||||
|
KAWS::DROPPED => AnimeWatchingStatus::DROPPED,
|
||||||
|
KAWS::PLAN_TO_WATCH => AnimeWatchingStatus::PLAN_TO_WATCH
|
||||||
|
];
|
||||||
|
|
||||||
public static function getIdToWatchingStatusMap()
|
public static function getIdToWatchingStatusMap()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@ -32,7 +44,12 @@ class MAL {
|
|||||||
2 => AnimeWatchingStatus::COMPLETED,
|
2 => AnimeWatchingStatus::COMPLETED,
|
||||||
3 => AnimeWatchingStatus::ON_HOLD,
|
3 => AnimeWatchingStatus::ON_HOLD,
|
||||||
4 => AnimeWatchingStatus::DROPPED,
|
4 => AnimeWatchingStatus::DROPPED,
|
||||||
5 => AnimeWatchingStatus::PLAN_TO_WATCH
|
6 => AnimeWatchingStatus::PLAN_TO_WATCH,
|
||||||
|
'watching' => AnimeWatchingStatus::WATCHING,
|
||||||
|
'completed' => AnimeWatchingStatus::COMPLETED,
|
||||||
|
'onhold' => AnimeWatchingStatus::ON_HOLD,
|
||||||
|
'dropped' => AnimeWatchingStatus::DROPPED,
|
||||||
|
'plantowatch' => AnimeWatchingStatus::PLAN_TO_WATCH
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +60,12 @@ class MAL {
|
|||||||
2 => MangaReadingStatus::COMPLETED,
|
2 => MangaReadingStatus::COMPLETED,
|
||||||
3 => MangaReadingStatus::ON_HOLD,
|
3 => MangaReadingStatus::ON_HOLD,
|
||||||
4 => MangaReadingStatus::DROPPED,
|
4 => MangaReadingStatus::DROPPED,
|
||||||
5 => MangaReadingStatus::PLAN_TO_READ
|
6 => MangaReadingStatus::PLAN_TO_READ,
|
||||||
|
'reading' => MangaReadingStatus::READING,
|
||||||
|
'completed' => MangaReadingStatus::COMPLETED,
|
||||||
|
'onhold' => MangaReadingStatus::ON_HOLD,
|
||||||
|
'dropped' => MangaReadingStatus::DROPPED,
|
||||||
|
'plantoread' => MangaReadingStatus::PLAN_TO_WATCH
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,9 +22,9 @@ use Aviat\Ion\Enum as BaseEnum;
|
|||||||
* Possible values for watching status for the current anime
|
* Possible values for watching status for the current anime
|
||||||
*/
|
*/
|
||||||
class AnimeWatchingStatus extends BaseEnum {
|
class AnimeWatchingStatus extends BaseEnum {
|
||||||
const WATCHING = 'watching';
|
const WATCHING = 1;
|
||||||
const COMPLETED = 'completed';
|
const COMPLETED = 2;
|
||||||
const ON_HOLD = 'onhold';
|
const ON_HOLD = 3;
|
||||||
const DROPPED = 'dropped';
|
const DROPPED = 4;
|
||||||
const PLAN_TO_WATCH = 'plantowatch';
|
const PLAN_TO_WATCH = 6;
|
||||||
}
|
}
|
@ -33,24 +33,24 @@ class ListItem {
|
|||||||
public function create(array $data): bool
|
public function create(array $data): bool
|
||||||
{
|
{
|
||||||
$id = $data['id'];
|
$id = $data['id'];
|
||||||
$body = (new FormBody)
|
$createData = [
|
||||||
->addField('id', $data['id'])
|
'id' => $id,
|
||||||
->addField('data', XML::toXML(['entry' => $data['data']]));
|
'data' => XML::toXML([
|
||||||
|
'entry' => $data['data']
|
||||||
|
])
|
||||||
|
];
|
||||||
|
|
||||||
$response = $this->getResponse('POST', "animelist/add/{$id}.xml", [
|
$response = $this->getResponse('POST', "animelist/add/{$id}.xml", [
|
||||||
'headers' => [
|
'body' => $this->fixBody((new FormBody)->addFields($createData))
|
||||||
'Content-type' => 'application/x-www-form-urlencoded',
|
|
||||||
'Accept' => 'text/plain'
|
|
||||||
],
|
|
||||||
'body' => $body
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $response->getStatus() === 201;
|
return $response->getBody() === 'Created';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(string $id): bool
|
public function delete(string $id): bool
|
||||||
{
|
{
|
||||||
$response = $this->getResponse('DELETE', "animeclient/delete/{$id}.xml", [
|
$response = $this->getResponse('DELETE', "animelist/delete/{$id}.xml", [
|
||||||
'body' => (new FormBody)->addField('id', $id)
|
'body' => $this->fixBody((new FormBody)->addField('id', $id))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $response->getBody() === 'Deleted';
|
return $response->getBody() === 'Deleted';
|
||||||
@ -61,18 +61,15 @@ class ListItem {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(string $id, array $data): Response
|
public function update(string $id, array $data)
|
||||||
{
|
{
|
||||||
|
$xml = XML::toXML(['entry' => $data]);
|
||||||
$body = (new FormBody)
|
$body = (new FormBody)
|
||||||
->addField('id', $id)
|
->addField('id', $id)
|
||||||
->addField('data', XML::toXML(['entry' => $data]))
|
->addField('data', $xml);
|
||||||
|
|
||||||
return $this->postRequest("animelist/update/{$id}.xml", [
|
return $this->getResponse('POST', "animelist/update/{$id}.xml", [
|
||||||
'headers' => [
|
'body' => $this->fixBody($body)
|
||||||
'Content-type' => 'application/x-www-form-urlencoded',
|
|
||||||
'Accept' => 'text/plain'
|
|
||||||
],
|
|
||||||
'body' => $body
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API\MAL;
|
namespace Aviat\AnimeClient\API\MAL;
|
||||||
|
|
||||||
use Amp\Artax\{Client, Request};
|
use Amp\Artax\{Client, FormBody, Request};
|
||||||
use Aviat\AnimeClient\API\{
|
use Aviat\AnimeClient\API\{
|
||||||
MAL as M,
|
MAL as M,
|
||||||
XML
|
XML
|
||||||
@ -38,9 +38,27 @@ trait MALTrait {
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $defaultHeaders = [
|
protected $defaultHeaders = [
|
||||||
|
'Accept' => 'text/xml',
|
||||||
|
'Accept-Encoding' => 'gzip',
|
||||||
|
'Content-type' => 'application/x-www-form-urlencoded',
|
||||||
'User-Agent' => "Tim's Anime Client/4.0"
|
'User-Agent' => "Tim's Anime Client/4.0"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unencode the dual-encoded ampersands in the body
|
||||||
|
*
|
||||||
|
* This is a dirty hack until I can fully track down where
|
||||||
|
* the dual-encoding happens
|
||||||
|
*
|
||||||
|
* @param FormBody $formBody The form builder object to fix
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function fixBody(FormBody $formBody): string
|
||||||
|
{
|
||||||
|
$rawBody = \Amp\wait($formBody->getBody());
|
||||||
|
return html_entity_decode($rawBody, \ENT_HTML5, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a request via Guzzle
|
* Make a request via Guzzle
|
||||||
*
|
*
|
||||||
@ -51,8 +69,10 @@ trait MALTrait {
|
|||||||
*/
|
*/
|
||||||
private function getResponse(string $type, string $url, array $options = [])
|
private function getResponse(string $type, string $url, array $options = [])
|
||||||
{
|
{
|
||||||
|
$this->defaultHeaders['User-Agent'] = $_SERVER['HTTP_USER_AGENT'] ?? $this->defaultHeaders;
|
||||||
|
|
||||||
$type = strtoupper($type);
|
$type = strtoupper($type);
|
||||||
$validTypes = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];
|
$validTypes = ['GET', 'POST', 'DELETE'];
|
||||||
|
|
||||||
if ( ! in_array($type, $validTypes))
|
if ( ! in_array($type, $validTypes))
|
||||||
{
|
{
|
||||||
@ -60,7 +80,7 @@ trait MALTrait {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$config = $this->container->get('config');
|
$config = $this->container->get('config');
|
||||||
$logger = $this->container->getLogger('request');
|
$logger = $this->container->getLogger('mal_request');
|
||||||
|
|
||||||
$headers = array_merge($this->defaultHeaders, $options['headers'] ?? [], [
|
$headers = array_merge($this->defaultHeaders, $options['headers'] ?? [], [
|
||||||
'Authorization' => 'Basic ' .
|
'Authorization' => 'Basic ' .
|
||||||
@ -70,20 +90,39 @@ trait MALTrait {
|
|||||||
$query = $options['query'] ?? [];
|
$query = $options['query'] ?? [];
|
||||||
|
|
||||||
$url = (strpos($url, '//') !== FALSE)
|
$url = (strpos($url, '//') !== FALSE)
|
||||||
? $url . '?' . http_build_query($query)
|
? $url
|
||||||
: $this->baseUrl . $url . '?' . http_build_query($query);
|
: $this->baseUrl . $url;
|
||||||
|
|
||||||
|
if ( ! empty($query))
|
||||||
|
{
|
||||||
|
$url .= '?' . http_build_query($query);
|
||||||
|
}
|
||||||
|
|
||||||
$request = (new Request)
|
$request = (new Request)
|
||||||
->setMethod($type)
|
->setMethod($type)
|
||||||
->setUri($url)
|
->setUri($url)
|
||||||
->setProtocol('1.1')
|
->setProtocol('1.1')
|
||||||
->setAllHeaders($headers)
|
->setAllHeaders($headers);
|
||||||
->setBody($options['body']);
|
|
||||||
|
|
||||||
$logger->debug(Json::encode([$type, $url]));
|
if (array_key_exists('body', $options))
|
||||||
$logger->debug(Json::encode($options));
|
{
|
||||||
|
$request->setBody($options['body']);
|
||||||
|
}
|
||||||
|
|
||||||
return \Amp\wait((new Client)->request($request));
|
$response = \Amp\wait((new Client)->request($request));
|
||||||
|
|
||||||
|
$logger->debug('MAL api request', [
|
||||||
|
'url' => $url,
|
||||||
|
'status' => $response->getStatus(),
|
||||||
|
'reason' => $response->getReason(),
|
||||||
|
'headers' => $response->getAllHeaders(),
|
||||||
|
'requestHeaders' => $request->getAllHeaders(),
|
||||||
|
'requestBody' => $request->hasBody() ? $request->getBody() : 'No request body',
|
||||||
|
'requestBodyBeforeEncode' => $request->hasBody() ? urldecode($request->getBody()) : '',
|
||||||
|
'body' => $response->getBody()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,7 +138,7 @@ trait MALTrait {
|
|||||||
$logger = null;
|
$logger = null;
|
||||||
if ($this->getContainer())
|
if ($this->getContainer())
|
||||||
{
|
{
|
||||||
$logger = $this->container->getLogger('request');
|
$logger = $this->container->getLogger('mal_request');
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $this->getResponse($type, $url, $options);
|
$response = $this->getResponse($type, $url, $options);
|
||||||
@ -108,8 +147,7 @@ trait MALTrait {
|
|||||||
{
|
{
|
||||||
if ($logger)
|
if ($logger)
|
||||||
{
|
{
|
||||||
$logger->warning('Non 200 response for api call');
|
$logger->warning('Non 200 response for api call', $response->getBody());
|
||||||
$logger->warning($response->getBody());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +176,7 @@ trait MALTrait {
|
|||||||
$logger = null;
|
$logger = null;
|
||||||
if ($this->getContainer())
|
if ($this->getContainer())
|
||||||
{
|
{
|
||||||
$logger = $this->container->getLogger('request');
|
$logger = $this->container->getLogger('mal_request');
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $this->getResponse('POST', ...$args);
|
$response = $this->getResponse('POST', ...$args);
|
||||||
@ -148,8 +186,7 @@ trait MALTrait {
|
|||||||
{
|
{
|
||||||
if ($logger)
|
if ($logger)
|
||||||
{
|
{
|
||||||
$logger->warning('Non 201 response for POST api call');
|
$logger->warning('Non 201 response for POST api call', $response->getBody());
|
||||||
$logger->warning($response->getBody());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,13 +17,10 @@
|
|||||||
namespace Aviat\AnimeClient\API\MAL;
|
namespace Aviat\AnimeClient\API\MAL;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\MAL as M;
|
use Aviat\AnimeClient\API\MAL as M;
|
||||||
use Aviat\AnimeClient\API\MAL\{
|
use Aviat\AnimeClient\API\MAL\ListItem;
|
||||||
AnimeListTransformer,
|
use Aviat\AnimeClient\API\MAL\Transformer\AnimeListTransformer;
|
||||||
ListItem
|
|
||||||
};
|
|
||||||
use Aviat\AnimeClient\API\XML;
|
use Aviat\AnimeClient\API\XML;
|
||||||
use Aviat\Ion\Di\ContainerAware;
|
use Aviat\Ion\Di\ContainerAware;
|
||||||
use Aviat\Ion\Json;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MyAnimeList API Model
|
* MyAnimeList API Model
|
||||||
@ -42,13 +39,37 @@ class Model {
|
|||||||
*/
|
*/
|
||||||
public function __construct(ListItem $listItem)
|
public function __construct(ListItem $listItem)
|
||||||
{
|
{
|
||||||
//$this->animeListTransformer = new AnimeListTransformer();
|
$this->animeListTransformer = new AnimeListTransformer();
|
||||||
$this->listItem = $listItem;
|
$this->listItem = $listItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createListItem(array $data): bool
|
public function createListItem(array $data): bool
|
||||||
{
|
{
|
||||||
return $this->listItem->create($data);
|
$createData = [
|
||||||
|
'id' => $data['id'],
|
||||||
|
'data' => [
|
||||||
|
'status' => M::KITSU_MAL_WATCHING_STATUS_MAP[$data['status']]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->listItem->create($createData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFullList(): array
|
||||||
|
{
|
||||||
|
$config = $this->container->get('config');
|
||||||
|
$userName = $config->get(['mal', 'username']);
|
||||||
|
$list = $this->getRequest('https://myanimelist.net/malappinfo.php', [
|
||||||
|
'headers' => [
|
||||||
|
'Accept' => 'text/xml'
|
||||||
|
],
|
||||||
|
'query' => [
|
||||||
|
'u' => $userName,
|
||||||
|
'status' => 'all'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $list;//['anime'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getListItem(string $listId): array
|
public function getListItem(string $listId): array
|
||||||
@ -58,8 +79,8 @@ class Model {
|
|||||||
|
|
||||||
public function updateListItem(array $data)
|
public function updateListItem(array $data)
|
||||||
{
|
{
|
||||||
//$updateData = $this->animeListTransformer->transform($data['data']);
|
$updateData = $this->animeListTransformer->untransform($data);
|
||||||
return $this->listItem->update($data['mal_id'], $updateData);
|
return $this->listItem->update($updateData['id'], $updateData['data']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteListItem(string $id): bool
|
public function deleteListItem(string $id): bool
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
* @link https://github.com/timw4mail/HummingBirdAnimeClient
|
* @link https://github.com/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\MAL;
|
namespace Aviat\AnimeClient\API\MAL\Transformer;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\API\Kitsu\Enum\AnimeWatchingStatus;
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,18 +24,22 @@ use Aviat\Ion\Transformer\AbstractTransformer;
|
|||||||
*/
|
*/
|
||||||
class AnimeListTransformer extends AbstractTransformer {
|
class AnimeListTransformer extends AbstractTransformer {
|
||||||
|
|
||||||
|
const statusMap = [
|
||||||
|
AnimeWatchingStatus::WATCHING => '1',
|
||||||
|
AnimeWatchingStatus::COMPLETED => '2',
|
||||||
|
AnimeWatchingStatus::ON_HOLD => '3',
|
||||||
|
AnimeWatchingStatus::DROPPED => '4',
|
||||||
|
AnimeWatchingStatus::PLAN_TO_WATCH => '6'
|
||||||
|
];
|
||||||
|
|
||||||
public function transform($item)
|
public function transform($item)
|
||||||
{
|
{
|
||||||
$rewatching = 'false';
|
$rewatching = (array_key_exists('rewatching', $item) && $item['rewatching']);
|
||||||
if (array_key_exists('rewatching', $item) && $item['rewatching'])
|
|
||||||
{
|
|
||||||
$rewatching = 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $item['id'],
|
'id' => $item['mal_id'],
|
||||||
'data' => [
|
'data' => [
|
||||||
'status' => $item['watching_status'],
|
'status' => self::statusMap[$item['watching_status']],
|
||||||
'rating' => $item['user_rating'],
|
'rating' => $item['user_rating'],
|
||||||
'rewatch_value' => (int) $rewatching,
|
'rewatch_value' => (int) $rewatching,
|
||||||
'times_rewatched' => $item['rewatched'],
|
'times_rewatched' => $item['rewatched'],
|
||||||
@ -43,4 +48,31 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
]
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform Kitsu episode data to MAL episode data
|
||||||
|
*
|
||||||
|
* @param array $item
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function untransform(array $item): array
|
||||||
|
{
|
||||||
|
$rewatching = (array_key_exists('reconsuming', $item['data']) && $item['data']['reconsuming']);
|
||||||
|
|
||||||
|
$map = [
|
||||||
|
'id' => $item['mal_id'],
|
||||||
|
'data' => [
|
||||||
|
'episode' => $item['data']['progress'],
|
||||||
|
'status' => self::statusMap[$item['data']['status']],
|
||||||
|
'score' => (array_key_exists('rating', $item['data']))
|
||||||
|
? $item['data']['rating'] * 2
|
||||||
|
: "",
|
||||||
|
// 'enable_rewatching' => $rewatching,
|
||||||
|
// 'times_rewatched' => $item['data']['reconsumeCount'],
|
||||||
|
// 'comments' => $item['data']['notes'],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
}
|
}
|
@ -107,12 +107,7 @@ class XML {
|
|||||||
{
|
{
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
// Get rid of unimportant text nodes by removing
|
$xml = static::stripXMLWhitespace($xml);
|
||||||
// whitespace characters from between xml tags,
|
|
||||||
// except for the xml declaration tag, Which looks
|
|
||||||
// something like:
|
|
||||||
/* <?xml version="1.0" encoding="UTF-8"?> */
|
|
||||||
$xml = preg_replace('/([^\?])>\s+</', '$1><', $xml);
|
|
||||||
|
|
||||||
$dom = new DOMDocument();
|
$dom = new DOMDocument();
|
||||||
$dom->loadXML($xml);
|
$dom->loadXML($xml);
|
||||||
@ -166,6 +161,16 @@ class XML {
|
|||||||
return static::toXML($this->getData());
|
return static::toXML($this->getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function stripXMLWhitespace(string $xml): string
|
||||||
|
{
|
||||||
|
// Get rid of unimportant text nodes by removing
|
||||||
|
// whitespace characters from between xml tags,
|
||||||
|
// except for the xml declaration tag, Which looks
|
||||||
|
// something like:
|
||||||
|
/* <?xml version="1.0" encoding="UTF-8"?> */
|
||||||
|
return preg_replace('/([^\?])>\s+</', '$1><', $xml);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively create array structure based on xml structure
|
* Recursively create array structure based on xml structure
|
||||||
*
|
*
|
||||||
|
@ -259,7 +259,7 @@ class Anime extends BaseController {
|
|||||||
$data = $this->request->getParsedBody();
|
$data = $this->request->getParsedBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $this->model->updateLibraryItem($data);
|
$response = $this->model->updateLibraryItem($data, $data);
|
||||||
|
|
||||||
$this->cache->clear();
|
$this->cache->clear();
|
||||||
$this->outputJSON($response['body'], $response['statusCode']);
|
$this->outputJSON($response['body'], $response['statusCode']);
|
||||||
@ -273,7 +273,7 @@ class Anime extends BaseController {
|
|||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
$body = $this->request->getParsedBody();
|
$body = $this->request->getParsedBody();
|
||||||
$response = $this->model->deleteLibraryItem($body['id']);
|
$response = $this->model->deleteLibraryItem($body['id'], $body['mal_id']);
|
||||||
|
|
||||||
if ((bool)$response === TRUE)
|
if ((bool)$response === TRUE)
|
||||||
{
|
{
|
||||||
|
@ -43,6 +43,12 @@ class Anime extends API {
|
|||||||
AnimeWatchingStatus::COMPLETED => self::COMPLETED,
|
AnimeWatchingStatus::COMPLETED => self::COMPLETED,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected $kitsuModel;
|
||||||
|
|
||||||
|
protected $malModel;
|
||||||
|
|
||||||
|
protected $useMALAPI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Anime constructor.
|
* Anime constructor.
|
||||||
* @param ContainerInterface $container
|
* @param ContainerInterface $container
|
||||||
@ -50,7 +56,11 @@ class Anime extends API {
|
|||||||
public function __construct(ContainerInterface $container) {
|
public function __construct(ContainerInterface $container) {
|
||||||
parent::__construct($container);
|
parent::__construct($container);
|
||||||
|
|
||||||
|
$config = $container->get('config');
|
||||||
$this->kitsuModel = $container->get('kitsu-model');
|
$this->kitsuModel = $container->get('kitsu-model');
|
||||||
|
$this->malModel = $container->get('mal-model');
|
||||||
|
|
||||||
|
$this->useMALAPI = $config->get(['use_mal_api']) === TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,8 +120,26 @@ class Anime extends API {
|
|||||||
return $this->kitsuModel->getListItem($itemId);
|
return $this->kitsuModel->getListItem($itemId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an anime to your list
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function createLibraryItem(array $data): bool
|
public function createLibraryItem(array $data): bool
|
||||||
{
|
{
|
||||||
|
if ($this->useMALAPI)
|
||||||
|
{
|
||||||
|
$malData = $data;
|
||||||
|
$malId = $this->kitsuModel->getMalIdForAnime($malData['id']);
|
||||||
|
|
||||||
|
if ( ! is_null($malId))
|
||||||
|
{
|
||||||
|
$malData['id'] = $malId;
|
||||||
|
$this->malModel->createListItem($malData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $this->kitsuModel->createListItem($data);
|
return $this->kitsuModel->createListItem($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,11 +151,28 @@ class Anime extends API {
|
|||||||
*/
|
*/
|
||||||
public function updateLibraryItem(array $data): array
|
public function updateLibraryItem(array $data): array
|
||||||
{
|
{
|
||||||
|
if ($this->useMALAPI)
|
||||||
|
{
|
||||||
|
$this->malModel->updateListItem($data);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->kitsuModel->updateListItem($data);
|
return $this->kitsuModel->updateListItem($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteLibraryItem($id): bool
|
/**
|
||||||
|
* Delete a list entry
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param string|null $malId
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function deleteLibraryItem(string $id, string $malId = null): bool
|
||||||
{
|
{
|
||||||
|
if ($this->useMALAPI && ! is_null($malId))
|
||||||
|
{
|
||||||
|
$this->malModel->deleteListItem($malId);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->kitsuModel->deleteListItem($id);
|
return $this->kitsuModel->deleteListItem($id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ class AnimeListTransformerTest extends AnimeClient_TestCase {
|
|||||||
],
|
],
|
||||||
'expected' => [
|
'expected' => [
|
||||||
'id' => 14047981,
|
'id' => 14047981,
|
||||||
|
'mal_id' => null,
|
||||||
'data' => [
|
'data' => [
|
||||||
'status' => 'current',
|
'status' => 'current',
|
||||||
'rating' => 4,
|
'rating' => 4,
|
||||||
@ -57,6 +58,7 @@ class AnimeListTransformerTest extends AnimeClient_TestCase {
|
|||||||
], [
|
], [
|
||||||
'input' => [
|
'input' => [
|
||||||
'id' => 14047981,
|
'id' => 14047981,
|
||||||
|
'mal_id' => '12345',
|
||||||
'watching_status' => 'current',
|
'watching_status' => 'current',
|
||||||
'user_rating' => 8,
|
'user_rating' => 8,
|
||||||
'episodes_watched' => 38,
|
'episodes_watched' => 38,
|
||||||
@ -68,6 +70,7 @@ class AnimeListTransformerTest extends AnimeClient_TestCase {
|
|||||||
],
|
],
|
||||||
'expected' => [
|
'expected' => [
|
||||||
'id' => 14047981,
|
'id' => 14047981,
|
||||||
|
'mal_id' => '12345',
|
||||||
'data' => [
|
'data' => [
|
||||||
'status' => 'current',
|
'status' => 'current',
|
||||||
'rating' => 4,
|
'rating' => 4,
|
||||||
|
Loading…
Reference in New Issue
Block a user