Streaming links, caching, and more MAL integration
This commit is contained in:
parent
68bee55f6a
commit
d79370deb9
@ -19,9 +19,15 @@ namespace Aviat\AnimeClient;
|
|||||||
use Aura\Html\HelperLocatorFactory;
|
use Aura\Html\HelperLocatorFactory;
|
||||||
use Aura\Router\RouterContainer;
|
use Aura\Router\RouterContainer;
|
||||||
use Aura\Session\SessionFactory;
|
use Aura\Session\SessionFactory;
|
||||||
use Aviat\AnimeClient\API\Kitsu\Auth as KitsuAuth;
|
use Aviat\AnimeClient\API\Kitsu\{
|
||||||
use Aviat\AnimeClient\API\Kitsu\ListItem as KitsuListItem;
|
Auth as KitsuAuth,
|
||||||
use Aviat\AnimeClient\API\Kitsu\KitsuModel;
|
ListItem as KitsuListItem,
|
||||||
|
KitsuModel
|
||||||
|
};
|
||||||
|
use Aviat\AnimeClient\API\MAL\{
|
||||||
|
ListItem as MALListItem,
|
||||||
|
Model as MALModel
|
||||||
|
};
|
||||||
use Aviat\AnimeClient\Model;
|
use Aviat\AnimeClient\Model;
|
||||||
use Aviat\Banker\Pool;
|
use Aviat\Banker\Pool;
|
||||||
use Aviat\Ion\Config;
|
use Aviat\Ion\Config;
|
||||||
@ -111,6 +117,15 @@ return function(array $config_array = []) {
|
|||||||
$listItem->setContainer($container);
|
$listItem->setContainer($container);
|
||||||
$model = new KitsuModel($listItem);
|
$model = new KitsuModel($listItem);
|
||||||
$model->setContainer($container);
|
$model->setContainer($container);
|
||||||
|
$cache = $container->get('cache');
|
||||||
|
$model->setCache($cache);
|
||||||
|
return $model;
|
||||||
|
});
|
||||||
|
$container->set('mal-model', function($container) {
|
||||||
|
$listItem = new MALListItem();
|
||||||
|
$listItem->setContainer($container);
|
||||||
|
$model = new MALModel($listItem);
|
||||||
|
$model->setContainer($container);
|
||||||
return $model;
|
return $model;
|
||||||
});
|
});
|
||||||
$container->set('api-model', function($container) {
|
$container->set('api-model', function($container) {
|
||||||
|
63
src/API/CacheTrait.php
Normal file
63
src/API/CacheTrait.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* Anime List Client
|
||||||
|
*
|
||||||
|
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||||
|
*
|
||||||
|
* PHP version 7
|
||||||
|
*
|
||||||
|
* @package AnimeListClient
|
||||||
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
|
* @copyright 2015 - 2017 Timothy J. Warren
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
|
* @version 4.0
|
||||||
|
* @link https://github.com/timw4mail/HummingBirdAnimeClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Aviat\AnimeClient\API;
|
||||||
|
|
||||||
|
use Aviat\Banker\Pool;
|
||||||
|
use Aviat\Ion\Di\ContainerAware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper methods for dealing with the Cache
|
||||||
|
*/
|
||||||
|
trait CacheTrait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Aviat\Banker\Pool
|
||||||
|
*/
|
||||||
|
protected $cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject the cache object
|
||||||
|
*
|
||||||
|
* @param Pool $cache
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setCache(Pool $cache): self
|
||||||
|
{
|
||||||
|
$this->cache = $cache;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a hash as a cache key from the current method call
|
||||||
|
*
|
||||||
|
* @param object $object
|
||||||
|
* @param string $method
|
||||||
|
* @param array $args
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getHashForMethodCall($object, string $method, array $args = []): string
|
||||||
|
{
|
||||||
|
$classname = get_class($object);
|
||||||
|
$keyObj = [
|
||||||
|
'class' => $classname,
|
||||||
|
'method' => $method,
|
||||||
|
'args' => $args,
|
||||||
|
];
|
||||||
|
$hash = sha1(json_encode($keyObj));
|
||||||
|
return $hash;
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@ use Aviat\AnimeClient\API\Kitsu\Enum\{
|
|||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constants and mappings for the Kitsu API
|
* Data massaging helpers for the Kitsu API
|
||||||
*/
|
*/
|
||||||
class Kitsu {
|
class Kitsu {
|
||||||
const AUTH_URL = 'https://kitsu.io/api/oauth/token';
|
const AUTH_URL = 'https://kitsu.io/api/oauth/token';
|
||||||
@ -45,6 +45,11 @@ class Kitsu {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of Kitsu Manga status to label for select menus
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public static function getStatusToMangaSelectMap()
|
public static function getStatusToMangaSelectMap()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@ -84,6 +89,78 @@ class Kitsu {
|
|||||||
return AnimeAiringStatus::NOT_YET_AIRED;
|
return AnimeAiringStatus::NOT_YET_AIRED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name and logo for the streaming service of the current link
|
||||||
|
*
|
||||||
|
* @param string $hostname
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected static function getServiceMetaData(string $hostname = null): array
|
||||||
|
{
|
||||||
|
switch($hostname)
|
||||||
|
{
|
||||||
|
case 'www.crunchyroll.com':
|
||||||
|
return [
|
||||||
|
'name' => 'Crunchyroll',
|
||||||
|
'link' => true,
|
||||||
|
'logo' => '<svg width="50" height="50" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"><g fill="#F78B24" fill-rule="evenodd"><path d="M22.549 49.145c-.815-.077-2.958-.456-3.753-.663-6.873-1.79-12.693-6.59-15.773-13.009C1.335 31.954.631 28.807.633 24.788c.003-4.025.718-7.235 2.38-10.686 1.243-2.584 2.674-4.609 4.706-6.66 3.8-3.834 8.614-6.208 14.067-6.936 1.783-.239 5.556-.161 7.221.148 3.463.642 6.571 1.904 9.357 3.797 5.788 3.934 9.542 9.951 10.52 16.861.21 1.48.332 4.559.19 4.816-.077.14-.117-.007-.167-.615-.25-3.015-1.528-6.66-3.292-9.388C40.253 7.836 30.249 4.32 20.987 7.467c-7.15 2.43-12.522 8.596-13.997 16.06-.73 3.692-.51 7.31.658 10.882a21.426 21.426 0 0 0 13.247 13.518c1.475.515 3.369.944 4.618 1.047 1.496.122 1.119.239-.727.224-1.006-.008-2.013-.032-2.237-.053z"></path><path d="M27.685 46.1c-7.731-.575-14.137-6.455-15.474-14.204-.243-1.41-.29-4.047-.095-5.345 1.16-7.706 6.97-13.552 14.552-14.639 1.537-.22 4.275-.143 5.746.162 1.28.266 2.7.737 3.814 1.266l.865.411-.814.392c-2.936 1.414-4.748 4.723-4.323 7.892.426 3.173 2.578 5.664 5.667 6.56 1.112.322 2.812.322 3.925 0 1.438-.417 2.566-1.1 3.593-2.173.346-.362.652-.621.68-.576.027.046.106.545.176 1.11.171 1.395.07 4.047-.204 5.371-.876 4.218-3.08 7.758-6.463 10.374-3.2 2.476-7.434 3.711-11.645 3.399z"></path></g></svg>'
|
||||||
|
];
|
||||||
|
|
||||||
|
case 'www.funimation.com':
|
||||||
|
return [
|
||||||
|
'name' => 'Funimation',
|
||||||
|
'link' => true,
|
||||||
|
'logo' => '<svg width="50" height="50" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"><path d="M24.066.017a24.922 24.922 0 0 1 13.302 3.286 25.098 25.098 0 0 1 7.833 7.058 24.862 24.862 0 0 1 4.207 9.575c.82 4.001.641 8.201-.518 12.117a24.946 24.946 0 0 1-4.868 9.009 24.98 24.98 0 0 1-7.704 6.118 24.727 24.727 0 0 1-10.552 2.718A24.82 24.82 0 0 1 13.833 47.3c-5.815-2.872-10.408-8.107-12.49-14.25-2.162-6.257-1.698-13.375 1.303-19.28C5.483 8.07 10.594 3.55 16.602 1.435A24.94 24.94 0 0 1 24.066.017zm-8.415 33.31c.464 2.284 1.939 4.358 3.99 5.48 2.174 1.217 4.765 1.444 7.202 1.181 2.002-.217 3.986-.992 5.455-2.397 1.173-1.151 2.017-2.648 2.33-4.267-1.189-.027-2.378 0-3.566-.03-.568.082-1.137-.048-1.705.014-1.232.012-2.465.003-3.697-.01-.655.066-1.309-.035-1.963.013-1.166-.053-2.334.043-3.5-.025-1.515.08-3.03-.035-4.546.042z" fill="#411299" fill-rule="evenodd"></path></svg>'
|
||||||
|
];
|
||||||
|
|
||||||
|
case 'www.hulu.com':
|
||||||
|
return [
|
||||||
|
'name' => 'Hulu',
|
||||||
|
'link' => true,
|
||||||
|
'logo' => '<svg width="50" height="50" viewBox="0 0 34 50" xmlns="http://www.w3.org/2000/svg"><path d="M22.222 13.889h-11.11V0H0v50h11.111V27.778c0-1.39 1.111-2.778 2.778-2.778h5.555c1.39 0 2.778 1.111 2.778 2.778V50h11.111V25c0-6.111-5-11.111-11.11-11.111z" fill="#8BC34A" fill-rule="evenodd"></path></svg>'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Default to Netflix, because the API links are broken,
|
||||||
|
// and there's no other real identifier for Netflix
|
||||||
|
default:
|
||||||
|
return [
|
||||||
|
'name' => 'Netflix',
|
||||||
|
'link' => false,
|
||||||
|
'logo' => '<svg width="50" height="50" viewBox="0 0 26 50" xmlns="http://www.w3.org/2000/svg"><path d="M.057.258C2.518.253 4.982.263 7.446.253c2.858 7.76 5.621 15.556 8.456 23.324.523 1.441 1.003 2.897 1.59 4.312.078-9.209.01-18.42.034-27.631h7.763v46.36c-2.812.372-5.637.627-8.457.957-1.203-3.451-2.396-6.902-3.613-10.348-1.796-5.145-3.557-10.302-5.402-15.428.129 8.954.015 17.912.057 26.871-2.603.39-5.227.637-7.815 1.119C.052 33.279.06 16.768.057.258z" fill="#E21221" fill-rule="evenodd"></path></svg>'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorganize streaming links
|
||||||
|
*
|
||||||
|
* @param array $included
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function parseStreamingLinks(array $included): array
|
||||||
|
{
|
||||||
|
if ( ! array_key_exists('streamingLinks', $included))
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$links = [];
|
||||||
|
|
||||||
|
foreach ($included['streamingLinks'] as $streamingLink)
|
||||||
|
{
|
||||||
|
$host = parse_url($streamingLink['url'], \PHP_URL_HOST);
|
||||||
|
|
||||||
|
$links[] = [
|
||||||
|
'meta' => static::getServiceMetaData($host),
|
||||||
|
'link' => $streamingLink['url'],
|
||||||
|
'subs' => $streamingLink['subs'],
|
||||||
|
'dubs' => $streamingLink['dubs']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $links;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter out duplicate and very similar names from
|
* Filter out duplicate and very similar names from
|
||||||
@ -110,66 +187,6 @@ class Kitsu {
|
|||||||
return $valid;
|
return $valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reorganizes 'included' data to be keyed by
|
|
||||||
* type => [
|
|
||||||
* id => data/attributes,
|
|
||||||
* ]
|
|
||||||
*
|
|
||||||
* @param array $includes
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function organizeIncludes(array $includes): array
|
|
||||||
{
|
|
||||||
$organized = [];
|
|
||||||
|
|
||||||
foreach ($includes as $item)
|
|
||||||
{
|
|
||||||
$type = $item['type'];
|
|
||||||
$id = $item['id'];
|
|
||||||
$organized[$type] = $organized[$type] ?? [];
|
|
||||||
$organized[$type][$id] = $item['attributes'];
|
|
||||||
|
|
||||||
if (array_key_exists('relationships', $item))
|
|
||||||
{
|
|
||||||
$organized[$type][$id]['relationships'] = self::organizeRelationships($item['relationships']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $organized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reorganize relationship mappings to make them simpler to use
|
|
||||||
*
|
|
||||||
* Remove verbose structure, and just map:
|
|
||||||
* type => [ idArray ]
|
|
||||||
*
|
|
||||||
* @param array $relationships
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function organizeRelationships(array $relationships): array
|
|
||||||
{
|
|
||||||
$organized = [];
|
|
||||||
|
|
||||||
foreach($relationships as $key => $data)
|
|
||||||
{
|
|
||||||
if ( ! array_key_exists('data', $data))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$organized[$key] = $organized[$key] ?? [];
|
|
||||||
|
|
||||||
foreach ($data['data'] as $item)
|
|
||||||
{
|
|
||||||
$organized[$key][] = $item['id'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $organized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if an alternate title is unique enough to list
|
* Determine if an alternate title is unique enough to list
|
||||||
*
|
*
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu;
|
namespace Aviat\AnimeClient\API\Kitsu;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\API\CacheTrait;
|
||||||
use Aviat\AnimeClient\API\JsonAPI;
|
use Aviat\AnimeClient\API\JsonAPI;
|
||||||
use Aviat\AnimeClient\API\Kitsu as K;
|
use Aviat\AnimeClient\API\Kitsu as K;
|
||||||
use Aviat\AnimeClient\API\Kitsu\Transformer\{
|
use Aviat\AnimeClient\API\Kitsu\Transformer\{
|
||||||
@ -29,6 +30,7 @@ use GuzzleHttp\Exception\ClientException;
|
|||||||
* Kitsu API Model
|
* Kitsu API Model
|
||||||
*/
|
*/
|
||||||
class KitsuModel {
|
class KitsuModel {
|
||||||
|
use CacheTrait;
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
use KitsuTrait;
|
use KitsuTrait;
|
||||||
|
|
||||||
@ -60,6 +62,7 @@ class KitsuModel {
|
|||||||
* @var MangaListTransformer
|
* @var MangaListTransformer
|
||||||
*/
|
*/
|
||||||
protected $mangaListTransformer;
|
protected $mangaListTransformer;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* KitsuModel constructor.
|
* KitsuModel constructor.
|
||||||
@ -131,6 +134,7 @@ class KitsuModel {
|
|||||||
*/
|
*/
|
||||||
public function getAnime(string $animeId): array
|
public function getAnime(string $animeId): array
|
||||||
{
|
{
|
||||||
|
// @TODO catch non-existent anime
|
||||||
$baseData = $this->getRawMediaData('anime', $animeId);
|
$baseData = $this->getRawMediaData('anime', $animeId);
|
||||||
return $this->animeTransformer->transform($baseData);
|
return $this->animeTransformer->transform($baseData);
|
||||||
}
|
}
|
||||||
@ -147,7 +151,13 @@ class KitsuModel {
|
|||||||
return $this->mangaTransformer->transform($baseData);
|
return $this->mangaTransformer->transform($baseData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAnimeList($status): array
|
/**
|
||||||
|
* Get the anime list for the configured user
|
||||||
|
*
|
||||||
|
* @param string $status - The watching status to filter the list with
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAnimeList(string $status): array
|
||||||
{
|
{
|
||||||
$options = [
|
$options = [
|
||||||
'query' => [
|
'query' => [
|
||||||
@ -156,26 +166,33 @@ class KitsuModel {
|
|||||||
'media_type' => 'Anime',
|
'media_type' => 'Anime',
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
],
|
],
|
||||||
'include' => 'media,media.genres,media.mappings',
|
'include' => 'media,media.genres,media.mappings,anime.streamingLinks',
|
||||||
'page' => [
|
'page' => [
|
||||||
'offset' => 0,
|
'offset' => 0,
|
||||||
'limit' => 500
|
'limit' => 500
|
||||||
],
|
]
|
||||||
'sort' => '-updated_at'
|
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
$data = $this->getRequest('library-entries', $options);
|
$cacheItem = $this->cache->getItem($this->getHashForMethodCall($this, __METHOD__, $options));
|
||||||
$included = JsonAPI::organizeIncludes($data['included']);
|
|
||||||
$included = JsonAPI::inlineIncludedRelationships($included, 'anime');
|
if ( ! $cacheItem->isHit())
|
||||||
|
|
||||||
foreach($data['data'] as $i => &$item)
|
|
||||||
{
|
{
|
||||||
$item['included'] =& $included;
|
$data = $this->getRequest('library-entries', $options);
|
||||||
}
|
$included = JsonAPI::organizeIncludes($data['included']);
|
||||||
$transformed = $this->animeListTransformer->transformCollection($data['data']);
|
$included = JsonAPI::inlineIncludedRelationships($included, 'anime');
|
||||||
|
|
||||||
return $transformed;
|
foreach($data['data'] as $i => &$item)
|
||||||
|
{
|
||||||
|
$item['included'] = $included;
|
||||||
|
}
|
||||||
|
$transformed = $this->animeListTransformer->transformCollection($data['data']);
|
||||||
|
|
||||||
|
$cacheItem->set($transformed);
|
||||||
|
$cacheItem->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cacheItem->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMangaList($status): array
|
public function getMangaList($status): array
|
||||||
@ -242,19 +259,24 @@ class KitsuModel {
|
|||||||
public function getListItem(string $listId): array
|
public function getListItem(string $listId): array
|
||||||
{
|
{
|
||||||
$baseData = $this->listItem->get($listId);
|
$baseData = $this->listItem->get($listId);
|
||||||
|
$included = JsonAPI::organizeIncludes($baseData['included']);
|
||||||
|
|
||||||
switch ($baseData['included'][0]['type'])
|
|
||||||
|
switch (TRUE)
|
||||||
{
|
{
|
||||||
case 'anime':
|
case in_array('anime', array_keys($included)):
|
||||||
$baseData['data']['anime'] = $baseData['included'][0];
|
$included = JsonAPI::inlineIncludedRelationships($included, 'anime');
|
||||||
|
$baseData['data']['included'] = $included;
|
||||||
return $this->animeListTransformer->transform($baseData['data']);
|
return $this->animeListTransformer->transform($baseData['data']);
|
||||||
|
|
||||||
case 'manga':
|
case in_array('manga', array_keys($included)):
|
||||||
|
$included = JsonAPI::inlineIncludedRelationships($included, 'manga');
|
||||||
|
$baseData['data']['included'] = $included;
|
||||||
$baseData['data']['manga'] = $baseData['included'][0];
|
$baseData['data']['manga'] = $baseData['included'][0];
|
||||||
return $this->mangaListTransformer->transform($baseData['data']);
|
return $this->mangaListTransformer->transform($baseData['data']);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return $baseData['data']['attributes'];
|
return $baseData['data'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ class ListItem extends AbstractListItem {
|
|||||||
|
|
||||||
public function create(array $data): bool
|
public function create(array $data): bool
|
||||||
{
|
{
|
||||||
/*?><pre><?= print_r($data, TRUE) ?></pre><?php */
|
|
||||||
$response = $this->getResponse('POST', 'library-entries', [
|
$response = $this->getResponse('POST', 'library-entries', [
|
||||||
'body' => Json::encode([
|
'body' => Json::encode([
|
||||||
'data' => [
|
'data' => [
|
||||||
@ -77,7 +76,7 @@ class ListItem extends AbstractListItem {
|
|||||||
{
|
{
|
||||||
return $this->getRequest("library-entries/{$id}", [
|
return $this->getRequest("library-entries/{$id}", [
|
||||||
'query' => [
|
'query' => [
|
||||||
'include' => 'media'
|
'include' => 'media,media.genres,media.mappings'
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -33,28 +33,30 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
*/
|
*/
|
||||||
public function transform($item)
|
public function transform($item)
|
||||||
{
|
{
|
||||||
$included = $item['included'] ?? [];
|
/* ?><pre><?= json_encode($item, \JSON_PRETTY_PRINT) ?></pre><?php */
|
||||||
|
$included = $item['included'];
|
||||||
$animeId = $item['relationships']['media']['data']['id'];
|
$animeId = $item['relationships']['media']['data']['id'];
|
||||||
$anime = $included['anime'][$animeId] ?? $item['anime'];
|
$anime = $included['anime'][$animeId];
|
||||||
$genres = array_column($anime['relationships']['genres'], 'name') ?? [];
|
|
||||||
|
|
||||||
|
$genres = array_column($anime['relationships']['genres'], 'name') ?? [];
|
||||||
|
sort($genres);
|
||||||
|
|
||||||
$rating = (int) 2 * $item['attributes']['rating'];
|
$rating = (int) 2 * $item['attributes']['rating'];
|
||||||
|
|
||||||
$total_episodes = array_key_exists('episodeCount', $anime) && (int) $anime['episodeCount'] !== 0
|
$total_episodes = array_key_exists('episodeCount', $anime) && (int) $anime['episodeCount'] !== 0
|
||||||
? (int) $anime['episodeCount']
|
? (int) $anime['episodeCount']
|
||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
$progress = (int) $item['attributes']['progress'] ?? '-';
|
|
||||||
|
|
||||||
$MALid = NULL;
|
$MALid = NULL;
|
||||||
|
|
||||||
if (array_key_exists('mappings', $included))
|
if (array_key_exists('mappings', $anime['relationships']))
|
||||||
{
|
{
|
||||||
foreach ($included['mappings'] as $mapping)
|
foreach ($anime['relationships']['mappings'] as $mapping)
|
||||||
{
|
{
|
||||||
if ($mapping['externalSite'] === 'myanimelist/anime')
|
if ($mapping['externalSite'] === 'myanimelist/anime')
|
||||||
{
|
{
|
||||||
$MALid = $mapping['externalId'];
|
$MALid = $mapping['externalId'];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,7 +65,9 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
'mal_id' => $MALid,
|
'mal_id' => $MALid,
|
||||||
'episodes' => [
|
'episodes' => [
|
||||||
'watched' => $item['attributes']['progress'],
|
'watched' => (int) $item['attributes']['progress'] !== '0'
|
||||||
|
? (int) $item['attributes']['progress']
|
||||||
|
: '-',
|
||||||
'total' => $total_episodes,
|
'total' => $total_episodes,
|
||||||
'length' => $anime['episodeLength'],
|
'length' => $anime['episodeLength'],
|
||||||
],
|
],
|
||||||
@ -79,6 +83,7 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
'type' => $this->string($anime['showType'])->upperCaseFirst()->__toString(),
|
'type' => $this->string($anime['showType'])->upperCaseFirst()->__toString(),
|
||||||
'image' => $anime['posterImage']['small'],
|
'image' => $anime['posterImage']['small'],
|
||||||
'genres' => $genres,
|
'genres' => $genres,
|
||||||
|
'streaming_links' => Kitsu::parseStreamingLinks($included),
|
||||||
],
|
],
|
||||||
'watching_status' => $item['attributes']['status'],
|
'watching_status' => $item['attributes']['status'],
|
||||||
'notes' => $item['attributes']['notes'],
|
'notes' => $item['attributes']['notes'],
|
||||||
|
@ -36,12 +36,15 @@ class AnimeTransformer extends AbstractTransformer {
|
|||||||
$item['included'] = JsonAPI::organizeIncludes($item['included']);
|
$item['included'] = JsonAPI::organizeIncludes($item['included']);
|
||||||
$item['genres'] = array_column($item['included']['genres'], 'name') ?? [];
|
$item['genres'] = array_column($item['included']['genres'], 'name') ?? [];
|
||||||
sort($item['genres']);
|
sort($item['genres']);
|
||||||
|
|
||||||
|
$titles = Kitsu::filterTitles($item);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'titles' => Kitsu::filterTitles($item),
|
'title' => $titles[0],
|
||||||
|
'titles' => $titles,
|
||||||
'status' => Kitsu::getAiringStatus($item['startDate'], $item['endDate']),
|
'status' => Kitsu::getAiringStatus($item['startDate'], $item['endDate']),
|
||||||
'cover_image' => $item['posterImage']['small'],
|
'cover_image' => $item['posterImage']['small'],
|
||||||
'show_type' => $item['showType'],
|
'show_type' => $this->string($item['showType'])->upperCaseFirst()->__toString(),
|
||||||
'episode_count' => $item['episodeCount'],
|
'episode_count' => $item['episodeCount'],
|
||||||
'episode_length' => $item['episodeLength'],
|
'episode_length' => $item['episodeLength'],
|
||||||
'synopsis' => $item['synopsis'],
|
'synopsis' => $item['synopsis'],
|
||||||
@ -49,7 +52,7 @@ class AnimeTransformer extends AbstractTransformer {
|
|||||||
'age_rating_guide' => $item['ageRatingGuide'],
|
'age_rating_guide' => $item['ageRatingGuide'],
|
||||||
'url' => "https://kitsu.io/anime/{$item['slug']}",
|
'url' => "https://kitsu.io/anime/{$item['slug']}",
|
||||||
'genres' => $item['genres'],
|
'genres' => $item['genres'],
|
||||||
'included' => $item['included']
|
'streaming_links' => Kitsu::parseStreamingLinks($item['included'])
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,108 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
/**
|
|
||||||
* Anime List Client
|
|
||||||
*
|
|
||||||
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
|
||||||
*
|
|
||||||
* PHP version 7
|
|
||||||
*
|
|
||||||
* @package AnimeListClient
|
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2017 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
|
||||||
* @version 4.0
|
|
||||||
* @link https://github.com/timw4mail/HummingBirdAnimeClient
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\MAL;
|
|
||||||
|
|
||||||
use Aviat\AnimeClient\AnimeClient;
|
|
||||||
use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MAL API Authentication
|
|
||||||
*/
|
|
||||||
class Auth {
|
|
||||||
|
|
||||||
use \Aviat\Ion\Di\ContainerAware;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Anime API Model
|
|
||||||
*
|
|
||||||
* @var \Aviat\AnimeClient\Model\API
|
|
||||||
*/
|
|
||||||
protected $model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Session object
|
|
||||||
*
|
|
||||||
* @var Aura\Session\Segment
|
|
||||||
*/
|
|
||||||
protected $segment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param ContainerInterface $container
|
|
||||||
*/
|
|
||||||
public function __construct(ContainerInterface $container)
|
|
||||||
{
|
|
||||||
$this->setContainer($container);
|
|
||||||
$this->segment = $container->get('session')
|
|
||||||
->getSegment(AnimeClient::SESSION_SEGMENT);
|
|
||||||
$this->model = $container->get('api-model');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make the appropriate authentication call,
|
|
||||||
* and save the resulting auth token if successful
|
|
||||||
*
|
|
||||||
* @param string $password
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function authenticate($password)
|
|
||||||
{
|
|
||||||
$username = $this->container->get('config')
|
|
||||||
->get('hummingbird_username');
|
|
||||||
$auth_token = $this->model->authenticate($username, $password);
|
|
||||||
|
|
||||||
if (FALSE !== $auth_token)
|
|
||||||
{
|
|
||||||
$this->segment->set('auth_token', $auth_token);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the current user is authenticated
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function is_authenticated()
|
|
||||||
{
|
|
||||||
return ($this->get_auth_token() !== FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear authentication values
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function logout()
|
|
||||||
{
|
|
||||||
$this->segment->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the authentication token from the session
|
|
||||||
*
|
|
||||||
* @return string|false
|
|
||||||
*/
|
|
||||||
public function get_auth_token()
|
|
||||||
{
|
|
||||||
return $this->segment->get('auth_token', FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// End of KitsuAuth.php
|
|
@ -24,6 +24,7 @@ use Aviat\Ion\Di\ContainerAware;
|
|||||||
*/
|
*/
|
||||||
class ListItem extends AbstractListItem {
|
class ListItem extends AbstractListItem {
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
|
use MALTrait;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@ -47,6 +48,6 @@ class ListItem extends AbstractListItem {
|
|||||||
|
|
||||||
public function update(string $id, array $data): Response
|
public function update(string $id, array $data): Response
|
||||||
{
|
{
|
||||||
// @TODO implement
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,29 +17,50 @@
|
|||||||
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\{
|
||||||
|
AnimeListTransformer,
|
||||||
|
ListItem
|
||||||
|
};
|
||||||
|
use Aviat\AnimeClient\API\XML;
|
||||||
use Aviat\Ion\Di\ContainerAware;
|
use Aviat\Ion\Di\ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MyAnimeList API Model
|
* MyAnimeList API Model
|
||||||
*/
|
*/
|
||||||
class Model {
|
class Model {
|
||||||
|
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
use MALTrait;
|
use MALTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var AnimeListTransformer
|
||||||
|
*/
|
||||||
|
protected $animeListTransformer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KitsuModel constructor.
|
||||||
|
*/
|
||||||
|
public function __construct(ListItem $listItem)
|
||||||
|
{
|
||||||
|
// Set up Guzzle trait
|
||||||
|
$this->init();
|
||||||
|
$this->animeListTransformer = new AnimeListTransformer();
|
||||||
|
$this->listItem = $listItem;
|
||||||
|
}
|
||||||
|
|
||||||
public function createListItem(array $data): bool
|
public function createListItem(array $data): bool
|
||||||
{
|
{
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getListItem(string $listId): array
|
public function getListItem(string $listId): array
|
||||||
{
|
{
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateListItem(array $data)
|
public function updateListItem(array $data)
|
||||||
{
|
{
|
||||||
|
$updateData = $this->animeListTransformer->transform($data['data']);
|
||||||
|
return $this->listItem->update($data['mal_id'], $updateData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteListItem(string $id): bool
|
public function deleteListItem(string $id): bool
|
||||||
|
Loading…
Reference in New Issue
Block a user