diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce2c5c1b..799612aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,8 @@
# Changelog
## Version 4
-* Updated to use Kitsu API after discontinuation of Hummingbird
+* Updated to use Kitsu API after discontinuation of Hummingbird
+* Added streaming links to list entries from the Kitsu API
## Version 3
* Converted user configuration to toml files
diff --git a/console b/console
index fb116f0a..638f9bcc 100755
--- a/console
+++ b/console
@@ -34,8 +34,8 @@ unset($CONF_DIR);
// Start console script
// ---------------------------------------------------------------------------------------------------------------------
$console = new \ConsoleKit\Console([
- 'cache-images' => '\Aviat\AnimeClient\Command\CacheImages',
'clear-cache' => '\Aviat\AnimeClient\Command\ClearCache',
+ 'sync-lists' => '\Aviat\AnimeClient\Command\SyncKitsuWithMal'
]);
$console->run();
\ No newline at end of file
diff --git a/public/css/base.css b/public/css/base.css
index c3bcb7b6..2192edcb 100644
--- a/public/css/base.css
+++ b/public/css/base.css
@@ -1307,4 +1307,13 @@ a:hover, a:active {
padding:0 0,5em 0.5em;
padding:0 0.5rem 0.5rem;
}
+}
+
+/* ----------------------------------------------------------------------------
+ Images / Logos
+-----------------------------------------------------------------------------*/
+
+.streaming-logo {
+ width: 50px;
+ height: 50px;
}
\ No newline at end of file
diff --git a/public/css/base.myth.css b/public/css/base.myth.css
index 3f481fb7..eabbf71b 100644
--- a/public/css/base.myth.css
+++ b/public/css/base.myth.css
@@ -560,4 +560,12 @@ a:hover, a:active {
padding:0 0,5em 0.5em;
padding:0 0.5rem 0.5rem;
}
+}
+
+/* ----------------------------------------------------------------------------
+ Images / Logos
+-----------------------------------------------------------------------------*/
+.streaming-logo {
+ width: 50px;
+ height: 50px;
}
\ No newline at end of file
diff --git a/src/API/Kitsu.php b/src/API/Kitsu.php
index e83c0be4..98378e5e 100644
--- a/src/API/Kitsu.php
+++ b/src/API/Kitsu.php
@@ -28,6 +28,8 @@ use DateTimeImmutable;
*/
class Kitsu {
const AUTH_URL = 'https://kitsu.io/api/oauth/token';
+ const AUTH_USER_ID_KEY = 'kitsu-auth-userid';
+ const AUTH_TOKEN_CACHE_KEY = 'kitsu-auth-token';
/**
* Map of Kitsu status to label for select menus
@@ -104,21 +106,21 @@ class Kitsu {
return [
'name' => 'Crunchyroll',
'link' => true,
- 'logo' => ''
+ 'logo' => ''
];
case 'www.funimation.com':
return [
'name' => 'Funimation',
'link' => true,
- 'logo' => ''
+ 'logo' => ''
];
case 'www.hulu.com':
return [
'name' => 'Hulu',
'link' => true,
- 'logo' => ''
+ 'logo' => ''
];
// Default to Netflix, because the API links are broken,
@@ -127,7 +129,7 @@ class Kitsu {
return [
'name' => 'Netflix',
'link' => false,
- 'logo' => ''
+ 'logo' => ''
];
}
}
diff --git a/src/API/Kitsu/Auth.php b/src/API/Kitsu/Auth.php
index 04e2e395..70691eb1 100644
--- a/src/API/Kitsu/Auth.php
+++ b/src/API/Kitsu/Auth.php
@@ -17,6 +17,10 @@
namespace Aviat\AnimeClient\API\Kitsu;
use Aviat\AnimeClient\AnimeClient;
+use Aviat\AnimeClient\API\{
+ CacheTrait,
+ Kitsu as K
+};
use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
use Exception;
@@ -24,7 +28,7 @@ use Exception;
* Kitsu API Authentication
*/
class Auth {
-
+ use CacheTrait;
use ContainerAware;
/**
@@ -49,6 +53,7 @@ class Auth {
public function __construct(ContainerInterface $container)
{
$this->setContainer($container);
+ $this->setCache($container->get('cache'));
$this->segment = $container->get('session')
->getSegment(AnimeClient::SESSION_SEGMENT);
$this->model = $container->get('kitsu-model');
@@ -68,7 +73,7 @@ class Auth {
try
{
- $auth_token = $this->model->authenticate($username, $password);
+ $auth = $this->model->authenticate($username, $password);
}
catch (Exception $e)
{
@@ -76,9 +81,14 @@ class Auth {
}
- if (FALSE !== $auth_token)
+ if (FALSE !== $auth)
{
- $this->segment->set('auth_token', $auth_token);
+ // Set the token in the cache for command line operations
+ $cacheItem = $this->cache->getItem(K::AUTH_TOKEN_CACHE_KEY);
+ $cacheItem->set($auth['access_token']);
+ $cacheItem->save();
+
+ $this->segment->set('auth_token', $auth['access_token']);
return TRUE;
}
diff --git a/src/API/Kitsu/Model.php b/src/API/Kitsu/Model.php
index 0d1a0c02..fb2e90c3 100644
--- a/src/API/Kitsu/Model.php
+++ b/src/API/Kitsu/Model.php
@@ -20,7 +20,10 @@ use Aviat\AnimeClient\API\CacheTrait;
use Aviat\AnimeClient\API\JsonAPI;
use Aviat\AnimeClient\API\Kitsu as K;
use Aviat\AnimeClient\API\Kitsu\Transformer\{
- AnimeTransformer, AnimeListTransformer, MangaTransformer, MangaListTransformer
+ AnimeTransformer,
+ AnimeListTransformer,
+ MangaTransformer,
+ MangaListTransformer
};
use Aviat\Ion\Di\ContainerAware;
use Aviat\Ion\Json;
@@ -85,9 +88,14 @@ class Model {
* @param string $username
* @return string
*/
- public function getUserIdByUsername(string $username)
+ public function getUserIdByUsername(string $username = NULL)
{
- $cacheItem = $this->cache->getItem($this->getHashForMethodCall($this, __METHOD__, [$username]));
+ if (is_null($username))
+ {
+ $username = $this->getUsername();
+ }
+
+ $cacheItem = $this->cache->getItem(K::AUTH_USER_ID_KEY);
if ( ! $cacheItem->isHit())
{
@@ -128,7 +136,7 @@ class Model {
if (array_key_exists('access_token', $data))
{
- return $data['access_token'];
+ return $data;
}
return false;
@@ -170,16 +178,16 @@ class Model {
$baseData = $this->getRawMediaData('manga', $mangaId);
return $this->mangaTransformer->transform($baseData);
}
-
+
/**
- * Get the anime list for the configured user
+ * Get the raw (unorganized) anime list for the configured user
*
* @param string $status - The watching status to filter the list with
* @param int $limit - The number of list entries to fetch for a page
* @param int $offset - The page offset
* @return array
*/
- public function getAnimeList(string $status, int $limit = 600, int $offset = 0): array
+ public function getRawAnimeList(string $status, int $limit = 600, int $offset = 0): array
{
$options = [
'query' => [
@@ -192,15 +200,29 @@ class Model {
'page' => [
'offset' => $offset,
'limit' => $limit
- ]
+ ],
+ 'sort' => '-updated_at'
]
];
- $cacheItem = $this->cache->getItem($this->getHashForMethodCall($this, __METHOD__, $options));
+ return $this->getRequest('library-entries', $options);
+ }
+
+ /**
+ * Get the anime list for the configured user
+ *
+ * @param string $status - The watching status to filter the list with
+ * @param int $limit - The number of list entries to fetch for a page
+ * @param int $offset - The page offset
+ * @return array
+ */
+ public function getAnimeList(string $status, int $limit = 600, int $offset = 0): array
+ {
+ $cacheItem = $this->cache->getItem($this->getHashForMethodCall($this, __METHOD__, [$status]));
if ( ! $cacheItem->isHit())
{
- $data = $this->getRequest('library-entries', $options);
+ $data = $this->getRawAnimeList($status, $limit, $offset);
$included = JsonAPI::organizeIncludes($data['included']);
$included = JsonAPI::inlineIncludedRelationships($included, 'anime');
diff --git a/src/Command/BaseCommand.php b/src/Command/BaseCommand.php
index fecb2131..e929578f 100644
--- a/src/Command/BaseCommand.php
+++ b/src/Command/BaseCommand.php
@@ -22,20 +22,30 @@ use Aviat\AnimeClient\{
Model,
Util
};
-use Aviat\AnimeClient\Auth\HummingbirdAuth;
+use Aviat\AnimeClient\API\CacheTrait;
+use Aviat\AnimeClient\API\Kitsu\{
+ Auth as KitsuAuth,
+ ListItem as KitsuListItem,
+ Model as KitsuModel
+};
+use Aviat\AnimeClient\API\MAL\{
+ ListItem as MALListItem,
+ Model as MALModel
+};
use Aviat\Banker\Pool;
use Aviat\Ion\Config;
-use Aviat\Ion\Di\Container;
+use Aviat\Ion\Di\{Container, ContainerAware};
use ConsoleKit\Command;
use ConsoleKit\Widgets\Box;
-use Monolog\Handler\RotatingFileHandler;
+use Monolog\Handler\NullHandler;
use Monolog\Logger;
/**
* Base class for console command setup
*/
class BaseCommand extends Command {
- use \Aviat\Ion\Di\ContainerAware;
+ use CacheTrait;
+ use ContainerAware;
/**
* Echo text in a box
@@ -68,9 +78,16 @@ class BaseCommand extends Command {
$di = function ($config_array) use ($APP_DIR) {
$container = new Container();
+ // -------------------------------------------------------------------------
+ // Logging
+ // -------------------------------------------------------------------------
+
$app_logger = new Logger('animeclient');
- $app_logger->pushHandler(new RotatingFileHandler("{$APP_DIR}/logs/app.log", Logger::NOTICE));
+ $app_logger->pushHandler(new NullHandler);
+ $request_logger = new Logger('request');
+ $request_logger->pushHandler(new NullHandler);
$container->setLogger($app_logger, 'default');
+ $container->setLogger($request_logger, 'request');
// Create Config Object
$container->set('config', function() use ($config_array) {
@@ -90,18 +107,21 @@ class BaseCommand extends Command {
});
// Models
- $container->set('api-model', function($container) {
- return new Model\API($container);
+ $container->set('kitsu-model', function($container) {
+ $listItem = new KitsuListItem();
+ $listItem->setContainer($container);
+ $model = new KitsuModel($listItem);
+ $model->setContainer($container);
+ $cache = $container->get('cache');
+ $model->setCache($cache);
+ return $model;
});
- $container->set('anime-model', function($container) {
- return new Model\Anime($container);
- });
- $container->set('manga-model', function($container) {
- return new Model\Manga($container);
- });
-
- $container->set('auth', function($container) {
- return new HummingbirdAuth($container);
+ $container->set('mal-model', function($container) {
+ $listItem = new MALListItem();
+ $listItem->setContainer($container);
+ $model = new MALModel($listItem);
+ $model->setContainer($container);
+ return $model;
});
$container->set('util', function($container) {
return new Util($container);
diff --git a/src/Command/SyncKitsuWithMal.php b/src/Command/SyncKitsuWithMal.php
new file mode 100644
index 00000000..93a714c2
--- /dev/null
+++ b/src/Command/SyncKitsuWithMal.php
@@ -0,0 +1,86 @@
+
+ * @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\Command;
+
+use Amp\Artax;
+use Aviat\AnimeClient\API\Kitsu;
+
+/**
+ * Clears the API Cache
+ */
+class SyncKitsuWithMal extends BaseCommand {
+
+ protected $kitsuModel;
+
+ public function getKitsuAnimeListPageCount()
+ {
+ $cacheItem = $this->cache->getItem(Kitsu::AUTH_TOKEN_CACHE_KEY);
+
+ $query = http_build_query([
+ 'filter' => [
+ 'user_id' => $this->kitsuModel->getUserIdByUsername(),
+ 'media_type' => 'Anime'
+ ],
+ 'include' => 'anime,anime.genres,anime.mappings,anime.streamingLinks',
+ 'page' => [
+ 'limit' => 1
+ ],
+ 'sort' => '-updated_at'
+ ]);
+ $request = (new Artax\Request)
+ ->setUri("https://kitsu.io/api/edge/library-entries?{$query}")
+ ->setProtocol('1.1')
+ ->setAllHeaders([
+ 'Accept' => 'application/vnd.api+json',
+ 'Content-Type' => 'application/vnd.api+json',
+ 'User-Agent' => "Tim's Anime Client/4.0"
+ ]);
+
+ if ($cacheItem->isHit())
+ {
+ $token = $cacheItem->get();
+ $request->setHeader('Authorization', "bearer {$token}");
+ }
+ else
+ {
+ $this->echoBox("WARNING: NOT LOGGED IN\nSome data might be missing");
+ }
+
+ $response = \Amp\wait((new Artax\Client)->request($request));
+
+ $body = json_decode($response->getBody(), TRUE);
+ return $body['meta']['count'];
+ }
+
+ /**
+ * Run the image conversion script
+ *
+ * @param array $args
+ * @param array $options
+ * @return void
+ * @throws \ConsoleKit\ConsoleException
+ */
+ public function execute(array $args, array $options = [])
+ {
+ $this->setContainer($this->setupContainer());
+ $this->setCache($this->container->get('cache'));
+ $this->kitsuModel = $this->container->get('kitsu-model');
+
+ $kitsuCount = $this->getKitsuAnimeListPageCount();
+ $this->echoBox("List item count: {$kitsuCount}");
+ }
+}
diff --git a/tests/RequirementsTest.php b/tests/RequirementsTest.php
index 7c8c3bce..9b5ef3e8 100644
--- a/tests/RequirementsTest.php
+++ b/tests/RequirementsTest.php
@@ -7,16 +7,6 @@ class RequirementsTest extends AnimeClient_TestCase {
$this->assertTrue(version_compare(PHP_VERSION, "5.4", "ge"));
}
- public function testHasGd()
- {
- $this->assertTrue(extension_loaded('gd'));
- }
-
- public function testHasMcrypt()
- {
- $this->assertTrue(extension_loaded('mcrypt'));
- }
-
public function testHasPDO()
{
$this->assertTrue(class_exists('PDO'));
diff --git a/tests/test_data/Kitsu/animeAfterTransform.json b/tests/test_data/Kitsu/animeAfterTransform.json
index af3e16ca..19230fe7 100644
--- a/tests/test_data/Kitsu/animeAfterTransform.json
+++ b/tests/test_data/Kitsu/animeAfterTransform.json
@@ -15,7 +15,7 @@
"meta": {
"name": "Crunchyroll",
"link": true,
- "logo": "