From 602759b471295bbd6e4dcd412941664872eb856f Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Thu, 17 Sep 2015 23:11:18 -0400 Subject: [PATCH] Decouple and generalise --- app/bootstrap.php | 94 +- app/config/base_config.php | 3 + app/config/routes.php | 124 +- app/views/anime/cover.php | 14 +- app/views/header.php | 6 +- app/views/manga/cover.php | 11 +- app/views/message.php | 4 +- composer.json | 4 +- index.php | 7 +- .../AnimeClient/Auth/HummingbirdAuth.php | 50 + src/Aviat/AnimeClient/Container.php | 6 +- src/Aviat/AnimeClient/Controller.php | 153 +- src/Aviat/AnimeClient/Controller/Anime.php | 7 +- .../AnimeClient/Controller/Collection.php | 4 +- src/Aviat/AnimeClient/Controller/Manga.php | 8 +- src/Aviat/AnimeClient/Controller/Stats.php | 2 +- src/Aviat/AnimeClient/Model.php | 3 +- src/Aviat/AnimeClient/Model/API.php | 7 +- src/Aviat/AnimeClient/Model/Anime.php | 8 +- .../AnimeClient/Model/AnimeCollection.php | 4 +- src/Aviat/AnimeClient/Model/DB.php | 7 +- src/Aviat/AnimeClient/Model/Manga.php | 6 +- src/Aviat/AnimeClient/Model/Stats.php | 11 +- src/Aviat/AnimeClient/Router.php | 13 +- src/Aviat/AnimeClient/RoutingBase.php | 4 +- .../Hummingbird/AnimeListTransformer.php | 15 + .../Hummingbird/MangaListsZipper.php | 78 + src/Aviat/AnimeClient/UrlGenerator.php | 2 +- src/Aviat/Ion/Base/Container.php | 54 - src/Aviat/Ion/Di/Container.php | 82 ++ src/Aviat/Ion/Di/ContainerAware.php | 36 + src/Aviat/Ion/Di/ContainerAwareInterface.php | 23 + src/Aviat/Ion/Di/ContainerInterface.php | 15 + .../Ion/Di/Exception/ContainerException.php | 10 + .../Ion/Di/Exception/NotFoundException.php | 10 + src/Aviat/Ion/View.php | 105 ++ src/Aviat/Ion/View/HtmlView.php | 50 + src/Aviat/Ion/View/HttpView.php | 36 + src/Aviat/Ion/View/JsonView.php | 32 + tests/AnimeClient/BaseModelTest.php | 1 - tests/AnimeClient/ControllerTest.php | 3 - tests/AnimeClient/Model/BaseApiModelTest.php | 3 +- tests/AnimeClient/RouterTest.php | 2 - .../Transformer/MangaListsZipperTest.php | 24 + tests/bootstrap.php | 44 +- .../anime-watching-transformed.json | 0 .../test_data/anime_list/anime-watching.json | 797 ++++++++++ .../manga_list/manga-transformed.json | 0 .../test_data/manga_list/manga-zippered.json | 1 + tests/test_data/manga_list/manga.json | 1288 +++++++++++++++++ 50 files changed, 2876 insertions(+), 395 deletions(-) create mode 100644 src/Aviat/AnimeClient/Auth/HummingbirdAuth.php create mode 100644 src/Aviat/AnimeClient/Transformer/Hummingbird/AnimeListTransformer.php create mode 100644 src/Aviat/AnimeClient/Transformer/Hummingbird/MangaListsZipper.php delete mode 100644 src/Aviat/Ion/Base/Container.php create mode 100644 src/Aviat/Ion/Di/Container.php create mode 100644 src/Aviat/Ion/Di/ContainerAware.php create mode 100644 src/Aviat/Ion/Di/ContainerAwareInterface.php create mode 100644 src/Aviat/Ion/Di/ContainerInterface.php create mode 100644 src/Aviat/Ion/Di/Exception/ContainerException.php create mode 100644 src/Aviat/Ion/Di/Exception/NotFoundException.php create mode 100644 src/Aviat/Ion/View.php create mode 100644 src/Aviat/Ion/View/HtmlView.php create mode 100644 src/Aviat/Ion/View/HttpView.php create mode 100644 src/Aviat/Ion/View/JsonView.php create mode 100644 tests/AnimeClient/Transformer/MangaListsZipperTest.php create mode 100644 tests/test_data/anime_list/anime-watching-transformed.json create mode 100644 tests/test_data/anime_list/anime-watching.json create mode 100644 tests/test_data/manga_list/manga-transformed.json create mode 100644 tests/test_data/manga_list/manga-zippered.json create mode 100644 tests/test_data/manga_list/manga.json diff --git a/app/bootstrap.php b/app/bootstrap.php index 4dd04b36..420fa344 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -9,64 +9,74 @@ use \Whoops\Handler\PrettyPageHandler; use \Whoops\Handler\JsonResponseHandler; use \Aura\Web\WebFactory; use \Aura\Router\RouterFactory; -use \Aura\Di\Container as DiContainer; -use \Aura\Di\Factory as DiFactory; +use \Aura\Session\SessionFactory; + +use Aviat\Ion\Di\Container; require _dir(SRC_DIR, '/functions.php'); // ----------------------------------------------------------------------------- // Setup DI container // ----------------------------------------------------------------------------- -$container = new Container(); +$di = function() { + $container = new Container(); -// ----------------------------------------------------------------------------- -// Setup error handling -// ----------------------------------------------------------------------------- -$whoops = new \Whoops\Run(); + // ------------------------------------------------------------------------- + // Setup error handling + // ------------------------------------------------------------------------- + $whoops = new \Whoops\Run(); -// Set up default handler for general errors -$defaultHandler = new PrettyPageHandler(); -$whoops->pushHandler($defaultHandler); + // Set up default handler for general errors + $defaultHandler = new PrettyPageHandler(); + $whoops->pushHandler($defaultHandler); -// Set up json handler for ajax errors -$jsonHandler = new JsonResponseHandler(); -$jsonHandler->onlyForAjaxRequests(true); -$whoops->pushHandler($jsonHandler); + // Set up json handler for ajax errors + $jsonHandler = new JsonResponseHandler(); + $jsonHandler->onlyForAjaxRequests(true); + $whoops->pushHandler($jsonHandler); -$whoops->register(); + //$whoops->register(); -$container->set('error-handler', $defaultHandler); + $container->set('error-handler', $defaultHandler); -// ----------------------------------------------------------------------------- -// Injected Objects -// ----------------------------------------------------------------------------- + // ------------------------------------------------------------------------- + // Injected Objects + // ------------------------------------------------------------------------- -// Create Config Object -$config = new Config(); -$container->set('config', $config); + // Create Config Object + $config = new Config(); + $container->set('config', $config); -// Create Aura Router Object -$router_factory = new RouterFactory(); -$aura_router = $router_factory->newInstance(); -$container->set('aura-router', $aura_router); + // Create Aura Router Object + $aura_router = (new RouterFactory())->newInstance(); + $container->set('aura-router', $aura_router); -// Create Request/Response Objects -$web_factory = new WebFactory([ - '_GET' => $_GET, - '_POST' => $_POST, - '_COOKIE' => $_COOKIE, - '_SERVER' => $_SERVER, - '_FILES' => $_FILES -]); -$container->set('request', $web_factory->newRequest()); -$container->set('response', $web_factory->newResponse()); + // Create Request/Response Objects + $web_factory = new WebFactory([ + '_GET' => $_GET, + '_POST' => $_POST, + '_COOKIE' => $_COOKIE, + '_SERVER' => $_SERVER, + '_FILES' => $_FILES + ]); + $container->set('request', $web_factory->newRequest()); + $container->set('response', $web_factory->newResponse()); -// ----------------------------------------------------------------------------- -// Router -// ----------------------------------------------------------------------------- -$container->set('url-generator', new UrlGenerator($container)); + // Create session Object + $session = (new SessionFactory())->newInstance($_COOKIE); + $container->set('session', $session); -$router = new Router($container); -$router->dispatch(); + $container->set('url-generator', new UrlGenerator($container)); + + // ------------------------------------------------------------------------- + // Router + // ------------------------------------------------------------------------- + $router = new Router($container); + $container->set('router', $router); + + return $container; +}; + +$di()->get('router')->dispatch(); // End of bootstrap.php \ No newline at end of file diff --git a/app/config/base_config.php b/app/config/base_config.php index 47346dfa..e78b5338 100644 --- a/app/config/base_config.php +++ b/app/config/base_config.php @@ -5,6 +5,9 @@ // You shouldn't generally need to change anything below this line // ---------------------------------------------------------------------------- $base_config = [ + // Template file path + 'view_path' => _dir(APP_DIR, 'views'), + // Cache paths 'data_cache_path' => _dir(APP_DIR, 'cache'), 'img_cache_path' => _dir(ROOT_DIR, 'public/images'), diff --git a/app/config/routes.php b/app/config/routes.php index 154f0c4d..1320249a 100644 --- a/app/config/routes.php +++ b/app/config/routes.php @@ -5,9 +5,6 @@ return [ 'default_namespace' => '\\Aviat\\AnimeClient\\Controller', 'default_controller' => '\\Aviat\\AnimeClient\\Controller\\Anime', 'default_method' => 'index' - ], - 'configuration' => [ - ], // Routes on all controllers 'common' => [ @@ -71,70 +68,19 @@ return [ 'action' => ['redirect'], 'params' => [ 'url' => '', // Determined by config - 'code' => '301' + 'code' => '301', + 'type' => 'anime' ] ], 'search' => [ 'path' => '/anime/search', 'action' => ['search'], ], - 'all' => [ - 'path' => '/anime/all{/view}', + 'anime_list' => [ + 'path' => '/anime/{type}{/view}', 'action' => ['anime_list'], - 'params' => [ - 'type' => 'all', - ], - 'tokens' => [ - 'view' => '[a-z_]+' - ] - ], - 'watching' => [ - 'path' => '/anime/watching{/view}', - 'action' => ['anime_list'], - 'params' => [ - 'type' => 'watching', - ], - 'tokens' => [ - 'view' => '[a-z_]+' - ] - ], - 'plan_to_watch' => [ - 'path' => '/anime/plan_to_watch{/view}', - 'action' => ['anime_list'], - 'params' => [ - 'type' => 'plan_to_watch', - ], - 'tokens' => [ - 'view' => '[a-z_]+' - ] - ], - 'on_hold' => [ - 'path' => '/anime/on_hold{/view}', - 'action' => ['anime_list'], - 'params' => [ - 'type' => 'on_hold', - ], - 'tokens' => [ - 'view' => '[a-z_]+' - ] - ], - 'dropped' => [ - 'path' => '/anime/dropped{/view}', - 'action' => ['anime_list'], - 'params' => [ - 'type' => 'dropped', - ], - 'tokens' => [ - 'view' => '[a-z_]+' - ] - ], - 'completed' => [ - 'path' => '/anime/completed{/view}', - 'action' => ['anime_list'], - 'params' => [ - 'type' => 'completed', - ], 'tokens' => [ + 'type' => '[a-z_]+', 'view' => '[a-z_]+' ] ], @@ -149,65 +95,13 @@ return [ 'type' => 'manga' ] ], - 'all' => [ - 'path' => '/manga/all{/view}', + 'manga_list' => [ + 'path' => '/manga/{type}{/view}', 'action' => ['manga_list'], - 'params' => [ - 'type' => 'all', - ], - 'tokens' => [ - 'view' => '[a-z_]+' - ] - ], - 'reading' => [ - 'path' => '/manga/reading{/view}', - 'action' => ['manga_list'], - 'params' => [ - 'type' => 'reading', - ], - 'tokens' => [ - 'view' => '[a-z_]+' - ] - ], - 'plan_to_read' => [ - 'path' => '/manga/plan_to_read{/view}', - 'action' => ['manga_list'], - 'params' => [ - 'type' => 'plan_to_read', - ], - 'tokens' => [ - 'view' => '[a-z_]+' - ] - ], - 'on_hold' => [ - 'path' => '/manga/on_hold{/view}', - 'action' => ['manga_list'], - 'params' => [ - 'type' => 'on_hold', - ], - 'tokens' => [ - 'view' => '[a-z_]+' - ] - ], - 'dropped' => [ - 'path' => '/manga/dropped{/view}', - 'action' => ['manga_list'], - 'params' => [ - 'type' => 'dropped', - ], - 'tokens' => [ - 'view' => '[a-z_]+' - ] - ], - 'completed' => [ - 'path' => '/manga/completed{/view}', - 'action' => ['manga_list'], - 'params' => [ - 'type' => 'completed', - ], 'tokens' => [ + 'type' => '[a-z_]+', 'view' => '[a-z_]+' ] ] ] -]; \ No newline at end of file +]; diff --git a/app/views/anime/cover.php b/app/views/anime/cover.php index 71141395..c3d5c7da 100644 --- a/app/views/anime/cover.php +++ b/app/views/anime/cover.php @@ -4,17 +4,17 @@ $items): ?>
-

+

html($name) ?>

diff --git a/app/views/header.php b/app/views/header.php index b9161ec5..507e1e5f 100644 --- a/app/views/header.php +++ b/app/views/header.php @@ -3,16 +3,16 @@ <?= $title ?> - + - +

- + whose_list ?>'s [ List] diff --git a/app/views/manga/cover.php b/app/views/manga/cover.php index 53f3541b..e455feb8 100644 --- a/app/views/manga/cover.php +++ b/app/views/manga/cover.php @@ -4,7 +4,7 @@ $items): ?>
-

+

html($name) ?>

@@ -49,5 +46,5 @@ - + \ No newline at end of file diff --git a/app/views/message.php b/app/views/message.php index f77682fc..64983131 100644 --- a/app/views/message.php +++ b/app/views/message.php @@ -1,5 +1,5 @@ -
+
- + html($message) ?> x
\ No newline at end of file diff --git a/composer.json b/composer.json index cddb03de..653df6b6 100644 --- a/composer.json +++ b/composer.json @@ -3,6 +3,7 @@ "description": "A self-hosted anime/manga client for hummingbird.", "license":"MIT", "require": { + "container-interop/container-interop": "1.*", "guzzlehttp/guzzle": "5.3.*", "filp/whoops": "dev-php7#fe32a402b086b21360e82013e8a0355575c7c6f4", "aura/router": "2.2.*", @@ -12,6 +13,7 @@ "aviat4ion/query": "2.5.*", "robmorgan/phinx": "0.4.*", "abeautifulsite/simpleimage": "2.5.*", - "szymach/c-pchart": "1.*" + "szymach/c-pchart": "1.*", + "league/fractal": "0.12.0" } } \ No newline at end of file diff --git a/index.php b/index.php index 5438dbd7..ab0b6dd0 100644 --- a/index.php +++ b/index.php @@ -2,7 +2,6 @@ /** * Here begins everything! */ - session_start(); // Work around the silly timezone error @@ -30,9 +29,6 @@ function _dir() return implode(DIRECTORY_SEPARATOR, func_get_args()); } -// Set up composer autoloader -require _dir(ROOT_DIR, '/vendor/autoload.php'); - /** * Set up autoloaders * @@ -50,7 +46,8 @@ spl_autoload_register(function ($class) { } }); -// Do dependency injection, and go! +// Dependency setup +require _dir(ROOT_DIR, '/vendor/autoload.php'); require _dir(APP_DIR, 'bootstrap.php'); // End of index.php \ No newline at end of file diff --git a/src/Aviat/AnimeClient/Auth/HummingbirdAuth.php b/src/Aviat/AnimeClient/Auth/HummingbirdAuth.php new file mode 100644 index 00000000..c3562755 --- /dev/null +++ b/src/Aviat/AnimeClient/Auth/HummingbirdAuth.php @@ -0,0 +1,50 @@ +setContainer($container); + $this->session = $container->get('sesion') + ->getSegment(__NAMESPACE__); + $this->model = new AnimeModel($container); + } + + public function authenticate($username, $password) + { + + } + + public function get_auth_token() + { + + } + +} +// End of HummingbirdAuth.php \ No newline at end of file diff --git a/src/Aviat/AnimeClient/Container.php b/src/Aviat/AnimeClient/Container.php index 3fc3a9b1..a3c2e199 100644 --- a/src/Aviat/AnimeClient/Container.php +++ b/src/Aviat/AnimeClient/Container.php @@ -2,10 +2,14 @@ namespace Aviat\AnimeClient; +use Aviat\Ion\Di\Container as BaseContainer; +use Aviat\Ion\Di\ContainerInterface; + /** * Dependency container */ -class Container extends \Aviat\Ion\Base\Container { +class Container + extends BaseContainer { } // End of Container.php \ No newline at end of file diff --git a/src/Aviat/AnimeClient/Controller.php b/src/Aviat/AnimeClient/Controller.php index c6e75d9e..34b78c44 100644 --- a/src/Aviat/AnimeClient/Controller.php +++ b/src/Aviat/AnimeClient/Controller.php @@ -4,23 +4,26 @@ */ namespace Aviat\AnimeClient; +use Aura\Web\ResponseSender; + +use \Aviat\Ion\Di\ContainerInterface; +use \Aviat\Ion\View\HttpView; +use \Aviat\Ion\View\HtmlView; +use \Aviat\Ion\View\JsonView; + /** - * Base class for controllers, defines output methods + * Controller base, defines output methods */ class Controller { + use \Aviat\Ion\Di\ContainerAware; + /** * The global configuration object * @var object $config */ protected $config; - /** - * Request object - * @var object $request - */ - protected $request; - /** * Response object * @var object $response @@ -54,26 +57,15 @@ class Controller { * * @param Container $container */ - public function __construct(Container $container) + public function __construct(ContainerInterface $container) { + $this->setContainer($container); + $urlGenerator = $container->get('url-generator'); $this->config = $container->get('config'); - $this->base_data['config'] = $this->config; - $this->base_data['urlGenerator'] = $container->get('url-generator'); - $this->request = $container->get('request'); $this->response = $container->get('response'); - - $this->urlGenerator = $container->get('url-generator'); - } - - /** - * Destructor - * - * @codeCoverageIgnore - */ - public function __destruct() - { - $this->output(); + $this->base_data['urlGenerator'] = $urlGenerator; + $this->urlGenerator = $urlGenerator; } /** @@ -84,7 +76,7 @@ class Controller { */ public function __get($key) { - $allowed = ['request', 'response', 'config']; + $allowed = ['response', 'config']; if (in_array($key, $allowed)) { @@ -97,78 +89,94 @@ class Controller { /** * Get the string output of a partial template * - * @codeCoverageIgnore + * @param HTMLView $view * @param string $template * @param array|object $data * @return string */ - public function load_partial($template, $data=[]) + public function load_partial($view, $template, $data=[]) { + $errorHandler = $this->container->get('error-handler'); + $router = $this->container->get('router'); + if (isset($this->base_data)) { $data = array_merge($this->base_data, $data); } - global $router, $defaultHandler; $route = $router->get_route(); $data['route_path'] = ($route) ? $router->get_route()->path : ""; - $defaultHandler->addDataTable('Template Data', $data); - - $template_path = _dir(APP_DIR, 'views', "{$template}.php"); + $errorHandler->addDataTable('Template Data', $data); + $template_path = _dir($this->config->__get('view_path'), "{$template}.php"); if ( ! is_file($template_path)) { - throw new \InvalidArgumentException("Invalid template : {$path}"); + throw new \InvalidArgumentException("Invalid template : {$template}"); } - ob_start(); - extract($data); - include _dir(APP_DIR, 'views', 'header.php'); - include $template_path; - include _dir(APP_DIR, 'views', 'footer.php'); - $buffer = ob_get_contents(); - ob_end_clean(); + return $view->render_template($template_path, $data); + } - return $buffer; + /** + * Render a template with header and footer + * + * @param HTMLView $view + * @param string $template + * @param array|object $data + * @return void + */ + public function render_full_page($view, $template, $data) + { + $view->appendOutput($this->load_partial($view, 'header', $data)); + $view->appendOutput($this->load_partial($view, $template, $data)); + $view->appendOutput($this->load_partial($view, 'footer', $data)); } /** * Output a template to HTML, using the provided data * - * @codeCoverageIgnore * @param string $template * @param array|object $data * @return void */ public function outputHTML($template, $data=[]) { - $buffer = $this->load_partial($template, $data); + $view = new HtmlView($this->container); + $this->render_full_page($view, $template, $data); + } - $this->response->content->setType('text/html'); - $this->response->content->set($buffer); + /** + * Output a JSON Response + * + * @param mixed $data + * @return void + */ + public function outputJSON($data=[]) + { + $view = new JsonView($this->container); + $view->setOutput($data); } /** * Redirect to the selected page * - * @codeCoverageIgnore - * @param string $url + * @param string $path * @param int $code * @param string $type * @return void */ - public function redirect($url, $code, $type="anime") + public function redirect($path, $code, $type="anime") { - $url = $this->urlGenerator->full_url($url, $type); - - $this->response->redirect->to($url, $code); + $url = $this->urlGenerator->full_url($path, $type); + $http = new HttpView($this->container); + + $http->redirect($url, $code); } /** * Add a message box to the page * - * @codeCoverageIgnore * @param string $type * @param string $message * @return string @@ -184,7 +192,6 @@ class Controller { /** * Clear the api session * - * @codeCoverageIgnore * @return void */ public function logout() @@ -196,7 +203,6 @@ class Controller { /** * Show the login form * - * @codeCoverageIgnore * @param string $status * @return void */ @@ -222,53 +228,22 @@ class Controller { */ public function login_action() { + $request = $this->container->get('request'); + if ( $this->model->authenticate( $this->config->hummingbird_username, - $this->request->post->get('password') + $request->post->get('password') ) ) { - $this->response->redirect->afterPost($this->urlGenerator->full_url('', $this->base_data['url_type'])); + $this->response->redirect->afterPost( + $this->urlGenerator->full_url('', $this->base_data['url_type']) + ); return; } $this->login("Invalid username or password."); } - - /** - * Send the appropriate response - * - * @codeCoverageIgnore - * @return void - */ - private function output() - { - // send status - @header($this->response->status->get(), true, $this->response->status->getCode()); - - // headers - foreach($this->response->headers->get() as $label => $value) - { - @header("{$label}: {$value}"); - } - - // cookies - foreach($this->response->cookies->get() as $name => $cookie) - { - @setcookie( - $name, - $cookie['value'], - $cookie['expire'], - $cookie['path'], - $cookie['domain'], - $cookie['secure'], - $cookie['httponly'] - ); - } - - // send the actual response - echo $this->response->content->get(); - } } // End of BaseController.php \ No newline at end of file diff --git a/src/Aviat/AnimeClient/Controller/Anime.php b/src/Aviat/AnimeClient/Controller/Anime.php index 7befede0..8367b2af 100644 --- a/src/Aviat/AnimeClient/Controller/Anime.php +++ b/src/Aviat/AnimeClient/Controller/Anime.php @@ -5,9 +5,8 @@ namespace Aviat\AnimeClient\Controller; -use Aviat\AnimeClient\Container; +use Aviat\Ion\Di\ContainerInterface; use Aviat\AnimeClient\Controller as BaseController; -use Aviat\AnimeClient\Config; use Aviat\AnimeClient\Model\Anime as AnimeModel; use Aviat\AnimeClient\Model\AnimeCollection as AnimeCollectionModel; @@ -53,12 +52,10 @@ class Anime extends BaseController { * * @param Container $container */ - public function __construct(Container $container) + public function __construct(ContainerInterface $container) { parent::__construct($container); - $config = $container->get('config'); - if ($this->config->show_anime_collection === FALSE) { unset($this->nav_routes['Collection']); diff --git a/src/Aviat/AnimeClient/Controller/Collection.php b/src/Aviat/AnimeClient/Controller/Collection.php index 0e7b5c34..17e2739f 100644 --- a/src/Aviat/AnimeClient/Controller/Collection.php +++ b/src/Aviat/AnimeClient/Controller/Collection.php @@ -5,7 +5,7 @@ namespace Aviat\AnimeClient\Controller; -use Aviat\AnimeClient\Container; +use Aviat\Ion\Di\ContainerInterface; use Aviat\AnimeClient\Controller as BaseController; use Aviat\AnimeClient\Config; use Aviat\AnimeClient\UrlGenerator; @@ -54,7 +54,7 @@ class Collection extends BaseController { * * @param Container $container */ - public function __construct(Container $container) + public function __construct(ContainerInterface $container) { parent::__construct($container); diff --git a/src/Aviat/AnimeClient/Controller/Manga.php b/src/Aviat/AnimeClient/Controller/Manga.php index 1a2f7218..5be58558 100644 --- a/src/Aviat/AnimeClient/Controller/Manga.php +++ b/src/Aviat/AnimeClient/Controller/Manga.php @@ -4,7 +4,7 @@ */ namespace Aviat\AnimeClient\Controller; -use Aviat\AnimeClient\Container; +use Aviat\Ion\Di\ContainerInterface; use Aviat\AnimeClient\Controller; use Aviat\AnimeClient\Config; use Aviat\AnimeClient\Model\Manga as MangaModel; @@ -45,7 +45,7 @@ class Manga extends Controller { * * @param Container $container */ - public function __construct(Container $container) + public function __construct(ContainerInterface $container) { parent::__construct($container); $config = $container->get('config'); @@ -86,7 +86,7 @@ class Manga extends Controller { 'on_hold' => 'On Hold' ]; - $title = $this->config->whose_list . "' Manga List · {$map[$status]}"; + $title = $this->config->whose_list . "'s Manga List · {$map[$status]}"; $view_map = [ '' => 'cover', @@ -99,7 +99,7 @@ class Manga extends Controller { $this->outputHTML('manga/' . $view_map[$view], [ 'title' => $title, - 'sections' => $data + 'sections' => $data, ]); } } diff --git a/src/Aviat/AnimeClient/Controller/Stats.php b/src/Aviat/AnimeClient/Controller/Stats.php index 1b5b78aa..2ebe84d0 100644 --- a/src/Aviat/AnimeClient/Controller/Stats.php +++ b/src/Aviat/AnimeClient/Controller/Stats.php @@ -2,7 +2,7 @@ namespace Aviat\AnimeClient\Controller; -use Aviat\AnimeClient\Container; +use Aviat\Ion\Di\ContainerInterface; use Aviat\AnimeClient\Controller; class Stats extends Controller { diff --git a/src/Aviat/AnimeClient/Model.php b/src/Aviat/AnimeClient/Model.php index 69c4d5b0..c8f07acb 100644 --- a/src/Aviat/AnimeClient/Model.php +++ b/src/Aviat/AnimeClient/Model.php @@ -4,6 +4,7 @@ */ namespace Aviat\AnimeClient; +use Aviat\Ion\Di\ContainerInterface; use abeautifulsite\SimpleImage; /** @@ -28,7 +29,7 @@ class Model { * * @param Container $container */ - public function __construct(Container $container) + public function __construct(ContainerInterface $container) { $this->container = $container; $this->config = $container->get('config'); diff --git a/src/Aviat/AnimeClient/Model/API.php b/src/Aviat/AnimeClient/Model/API.php index b774eda1..5250aa32 100644 --- a/src/Aviat/AnimeClient/Model/API.php +++ b/src/Aviat/AnimeClient/Model/API.php @@ -6,12 +6,13 @@ namespace Aviat\AnimeClient\Model; use \GuzzleHttp\Client; use \GuzzleHttp\Cookie\CookieJar; -use \Aviat\AnimeClient\Container; +use Aviat\Ion\Di\ContainerInterface; +use Aviat\AnimeClient\Model as BaseModel; /** * Base model for api interaction */ -class API extends \Aviat\AnimeClient\Model { +class API extends BaseModel { /** * Base url for making api requests @@ -36,7 +37,7 @@ class API extends \Aviat\AnimeClient\Model { * * @param Container $container */ - public function __construct(Container $container) + public function __construct(ContainerInterface $container) { parent::__construct($container); $this->cookieJar = new CookieJar(); diff --git a/src/Aviat/AnimeClient/Model/Anime.php b/src/Aviat/AnimeClient/Model/Anime.php index 61e30533..84c6cfa8 100644 --- a/src/Aviat/AnimeClient/Model/Anime.php +++ b/src/Aviat/AnimeClient/Model/Anime.php @@ -138,7 +138,7 @@ class Anime extends API { */ public function search($name) { - global $defaultHandler; + $errorHandler = $this->container->get('error-handler'); $config = [ 'query' => [ @@ -147,7 +147,7 @@ class Anime extends API { ]; $response = $this->client->get('search/anime', $config); - $defaultHandler->addDataTable('anime_search_response', (array)$response); + $errorHandler->addDataTable('anime_search_response', (array)$response); if ($response->getStatusCode() != 200) { @@ -165,7 +165,7 @@ class Anime extends API { */ private function _get_list($status="all") { - global $defaultHandler; + $errorHandler = $this->container->get('error-handler'); $cache_file = "{$this->config->data_cache_path}/anime-{$status}.json"; @@ -180,7 +180,7 @@ class Anime extends API { $response = $this->client->get("users/{$this->config->hummingbird_username}/library", $config); - $defaultHandler->addDataTable('anime_list_response', (array)$response); + $errorHandler->addDataTable('anime_list_response', (array)$response); if ($response->getStatusCode() != 200) { diff --git a/src/Aviat/AnimeClient/Model/AnimeCollection.php b/src/Aviat/AnimeClient/Model/AnimeCollection.php index 78c89ac7..c966db47 100644 --- a/src/Aviat/AnimeClient/Model/AnimeCollection.php +++ b/src/Aviat/AnimeClient/Model/AnimeCollection.php @@ -5,8 +5,8 @@ namespace Aviat\AnimeClient\Model; +use Aviat\Ion\Di\ContainerInterface; use Aviat\AnimeClient\Model\DB; -use Aviat\AnimeClient\Container; use Aviat\AnimeClient\Model\Anime as AnimeModel; /** @@ -31,7 +31,7 @@ class AnimeCollection extends DB { * * @param Container $container */ - public function __construct(Container $container) + public function __construct(ContainerInterface $container) { parent::__construct($container); diff --git a/src/Aviat/AnimeClient/Model/DB.php b/src/Aviat/AnimeClient/Model/DB.php index 2f813aee..33564c21 100644 --- a/src/Aviat/AnimeClient/Model/DB.php +++ b/src/Aviat/AnimeClient/Model/DB.php @@ -4,12 +4,13 @@ */ namespace Aviat\AnimeClient\Model; -use Aviat\AnimeClient\Container; +use Aviat\Ion\Di\ContainerInterface; +use Aviat\AnimeClient\Model as BaseModel; /** * Base model for database interaction */ -class DB extends \Aviat\AnimeClient\Model { +class DB extends BaseModel { /** * The query builder object * @var object $db @@ -27,7 +28,7 @@ class DB extends \Aviat\AnimeClient\Model { * * @param Container $container */ - public function __construct(Container $container) + public function __construct(ContainerInterface $container) { parent::__construct($container); $this->db_config = $this->config->database; diff --git a/src/Aviat/AnimeClient/Model/Manga.php b/src/Aviat/AnimeClient/Model/Manga.php index 03ed5768..ab7620ca 100644 --- a/src/Aviat/AnimeClient/Model/Manga.php +++ b/src/Aviat/AnimeClient/Model/Manga.php @@ -76,7 +76,7 @@ class Manga extends API { */ private function _get_list($status="all") { - global $defaultHandler; + $errorHandler = $this->container->get('error-handler'); $cache_file = _dir($this->config->data_cache_path, 'manga.json'); @@ -89,7 +89,7 @@ class Manga extends API { $response = $this->client->get('manga_library_entries', $config); - $defaultHandler->addDataTable('response', (array)$response); + $errorHandler->addDataTable('response', (array)$response); if ($response->getStatusCode() != 200) { @@ -189,4 +189,4 @@ class Manga extends API { array_multisort($sort, SORT_ASC, $array); } } -// End of MangaModel.php \ No newline at end of file +// End of MangaModel.php diff --git a/src/Aviat/AnimeClient/Model/Stats.php b/src/Aviat/AnimeClient/Model/Stats.php index 993ea1be..653fffd8 100644 --- a/src/Aviat/AnimeClient/Model/Stats.php +++ b/src/Aviat/AnimeClient/Model/Stats.php @@ -5,19 +5,22 @@ namespace Aviat\AnimeClient\Model; +use Avait\Ion\Di\ContainerInterface; use Aviat\AnimeClient\Model\DB; -use Aviat\AnimeClient\Container; - -use StatsChartsTrait; +/** + * Base Model for stats about lists and collection(s) + */ class Stats extends DB { + use StatsChartsTrait; + /** * Constructor * * @param Container $container */ - public function __construct(Container $container) + public function __construct(ContainerInterface $container) { parent::__construct($container); $this->chartSetup(); diff --git a/src/Aviat/AnimeClient/Router.php b/src/Aviat/AnimeClient/Router.php index f496b59f..4d5a1829 100644 --- a/src/Aviat/AnimeClient/Router.php +++ b/src/Aviat/AnimeClient/Router.php @@ -7,6 +7,8 @@ namespace Aviat\AnimeClient; use Aura\Web\Request; use Aura\Web\Response; +use Aviat\Ion\Di\ContainerInterface; + /** * Basic routing/ dispatch */ @@ -35,7 +37,7 @@ class Router extends RoutingBase { * * @param Container $container */ - public function __construct(Container $container) + public function __construct(ContainerInterface $container) { parent::__construct($container); $this->router = $container->get('aura-router'); @@ -100,6 +102,12 @@ class Router extends RoutingBase { else { list($controller_name, $action_method) = $route->params['action']; + + if (is_null($controller_name)) + { + throw new \LogicException("Missing controller"); + } + $params = (isset($route->params['params'])) ? $route->params['params'] : []; if ( ! empty($route->tokens)) @@ -205,7 +213,8 @@ class Router extends RoutingBase { array_unshift($route['action'], $controller_class); // Select the appropriate router method based on the http verb - $add = (array_key_exists('verb', $route)) ? "add" . ucfirst(strtolower($route['verb'])) : "addGet"; + $add = (array_key_exists('verb', $route)) + ? "add" . ucfirst(strtolower($route['verb'])) : "addGet"; // Add the route to the router object if ( ! array_key_exists('tokens', $route)) diff --git a/src/Aviat/AnimeClient/RoutingBase.php b/src/Aviat/AnimeClient/RoutingBase.php index 541d9ee8..c4eda02b 100644 --- a/src/Aviat/AnimeClient/RoutingBase.php +++ b/src/Aviat/AnimeClient/RoutingBase.php @@ -5,6 +5,8 @@ */ namespace Aviat\AnimeClient; +use Aviat\Ion\Di\ContainerInterface; + /** * Base for routing/url classes */ @@ -32,7 +34,7 @@ class RoutingBase { * * @param Container $container */ - public function __construct(Container $container) + public function __construct(ContainerInterface $container) { $this->container = $container; $this->config = $container->get('config'); diff --git a/src/Aviat/AnimeClient/Transformer/Hummingbird/AnimeListTransformer.php b/src/Aviat/AnimeClient/Transformer/Hummingbird/AnimeListTransformer.php new file mode 100644 index 00000000..ee27b4d4 --- /dev/null +++ b/src/Aviat/AnimeClient/Transformer/Hummingbird/AnimeListTransformer.php @@ -0,0 +1,15 @@ +manga_series_list = $merge_lists['manga']; + $this->manga_tracking_list = $merge_lists['manga_library_entries']; + } + + /** + * Do the transformation, and return the output + * + * @return array + */ + public function transform() + { + $this->index_manga_entries(); + + $output = []; + + foreach($this->manga_tracking_list as &$entry) + { + $id = $entry['manga_id']; + $entry['manga'] = $this->manga_series_list[$id]; + unset($entry['manga_id']); + + $output[] = $entry; + } + + return $output; + } + + /** + * Index manga series by the id + * + * @return void + */ + protected function index_manga_entries() + { + $orig_list = $this->manga_series_list; + $indexed_list = []; + + foreach($orig_list as $manga) + { + $id = $manga['id']; + $indexed_list[$id] = $manga; + } + + $this->manga_series_list = $indexed_list; + } + +} +// End of ManagListsZipper.php \ No newline at end of file diff --git a/src/Aviat/AnimeClient/UrlGenerator.php b/src/Aviat/AnimeClient/UrlGenerator.php index 8b41f477..ac27724d 100644 --- a/src/Aviat/AnimeClient/UrlGenerator.php +++ b/src/Aviat/AnimeClient/UrlGenerator.php @@ -119,4 +119,4 @@ class UrlGenerator extends RoutingBase { return "//{$host}/{$path}"; } } -// End of UrlGenerator.php \ No newline at end of file +// End of UrlGenerator.php diff --git a/src/Aviat/Ion/Base/Container.php b/src/Aviat/Ion/Base/Container.php deleted file mode 100644 index cfb40db3..00000000 --- a/src/Aviat/Ion/Base/Container.php +++ /dev/null @@ -1,54 +0,0 @@ -container = $values; - } - - /** - * Get a value - * - * @param string $key - * @retun mixed - */ - public function get($key) - { - if (array_key_exists($key, $this->container)) - { - return $this->container[$key]; - } - } - - /** - * Add a value to the container - * - * @param string $key - * @param mixed $value - * @return Container - */ - public function set($key, $value) - { - $this->container[$key] = $value; - return $this; - } -} -// End of Container.php \ No newline at end of file diff --git a/src/Aviat/Ion/Di/Container.php b/src/Aviat/Ion/Di/Container.php new file mode 100644 index 00000000..098cfd3d --- /dev/null +++ b/src/Aviat/Ion/Di/Container.php @@ -0,0 +1,82 @@ +container = new ArrayObject($values); + } + + /** + * Finds an entry of the container by its identifier and returns it. + * + * @param string $id Identifier of the entry to look for. + * + * @throws NotFoundException No entry was found for this identifier. + * @throws ContainerException Error while retrieving the entry. + * + * @return mixed Entry. + */ + public function get($id) + { + if ( ! is_string($id)) + { + throw new Exception\ContainerException("Id must be a string"); + } + + if ($this->has($id)) + { + return $this->container[$id]; + } + + throw new Exception\NotFoundException("Item {$id} does not exist in container."); + } + + /** + * Add a value to the container + * + * @param string $id + * @param mixed $value + * @return Container + */ + public function set($id, $value) + { + $this->container[$id] = $value; + return $this; + } + + /** + * Returns true if the container can return an entry for the given identifier. + * Returns false otherwise. + * + * @param string $id Identifier of the entry to look for. + * + * @return boolean + */ + public function has($id) + { + return $this->container->offsetExists($id); + } +} +// End of Container.php \ No newline at end of file diff --git a/src/Aviat/Ion/Di/ContainerAware.php b/src/Aviat/Ion/Di/ContainerAware.php new file mode 100644 index 00000000..9b1d8784 --- /dev/null +++ b/src/Aviat/Ion/Di/ContainerAware.php @@ -0,0 +1,36 @@ +container = $container; + return $this; + } + + /** + * Get the container object + * + * @return ContainerInterface + */ + public function getContainer() + { + return $this->container; + } +} +// End of ContainerAware.php diff --git a/src/Aviat/Ion/Di/ContainerAwareInterface.php b/src/Aviat/Ion/Di/ContainerAwareInterface.php new file mode 100644 index 00000000..b2a8f4fb --- /dev/null +++ b/src/Aviat/Ion/Di/ContainerAwareInterface.php @@ -0,0 +1,23 @@ +setContainer($container); + $this->response = $container->get('response'); + } + + /** + * Send output to client + */ + public function __destruct() + { + $this->output(); + } + + /** + * Set the output string + * + * @param string $string + * @return View + */ + public function setOutput($string) + { + $this->output = $string; + return $this; + } + + /** + * Append additional output + * + * @param string $string + * @return View + */ + public function appendOutput($string) + { + $this->output .= $string; + return $this; + } + + /** + * Get the current output string + * + * @return string + */ + public function getOutput() + { + return $this->output; + } + + /** + * Send the appropriate response + * + * @return void + */ + protected function output() + { + $content =& $this->response->content; + $content->set($this->output); + $content->setType($this->contentType); + $content->setCharset('utf-8'); + } +} +// End of View.php \ No newline at end of file diff --git a/src/Aviat/Ion/View/HtmlView.php b/src/Aviat/Ion/View/HtmlView.php new file mode 100644 index 00000000..8d9f6f2e --- /dev/null +++ b/src/Aviat/Ion/View/HtmlView.php @@ -0,0 +1,50 @@ +helper = (new HelperLocatorFactory)->newInstance(); + } + + /** + * Response mime type + * + * @var string + */ + protected $contentType = 'text/html'; + + /** + * Render a basic html Template + * + * @param string $path + * @param array $data + * @return string + */ + public function render_template($path, $data) + { + $buffer = ""; + + $data['helper'] = $this->helper; + $data['escape'] = $this->helper->escape(); + + ob_start(); + extract($data); + include $path; + $buffer = ob_get_contents(); + ob_end_clean(); + + return $buffer; + } +} +// End of HtmlView.php \ No newline at end of file diff --git a/src/Aviat/Ion/View/HttpView.php b/src/Aviat/Ion/View/HttpView.php new file mode 100644 index 00000000..0fee05a8 --- /dev/null +++ b/src/Aviat/Ion/View/HttpView.php @@ -0,0 +1,36 @@ +response->redirect->to($url, $code); + } + + /** + * Send the appropriate response + * + * @return void + */ + protected function output() + { + parent::output(); + + $sender = new ResponseSender($this->response); + $sender->__invoke(); + } + +} \ No newline at end of file diff --git a/src/Aviat/Ion/View/JsonView.php b/src/Aviat/Ion/View/JsonView.php new file mode 100644 index 00000000..75ce87a9 --- /dev/null +++ b/src/Aviat/Ion/View/JsonView.php @@ -0,0 +1,32 @@ + [ - 'key' => 'request', - ], 'response' => [ 'key' => 'response', ], diff --git a/tests/AnimeClient/Model/BaseApiModelTest.php b/tests/AnimeClient/Model/BaseApiModelTest.php index baede679..a67edb6b 100644 --- a/tests/AnimeClient/Model/BaseApiModelTest.php +++ b/tests/AnimeClient/Model/BaseApiModelTest.php @@ -1,11 +1,12 @@ ['anime_list'], 'params' => [ 'type' => 'currently-watching', - 'title' => WHOSE . " Anime List · Watching" ], 'tokens' => [ 'view' => '[a-z_]+' @@ -87,7 +86,6 @@ class RouterTest extends AnimeClient_TestCase { 'action' => ['manga_list'], 'params' => [ 'type' => 'Plan to Read', - 'title' => WHOSE . " Manga List · Plan to Read" ], 'tokens' => [ 'view' => '[a-z_]+' diff --git a/tests/AnimeClient/Transformer/MangaListsZipperTest.php b/tests/AnimeClient/Transformer/MangaListsZipperTest.php new file mode 100644 index 00000000..1fe4e429 --- /dev/null +++ b/tests/AnimeClient/Transformer/MangaListsZipperTest.php @@ -0,0 +1,24 @@ +start_file), TRUE); + $this->mangaListsZipper = new MangaListsZipper($json); + } + + public function testTransform() + { + $zippered_json = json_decode(file_get_contents($this->res_file), TRUE); + $transformed = $this->mangaListsZipper->transform(); + + $this->assertEquals($zippered_json, $transformed); + } + +} \ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 3847c4eb..af8cce65 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -5,6 +5,7 @@ use Aviat\AnimeClient\Config; use Aviat\AnimeClient\Container; +use Aviat\AnimeClient\UrlGenerator; // ----------------------------------------------------------------------------- // Mock the default error handler @@ -14,8 +15,6 @@ class MockErrorHandler { public function addDataTable($name, Array $values) {} } -$defaultHandler = new MockErrorHandler(); - // ----------------------------------------------------------------------------- // Define a base testcase class // ----------------------------------------------------------------------------- @@ -41,9 +40,12 @@ class AnimeClient_TestCase extends PHPUnit_Framework_TestCase { ]); $container = new Container([ - 'config' => $config + 'config' => $config, + 'error-handler' => new MockErrorHandler() ]); + $container->set('url-generator', new UrlGenerator($container)); + $this->container = $container; } } @@ -52,12 +54,6 @@ class AnimeClient_TestCase extends PHPUnit_Framework_TestCase { // Autoloaders // ----------------------------------------------------------------------------- -// Define WHOSE constant -define('WHOSE', "Foo's"); - -// Define base path constants -define('ROOT_DIR', realpath(__DIR__ . DIRECTORY_SEPARATOR . "/../")); - /** * Joins paths together. Variadic to take an * arbitrary number of arguments @@ -69,10 +65,14 @@ function _dir() return implode(DIRECTORY_SEPARATOR, func_get_args()); } +// Define base path constants +define('ROOT_DIR', realpath(__DIR__ . DIRECTORY_SEPARATOR . "/../")); define('APP_DIR', _dir(ROOT_DIR, 'app')); define('CONF_DIR', _dir(APP_DIR, 'config')); define('SRC_DIR', _dir(ROOT_DIR, 'src')); define('BASE_DIR', _dir(SRC_DIR, 'Base')); +require _dir(ROOT_DIR, '/vendor/autoload.php'); +require _dir(SRC_DIR, 'functions.php'); /** * Set up autoloaders @@ -80,24 +80,16 @@ define('BASE_DIR', _dir(SRC_DIR, 'Base')); * @codeCoverageIgnore * @return void */ -function _setup_autoloaders() -{ - require _dir(ROOT_DIR, '/vendor/autoload.php'); - spl_autoload_register(function ($class) { - $class_parts = explode('\\', $class); - $ns_path = SRC_DIR . '/' . implode('/', $class_parts) . ".php"; +spl_autoload_register(function ($class) { + $class_parts = explode('\\', $class); + $ns_path = SRC_DIR . '/' . implode('/', $class_parts) . ".php"; - if (file_exists($ns_path)) - { - require_once($ns_path); - return; - } - }); -} - -// Setup autoloaders -_setup_autoloaders(); -require(_dir(SRC_DIR, 'functions.php')); + if (file_exists($ns_path)) + { + require_once($ns_path); + return; + } +}); // Pre-define some superglobals $_SESSION = []; diff --git a/tests/test_data/anime_list/anime-watching-transformed.json b/tests/test_data/anime_list/anime-watching-transformed.json new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_data/anime_list/anime-watching.json b/tests/test_data/anime_list/anime-watching.json new file mode 100644 index 00000000..44275ee8 --- /dev/null +++ b/tests/test_data/anime_list/anime-watching.json @@ -0,0 +1,797 @@ +[ + { + "id": 9131610, + "episodes_watched": 2, + "last_watched": "2015-09-17T16:52:19.028Z", + "updated_at": "2015-09-17T16:52:19.029Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 7190, + "mal_id": 14967, + "slug": "boku-wa-tomodachi-ga-sukunai-next", + "status": "Finished Airing", + "url": "https://hummingbird.me/anime/boku-wa-tomodachi-ga-sukunai-next", + "title": "Boku wa Tomodachi ga Sukunai NEXT", + "alternate_title": "Haganai NEXT", + "episode_count": 12, + "episode_length": 24, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/007/190/large/0.jpg?1417468876", + "synopsis": "The Neighbor's Club—a club founded for the purpose of making friends,where misfortunate boys and girls with few friends live out their regrettable lives.\r\nAlthough Yozora Mikazuki faced a certain incident at the end of summer,the daily life of the Neighbor's Club goes on as usual.A strange nun,members of the student council and other new faces make an appearance,causing Kodaka Hasegawa's life to grow even busier.\r\nWhile they all enjoy going to the amusement park,playing games,celebrating birthdays,and challenging the\"school festival\"—a symbol of the school life normal people live—the relations amongst the members slowly begins to change...\r\nLet the next stage begin,on this unfortunate coming-of-age love comedy!!\r\n(Source:ANN)", + "show_type": "TV", + "started_airing": "2013-01-11", + "finished_airing": "2013-03-29", + "community_rating": 3.8820340732555, + "age_rating": "R17+", + "genres": [ + { + "name": "Comedy" + }, + { + "name": "Romance" + }, + { + "name": "School" + }, + { + "name": "Harem" + } + ] + }, + "rating": { + "type": "advanced", + "value": null + } + }, + { + "id": 10177172, + "episodes_watched": 11, + "last_watched": "2015-09-14T23:49:37.044Z", + "updated_at": "2015-09-14T23:49:37.045Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 10350, + "mal_id": 29785, + "slug": "jitsu-wa-watashi-wa", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/jitsu-wa-watashi-wa", + "title": "Jitsu wa Watashi wa", + "alternate_title": "Actually, I Am…", + "episode_count": 13, + "episode_length": 24, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/010/350/large/ndmkhu.jpg?1431603318", + "synopsis": "Asahi Kuromine has a crush on a cute girl named Youko Shiragami. Shiragami just happens to be a vampire. Asahi cannot keep a secret, but he is determined to keep Shiragami's secret anyway.\r\n\r\n(Source: ANN)", + "show_type": "TV", + "started_airing": "2015-07-07", + "finished_airing": null, + "community_rating": 3.768867119294, + "age_rating": "PG13", + "genres": [ + { + "name": "Comedy" + }, + { + "name": "Fantasy" + }, + { + "name": "Romance" + }, + { + "name": "School" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.0" + } + }, + { + "id": 9131615, + "episodes_watched": 8, + "last_watched": "2015-09-12T18:14:16.370Z", + "updated_at": "2015-09-12T18:14:16.371Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 9095, + "mal_id": 27525, + "slug": "fate-kaleid-liner-prisma-illya-2wei-herz", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/fate-kaleid-liner-prisma-illya-2wei-herz", + "title": "Fate/kaleid liner Prisma☆Illya 2wei Herz!", + "alternate_title": null, + "episode_count": 10, + "episode_length": 23, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/009/095/large/Q0l30yH.jpg?1427031275", + "synopsis": "Third season of Fate/kaleid Liner Prisma Illya.", + "show_type": "TV", + "started_airing": "2015-07-24", + "finished_airing": null, + "community_rating": 3.7841266617022, + "age_rating": "PG13", + "genres": [ + { + "name": "Action" + }, + { + "name": "Comedy" + }, + { + "name": "Magic" + }, + { + "name": "Fantasy" + }, + { + "name": "Mahou Shoujo" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.5" + } + }, + { + "id": 10426033, + "episodes_watched": 8, + "last_watched": "2015-08-01T23:26:21.869Z", + "updated_at": "2015-08-01T23:26:21.870Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 475, + "mal_id": 516, + "slug": "keroro-gunsou", + "status": "Finished Airing", + "url": "https://hummingbird.me/anime/keroro-gunsou", + "title": "Keroro Gunsou", + "alternate_title": "Sergeant Frog", + "episode_count": 358, + "episode_length": 23, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/000/475/large/475.jpg?1416242348", + "synopsis": "Keroro is a frog-like alien sent from his home planet on a mission to conquer Earth. But when his cover is blown, his battalion abandons him and he ends up in the home of the Hinata family. There, he's forced to do household chores and sleep in a dark basement that was once supposedly a prison cell haunted by the ghost of an innocent girl. He even spends his free time assembling Gundam model kits. During his stay, Keroro meets up with subordinates who were also stranded during their failed invasion. \n(Source: ANN)", + "show_type": "TV", + "started_airing": "2004-04-03", + "finished_airing": "2011-04-04", + "community_rating": 3.8815806455204, + "age_rating": "PG13", + "genres": [ + { + "name": "Comedy" + }, + { + "name": "Sci-Fi" + } + ] + }, + "rating": { + "type": "advanced", + "value": "3.5" + } + }, + { + "id": 10299917, + "episodes_watched": 11, + "last_watched": "2015-09-14T23:55:59.297Z", + "updated_at": "2015-09-14T23:55:59.298Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 10352, + "mal_id": 29786, + "slug": "shimoneta-to-iu-gainen-ga-sonzai-shinai-taikutsu-na-sekai", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/shimoneta-to-iu-gainen-ga-sonzai-shinai-taikutsu-na-sekai", + "title": "Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai", + "alternate_title": "SHIMONETA: A Boring World Where the Concept of Dirty Jokes Doesn't Exist", + "episode_count": 12, + "episode_length": 24, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/010/352/large/shimoneta02.jpg?1433942845", + "synopsis": "Who is the panty-masked villainess spreading obscenity in a country where even the mildest off-color musing can land you in jail?\r\n\r\nWhen the student council president of the most elite public morals school in the country has a feeling that the lewd is coming from within the walls, she recruits Tanukichi, a recent transfer student, to her upstanding moral squad.\r\n\r\nLittle does she know he’s already been blackmailed by Ayame, her own vice president who is secretly the panty-masked bandit, into committing mass acts of public obscenity in the name of SOX—a brigade of sorts—dedicated to spreading the good news of being lewd.\r\n\r\n(Source: FUNimation)", + "show_type": "TV", + "started_airing": "2015-07-04", + "finished_airing": null, + "community_rating": 4.0207233212975, + "age_rating": "R17+", + "genres": [ + { + "name": "Comedy" + }, + { + "name": "School" + }, + { + "name": "Ecchi" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.0" + } + }, + { + "id": 10299832, + "episodes_watched": 10, + "last_watched": "2015-09-14T01:56:45.778Z", + "updated_at": "2015-09-14T01:56:45.778Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 10621, + "mal_id": 30123, + "slug": "akagami-no-shirayuki-hime", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/akagami-no-shirayuki-hime", + "title": "Akagami no Shirayuki-hime", + "alternate_title": "Snow White with the Red Hair", + "episode_count": 12, + "episode_length": 24, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/010/621/large/e5ac7bdd2b175b6aee20d8f8528147731432360559_full.jpg?1432401413", + "synopsis": "In the kingdom of Tanbarun lives Shirayuki, an independent and strong-willed young woman. Her resourceful intelligence has led her become a skilled pharmacist, but her most defining trait is her shock of beautiful apple-red hair. Her dazzling mane gets her noticed by the prince of the kingdom, but instead of romancing her, he demands she be his concubine. Shirayuki refuses, chops off her lovely locks, and runs away to the neighboring kingdom of Clarines. There, she befriends a young man named Zen, who, SURPRISE, is also a prince, although with a much better temperament than the previous one. Watch as Shirayuki finds her place in the new kingdom, and in Zen’s heart.\r\n\r\n(Source: FUNimation)", + "show_type": "TV", + "started_airing": "2015-07-07", + "finished_airing": "2015-09-22", + "community_rating": 4.1011684647044, + "age_rating": "PG13", + "genres": [ + { + "name": "Drama" + }, + { + "name": "Fantasy" + }, + { + "name": "Romance" + }, + { + "name": "Historical" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.0" + } + }, + { + "id": 10299826, + "episodes_watched": 11, + "last_watched": "2015-09-12T13:36:42.211Z", + "updated_at": "2015-09-12T13:36:42.212Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 10069, + "mal_id": 28819, + "slug": "oku-sama-ga-seito-kaichou", + "status": "Finished Airing", + "url": "https://hummingbird.me/anime/oku-sama-ga-seito-kaichou", + "title": "Oku-sama ga Seito Kaichou!", + "alternate_title": "My Wife is the Student Council President!", + "episode_count": 12, + "episode_length": 8, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/010/069/large/173744.jpg?1432381972", + "synopsis": "The story begins with Izumi Hayato running to be student body president. But when a beautiful girl swings in promising the liberalization of love while flinging condoms into the audience, he ends up losing to her and becoming the vice president. At the student council meeting, the newly-elected president invites herself over to Izumi's house, where she promptly announces she is to become Izumi's wife thanks to an agreement—facilitated by alcohol—made between their parents when they were only 3.\r\n\r\n(Source: MAL Scanlations)", + "show_type": "TV", + "started_airing": "2015-07-02", + "finished_airing": "2015-09-17", + "community_rating": 3.3822121645568, + "age_rating": "R17+", + "genres": [ + { + "name": "Comedy" + }, + { + "name": "Romance" + }, + { + "name": "School" + }, + { + "name": "Ecchi" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.0" + } + }, + { + "id": 10271011, + "episodes_watched": 11, + "last_watched": "2015-09-14T01:26:22.895Z", + "updated_at": "2015-09-14T01:26:22.895Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 10029, + "mal_id": 28497, + "slug": "rokka-no-yuusha", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/rokka-no-yuusha", + "title": "Rokka no Yuusha", + "alternate_title": "Rokka: Braves of the Six Flowers", + "episode_count": 12, + "episode_length": 24, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/010/029/large/rokkanoyuusha.jpg?1436386289", + "synopsis": "Legend says, when the Evil God awakens from the deepest of darkness, the god of fate will summon Six Braves and grant them with the power to save the world. \r\n \r\nAdlet, who claims to be the strongest on the face of this earth, is chosen as one of the “Brave Six Flowers,” and sets out on a battle to prevent the resurrection of the Evil God. However, it turns out that there are Seven Braves who gathered at the promised land... \r\n \r\nThe Seven Braves notice there must be one enemy among themselves, and feelings of suspicion toward each other spreads throughout the group, with Adlet being the one who gets suspected first and foremost. \r\n \r\nThus begins an overwhelming fantasy adventure that brings upon mystery after mystery!\r\n\r\n(Source: Crunchyroll)", + "show_type": "TV", + "started_airing": "2015-07-05", + "finished_airing": "2015-09-20", + "community_rating": 3.9872922407283, + "age_rating": "PG13", + "genres": [ + { + "name": "Action" + }, + { + "name": "Adventure" + }, + { + "name": "Mystery" + }, + { + "name": "Magic" + }, + { + "name": "Fantasy" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.0" + } + }, + { + "id": 10296163, + "episodes_watched": 10, + "last_watched": "2015-09-12T18:38:06.334Z", + "updated_at": "2015-09-12T18:38:06.335Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 9726, + "mal_id": 27831, + "slug": "durarara-x2-ten", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/durarara-x2-ten", + "title": "Durarara!!x2 Ten", + "alternate_title": "Durarara!! x2 The Second Arc", + "episode_count": 12, + "episode_length": 24, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/009/726/large/durararax2tenv2.jpg?1435341790", + "synopsis": "Ikebukuro, a city teeming with the most peculiar characters and the twisted schemes they indulge in. In the aftermath of the assault against the information broker, signs of new disorder begin to develop like ripples across the water. Holding his own ideals, the young man who gains the powers of both the “Dollars” and the “Blue Squares” treads the path to total annihilation. Someone struggles to save their best friend while a psychopath creeps up on a popular idol. Slowly but surely a new threat gains power within the city’s shadows…\n\nPaths cross and trouble brews as the plot thickens in this complicated web of conspiracies.\n\n(Source: Aniplex USA)", + "show_type": "TV", + "started_airing": "2015-07-04", + "finished_airing": "2015-09-26", + "community_rating": 4.3105326468495, + "age_rating": "R17+", + "genres": [ + { + "name": "Action" + }, + { + "name": "Mystery" + }, + { + "name": "Supernatural" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.0" + } + }, + { + "id": 10295958, + "episodes_watched": 11, + "last_watched": "2015-09-17T01:54:16.472Z", + "updated_at": "2015-09-17T01:54:16.472Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 10748, + "mal_id": 30307, + "slug": "monster-musume-no-iru-nichijou", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/monster-musume-no-iru-nichijou", + "title": "Monster Musume no Iru Nichijou", + "alternate_title": "Everyday Life with Monster Girls", + "episode_count": 12, + "episode_length": 23, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/010/748/large/hcxfyjp1_l-anime-monster-musume-no-iru-nichijou-en-promotion-video.jpg?1434653745", + "synopsis": "Monsters—they're real, and they want to date us! Three years ago, the world learned that harpies, centaurs, catgirls, and all manners of fabulous creatures are not merely fiction; they are flesh and blood—not to mention scale, feather, horn, and fang. Thanks to the \"Cultural Exchange Between Species Act,\" these once-mythical creatures have assimilated into society, or at least, they're trying.\r\n\r\nWhen a hapless human named Kurusu Kimihito is inducted as a \"volunteer\" into the government exchange program, his world is turned upside down. A snake-like lamia named Miia comes to live with him, and it is Kurusu's job to take care of her and make sure she integrates into his everyday life. Unfortunately for Kurusu, Miia is undeniably sexy, and the law against interspecies breeding is very strict. Even worse, when a ravishing centaur girl and a flirtatious harpy move in, what's a full-blooded young man with raging hormones to do?!\r\n\r\n(Source: Seven Seas Entertainment)", + "show_type": "TV", + "started_airing": "2015-07-08", + "finished_airing": "2015-09-23", + "community_rating": 3.8451747238313, + "age_rating": "PG13", + "genres": [ + { + "name": "Comedy" + }, + { + "name": "Fantasy" + }, + { + "name": "Romance" + }, + { + "name": "Ecchi" + }, + { + "name": "Harem" + } + ] + }, + "rating": { + "type": "advanced", + "value": "3.5" + } + }, + { + "id": 10295719, + "episodes_watched": 11, + "last_watched": "2015-09-12T14:20:43.922Z", + "updated_at": "2015-09-12T14:20:43.923Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 10085, + "mal_id": 28907, + "slug": "gate-jieitai-kanochi-nite-kaku-tatakaeri", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/gate-jieitai-kanochi-nite-kaku-tatakaeri", + "title": "Gate: Jieitai Kanochi nite, Kaku Tatakaeri", + "alternate_title": "GATE", + "episode_count": 12, + "episode_length": 24, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/010/085/large/85a5d8cc2972ae422158be7069076be41435868848_full.jpg?1435924413", + "synopsis": "In August of 20XX, a portal to a parallel world, known as the \"Gate,\" suddenly appeared in Ginza, Tokyo. Monsters and troops poured out of the portal, turning the shopping district into a bloody inferno.\r\n\r\nThe Japan Ground-Self Defence Force immediately took action and pushed the fantasy creatures back to the \"Gate.\" To facilitate negotiations and prepare for future fights, the JGSDF dispatched the Third Reconnaissance Team to the \"Special Region\" at the other side of the Gate.\r\n\r\nYouji Itami, a JSDF officer as well as a 33-year-old otaku, was appointed as the leader of the Team. Amid attacks from enemy troops the team visited a variety of places and learnt a lot about the local culture and geography.\r\n\r\nThanks to their efforts in humanitarian relief, although with some difficulties they were gradually able to reach out to the locals. They even had a cute elf, a sorceress and a demigoddess in their circle of new friends. On the other hand, the major powers outside the Gate such as the United States, China, and Russia were extremely interested in the abundant resources available in the Special Region. They began to exert diplomatic pressure over Japan.\r\n\r\nA suddenly appearing portal to an unknown world—to the major powers it may be no more than a mere asset for toppling the international order. But to our protagonists it is an invaluable opportunity to broaden knowledge, friendship, and ultimately their perspective towards the world.\r\n\r\n(Source: Baka-Tsuki)", + "show_type": "TV", + "started_airing": "2015-07-04", + "finished_airing": null, + "community_rating": 4.10315369511, + "age_rating": null, + "genres": [ + { + "name": "Action" + }, + { + "name": "Adventure" + }, + { + "name": "Fantasy" + }, + { + "name": "Military" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.5" + } + }, + { + "id": 10215731, + "episodes_watched": 11, + "last_watched": "2015-09-12T13:45:12.780Z", + "updated_at": "2015-09-12T13:45:12.780Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 10765, + "mal_id": 30384, + "slug": "miss-monochrome-the-animation-2nd-season", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/miss-monochrome-the-animation-2nd-season", + "title": "Miss Monochrome: The Animation 2nd Season", + "alternate_title": null, + "episode_count": 13, + "episode_length": 8, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/010/765/large/20150511_summer02.jpg?1432381052", + "synopsis": "The Ultra Super Pictures Special Stage event announced at AnimeJapan 2015 on Saturday that the Miss Monochrome television anime series will receive a second season. The season will run within the 30-minute Ultra Super Anime Time block beginning on July 3, 2015.\r\n\r\n(Source: ANN)", + "show_type": "TV", + "started_airing": "2015-07-03", + "finished_airing": null, + "community_rating": 3.6555205723713, + "age_rating": "G", + "genres": [ + { + "name": "Slice of Life" + }, + { + "name": "Music" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.0" + } + }, + { + "id": 10177163, + "episodes_watched": 11, + "last_watched": "2015-09-12T17:47:16.672Z", + "updated_at": "2015-09-12T17:47:16.672Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 10782, + "mal_id": 30383, + "slug": "classroom-crisis", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/classroom-crisis", + "title": "Classroom☆Crisis", + "alternate_title": "", + "episode_count": 12, + "episode_length": 24, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/010/782/large/gUUHG7u.jpg?1432480149", + "synopsis": "Fourth Tokyo--one of Japan’s new prefectures on Mars. Kirishina City, Fourth Tokyo’s special economic zone, is home to the Kirishina Corporation, an elite corporation renowned for its aerospace business. The company has been expanding its market share in various industries, while also running a private school, the Kirishina Science and Technology Academy High School. That alone would make it unique, but there’s also a high-profile class on campus. \r\n \r\nDevoting themselves to their studies during the day, they then report to the company after school to take part in a crucial project, the development of prototype variants for rockets. This is the Kirishina Corporation’s Advanced Technological Development Department, Educational Development Class, a.k.a. A-TEC. A-TEC’s chief, the young engineering genius, Kaito Sera, is also the homeroom teacher of the A- TEC students attending the academy, affectionately (?) known as the Raving Rocket Teacher. \r\n \r\nThe story begins with the arrival of a transfer student to A-TEC. \r\n \r\nThe A-TEC members are ready to welcome their new classmate, but the student in question is kidnapped en route to Mars. Determining that they themselves will have to be the ones to overcome this crisis, Kaito and the A-TEC students embark on an unprecedented rescue mission.\r\n\r\n(Source: Aniplex USA)", + "show_type": "TV", + "started_airing": "2015-07-04", + "finished_airing": null, + "community_rating": 3.3777667556786, + "age_rating": "PG13", + "genres": [ + { + "name": "Comedy" + }, + { + "name": "Sci-Fi" + }, + { + "name": "Romance" + }, + { + "name": "Slice of Life" + }, + { + "name": "School" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.5" + } + }, + { + "id": 10177168, + "episodes_watched": 11, + "last_watched": "2015-09-14T01:01:35.226Z", + "updated_at": "2015-09-14T01:01:35.227Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 10103, + "mal_id": 28999, + "slug": "charlotte", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/charlotte", + "title": "Charlotte", + "alternate_title": "", + "episode_count": 13, + "episode_length": 24, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/010/103/large/charlotte.jpg?1434903194", + "synopsis": "In a world where children have a chance to develop special powers upon reaching puberty. Otosaka Yuu is one such child, choosing to live a relatively normal, satisfying life despite possessing an ability to control others’ bodies for a short period of time. One day, Yuu is suddenly approached by Tomori Nao, another child with special powers. Their meeting sets the stage for a story about growth, their many experiences, and a cruel fate that links the two. A routine life changes to one filled with the unexpected, a promise to return home becoming their only guide down an uncertain road. \r\n\r\n(Source: Aniplex of America)", + "show_type": "TV", + "started_airing": "2015-07-05", + "finished_airing": "2015-09-27", + "community_rating": 4.0201120371147, + "age_rating": "PG13", + "genres": [ + { + "name": "Comedy" + }, + { + "name": "Drama" + }, + { + "name": "Super Power" + }, + { + "name": "School" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.0" + } + }, + { + "id": 9131652, + "episodes_watched": 12, + "last_watched": "2015-09-12T20:06:39.355Z", + "updated_at": "2015-09-12T20:06:39.355Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 8712, + "mal_id": 25879, + "slug": "working-3", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/working-3", + "title": "Working!!!", + "alternate_title": "Wagnaria!!!", + "episode_count": 13, + "episode_length": 23, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/008/712/large/Working-Saison-3-Visual-Art.jpg?1427928008", + "synopsis": "The third season of the Working!! series.", + "show_type": "TV", + "started_airing": "2015-07-05", + "finished_airing": null, + "community_rating": 4.2499808378722, + "age_rating": "PG13", + "genres": [ + { + "name": "Comedy" + }, + { + "name": "Slice of Life" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.5" + } + }, + { + "id": 9719799, + "episodes_watched": 23, + "last_watched": "2015-09-12T13:02:56.219Z", + "updated_at": "2015-09-12T13:02:56.220Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 10016, + "mal_id": 28297, + "slug": "ore-monogatari", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/ore-monogatari", + "title": "Ore Monogatari!!", + "alternate_title": "My Love Story!!", + "episode_count": 24, + "episode_length": 22, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/010/016/large/98d170b9e221550a05ea0309462510041423372549_full.jpg?1429885511", + "synopsis": "Gouda Takeo is a freshman in high school. (Both estimates) Weight: 120kg, Height: 2 meters. He spends his days peacefully with his super-popular-with-girls, yet insensitive childhood friend, Sunakawa. One morning, on the train to school, Takeo saves a girl, Yamato, from being molested by a pervert. Could this be the beginning of spring for Takeo?\n\n(Source: MU)", + "show_type": "TV", + "started_airing": "2015-04-09", + "finished_airing": "2015-09-24", + "community_rating": 4.2192057339959, + "age_rating": "PG13", + "genres": [ + { + "name": "Comedy" + }, + { + "name": "Romance" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.0" + } + }, + { + "id": 9131608, + "episodes_watched": 24, + "last_watched": "2015-09-13T11:36:06.608Z", + "updated_at": "2015-09-13T11:36:06.609Z", + "rewatched_times": 0, + "notes": null, + "notes_present": null, + "status": "currently-watching", + "private": false, + "rewatching": false, + "anime": { + "id": 9142, + "mal_id": 27663, + "slug": "baby-steps-2", + "status": "Currently Airing", + "url": "https://hummingbird.me/anime/baby-steps-2", + "title": "Baby Steps 2nd Season", + "alternate_title": "", + "episode_count": 0, + "episode_length": 24, + "cover_image": "https://static.hummingbird.me/anime/poster_images/000/009/142/large/0WCindC.jpg?1428540276", + "synopsis": "Season 2 of Baby Steps. ", + "show_type": "TV", + "started_airing": "2015-04-05", + "finished_airing": null, + "community_rating": 4.2037554731763, + "age_rating": "PG13", + "genres": [ + { + "name": "Sports" + }, + { + "name": "Romance" + }, + { + "name": "School" + } + ] + }, + "rating": { + "type": "advanced", + "value": "4.5" + } + } +] \ No newline at end of file diff --git a/tests/test_data/manga_list/manga-transformed.json b/tests/test_data/manga_list/manga-transformed.json new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_data/manga_list/manga-zippered.json b/tests/test_data/manga_list/manga-zippered.json new file mode 100644 index 00000000..4818a6e8 --- /dev/null +++ b/tests/test_data/manga_list/manga-zippered.json @@ -0,0 +1 @@ +[{"id":401735,"status":"Currently Reading","is_favorite":null,"rating":null,"notes":null,"chapters_read":6,"volumes_read":1,"rereading":false,"reread_count":0,"last_read":"2015-06-23T21:00:20.169Z","manga":{"id":"love-hina","romaji_title":"Love Hina","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/047\/large\/52139.jpg?1434249493","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/047\/large\/52139.jpg?1434249493","synopsis":"Keitaro has had great difficulty getting into the university of his choice and no luck in meeting women. In a desperate effort to go into seclusion and study for his entrance exams, he volunteers to take over running his grandmother's hotel. His plans are ruined when he discovers that the \"hotel\" is actually an all-girls dormitory ... and some serious distractions ensue.\r\n(Source: Tokyopop)","chapter_count":120,"volume_count":14,"genres":["Comedy","Ecchi","Harem","Romance"],"manga_type":"Manga","updated_at":"2015-06-14T02:38:14.115Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400982,"status":"Plan to Read","is_favorite":null,"rating":null,"notes":null,"chapters_read":0,"volumes_read":0,"rereading":false,"reread_count":0,"last_read":"2015-05-26T23:37:37.364Z","manga":{"id":"murder-incarnation","romaji_title":"Murder Incarnation","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/026\/632\/large\/115683.jpg?1434307495","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/026\/632\/large\/115683.jpg?1434307495","synopsis":"A tragic loss. The endless despair that accompanies losing a loved one. A mysterious girl who appears at just the right moment. An unbelievable offer. \"I can bring your lost loved one back to life, if you complete a simple task for me. Please kill three people, any three people, in the next 24 hours. Do that, and without fail I will revive them just as they were.\" Could YOU take three lives to bring someone you love back from the dead? What value do you place on human life?\r\n\r\n(Source: Crunchyroll)","chapter_count":0,"volume_count":2,"genres":["Psychological"],"manga_type":"Manga","updated_at":"2015-06-14T18:44:56.665Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400980,"status":"Plan to Read","is_favorite":null,"rating":null,"notes":null,"chapters_read":0,"volumes_read":0,"rereading":false,"reread_count":0,"last_read":"2015-05-26T23:37:12.694Z","manga":{"id":"doll-the-hotel-detective","romaji_title":"DOLL The Hotel Detective","english_title":"Doll: The Hotel Detective","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/010\/076\/large\/34469.jpg?1434271227","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/010\/076\/large\/34469.jpg?1434271227","synopsis":"Hotel detective Doll is assigned to protect the president of the United States during his stay at the luxurious Sunrise Hotel. While assisting a hotel guest who has fallen ill, she discovers and kills an assassin, but something tells her the danger isn\u2019t over yet\u2026 \u201cBefore the President\u2019s Arrival\u201d plus four more stories! (Source: Jmanga)","chapter_count":17,"volume_count":3,"genres":["Action"],"manga_type":"Manga","updated_at":"2015-06-14T08:40:28.786Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400978,"status":"Plan to Read","is_favorite":null,"rating":null,"notes":null,"chapters_read":0,"volumes_read":0,"rereading":false,"reread_count":0,"last_read":"2015-05-26T23:36:49.961Z","manga":{"id":"fuuka","romaji_title":"Fuuka","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/025\/292\/large\/4407752-04.jpg?1434304607","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/025\/292\/large\/4407752-04.jpg?1434304607","synopsis":"The protagonist Yuu Haruna moves into a town and meets a strange girl named Fuuka (whose name has kanji characters for \"wind\" and \"summer\"). This girl who is like a summer wind possesses a mysterious power to attract people.\n\n(Source: ANN)","chapter_count":0,"volume_count":0,"genres":["Ecchi","Romance","School"],"manga_type":"Manga","updated_at":"2015-06-14T17:56:49.512Z","cover_image":"https:\/\/static.hummingbird.me\/manga\/cover_images\/000\/025\/292\/original\/6ctYENJ.png?1433948658","cover_image_top_offset":305}},{"id":400977,"status":"Plan to Read","is_favorite":null,"rating":null,"notes":null,"chapters_read":0,"volumes_read":0,"rereading":false,"reread_count":0,"last_read":"2015-05-26T23:36:34.644Z","manga":{"id":"yamada-kun-to-7-nin-no-majo","romaji_title":"Yamada-kun to 7-nin no Majo","english_title":"Yamada-kun and the Seven Witches","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/011\/777\/large\/82656l.jpg?1438784325","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/011\/777\/large\/82656l.jpg?1438784325","synopsis":"Ryuu Yamada is a second-year student at Suzaku High. Ryuu is always late for school, naps in class and gets abysmal grades. His life is a dead bore. The beautiful Urara Shiraishi, on the other hand, is Suzaku High's brightest student. One day, without explanation, their bodies are swapped! Ryuu ends up in Urara's body, and Urara in Ryuu's.\r\n\r\n(Source: MU)","chapter_count":0,"volume_count":0,"genres":["Comedy","Ecchi","Gender Bender","Romance","School","Supernatural"],"manga_type":"Manga","updated_at":"2015-08-12T13:12:01.532Z","cover_image":"https:\/\/static.hummingbird.me\/manga\/cover_images\/000\/011\/777\/original\/Yamada-kun.to.7-nin.no.Majo.full.1319881.jpg?1438784293","cover_image_top_offset":75}},{"id":400904,"status":"On Hold","is_favorite":null,"rating":"4.5","notes":null,"chapters_read":86,"volumes_read":12,"rereading":false,"reread_count":0,"last_read":"2015-06-25T00:53:09.733Z","manga":{"id":"yotsubato","romaji_title":"Yotsubato!","english_title":"Yotsuba&!","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/272\/large\/Yotsuba-Cover-Images-yotsuba-and-5465671-434-600.jpg?1434249971","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/272\/large\/Yotsuba-Cover-Images-yotsuba-and-5465671-434-600.jpg?1434249971","synopsis":"Yotsuba's daily life is full of adventure. She is energetic, curious, and a bit odd\u2014odd enough to be called strange by her father as well as ignorant of many things that even a five-year-old should know. Because of this, the most ordinary experience can become an adventure for her. As the days progress, she makes new friends and shows those around her that every day can be enjoyable. \n[Written by MAL Rewrite]","chapter_count":null,"volume_count":null,"genres":["Comedy","Slice of Life"],"manga_type":"Manga","updated_at":"2015-06-14T02:46:12.931Z","cover_image":"https:\/\/static.hummingbird.me\/manga\/cover_images\/000\/000\/272\/original\/Yotsuba-yotsuba-and-5465982-2037-1020.jpg?1431898957","cover_image_top_offset":88}},{"id":400903,"status":"Completed","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":111,"volumes_read":13,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.744Z","manga":{"id":"wagatsuma-san-wa-ore-no-yome","romaji_title":"Wagatsuma-san wa Ore no Yome","english_title":"My Wife Is Wagatsuma-san","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/005\/516\/large\/48035.jpg?1434261178","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/005\/516\/large\/48035.jpg?1434261178","synopsis":"Aoshima Hitoshi is a second year student in high school, who wishes he had a girlfriend. One day he wakes up for an unknown reason 10 years in the future, and he is married to the prettiest girl in school, Wagatsuma Ai! How has their relationship grown from mere acquaintances to husband and wife!?\n(Source: MU)","chapter_count":111,"volume_count":13,"genres":["Comedy","Romance","School","Slice of Life"],"manga_type":"Manga","updated_at":"2015-06-14T05:53:00.176Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400902,"status":"Completed","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":4,"volumes_read":1,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.732Z","manga":{"id":"usotsuki-marriage","romaji_title":"Usotsuki Marriage","english_title":"Deceitful Marriage","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/023\/295\/large\/12823.jpg?1434300356","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/023\/295\/large\/12823.jpg?1434300356","synopsis":"1. Kekkon no Jouken (Wedding's Condition)\nAs a Bridal Advisor, finding soul mates for people is Yoshimi Nishihara's job. Yet she simply cannot find a suitable match for this particular client.\n2. Mujouken no Koufuku (Unlimited Conditions for Happiness)\nMisako attends her high school reunion determined to show her old rival just how successful she now is... Only to find him unemployed and homeless! This simply will not do.\n3. Yuuwaku no Rakuen (Paradise Temptation)\n4. Usotsuki Marriage (The Lying Marriage)\nEven though Narumi is an amateur when it comes to flower arranging, it is still her dream to make flower arrangements for weddings and to have a romantic wedding surrounded by flowers and lights with the person she loves most. However, while she was delivering some things to the wedding place, she suddenly has to take the bridal wear\u2019s role\u2026?! \n(Source: Midnight Scans)","chapter_count":4,"volume_count":1,"genres":["Comedy","Romance"],"manga_type":"Manga","updated_at":"2015-06-14T16:45:57.832Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400901,"status":"Currently Reading","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":28,"volumes_read":1,"rereading":false,"reread_count":0,"last_read":"2015-06-26T02:10:09.083Z","manga":{"id":"usagi-drop","romaji_title":"Usagi Drop","english_title":"Bunny Drop","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/007\/629\/large\/53493.jpg?1434265873","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/007\/629\/large\/53493.jpg?1434265873","synopsis":"When 30-year-old Daikichi returns home for his grandfather's funeral he meets an unfamiliar child in the garden. His mother explains that Rin is his grandfather's illegitimate daughter by an unknown mother. The girl is an embarrassment to all his relatives and nobody wants to take her in because of the scandal. Annoyed by their attitude, Daikichi decides to take care of Rin himself, even though he is single and has no experience raising a child.","chapter_count":62,"volume_count":10,"genres":["Comedy","Drama","Slice of Life"],"manga_type":"Manga","updated_at":"2015-06-14T07:11:15.030Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400900,"status":"Dropped","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":269,"volumes_read":12,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.708Z","manga":{"id":"urusei-yatsura","romaji_title":"Urusei Yatsura","english_title":"Those Obnoxious Aliens","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/702\/large\/3465.jpg?1434250836","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/702\/large\/3465.jpg?1434250836","synopsis":"What would you do if a tiger skin bikini-clad alien followed you to school every day? Poor Ataru's life has never returned to normal since volatile extraterrestrial princess Lum fell for him. Now an excruciatingly wealthy and genteel rival, Mendo, adds to Ataru's torment. Not to mention an unending stream of extraordinary classroom visitors and educational materials including incompetent cherry blossom spirits, a legendary nightmare-eating tapir, and a fourth-dimensional camera that breaches alternate realities. \n(Source: Viz)","chapter_count":366,"volume_count":34,"genres":["Comedy","Romance","Sci-Fi"],"manga_type":"Manga","updated_at":"2015-06-14T03:00:37.158Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400899,"status":"Completed","is_favorite":null,"rating":"3.5","notes":null,"chapters_read":6,"volumes_read":1,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.697Z","manga":{"id":"sold-out","romaji_title":"SOLD OUT!","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/009\/061\/large\/4134.jpg?1434268999","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/009\/061\/large\/4134.jpg?1434268999","synopsis":"Ina wants to meet a normal boy, so she asks her best friend, Mako, for help. At first, they went shopping in the new \"Se Rejouir\". There, Ina suddenly confesses her love to the Manager. Is that the romantic beginning of a love story?\r\n(Source: MangaUpdates)","chapter_count":6,"volume_count":1,"genres":["Drama","Romance"],"manga_type":"Manga","updated_at":"2015-06-14T08:03:21.427Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400898,"status":"On Hold","is_favorite":null,"rating":"5.0","notes":null,"chapters_read":190,"volumes_read":30,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.685Z","manga":{"id":"skip-beat","romaji_title":"Skip Beat!","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/388\/large\/26110.jpg?1434252296","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/388\/large\/26110.jpg?1434252296","synopsis":"Kyoko Mogami followed her true love Sho to Tokyo to support him while he made it big as an idol. But he's casting her out now that he's famous! Kyoko won't suffer in silence--she's going to get her sweet revenge by beating Sho in show biz!\n(Source: Viz)","chapter_count":0,"volume_count":0,"genres":["Comedy","Drama","Romance"],"manga_type":"Manga","updated_at":"2015-06-14T03:24:58.679Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400897,"status":"Completed","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":10,"volumes_read":2,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.673Z","manga":{"id":"samurai-champloo","romaji_title":"Samurai Champloo","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/171\/large\/56743.jpg?1434251812","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/171\/large\/56743.jpg?1434251812","synopsis":"Mugen is a rough-around-the-edges mercenary with a killer technique and nothing left to lose. Jin is a disciplined samurai who's as deadly as he is reserved. Fuu is a young waitress with a good heart and a resourcefulness that emerges when you least expect it. These three unlikely companions are about to begin a journey that will change all of their lives.\nIt's a dangerous quest for a mysterious samurai that will see our squabbling group of heroes get into and out of trouble more times than they can count (which admittedly, isn't very high). From the cynical gentility of the nobles to the backstabbing of the Japanese underworld, Mugen, Jin and Fuu will face threats from without and within as they hurl insults and throwing stars alike. Ancient Japan is about to get a lethal dose of street justice -- Champloo style. And it will never be the same.\n(Source: Tokyopop)","chapter_count":10,"volume_count":2,"genres":["Action","Adventure","Comedy"],"manga_type":"Manga","updated_at":"2015-06-14T03:16:53.988Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400896,"status":"Completed","is_favorite":null,"rating":"4.5","notes":null,"chapters_read":407,"volumes_read":38,"rereading":false,"reread_count":0,"last_read":"2015-06-25T00:53:37.426Z","manga":{"id":"ranma","romaji_title":"Ranma \u00bd","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/062\/large\/5616.jpg?1434249522","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/062\/large\/5616.jpg?1434249522","synopsis":"In China, there lies a famous training springs, a place where martial artists can hone their skills to great levels. Unfortunately, the springs are also cursed! Teenage martial artist Ranma falls into the \"spring of drowned girl\" and now changes into a woman every time he's splashed with cold water. That doesn't stop his father from engaging him to Akane, the daughter of an old friend and a tough girl who has better thing to do than worry about boys. But Akane isn't the only girl who has a chance for Ranma's affections -- two other girls have also been betrothed to him. But Ranma has better things to do than worry about his love life -- such as making a plethora of crazy rivals and even more suitors!","chapter_count":407,"volume_count":38,"genres":["Action","Comedy","Ecchi","Gender Bender","Harem","Martial Arts","Romance","School"],"manga_type":"Manga","updated_at":"2015-06-25T00:16:50.091Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400895,"status":"Completed","is_favorite":null,"rating":"3.5","notes":null,"chapters_read":5,"volumes_read":1,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.651Z","manga":{"id":"otome-no-iroha","romaji_title":"Otome no Iroha!","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/022\/436\/large\/12188.jpg?1434298544","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/022\/436\/large\/12188.jpg?1434298544","synopsis":"Iroha, a masculine girl and Hifumi, a feminine boy are siblings who has transfered to a different middle school and moved to their grandparents house. However, after the first night much to their surprise...","chapter_count":5,"volume_count":1,"genres":["Comedy","Ecchi","School"],"manga_type":"Manga","updated_at":"2015-06-14T16:15:45.684Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400894,"status":"Completed","is_favorite":null,"rating":"5.0","notes":null,"chapters_read":26,"volumes_read":4,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.639Z","manga":{"id":"ore-no-imouto-ga-konnani-kawaii-wake-ga-nai","romaji_title":"Ore no Imouto ga Konnani Kawaii Wake ga Nai","english_title":"Oreimo","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/714\/large\/71Zqo5clDfL._SL1200_.jpg?1439399108","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/714\/large\/71Zqo5clDfL._SL1200_.jpg?1439399108","synopsis":"Kyousuke Kousaka, a normal seventeen-year-old high school student, hasn't gotten along with his younger sister, Kirino, in years. For longer than he can remember, Kirino has ignored his comings and goings and looked at him with spurning eyes. It seemed as if the relationship between Kyousuke and his sister, now fourteen, would continue this way forever.\n\nOne day, however, Kyousuke finds a DVD case of a magical girl anime entitled Hoshikuzu Witch Merle (Stardust Witch Merle), which had fallen into the entranceway of his house. To Kyousuke's surprise, inside the case is a hidden adult video game titled Imouto to Koishiyo! (Love with Little Sister!). Kyousuke attempts to fish out the culprit who dropped the case by bringing up the topic of magical girl anime at the family dinner table. All that comes out is a strong negative reaction from his parents, especially his anti-otaku policeman father.\n\nThat night, Kirino bursts into Kyousuke's room and, in perhaps the first conversation she has initiated with him in years, says they \"have things to talk about.\" Kirino brings Kyousuke to her room and shows him an extensive collection of moe anime and lolicon bishoujo games she has been collecting in secret.\n\n(Source: Wikipedia)","chapter_count":26,"volume_count":4,"genres":["Comedy","Drama","Ecchi","School"],"manga_type":"Manga","updated_at":"2015-08-12T17:05:09.128Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400893,"status":"On Hold","is_favorite":null,"rating":"4.5","notes":null,"chapters_read":44,"volumes_read":6,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.624Z","manga":{"id":"onii-chan-no-koto-nanka-zenzen-suki-janain-dakara-ne","romaji_title":"Onii-chan no Koto nanka Zenzen Suki Janain Dakara ne!!","english_title":"I don't like you at all, Big Brother!!","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/021\/900\/large\/11793.jpg?1434297436","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/021\/900\/large\/11793.jpg?1434297436","synopsis":"High School junior Takanashi Nao has a problem: she has a crush on her dreamy older brother, Shuusuke. Fortunately, when Nao discovers that she was adopted as a child and they\u2019re not related by blood, it seems like the coast is clear\u2014but Shuusuke just doesn\u2019t see it that way.\nTo make matters worse, Nao finds herself in direct competition against Shuusuke\u2019s hot childhood friend, Iroha, not to mention class president Mayuka. As all three girls vie for Shuusuke\u2019s attention, Nao soon learns that all is fair in love and war!\n(Source: Seven Seas)","chapter_count":0,"volume_count":0,"genres":["Comedy","Ecchi","Harem","Romance","School"],"manga_type":"Manga","updated_at":"2015-06-14T15:57:17.592Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400892,"status":"Completed","is_favorite":null,"rating":"4.5","notes":null,"chapters_read":3,"volumes_read":1,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.610Z","manga":{"id":"onegai-sensei-manga","romaji_title":"Onegai, Sensei","english_title":"Please, Teacher","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/019\/137\/large\/9625.jpg?1434291544","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/019\/137\/large\/9625.jpg?1434291544","synopsis":"Consists of 3 One-Shots:\r\n1. Onegai Teacher:\r\nAfter a painful experience in love, Tani Rika started to have a cynical view of love. She falls in love easily, confesses her love easily, but the moment the guy tells her that he loves her, she dumps him. This time, her new target is Tanabe-sensei, a teacher at the cram school she's going to. Making him fall for her is just another game to Rika - or so she thought, but she started to develop feelings that she thought she had forgotten a long time ago...\r\n2. Altair's Love Letter\r\n3. The Boy from the Sleeping Country\r\n(Source: Aerandria Scans)","chapter_count":3,"volume_count":1,"genres":["Romance","School"],"manga_type":"Manga","updated_at":"2015-06-14T14:19:05.704Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400891,"status":"Dropped","is_favorite":null,"rating":null,"notes":null,"chapters_read":0,"volumes_read":0,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.598Z","manga":{"id":"obaa-chan-wa-idol","romaji_title":"Obaa-chan wa Idol","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/008\/089\/large\/3634.jpg?1434266860","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/008\/089\/large\/3634.jpg?1434266860","synopsis":"Yamada Momoka is your average 16 year old girl. Her family consists of herself, her dad who works at a TV station, and her mom. Apparently she also has a strict prune of a grandma, but who doesn't? Except that the grandma, Yamada Tamaki, had an accident at the TV station where she got electrocuted and now looks like a 16 year old Yamato Nadeshiko. It isn't easy for Momoka when her grandma arbitrarily decides to attend Momoka's high school as a student as well. Tamaki isn't just pretty, she's also very cultured, well-mannered, and still maintains her old-fashioned streak from her 65 years of wisdom. It's bad enough when Momoka starts being referred to as \"Old Yamada\" and her grandma (Tamaki) referred to as \"New Yamada\", but it's even worse when Momoka's crush on a dashing young man starts to take an interest in Tamaki as well. Fight-o, Momoka! Protect your beloved grandma, Momoka! And don't let her walk off with your boytoy, Momoka!\r\n(Source: mahouneko)","chapter_count":22,"volume_count":4,"genres":["Comedy","Drama","Romance","Supernatural"],"manga_type":"Manga","updated_at":"2015-06-14T07:27:41.464Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400890,"status":"Completed","is_favorite":null,"rating":"4.5","notes":null,"chapters_read":96,"volumes_read":12,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.585Z","manga":{"id":"nazo-no-kanojo-x","romaji_title":"Nazo no Kanojo X","english_title":"Mysterious Girlfriend X","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/004\/029\/large\/1926.jpg?1434257986","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/004\/029\/large\/1926.jpg?1434257986","synopsis":"One day, a strange transfer student appears before Tsubaki. Urabe Mikoto is an antisocial girl, whose hobby is just sleeping during class-breaks. One day, Tsubaki goes to wake her up and accidentally tastes her drool... And gets hooked on that!\nAfter that, he starts going out with her and gets to know her better. Her second hobby, as it turns out, is carrying around scissors in her panties and cutting paper into flowers...\n(Source: MU)","chapter_count":96,"volume_count":12,"genres":["Ecchi","Mystery","Romance","School"],"manga_type":"Manga","updated_at":"2015-06-14T04:59:47.843Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400889,"status":"Completed","is_favorite":null,"rating":"3.5","notes":null,"chapters_read":7,"volumes_read":2,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.567Z","manga":{"id":"milk-to-vitamin","romaji_title":"Milk to Vitamin","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/007\/616\/large\/3843.jpg?1434265843","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/007\/616\/large\/3843.jpg?1434265843","synopsis":"Milk is a young and childish girl living with her aunt in Orange Town. One day, she is told that a guest is coming over to stay with them for a while. Milk's aunt had said that the guest is cute and pretty. Milk, excited about her new friend goes to meet the guest at the fountain. Milk's childhood friend Vitamin and others accompany her at this time. Through an unforseen event, Milk arrives late at the fountain with the guest nowhere to be seen. They did however, find a handsome young boy asking for directions to Orange Town. \r\n(Baka-Updates)","chapter_count":7,"volume_count":2,"genres":["Comedy","Drama","Romance"],"manga_type":"Manga","updated_at":"2015-06-14T07:10:44.251Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400888,"status":"Completed","is_favorite":null,"rating":"4.5","notes":null,"chapters_read":12,"volumes_read":2,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.548Z","manga":{"id":"mama-wa-shougaku-4-nensei","romaji_title":"Mama wa Shougaku 4 Nensei","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/007\/618\/large\/3464.jpg?1434265846","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/007\/618\/large\/3464.jpg?1434265846","synopsis":"Because her father was sent to London to work, Natsumi, a 4th grade student, also must leave Japan along with him. Her classmates throw a farewell party for her. Natsumi is prepared to go to London, but on the night before Natsumi's arranged departure, a baby suddenly appears in her house after a roar of thunder! What's more is that this little baby is actually the one that Natsumi will give birth to in fifteen years!\r\n(Source: Aku Tenshi)","chapter_count":12,"volume_count":2,"genres":["Comedy","Drama","Sci-Fi"],"manga_type":"Manga","updated_at":"2015-06-14T07:10:48.232Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400887,"status":"Completed","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":13,"volumes_read":2,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.534Z","manga":{"id":"maburaho-7719eaec-27ba-4375-847e-7b140a29257a","romaji_title":"Maburaho","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/649\/large\/5194.jpg?1434252868","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/649\/large\/5194.jpg?1434252868","synopsis":"Kazuki Shikimori has lost his memory and has come to find out that there are three young girls after his DNA. Even though his magic is extremely limited compared to others, it is believe that his offspring will wield incredible magic. Kuriko Kazetsubaki claims to be his girlfriend. Rin Kamishiro is urged by her family to be his wife. And Yuuna Miyami claims to be Kazuki's wife, as per a promise made when they were kids.","chapter_count":14,"volume_count":2,"genres":["Comedy","Harem","Magic","Romance"],"manga_type":"Manga","updated_at":"2015-06-14T03:34:29.466Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400886,"status":"Completed","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":49,"volumes_read":8,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.521Z","manga":{"id":"kono-onee-san-wa-fiction-desu","romaji_title":"Kono Onee-san wa Fiction desu!?","english_title":"Is this Girl for Real!?","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/015\/503\/large\/74249.jpg?1434283423","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/015\/503\/large\/74249.jpg?1434283423","synopsis":"Late one night when Jun was out on his bike, he came across a drunk, half-naked girl sprawled on the side of the road. She came round just long enough to be uncomfortably affectionate. Jun took her to his home so she could sleep it off. It turned out that she is Kawase Narumi, his author mother's new assistant. Unfortunately, she has no idea what she's doing in her new job, so Jun's going to have to coach her. He's also going to have to deal with her habit of getting drunk, mostly naked, and cuddly. Jun's life will never be the same! \n(Source: MangaHelpers)","chapter_count":49,"volume_count":8,"genres":["Comedy","Ecchi","Romance","School"],"manga_type":"Manga","updated_at":"2015-06-14T12:03:44.559Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400885,"status":"Completed","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":5,"volumes_read":1,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.509Z","manga":{"id":"kimi-dake-no-devil","romaji_title":"Kimi Dake no Devil","english_title":"A Devil Just for You","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/014\/606\/large\/7082.jpg?1434281449","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/014\/606\/large\/7082.jpg?1434281449","synopsis":"Sango Minamino, a 16 year-old cute, hyper and somewhat reckless girl, gets rescued one day by a green-eyed boy with black wings who calls himself Kai and claims to be Sango's guardian angel... or is he a devil? (Source: Emily's Random Shoujo Page)","chapter_count":5,"volume_count":1,"genres":["Comedy","Fantasy"],"manga_type":"Manga","updated_at":"2015-06-14T11:30:51.028Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400884,"status":"Completed","is_favorite":null,"rating":"4.5","notes":null,"chapters_read":2,"volumes_read":1,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.495Z","manga":{"id":"kanaete-aizen","romaji_title":"Kanaete Aizen","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/013\/080\/large\/66091.jpg?1434278021","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/013\/080\/large\/66091.jpg?1434278021","synopsis":"Aizen Kanou, just like any high-school boy, yearns for a girlfriend. But he's so painfully shy he flees when any girl tries to talk to him. Except his childhood friend, Yuzu, who scolds him for being so shy. But she leaves behind a temple love-charm. That night in his room Kanou uses the charm to demand heaven grant him his wish for a beautiful girl. When he wakes up in the morning, he finds his wish has been granted--and the beautiful girl is himself.\n(Source: MU)","chapter_count":2,"volume_count":0,"genres":["Ecchi","Romance","School","Supernatural"],"manga_type":"Manga","updated_at":"2015-06-14T10:33:45.399Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400883,"status":"Currently Reading","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":34,"volumes_read":0,"rereading":false,"reread_count":0,"last_read":"2015-07-08T23:55:28.830Z","manga":{"id":"joshikausei","romaji_title":"Joshikausei","english_title":"Joshi Kausei","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/025\/491\/large\/121107.jpg?1434305043","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/025\/491\/large\/121107.jpg?1434305043","synopsis":"Who needs dialog when you're this cute? The beautiful (but unlucky) Momoko, the cool, collected Shibumi, and the refreshingly innocent Mayumi star in a \"silent manga.\" No speeches, no dialog! Just pictures, sound effects, and three high school girls living their daily lives.\r\n\r\n(Source: Crunchyroll)","chapter_count":0,"volume_count":0,"genres":["Comedy","School","Slice of Life"],"manga_type":"Manga","updated_at":"2015-06-14T18:04:04.736Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400882,"status":"Completed","is_favorite":null,"rating":"3.5","notes":null,"chapters_read":558,"volumes_read":56,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.462Z","manga":{"id":"inuyasha","romaji_title":"InuYasha","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/531\/large\/32468.jpg?1434252597","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/531\/large\/32468.jpg?1434252597","synopsis":"Kagome is a modern Japanese high school girl. Never the type to believe in myths and legends, her world view dramatically changes when, one day, she's pulled out of her own time and into another! There, in Japan's ancient past, Kagome discovers more than a few of those dusty old legends are true, and that her destiny is linked to one legendary creature in particular--the dog-like half-demon called Inuyasha! That same trick of fate also ties them both to the Shikon Jewel, or \"Jewel of Four Souls.\" But demons beware...the smallest shard of the Shikon Jewel can give the user unimaginable power.\n(Source: Viz)","chapter_count":558,"volume_count":56,"genres":["Adventure","Comedy","Demons","Drama","Fantasy","Historical","Romance","Supernatural"],"manga_type":"Manga","updated_at":"2015-06-14T03:29:58.614Z","cover_image":"https:\/\/static.hummingbird.me\/manga\/cover_images\/000\/001\/531\/original\/01-020-021.jpg?1430840015","cover_image_top_offset":250}},{"id":400881,"status":"Completed","is_favorite":null,"rating":"4.5","notes":null,"chapters_read":19,"volumes_read":3,"rereading":false,"reread_count":0,"last_read":"2015-06-25T00:53:52.427Z","manga":{"id":"inumimi","romaji_title":"Inumimi","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/004\/025\/large\/1924.jpg?1434257977","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/004\/025\/large\/1924.jpg?1434257977","synopsis":"After spending half a year abroad, Kinosaki Yuichiro is in for a shocking homecoming when he discovers that his inventor\/scientist father has given his 3 dogs the appearance and abilities of girls. Now he is in for a ton of grief as he tries to cope with these changes.\n(Source: Solaris-SVU)","chapter_count":19,"volume_count":3,"genres":["Comedy","Ecchi","Harem","Romance"],"manga_type":"Manga","updated_at":"2015-06-14T04:59:38.807Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400880,"status":"Completed","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":41,"volumes_read":5,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.437Z","manga":{"id":"inu-neko-jump","romaji_title":"Inu Neko Jump","english_title":"Dog Cat Jump","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/002\/136\/large\/978.jpg?1434253893","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/002\/136\/large\/978.jpg?1434253893","synopsis":"(synopsis courtesy of AnimeWaves)\r\nEver since middle school, Takahiro Ozu was famous in the world of track and field as the \u201clong jump specialist?. But after losing his final competition in high school, he hung up his track shoes for good. Now in college, having taken up smoking, he just wants to get a girlfriend and lead a normal student life. Noriko Watsuki has had a crush on Takahiro since she first saw him jump and wants him to join the college track team so she can get close to him. Yuki \u201cThe Headphone Girl? Hoguchi, a high school student who likes to hang out at the university, claims Takahiro took her virginity 13 years ago when he was in kindergarten. She considers him her property to do with as she pleases. Throw in a full cast of zany and unique characters, sprinkle with fan service, and you have the world of Inu Neko Jump.","chapter_count":41,"volume_count":5,"genres":["Comedy","Romance"],"manga_type":"Manga","updated_at":"2015-06-14T03:51:34.141Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400879,"status":"Completed","is_favorite":null,"rating":"3.5","notes":null,"chapters_read":9,"volumes_read":2,"rereading":false,"reread_count":0,"last_read":"2015-06-25T00:53:56.050Z","manga":{"id":"i-hs","romaji_title":"I \u2665 HS","english_title":"I Love High School","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/023\/195\/large\/17718.jpg?1434300143","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/023\/195\/large\/17718.jpg?1434300143","synopsis":"Yamato Onidzuka. Childhood bully, punk, and sports prodigy. His old childhood friends are terrified of him, as he used to bully and harass them on a daily basis. When he transferred to a special sport's school, it seemed like his friends' worst nightmare had finally come to an end. But now that he's back, it seems like the nightmare has returned. Join Megu, Yamato, and their 4 other friends on their hilarious roller-coaster ride known as High School!\n(Source: Operation Boredom)","chapter_count":9,"volume_count":2,"genres":["Comedy","Drama","Romance","School"],"manga_type":"Manga","updated_at":"2015-06-14T16:42:24.286Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400878,"status":"Completed","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":48,"volumes_read":8,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.410Z","manga":{"id":"futaba-kun-change","romaji_title":"Futaba-kun Change\u2661","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/004\/367\/large\/2114.jpg?1434258719","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/004\/367\/large\/2114.jpg?1434258719","synopsis":"Futaba Shimeru is a normal high-schooler living a normal life, active in his school's wrestling club and slowly getting closer to his awkward love interest, Misaki. This fails to last as he discovers his family's hereditary genetic defect that becomes active at adolescence. Although it will eventually become controllable, either excitement or stress now makes Futaba switch sex. Mayhem ensues.\n(Source: Wikipedia)","chapter_count":48,"volume_count":8,"genres":["Comedy","Ecchi","Romance","School"],"manga_type":"Manga","updated_at":"2015-06-14T05:12:00.314Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400877,"status":"Completed","is_favorite":null,"rating":"5.0","notes":null,"chapters_read":58,"volumes_read":9,"rereading":false,"reread_count":0,"last_read":"2015-06-25T00:54:02.851Z","manga":{"id":"full-metal-panic","romaji_title":"Full Metal Panic!","english_title":"Full Metal Panic","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/735\/large\/5190.jpg?1434253058","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/735\/large\/5190.jpg?1434253058","synopsis":"A sergeant by the name of Sousuke Sagara is assigned an important task. That of guarding high school girl Chidori Kaname. Sousuke is a military genius, gaining high rank at an early age, but because of his strange upbringing, he lacks social skill. Now, he finds himself as a fish out of water as he attempts to protect a girl from an evil organization and turn in his school work on time. \n(Source: ANN)","chapter_count":58,"volume_count":9,"genres":["Action","Comedy","Mecha","Military","Romance"],"manga_type":"Manga","updated_at":"2015-06-14T03:37:39.128Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400876,"status":"Completed","is_favorite":null,"rating":"4.5","notes":null,"chapters_read":88,"volumes_read":8,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.366Z","manga":{"id":"chobits","romaji_title":"Chobits","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/278\/large\/19440.jpg?1434249984","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/278\/large\/19440.jpg?1434249984","synopsis":"Hideki's just like every other guy in the 22nd century. He just wants a good job, a good car, and a sexy robot girlfriend to call his own. Until he lands a job, he'll never be able to afford his own 'Persocom' companion. Hideki's luck changes when he discovers Chi--an adorable but seemingly stupid Persocom--tied up in a pile of trash. His first robot companion turns out to be a lot more responsibility than he expected, and she gets him into quite a few embarrassing situations. It's 'boy-meets-girl' for the cyber age. (Source: Tokyopop)","chapter_count":88,"volume_count":8,"genres":["Comedy","Ecchi","Psychological","Romance","Sci-Fi"],"manga_type":"Manga","updated_at":"2015-06-14T02:46:25.229Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400875,"status":"Completed","is_favorite":null,"rating":"5.0","notes":null,"chapters_read":4,"volumes_read":1,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.342Z","manga":{"id":"change-2","romaji_title":"Change 2!!","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/016\/486\/large\/8072.jpg?1434285566","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/016\/486\/large\/8072.jpg?1434285566","synopsis":"Kisaragi Maki is an ordinary high school student. One day, when she's going to help someone who is being beaten up by a gangster, Maki who don't know how to fight become the opposite person. What makes her personality can change like that?\n(Source: MU)","chapter_count":4,"volume_count":1,"genres":["Action","Ecchi","School"],"manga_type":"Manga","updated_at":"2015-06-14T12:39:27.882Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400874,"status":"Currently Reading","is_favorite":null,"rating":"4.5","notes":null,"chapters_read":62,"volumes_read":6,"rereading":false,"reread_count":0,"last_read":"2015-07-08T23:53:42.493Z","manga":{"id":"bokura-wa-minna-kawaisou","romaji_title":"Bokura wa Minna Kawaisou","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/020\/286\/large\/17950117v1.jpg?1434293999","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/020\/286\/large\/17950117v1.jpg?1434293999","synopsis":"Usa, a high-school student aspiring to begin a bachelor lifestyle, moves into a new apartment only to discover that he not only shares a room with a perverted roommate that has an obsession for underaged girls, but also that another girl, Ritsu, a love-at-first-sight, is living in the same building as well!\n(Source: Kirei Cake)","chapter_count":0,"volume_count":0,"genres":["Comedy","Romance","School","Slice of Life"],"manga_type":"Manga","updated_at":"2015-06-14T15:00:01.343Z","cover_image":"https:\/\/static.hummingbird.me\/manga\/cover_images\/000\/020\/286\/original\/11282013_bokura-wa-minna-kawaisou.jpg?1430793688","cover_image_top_offset":40}},{"id":400873,"status":"Completed","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":21,"volumes_read":5,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.292Z","manga":{"id":"boku-ni-natta-watashi","romaji_title":"Boku ni Natta Watashi","english_title":"I Became a Boy","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/379\/large\/20745.jpg?1434252279","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/379\/large\/20745.jpg?1434252279","synopsis":"Welcome to Momoko's waking nightmare. Things were settled. They were! She was SUPPOSED to have gone to a normal school, made normal friends, and led a blissfully normal life. But the universe is just cruelly, irredeemably, monstrously unfair, so instead she found herself thrown out of home, stuck in an all-boys boarding school with a roommate she hates, cursed with a hideous haircut and wearing clothes which, to be frank, she wouldn't be seen dead in.\r\nAnd the only thing worse than her current situation is the one that she'll be in if anyone ever realizes that she is, in fact, a girl. Everything is wrong! Everything! Particularly the fact that, even though she's surrounded by amazingly gorgeous guys, her chances of romance are less than zero. But with life this complicated, something is bound to give. In fact, it just did. Damn. (Source: Storm in Heaven)\r\nThis title is 21 chapters including the extra chapters.","chapter_count":21,"volume_count":5,"genres":["Drama","Romance","School"],"manga_type":"Manga","updated_at":"2015-06-14T03:24:40.188Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400872,"status":"Dropped","is_favorite":null,"rating":"4.0","notes":null,"chapters_read":30,"volumes_read":5,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.267Z","manga":{"id":"bishoujo-senshi-sailor-moon","romaji_title":"Bishoujo Senshi Sailor Moon","english_title":"Sailor Moon","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/241\/large\/6601.jpg?1434249905","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/000\/241\/large\/6601.jpg?1434249905","synopsis":"Tsukino Usagi is 14 years old and in her second year of middle school. She's a bit of a crybaby and klutzy. However, she can transform into a warrior of justice, Sailormoon! An eternal classic that should be read by all.\n(Source: MU)","chapter_count":61,"volume_count":18,"genres":["Drama","Fantasy","Magic","Mahou Shoujo","Romance"],"manga_type":"Manga","updated_at":"2015-09-12T22:55:37.124Z","cover_image":"https:\/\/static.hummingbird.me\/manga\/cover_images\/000\/000\/241\/original\/2-20-21.jpg?1442098535","cover_image_top_offset":175}},{"id":400871,"status":"Completed","is_favorite":null,"rating":"3.5","notes":null,"chapters_read":4,"volumes_read":1,"rereading":false,"reread_count":0,"last_read":"2015-06-25T00:53:58.689Z","manga":{"id":"anta-nanka-daikirai","romaji_title":"Anta Nanka Daikirai","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/024\/984\/large\/14617.jpg?1434303960","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/024\/984\/large\/14617.jpg?1434303960","synopsis":"Collection of one shots.\n1) I Can't Stand You\n2) Caught on You\n3) Something's Wrong\n4) See You Tomorrow","chapter_count":4,"volume_count":1,"genres":["Drama","Romance","School"],"manga_type":"Manga","updated_at":"2015-06-14T17:46:02.005Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}},{"id":400870,"status":"Completed","is_favorite":null,"rating":"3.5","notes":null,"chapters_read":10,"volumes_read":2,"rereading":false,"reread_count":0,"last_read":"2015-05-26T21:39:11.214Z","manga":{"id":"akane-chan-overdrive","romaji_title":"Akane-chan Overdrive","poster_image":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/961\/large\/900.jpg?1434253542","poster_image_thumb":"https:\/\/static.hummingbird.me\/manga\/poster_images\/000\/001\/961\/large\/900.jpg?1434253542","synopsis":"Nineteen-year-old Takashi Amamiya dies after tripping on a bottle but is transported into a body of a cute girl, Akane Hagiwara. Following this, Amamiya goes through various trials and tribulations dealing with, being a girl, getting his body back, and dealing with old and new friends. \n-Wikipedia Entry","chapter_count":10,"volume_count":2,"genres":["Comedy","Ecchi","Gender Bender"],"manga_type":"Manga","updated_at":"2015-06-14T03:45:44.128Z","cover_image":"\/cover_images\/original\/missing.png","cover_image_top_offset":0}}] \ No newline at end of file diff --git a/tests/test_data/manga_list/manga.json b/tests/test_data/manga_list/manga.json new file mode 100644 index 00000000..c13c70df --- /dev/null +++ b/tests/test_data/manga_list/manga.json @@ -0,0 +1,1288 @@ +{ + "manga": [ + { + "id": "love-hina", + "romaji_title": "Love Hina", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/000/047/large/52139.jpg?1434249493", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/000/047/large/52139.jpg?1434249493", + "synopsis": "Keitaro has had great difficulty getting into the university of his choice and no luck in meeting women. In a desperate effort to go into seclusion and study for his entrance exams, he volunteers to take over running his grandmother's hotel. His plans are ruined when he discovers that the \"hotel\" is actually an all-girls dormitory ... and some serious distractions ensue.\r\n(Source: Tokyopop)", + "chapter_count": 120, + "volume_count": 14, + "genres": [ + "Comedy", + "Ecchi", + "Harem", + "Romance" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T02:38:14.115Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "murder-incarnation", + "romaji_title": "Murder Incarnation", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/026/632/large/115683.jpg?1434307495", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/026/632/large/115683.jpg?1434307495", + "synopsis": "A tragic loss. The endless despair that accompanies losing a loved one. A mysterious girl who appears at just the right moment. An unbelievable offer. \"I can bring your lost loved one back to life, if you complete a simple task for me. Please kill three people, any three people, in the next 24 hours. Do that, and without fail I will revive them just as they were.\" Could YOU take three lives to bring someone you love back from the dead? What value do you place on human life?\r\n\r\n(Source: Crunchyroll)", + "chapter_count": 0, + "volume_count": 2, + "genres": [ + "Psychological" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T18:44:56.665Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "doll-the-hotel-detective", + "romaji_title": "DOLL The Hotel Detective", + "english_title": "Doll: The Hotel Detective", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/010/076/large/34469.jpg?1434271227", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/010/076/large/34469.jpg?1434271227", + "synopsis": "Hotel detective Doll is assigned to protect the president of the United States during his stay at the luxurious Sunrise Hotel. While assisting a hotel guest who has fallen ill, she discovers and kills an assassin, but something tells her the danger isn’t over yet… “Before the President’s Arrival” plus four more stories! (Source: Jmanga)", + "chapter_count": 17, + "volume_count": 3, + "genres": [ + "Action" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T08:40:28.786Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "fuuka", + "romaji_title": "Fuuka", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/025/292/large/4407752-04.jpg?1434304607", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/025/292/large/4407752-04.jpg?1434304607", + "synopsis": "The protagonist Yuu Haruna moves into a town and meets a strange girl named Fuuka (whose name has kanji characters for \"wind\" and \"summer\"). This girl who is like a summer wind possesses a mysterious power to attract people.\n\n(Source: ANN)", + "chapter_count": 0, + "volume_count": 0, + "genres": [ + "Ecchi", + "Romance", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T17:56:49.512Z", + "cover_image": "https://static.hummingbird.me/manga/cover_images/000/025/292/original/6ctYENJ.png?1433948658", + "cover_image_top_offset": 305 + }, + { + "id": "yamada-kun-to-7-nin-no-majo", + "romaji_title": "Yamada-kun to 7-nin no Majo", + "english_title": "Yamada-kun and the Seven Witches", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/011/777/large/82656l.jpg?1438784325", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/011/777/large/82656l.jpg?1438784325", + "synopsis": "Ryuu Yamada is a second-year student at Suzaku High. Ryuu is always late for school, naps in class and gets abysmal grades. His life is a dead bore. The beautiful Urara Shiraishi, on the other hand, is Suzaku High's brightest student. One day, without explanation, their bodies are swapped! Ryuu ends up in Urara's body, and Urara in Ryuu's.\r\n\r\n(Source: MU)", + "chapter_count": 0, + "volume_count": 0, + "genres": [ + "Comedy", + "Ecchi", + "Gender Bender", + "Romance", + "School", + "Supernatural" + ], + "manga_type": "Manga", + "updated_at": "2015-08-12T13:12:01.532Z", + "cover_image": "https://static.hummingbird.me/manga/cover_images/000/011/777/original/Yamada-kun.to.7-nin.no.Majo.full.1319881.jpg?1438784293", + "cover_image_top_offset": 75 + }, + { + "id": "yotsubato", + "romaji_title": "Yotsubato!", + "english_title": "Yotsuba&!", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/000/272/large/Yotsuba-Cover-Images-yotsuba-and-5465671-434-600.jpg?1434249971", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/000/272/large/Yotsuba-Cover-Images-yotsuba-and-5465671-434-600.jpg?1434249971", + "synopsis": "Yotsuba's daily life is full of adventure. She is energetic, curious, and a bit odd—odd enough to be called strange by her father as well as ignorant of many things that even a five-year-old should know. Because of this, the most ordinary experience can become an adventure for her. As the days progress, she makes new friends and shows those around her that every day can be enjoyable. \n[Written by MAL Rewrite]", + "chapter_count": null, + "volume_count": null, + "genres": [ + "Comedy", + "Slice of Life" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T02:46:12.931Z", + "cover_image": "https://static.hummingbird.me/manga/cover_images/000/000/272/original/Yotsuba-yotsuba-and-5465982-2037-1020.jpg?1431898957", + "cover_image_top_offset": 88 + }, + { + "id": "wagatsuma-san-wa-ore-no-yome", + "romaji_title": "Wagatsuma-san wa Ore no Yome", + "english_title": "My Wife Is Wagatsuma-san", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/005/516/large/48035.jpg?1434261178", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/005/516/large/48035.jpg?1434261178", + "synopsis": "Aoshima Hitoshi is a second year student in high school, who wishes he had a girlfriend. One day he wakes up for an unknown reason 10 years in the future, and he is married to the prettiest girl in school, Wagatsuma Ai! How has their relationship grown from mere acquaintances to husband and wife!?\n(Source: MU)", + "chapter_count": 111, + "volume_count": 13, + "genres": [ + "Comedy", + "Romance", + "School", + "Slice of Life" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T05:53:00.176Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "usotsuki-marriage", + "romaji_title": "Usotsuki Marriage", + "english_title": "Deceitful Marriage", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/023/295/large/12823.jpg?1434300356", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/023/295/large/12823.jpg?1434300356", + "synopsis": "1. Kekkon no Jouken (Wedding's Condition)\nAs a Bridal Advisor, finding soul mates for people is Yoshimi Nishihara's job. Yet she simply cannot find a suitable match for this particular client.\n2. Mujouken no Koufuku (Unlimited Conditions for Happiness)\nMisako attends her high school reunion determined to show her old rival just how successful she now is... Only to find him unemployed and homeless! This simply will not do.\n3. Yuuwaku no Rakuen (Paradise Temptation)\n4. Usotsuki Marriage (The Lying Marriage)\nEven though Narumi is an amateur when it comes to flower arranging, it is still her dream to make flower arrangements for weddings and to have a romantic wedding surrounded by flowers and lights with the person she loves most. However, while she was delivering some things to the wedding place, she suddenly has to take the bridal wear’s role…?! \n(Source: Midnight Scans)", + "chapter_count": 4, + "volume_count": 1, + "genres": [ + "Comedy", + "Romance" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T16:45:57.832Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "usagi-drop", + "romaji_title": "Usagi Drop", + "english_title": "Bunny Drop", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/007/629/large/53493.jpg?1434265873", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/007/629/large/53493.jpg?1434265873", + "synopsis": "When 30-year-old Daikichi returns home for his grandfather's funeral he meets an unfamiliar child in the garden. His mother explains that Rin is his grandfather's illegitimate daughter by an unknown mother. The girl is an embarrassment to all his relatives and nobody wants to take her in because of the scandal. Annoyed by their attitude, Daikichi decides to take care of Rin himself, even though he is single and has no experience raising a child.", + "chapter_count": 62, + "volume_count": 10, + "genres": [ + "Comedy", + "Drama", + "Slice of Life" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T07:11:15.030Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "urusei-yatsura", + "romaji_title": "Urusei Yatsura", + "english_title": "Those Obnoxious Aliens", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/000/702/large/3465.jpg?1434250836", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/000/702/large/3465.jpg?1434250836", + "synopsis": "What would you do if a tiger skin bikini-clad alien followed you to school every day? Poor Ataru's life has never returned to normal since volatile extraterrestrial princess Lum fell for him. Now an excruciatingly wealthy and genteel rival, Mendo, adds to Ataru's torment. Not to mention an unending stream of extraordinary classroom visitors and educational materials including incompetent cherry blossom spirits, a legendary nightmare-eating tapir, and a fourth-dimensional camera that breaches alternate realities. \n(Source: Viz)", + "chapter_count": 366, + "volume_count": 34, + "genres": [ + "Comedy", + "Romance", + "Sci-Fi" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T03:00:37.158Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "sold-out", + "romaji_title": "SOLD OUT!", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/009/061/large/4134.jpg?1434268999", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/009/061/large/4134.jpg?1434268999", + "synopsis": "Ina wants to meet a normal boy, so she asks her best friend, Mako, for help. At first, they went shopping in the new \"Se Rejouir\". There, Ina suddenly confesses her love to the Manager. Is that the romantic beginning of a love story?\r\n(Source: MangaUpdates)", + "chapter_count": 6, + "volume_count": 1, + "genres": [ + "Drama", + "Romance" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T08:03:21.427Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "skip-beat", + "romaji_title": "Skip Beat!", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/001/388/large/26110.jpg?1434252296", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/001/388/large/26110.jpg?1434252296", + "synopsis": "Kyoko Mogami followed her true love Sho to Tokyo to support him while he made it big as an idol. But he's casting her out now that he's famous! Kyoko won't suffer in silence--she's going to get her sweet revenge by beating Sho in show biz!\n(Source: Viz)", + "chapter_count": 0, + "volume_count": 0, + "genres": [ + "Comedy", + "Drama", + "Romance" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T03:24:58.679Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "samurai-champloo", + "romaji_title": "Samurai Champloo", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/001/171/large/56743.jpg?1434251812", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/001/171/large/56743.jpg?1434251812", + "synopsis": "Mugen is a rough-around-the-edges mercenary with a killer technique and nothing left to lose. Jin is a disciplined samurai who's as deadly as he is reserved. Fuu is a young waitress with a good heart and a resourcefulness that emerges when you least expect it. These three unlikely companions are about to begin a journey that will change all of their lives.\nIt's a dangerous quest for a mysterious samurai that will see our squabbling group of heroes get into and out of trouble more times than they can count (which admittedly, isn't very high). From the cynical gentility of the nobles to the backstabbing of the Japanese underworld, Mugen, Jin and Fuu will face threats from without and within as they hurl insults and throwing stars alike. Ancient Japan is about to get a lethal dose of street justice -- Champloo style. And it will never be the same.\n(Source: Tokyopop)", + "chapter_count": 10, + "volume_count": 2, + "genres": [ + "Action", + "Adventure", + "Comedy" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T03:16:53.988Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "ranma", + "romaji_title": "Ranma ½", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/000/062/large/5616.jpg?1434249522", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/000/062/large/5616.jpg?1434249522", + "synopsis": "In China, there lies a famous training springs, a place where martial artists can hone their skills to great levels. Unfortunately, the springs are also cursed! Teenage martial artist Ranma falls into the \"spring of drowned girl\" and now changes into a woman every time he's splashed with cold water. That doesn't stop his father from engaging him to Akane, the daughter of an old friend and a tough girl who has better thing to do than worry about boys. But Akane isn't the only girl who has a chance for Ranma's affections -- two other girls have also been betrothed to him. But Ranma has better things to do than worry about his love life -- such as making a plethora of crazy rivals and even more suitors!", + "chapter_count": 407, + "volume_count": 38, + "genres": [ + "Action", + "Comedy", + "Ecchi", + "Gender Bender", + "Harem", + "Martial Arts", + "Romance", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-25T00:16:50.091Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "otome-no-iroha", + "romaji_title": "Otome no Iroha!", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/022/436/large/12188.jpg?1434298544", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/022/436/large/12188.jpg?1434298544", + "synopsis": "Iroha, a masculine girl and Hifumi, a feminine boy are siblings who has transfered to a different middle school and moved to their grandparents house. However, after the first night much to their surprise...", + "chapter_count": 5, + "volume_count": 1, + "genres": [ + "Comedy", + "Ecchi", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T16:15:45.684Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "ore-no-imouto-ga-konnani-kawaii-wake-ga-nai", + "romaji_title": "Ore no Imouto ga Konnani Kawaii Wake ga Nai", + "english_title": "Oreimo", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/000/714/large/71Zqo5clDfL._SL1200_.jpg?1439399108", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/000/714/large/71Zqo5clDfL._SL1200_.jpg?1439399108", + "synopsis": "Kyousuke Kousaka, a normal seventeen-year-old high school student, hasn't gotten along with his younger sister, Kirino, in years. For longer than he can remember, Kirino has ignored his comings and goings and looked at him with spurning eyes. It seemed as if the relationship between Kyousuke and his sister, now fourteen, would continue this way forever.\n\nOne day, however, Kyousuke finds a DVD case of a magical girl anime entitled Hoshikuzu Witch Merle (Stardust Witch Merle), which had fallen into the entranceway of his house. To Kyousuke's surprise, inside the case is a hidden adult video game titled Imouto to Koishiyo! (Love with Little Sister!). Kyousuke attempts to fish out the culprit who dropped the case by bringing up the topic of magical girl anime at the family dinner table. All that comes out is a strong negative reaction from his parents, especially his anti-otaku policeman father.\n\nThat night, Kirino bursts into Kyousuke's room and, in perhaps the first conversation she has initiated with him in years, says they \"have things to talk about.\" Kirino brings Kyousuke to her room and shows him an extensive collection of moe anime and lolicon bishoujo games she has been collecting in secret.\n\n(Source: Wikipedia)", + "chapter_count": 26, + "volume_count": 4, + "genres": [ + "Comedy", + "Drama", + "Ecchi", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-08-12T17:05:09.128Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "onii-chan-no-koto-nanka-zenzen-suki-janain-dakara-ne", + "romaji_title": "Onii-chan no Koto nanka Zenzen Suki Janain Dakara ne!!", + "english_title": "I don't like you at all, Big Brother!!", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/021/900/large/11793.jpg?1434297436", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/021/900/large/11793.jpg?1434297436", + "synopsis": "High School junior Takanashi Nao has a problem: she has a crush on her dreamy older brother, Shuusuke. Fortunately, when Nao discovers that she was adopted as a child and they’re not related by blood, it seems like the coast is clear—but Shuusuke just doesn’t see it that way.\nTo make matters worse, Nao finds herself in direct competition against Shuusuke’s hot childhood friend, Iroha, not to mention class president Mayuka. As all three girls vie for Shuusuke’s attention, Nao soon learns that all is fair in love and war!\n(Source: Seven Seas)", + "chapter_count": 0, + "volume_count": 0, + "genres": [ + "Comedy", + "Ecchi", + "Harem", + "Romance", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T15:57:17.592Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "onegai-sensei-manga", + "romaji_title": "Onegai, Sensei", + "english_title": "Please, Teacher", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/019/137/large/9625.jpg?1434291544", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/019/137/large/9625.jpg?1434291544", + "synopsis": "Consists of 3 One-Shots:\r\n1. Onegai Teacher:\r\nAfter a painful experience in love, Tani Rika started to have a cynical view of love. She falls in love easily, confesses her love easily, but the moment the guy tells her that he loves her, she dumps him. This time, her new target is Tanabe-sensei, a teacher at the cram school she's going to. Making him fall for her is just another game to Rika - or so she thought, but she started to develop feelings that she thought she had forgotten a long time ago...\r\n2. Altair's Love Letter\r\n3. The Boy from the Sleeping Country\r\n(Source: Aerandria Scans)", + "chapter_count": 3, + "volume_count": 1, + "genres": [ + "Romance", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T14:19:05.704Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "obaa-chan-wa-idol", + "romaji_title": "Obaa-chan wa Idol", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/008/089/large/3634.jpg?1434266860", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/008/089/large/3634.jpg?1434266860", + "synopsis": "Yamada Momoka is your average 16 year old girl. Her family consists of herself, her dad who works at a TV station, and her mom. Apparently she also has a strict prune of a grandma, but who doesn't? Except that the grandma, Yamada Tamaki, had an accident at the TV station where she got electrocuted and now looks like a 16 year old Yamato Nadeshiko. It isn't easy for Momoka when her grandma arbitrarily decides to attend Momoka's high school as a student as well. Tamaki isn't just pretty, she's also very cultured, well-mannered, and still maintains her old-fashioned streak from her 65 years of wisdom. It's bad enough when Momoka starts being referred to as \"Old Yamada\" and her grandma (Tamaki) referred to as \"New Yamada\", but it's even worse when Momoka's crush on a dashing young man starts to take an interest in Tamaki as well. Fight-o, Momoka! Protect your beloved grandma, Momoka! And don't let her walk off with your boytoy, Momoka!\r\n(Source: mahouneko)", + "chapter_count": 22, + "volume_count": 4, + "genres": [ + "Comedy", + "Drama", + "Romance", + "Supernatural" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T07:27:41.464Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "nazo-no-kanojo-x", + "romaji_title": "Nazo no Kanojo X", + "english_title": "Mysterious Girlfriend X", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/004/029/large/1926.jpg?1434257986", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/004/029/large/1926.jpg?1434257986", + "synopsis": "One day, a strange transfer student appears before Tsubaki. Urabe Mikoto is an antisocial girl, whose hobby is just sleeping during class-breaks. One day, Tsubaki goes to wake her up and accidentally tastes her drool... And gets hooked on that!\nAfter that, he starts going out with her and gets to know her better. Her second hobby, as it turns out, is carrying around scissors in her panties and cutting paper into flowers...\n(Source: MU)", + "chapter_count": 96, + "volume_count": 12, + "genres": [ + "Ecchi", + "Mystery", + "Romance", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T04:59:47.843Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "milk-to-vitamin", + "romaji_title": "Milk to Vitamin", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/007/616/large/3843.jpg?1434265843", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/007/616/large/3843.jpg?1434265843", + "synopsis": "Milk is a young and childish girl living with her aunt in Orange Town. One day, she is told that a guest is coming over to stay with them for a while. Milk's aunt had said that the guest is cute and pretty. Milk, excited about her new friend goes to meet the guest at the fountain. Milk's childhood friend Vitamin and others accompany her at this time. Through an unforseen event, Milk arrives late at the fountain with the guest nowhere to be seen. They did however, find a handsome young boy asking for directions to Orange Town. \r\n(Baka-Updates)", + "chapter_count": 7, + "volume_count": 2, + "genres": [ + "Comedy", + "Drama", + "Romance" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T07:10:44.251Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "mama-wa-shougaku-4-nensei", + "romaji_title": "Mama wa Shougaku 4 Nensei", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/007/618/large/3464.jpg?1434265846", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/007/618/large/3464.jpg?1434265846", + "synopsis": "Because her father was sent to London to work, Natsumi, a 4th grade student, also must leave Japan along with him. Her classmates throw a farewell party for her. Natsumi is prepared to go to London, but on the night before Natsumi's arranged departure, a baby suddenly appears in her house after a roar of thunder! What's more is that this little baby is actually the one that Natsumi will give birth to in fifteen years!\r\n(Source: Aku Tenshi)", + "chapter_count": 12, + "volume_count": 2, + "genres": [ + "Comedy", + "Drama", + "Sci-Fi" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T07:10:48.232Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "maburaho-7719eaec-27ba-4375-847e-7b140a29257a", + "romaji_title": "Maburaho", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/001/649/large/5194.jpg?1434252868", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/001/649/large/5194.jpg?1434252868", + "synopsis": "Kazuki Shikimori has lost his memory and has come to find out that there are three young girls after his DNA. Even though his magic is extremely limited compared to others, it is believe that his offspring will wield incredible magic. Kuriko Kazetsubaki claims to be his girlfriend. Rin Kamishiro is urged by her family to be his wife. And Yuuna Miyami claims to be Kazuki's wife, as per a promise made when they were kids.", + "chapter_count": 14, + "volume_count": 2, + "genres": [ + "Comedy", + "Harem", + "Magic", + "Romance" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T03:34:29.466Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "kono-onee-san-wa-fiction-desu", + "romaji_title": "Kono Onee-san wa Fiction desu!?", + "english_title": "Is this Girl for Real!?", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/015/503/large/74249.jpg?1434283423", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/015/503/large/74249.jpg?1434283423", + "synopsis": "Late one night when Jun was out on his bike, he came across a drunk, half-naked girl sprawled on the side of the road. She came round just long enough to be uncomfortably affectionate. Jun took her to his home so she could sleep it off. It turned out that she is Kawase Narumi, his author mother's new assistant. Unfortunately, she has no idea what she's doing in her new job, so Jun's going to have to coach her. He's also going to have to deal with her habit of getting drunk, mostly naked, and cuddly. Jun's life will never be the same! \n(Source: MangaHelpers)", + "chapter_count": 49, + "volume_count": 8, + "genres": [ + "Comedy", + "Ecchi", + "Romance", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T12:03:44.559Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "kimi-dake-no-devil", + "romaji_title": "Kimi Dake no Devil", + "english_title": "A Devil Just for You", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/014/606/large/7082.jpg?1434281449", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/014/606/large/7082.jpg?1434281449", + "synopsis": "Sango Minamino, a 16 year-old cute, hyper and somewhat reckless girl, gets rescued one day by a green-eyed boy with black wings who calls himself Kai and claims to be Sango's guardian angel... or is he a devil? (Source: Emily's Random Shoujo Page)", + "chapter_count": 5, + "volume_count": 1, + "genres": [ + "Comedy", + "Fantasy" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T11:30:51.028Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "kanaete-aizen", + "romaji_title": "Kanaete Aizen", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/013/080/large/66091.jpg?1434278021", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/013/080/large/66091.jpg?1434278021", + "synopsis": "Aizen Kanou, just like any high-school boy, yearns for a girlfriend. But he's so painfully shy he flees when any girl tries to talk to him. Except his childhood friend, Yuzu, who scolds him for being so shy. But she leaves behind a temple love-charm. That night in his room Kanou uses the charm to demand heaven grant him his wish for a beautiful girl. When he wakes up in the morning, he finds his wish has been granted--and the beautiful girl is himself.\n(Source: MU)", + "chapter_count": 2, + "volume_count": 0, + "genres": [ + "Ecchi", + "Romance", + "School", + "Supernatural" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T10:33:45.399Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "joshikausei", + "romaji_title": "Joshikausei", + "english_title": "Joshi Kausei", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/025/491/large/121107.jpg?1434305043", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/025/491/large/121107.jpg?1434305043", + "synopsis": "Who needs dialog when you're this cute? The beautiful (but unlucky) Momoko, the cool, collected Shibumi, and the refreshingly innocent Mayumi star in a \"silent manga.\" No speeches, no dialog! Just pictures, sound effects, and three high school girls living their daily lives.\r\n\r\n(Source: Crunchyroll)", + "chapter_count": 0, + "volume_count": 0, + "genres": [ + "Comedy", + "School", + "Slice of Life" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T18:04:04.736Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "inuyasha", + "romaji_title": "InuYasha", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/001/531/large/32468.jpg?1434252597", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/001/531/large/32468.jpg?1434252597", + "synopsis": "Kagome is a modern Japanese high school girl. Never the type to believe in myths and legends, her world view dramatically changes when, one day, she's pulled out of her own time and into another! There, in Japan's ancient past, Kagome discovers more than a few of those dusty old legends are true, and that her destiny is linked to one legendary creature in particular--the dog-like half-demon called Inuyasha! That same trick of fate also ties them both to the Shikon Jewel, or \"Jewel of Four Souls.\" But demons beware...the smallest shard of the Shikon Jewel can give the user unimaginable power.\n(Source: Viz)", + "chapter_count": 558, + "volume_count": 56, + "genres": [ + "Adventure", + "Comedy", + "Demons", + "Drama", + "Fantasy", + "Historical", + "Romance", + "Supernatural" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T03:29:58.614Z", + "cover_image": "https://static.hummingbird.me/manga/cover_images/000/001/531/original/01-020-021.jpg?1430840015", + "cover_image_top_offset": 250 + }, + { + "id": "inumimi", + "romaji_title": "Inumimi", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/004/025/large/1924.jpg?1434257977", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/004/025/large/1924.jpg?1434257977", + "synopsis": "After spending half a year abroad, Kinosaki Yuichiro is in for a shocking homecoming when he discovers that his inventor/scientist father has given his 3 dogs the appearance and abilities of girls. Now he is in for a ton of grief as he tries to cope with these changes.\n(Source: Solaris-SVU)", + "chapter_count": 19, + "volume_count": 3, + "genres": [ + "Comedy", + "Ecchi", + "Harem", + "Romance" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T04:59:38.807Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "inu-neko-jump", + "romaji_title": "Inu Neko Jump", + "english_title": "Dog Cat Jump", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/002/136/large/978.jpg?1434253893", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/002/136/large/978.jpg?1434253893", + "synopsis": "(synopsis courtesy of AnimeWaves)\r\nEver since middle school, Takahiro Ozu was famous in the world of track and field as the “long jump specialist?. But after losing his final competition in high school, he hung up his track shoes for good. Now in college, having taken up smoking, he just wants to get a girlfriend and lead a normal student life. Noriko Watsuki has had a crush on Takahiro since she first saw him jump and wants him to join the college track team so she can get close to him. Yuki “The Headphone Girl? Hoguchi, a high school student who likes to hang out at the university, claims Takahiro took her virginity 13 years ago when he was in kindergarten. She considers him her property to do with as she pleases. Throw in a full cast of zany and unique characters, sprinkle with fan service, and you have the world of Inu Neko Jump.", + "chapter_count": 41, + "volume_count": 5, + "genres": [ + "Comedy", + "Romance" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T03:51:34.141Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "i-hs", + "romaji_title": "I ♥ HS", + "english_title": "I Love High School", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/023/195/large/17718.jpg?1434300143", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/023/195/large/17718.jpg?1434300143", + "synopsis": "Yamato Onidzuka. Childhood bully, punk, and sports prodigy. His old childhood friends are terrified of him, as he used to bully and harass them on a daily basis. When he transferred to a special sport's school, it seemed like his friends' worst nightmare had finally come to an end. But now that he's back, it seems like the nightmare has returned. Join Megu, Yamato, and their 4 other friends on their hilarious roller-coaster ride known as High School!\n(Source: Operation Boredom)", + "chapter_count": 9, + "volume_count": 2, + "genres": [ + "Comedy", + "Drama", + "Romance", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T16:42:24.286Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "futaba-kun-change", + "romaji_title": "Futaba-kun Change♡", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/004/367/large/2114.jpg?1434258719", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/004/367/large/2114.jpg?1434258719", + "synopsis": "Futaba Shimeru is a normal high-schooler living a normal life, active in his school's wrestling club and slowly getting closer to his awkward love interest, Misaki. This fails to last as he discovers his family's hereditary genetic defect that becomes active at adolescence. Although it will eventually become controllable, either excitement or stress now makes Futaba switch sex. Mayhem ensues.\n(Source: Wikipedia)", + "chapter_count": 48, + "volume_count": 8, + "genres": [ + "Comedy", + "Ecchi", + "Romance", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T05:12:00.314Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "full-metal-panic", + "romaji_title": "Full Metal Panic!", + "english_title": "Full Metal Panic", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/001/735/large/5190.jpg?1434253058", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/001/735/large/5190.jpg?1434253058", + "synopsis": "A sergeant by the name of Sousuke Sagara is assigned an important task. That of guarding high school girl Chidori Kaname. Sousuke is a military genius, gaining high rank at an early age, but because of his strange upbringing, he lacks social skill. Now, he finds himself as a fish out of water as he attempts to protect a girl from an evil organization and turn in his school work on time. \n(Source: ANN)", + "chapter_count": 58, + "volume_count": 9, + "genres": [ + "Action", + "Comedy", + "Mecha", + "Military", + "Romance" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T03:37:39.128Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "chobits", + "romaji_title": "Chobits", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/000/278/large/19440.jpg?1434249984", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/000/278/large/19440.jpg?1434249984", + "synopsis": "Hideki's just like every other guy in the 22nd century. He just wants a good job, a good car, and a sexy robot girlfriend to call his own. Until he lands a job, he'll never be able to afford his own 'Persocom' companion. Hideki's luck changes when he discovers Chi--an adorable but seemingly stupid Persocom--tied up in a pile of trash. His first robot companion turns out to be a lot more responsibility than he expected, and she gets him into quite a few embarrassing situations. It's 'boy-meets-girl' for the cyber age. (Source: Tokyopop)", + "chapter_count": 88, + "volume_count": 8, + "genres": [ + "Comedy", + "Ecchi", + "Psychological", + "Romance", + "Sci-Fi" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T02:46:25.229Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "change-2", + "romaji_title": "Change 2!!", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/016/486/large/8072.jpg?1434285566", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/016/486/large/8072.jpg?1434285566", + "synopsis": "Kisaragi Maki is an ordinary high school student. One day, when she's going to help someone who is being beaten up by a gangster, Maki who don't know how to fight become the opposite person. What makes her personality can change like that?\n(Source: MU)", + "chapter_count": 4, + "volume_count": 1, + "genres": [ + "Action", + "Ecchi", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T12:39:27.882Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "bokura-wa-minna-kawaisou", + "romaji_title": "Bokura wa Minna Kawaisou", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/020/286/large/17950117v1.jpg?1434293999", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/020/286/large/17950117v1.jpg?1434293999", + "synopsis": "Usa, a high-school student aspiring to begin a bachelor lifestyle, moves into a new apartment only to discover that he not only shares a room with a perverted roommate that has an obsession for underaged girls, but also that another girl, Ritsu, a love-at-first-sight, is living in the same building as well!\n(Source: Kirei Cake)", + "chapter_count": 0, + "volume_count": 0, + "genres": [ + "Comedy", + "Romance", + "School", + "Slice of Life" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T15:00:01.343Z", + "cover_image": "https://static.hummingbird.me/manga/cover_images/000/020/286/original/11282013_bokura-wa-minna-kawaisou.jpg?1430793688", + "cover_image_top_offset": 40 + }, + { + "id": "boku-ni-natta-watashi", + "romaji_title": "Boku ni Natta Watashi", + "english_title": "I Became a Boy", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/001/379/large/20745.jpg?1434252279", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/001/379/large/20745.jpg?1434252279", + "synopsis": "Welcome to Momoko's waking nightmare. Things were settled. They were! She was SUPPOSED to have gone to a normal school, made normal friends, and led a blissfully normal life. But the universe is just cruelly, irredeemably, monstrously unfair, so instead she found herself thrown out of home, stuck in an all-boys boarding school with a roommate she hates, cursed with a hideous haircut and wearing clothes which, to be frank, she wouldn't be seen dead in.\r\nAnd the only thing worse than her current situation is the one that she'll be in if anyone ever realizes that she is, in fact, a girl. Everything is wrong! Everything! Particularly the fact that, even though she's surrounded by amazingly gorgeous guys, her chances of romance are less than zero. But with life this complicated, something is bound to give. In fact, it just did. Damn. (Source: Storm in Heaven)\r\nThis title is 21 chapters including the extra chapters.", + "chapter_count": 21, + "volume_count": 5, + "genres": [ + "Drama", + "Romance", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T03:24:40.188Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "bishoujo-senshi-sailor-moon", + "romaji_title": "Bishoujo Senshi Sailor Moon", + "english_title": "Sailor Moon", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/000/241/large/6601.jpg?1434249905", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/000/241/large/6601.jpg?1434249905", + "synopsis": "Tsukino Usagi is 14 years old and in her second year of middle school. She's a bit of a crybaby and klutzy. However, she can transform into a warrior of justice, Sailormoon! An eternal classic that should be read by all.\n(Source: MU)", + "chapter_count": 61, + "volume_count": 18, + "genres": [ + "Drama", + "Fantasy", + "Magic", + "Mahou Shoujo", + "Romance" + ], + "manga_type": "Manga", + "updated_at": "2015-09-12T22:55:37.124Z", + "cover_image": "https://static.hummingbird.me/manga/cover_images/000/000/241/original/2-20-21.jpg?1442098535", + "cover_image_top_offset": 175 + }, + { + "id": "anta-nanka-daikirai", + "romaji_title": "Anta Nanka Daikirai", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/024/984/large/14617.jpg?1434303960", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/024/984/large/14617.jpg?1434303960", + "synopsis": "Collection of one shots.\n1) I Can't Stand You\n2) Caught on You\n3) Something's Wrong\n4) See You Tomorrow", + "chapter_count": 4, + "volume_count": 1, + "genres": [ + "Drama", + "Romance", + "School" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T17:46:02.005Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + }, + { + "id": "akane-chan-overdrive", + "romaji_title": "Akane-chan Overdrive", + "poster_image": "https://static.hummingbird.me/manga/poster_images/000/001/961/large/900.jpg?1434253542", + "poster_image_thumb": "https://static.hummingbird.me/manga/poster_images/000/001/961/large/900.jpg?1434253542", + "synopsis": "Nineteen-year-old Takashi Amamiya dies after tripping on a bottle but is transported into a body of a cute girl, Akane Hagiwara. Following this, Amamiya goes through various trials and tribulations dealing with, being a girl, getting his body back, and dealing with old and new friends. \n-Wikipedia Entry", + "chapter_count": 10, + "volume_count": 2, + "genres": [ + "Comedy", + "Ecchi", + "Gender Bender" + ], + "manga_type": "Manga", + "updated_at": "2015-06-14T03:45:44.128Z", + "cover_image": "/cover_images/original/missing.png", + "cover_image_top_offset": 0 + } + ], + "manga_library_entries": [ + { + "id": 401735, + "status": "Currently Reading", + "is_favorite": null, + "rating": null, + "notes": null, + "chapters_read": 6, + "volumes_read": 1, + "rereading": false, + "reread_count": 0, + "last_read": "2015-06-23T21:00:20.169Z", + "manga_id": "love-hina" + }, + { + "id": 400982, + "status": "Plan to Read", + "is_favorite": null, + "rating": null, + "notes": null, + "chapters_read": 0, + "volumes_read": 0, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T23:37:37.364Z", + "manga_id": "murder-incarnation" + }, + { + "id": 400980, + "status": "Plan to Read", + "is_favorite": null, + "rating": null, + "notes": null, + "chapters_read": 0, + "volumes_read": 0, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T23:37:12.694Z", + "manga_id": "doll-the-hotel-detective" + }, + { + "id": 400978, + "status": "Plan to Read", + "is_favorite": null, + "rating": null, + "notes": null, + "chapters_read": 0, + "volumes_read": 0, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T23:36:49.961Z", + "manga_id": "fuuka" + }, + { + "id": 400977, + "status": "Plan to Read", + "is_favorite": null, + "rating": null, + "notes": null, + "chapters_read": 0, + "volumes_read": 0, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T23:36:34.644Z", + "manga_id": "yamada-kun-to-7-nin-no-majo" + }, + { + "id": 400904, + "status": "On Hold", + "is_favorite": null, + "rating": "4.5", + "notes": null, + "chapters_read": 86, + "volumes_read": 12, + "rereading": false, + "reread_count": 0, + "last_read": "2015-06-25T00:53:09.733Z", + "manga_id": "yotsubato" + }, + { + "id": 400903, + "status": "Completed", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 111, + "volumes_read": 13, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.744Z", + "manga_id": "wagatsuma-san-wa-ore-no-yome" + }, + { + "id": 400902, + "status": "Completed", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 4, + "volumes_read": 1, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.732Z", + "manga_id": "usotsuki-marriage" + }, + { + "id": 400901, + "status": "Currently Reading", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 28, + "volumes_read": 1, + "rereading": false, + "reread_count": 0, + "last_read": "2015-06-26T02:10:09.083Z", + "manga_id": "usagi-drop" + }, + { + "id": 400900, + "status": "Dropped", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 269, + "volumes_read": 12, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.708Z", + "manga_id": "urusei-yatsura" + }, + { + "id": 400899, + "status": "Completed", + "is_favorite": null, + "rating": "3.5", + "notes": null, + "chapters_read": 6, + "volumes_read": 1, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.697Z", + "manga_id": "sold-out" + }, + { + "id": 400898, + "status": "On Hold", + "is_favorite": null, + "rating": "5.0", + "notes": null, + "chapters_read": 190, + "volumes_read": 30, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.685Z", + "manga_id": "skip-beat" + }, + { + "id": 400897, + "status": "Completed", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 10, + "volumes_read": 2, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.673Z", + "manga_id": "samurai-champloo" + }, + { + "id": 400896, + "status": "Completed", + "is_favorite": null, + "rating": "4.5", + "notes": null, + "chapters_read": 407, + "volumes_read": 38, + "rereading": false, + "reread_count": 0, + "last_read": "2015-06-25T00:53:37.426Z", + "manga_id": "ranma" + }, + { + "id": 400895, + "status": "Completed", + "is_favorite": null, + "rating": "3.5", + "notes": null, + "chapters_read": 5, + "volumes_read": 1, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.651Z", + "manga_id": "otome-no-iroha" + }, + { + "id": 400894, + "status": "Completed", + "is_favorite": null, + "rating": "5.0", + "notes": null, + "chapters_read": 26, + "volumes_read": 4, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.639Z", + "manga_id": "ore-no-imouto-ga-konnani-kawaii-wake-ga-nai" + }, + { + "id": 400893, + "status": "On Hold", + "is_favorite": null, + "rating": "4.5", + "notes": null, + "chapters_read": 44, + "volumes_read": 6, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.624Z", + "manga_id": "onii-chan-no-koto-nanka-zenzen-suki-janain-dakara-ne" + }, + { + "id": 400892, + "status": "Completed", + "is_favorite": null, + "rating": "4.5", + "notes": null, + "chapters_read": 3, + "volumes_read": 1, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.610Z", + "manga_id": "onegai-sensei-manga" + }, + { + "id": 400891, + "status": "Dropped", + "is_favorite": null, + "rating": null, + "notes": null, + "chapters_read": 0, + "volumes_read": 0, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.598Z", + "manga_id": "obaa-chan-wa-idol" + }, + { + "id": 400890, + "status": "Completed", + "is_favorite": null, + "rating": "4.5", + "notes": null, + "chapters_read": 96, + "volumes_read": 12, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.585Z", + "manga_id": "nazo-no-kanojo-x" + }, + { + "id": 400889, + "status": "Completed", + "is_favorite": null, + "rating": "3.5", + "notes": null, + "chapters_read": 7, + "volumes_read": 2, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.567Z", + "manga_id": "milk-to-vitamin" + }, + { + "id": 400888, + "status": "Completed", + "is_favorite": null, + "rating": "4.5", + "notes": null, + "chapters_read": 12, + "volumes_read": 2, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.548Z", + "manga_id": "mama-wa-shougaku-4-nensei" + }, + { + "id": 400887, + "status": "Completed", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 13, + "volumes_read": 2, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.534Z", + "manga_id": "maburaho-7719eaec-27ba-4375-847e-7b140a29257a" + }, + { + "id": 400886, + "status": "Completed", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 49, + "volumes_read": 8, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.521Z", + "manga_id": "kono-onee-san-wa-fiction-desu" + }, + { + "id": 400885, + "status": "Completed", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 5, + "volumes_read": 1, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.509Z", + "manga_id": "kimi-dake-no-devil" + }, + { + "id": 400884, + "status": "Completed", + "is_favorite": null, + "rating": "4.5", + "notes": null, + "chapters_read": 2, + "volumes_read": 1, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.495Z", + "manga_id": "kanaete-aizen" + }, + { + "id": 400883, + "status": "Currently Reading", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 34, + "volumes_read": 0, + "rereading": false, + "reread_count": 0, + "last_read": "2015-07-08T23:55:28.830Z", + "manga_id": "joshikausei" + }, + { + "id": 400882, + "status": "Completed", + "is_favorite": null, + "rating": "3.5", + "notes": null, + "chapters_read": 558, + "volumes_read": 56, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.462Z", + "manga_id": "inuyasha" + }, + { + "id": 400881, + "status": "Completed", + "is_favorite": null, + "rating": "4.5", + "notes": null, + "chapters_read": 19, + "volumes_read": 3, + "rereading": false, + "reread_count": 0, + "last_read": "2015-06-25T00:53:52.427Z", + "manga_id": "inumimi" + }, + { + "id": 400880, + "status": "Completed", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 41, + "volumes_read": 5, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.437Z", + "manga_id": "inu-neko-jump" + }, + { + "id": 400879, + "status": "Completed", + "is_favorite": null, + "rating": "3.5", + "notes": null, + "chapters_read": 9, + "volumes_read": 2, + "rereading": false, + "reread_count": 0, + "last_read": "2015-06-25T00:53:56.050Z", + "manga_id": "i-hs" + }, + { + "id": 400878, + "status": "Completed", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 48, + "volumes_read": 8, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.410Z", + "manga_id": "futaba-kun-change" + }, + { + "id": 400877, + "status": "Completed", + "is_favorite": null, + "rating": "5.0", + "notes": null, + "chapters_read": 58, + "volumes_read": 9, + "rereading": false, + "reread_count": 0, + "last_read": "2015-06-25T00:54:02.851Z", + "manga_id": "full-metal-panic" + }, + { + "id": 400876, + "status": "Completed", + "is_favorite": null, + "rating": "4.5", + "notes": null, + "chapters_read": 88, + "volumes_read": 8, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.366Z", + "manga_id": "chobits" + }, + { + "id": 400875, + "status": "Completed", + "is_favorite": null, + "rating": "5.0", + "notes": null, + "chapters_read": 4, + "volumes_read": 1, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.342Z", + "manga_id": "change-2" + }, + { + "id": 400874, + "status": "Currently Reading", + "is_favorite": null, + "rating": "4.5", + "notes": null, + "chapters_read": 62, + "volumes_read": 6, + "rereading": false, + "reread_count": 0, + "last_read": "2015-07-08T23:53:42.493Z", + "manga_id": "bokura-wa-minna-kawaisou" + }, + { + "id": 400873, + "status": "Completed", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 21, + "volumes_read": 5, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.292Z", + "manga_id": "boku-ni-natta-watashi" + }, + { + "id": 400872, + "status": "Dropped", + "is_favorite": null, + "rating": "4.0", + "notes": null, + "chapters_read": 30, + "volumes_read": 5, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.267Z", + "manga_id": "bishoujo-senshi-sailor-moon" + }, + { + "id": 400871, + "status": "Completed", + "is_favorite": null, + "rating": "3.5", + "notes": null, + "chapters_read": 4, + "volumes_read": 1, + "rereading": false, + "reread_count": 0, + "last_read": "2015-06-25T00:53:58.689Z", + "manga_id": "anta-nanka-daikirai" + }, + { + "id": 400870, + "status": "Completed", + "is_favorite": null, + "rating": "3.5", + "notes": null, + "chapters_read": 10, + "volumes_read": 2, + "rereading": false, + "reread_count": 0, + "last_read": "2015-05-26T21:39:11.214Z", + "manga_id": "akane-chan-overdrive" + } + ] +} \ No newline at end of file