diff --git a/app/Base/ApiModel.php b/app/Base/ApiModel.php deleted file mode 100644 index 0beb78b3..00000000 --- a/app/Base/ApiModel.php +++ /dev/null @@ -1,81 +0,0 @@ -cookieJar = new CookieJar(); - $this->client = new Client([ - 'base_url' => $this->base_url, - 'defaults' => [ - 'cookies' => $this->cookieJar, - 'headers' => [ - 'User-Agent' => $_SERVER['HTTP_USER_AGENT'], - 'Accept-Encoding' => 'application/json' - ], - 'timeout' => 5, - 'connect_timeout' => 5 - ] - ]); - } - - /** - * Attempt login via the api - * - * @codeCoverageIgnore - * @param string $username - * @param string $password - * @return bool - */ - public function authenticate($username, $password) - { - $result = $this->client->post('https://hummingbird.me/api/v1/users/authenticate', [ - 'body' => [ - 'username' => $username, - 'password' => $password - ] - ]); - - if ($result->getStatusCode() === 201) - { - $_SESSION['hummingbird_anime_token'] = $result->json(); - return TRUE; - } - - return FALSE; - } -} -// End of BaseApiModel.php \ No newline at end of file diff --git a/app/Base/Config.php b/app/Base/Config.php deleted file mode 100644 index 9ed8ff78..00000000 --- a/app/Base/Config.php +++ /dev/null @@ -1,131 +0,0 @@ -config = array_merge($config, $base_config); - - } - - /** - * Getter for config values - * - * @param string $key - * @return mixed - */ - public function __get($key) - { - if (isset($this->config[$key])) - { - return $this->config[$key]; - } - - return NULL; - } - - /** - * Get the base url for css/js/images - * - * @return string - */ - public function asset_url(/*...*/) - { - $args = func_get_args(); - $base_url = rtrim($this->__get('asset_path'), '/'); - - array_unshift($args, $base_url); - - return implode("/", $args); - } - - /** - * Get the base url from the config - * - * @param string $type - (optional) The controller - * @return string - */ - public function base_url($type="anime") - { - $config_path = trim($this->__get("{$type}_path"), "/"); - $config_host = $this->__get("{$type}_host"); - - // Set the appropriate HTTP host - $host = ($config_host !== '') ? $config_host : $_SERVER['HTTP_HOST']; - $path = ($config_path !== '') ? $config_path : ""; - - return implode("/", ['/', $host, $path]); - } - - /** - * Generate full url path from the route path based on config - * - * @param string $path - (optional) The route path - * @param string $type - (optional) The controller (anime or manga), defaults to anime - * @return string - */ - public function full_url($path="", $type="anime") - { - $config_path = trim($this->__get("{$type}_path"), "/"); - $config_host = $this->__get("{$type}_host"); - $config_default_route = $this->__get("default_{$type}_path"); - - // Remove beginning/trailing slashes - $config_path = trim($config_path, '/'); - $path = trim($path, '/'); - - // Remove any optional parameters from the route - $path = preg_replace('`{/.*?}`i', '', $path); - - // Set the appropriate HTTP host - $host = ($config_host !== '') ? $config_host : $_SERVER['HTTP_HOST']; - - // Set the default view - if ($path === '') - { - $path .= trim($config_default_route, '/'); - if ($this->__get('default_to_list_view')) $path .= '/list'; - } - - // Set an leading folder - if ($config_path !== '') - { - $path = "{$config_path}/{$path}"; - } - - return "//{$host}/{$path}"; - } -} -// End of config.php \ No newline at end of file diff --git a/app/Base/Controller.php b/app/Base/Controller.php deleted file mode 100644 index 910e5854..00000000 --- a/app/Base/Controller.php +++ /dev/null @@ -1,285 +0,0 @@ - 'anime', - 'other_type' => 'manga', - 'nav_routes' => [] - ]; - - /** - * Constructor - * - * @param \AnimeClient\Client $config - * @param array $web - */ - public function __construct(Config &$config, Array $web) - { - $this->config = $config; - $this->base_data['config'] = $config; - - list($request, $response) = $web; - $this->request = $request; - $this->response = $response; - } - - /** - * Destructor - * - * @codeCoverageIgnore - */ - public function __destruct() - { - $this->output(); - } - - /** - * Get a class member - * - * @param string $key - * @return object - */ - public function __get($key) - { - $allowed = ['request', 'response', 'config']; - - if (in_array($key, $allowed)) - { - return $this->$key; - } - - return NULL; - } - - /** - * Get the string output of a partial template - * - * @codeCoverageIgnore - * @param string $template - * @param array|object $data - * @return string - */ - public function load_partial($template, $data=[]) - { - 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"); - - if ( ! is_file($template_path)) - { - throw new InvalidArgumentException("Invalid template : {$path}"); - } - - 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 $buffer; - } - - /** - * 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); - - $this->response->content->setType('text/html'); - $this->response->content->set($buffer); - } - - /** - * Output json with the proper content type - * - * @param mixed $data - * @return void - */ - public function outputJSON($data) - { - if ( ! is_string($data)) - { - $data = json_encode($data); - } - - $this->response->content->setType('application/json'); - $this->response->content->set($data); - } - - /** - * Redirect to the selected page - * - * @codeCoverageIgnore - * @param string $url - * @param int $code - * @return void - */ - public function redirect($url, $code, $type="anime") - { - $url = $this->config->full_url($url, $type); - - $this->response->redirect->to($url, $code); - } - - /** - * Add a message box to the page - * - * @codeCoverageIgnore - * @param string $type - * @param string $message - * @return string - */ - public function show_message($type, $message) - { - return $this->load_partial('message', [ - 'stat_class' => $type, - 'message' => $message - ]); - } - - /** - * Clear the api session - * - * @codeCoverageIgnore - * @return void - */ - public function logout() - { - session_destroy(); - $this->response->redirect->seeOther($this->config->full_url('')); - } - - /** - * Show the login form - * - * @codeCoverageIgnore - * @param string $status - * @return void - */ - public function login($status="") - { - $message = ""; - - if ($status != "") - { - $message = $this->show_message('error', $status); - } - - $this->outputHTML('login', [ - 'title' => 'Api login', - 'message' => $message - ]); - } - - /** - * Attempt to log in with the api - * - * @return void - */ - public function login_action() - { - if ( - $this->model->authenticate( - $this->config->hummingbird_username, - $this->request->post->get('password') - ) - ) - { - $this->response->redirect->afterPost($this->config->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/app/Base/DBModel.php b/app/Base/DBModel.php deleted file mode 100644 index d6b51a22..00000000 --- a/app/Base/DBModel.php +++ /dev/null @@ -1,32 +0,0 @@ -db_config = $this->config->database; - } -} -// End of BaseDBModel.php \ No newline at end of file diff --git a/app/Base/Model.php b/app/Base/Model.php deleted file mode 100644 index e0e167d3..00000000 --- a/app/Base/Model.php +++ /dev/null @@ -1,105 +0,0 @@ -config = $config; - } - - /** - * Get the path of the cached version of the image. Create the cached image - * if the file does not already exist - * - * @codeCoverageIgnore - * @param string $api_path - The original image url - * @param string $series_slug - The part of the url with the series name, becomes the image name - * @param string $type - Anime or Manga, controls cache path - * @return string - the frontend path for the cached image - */ - public function get_cached_image($api_path, $series_slug, $type="anime") - { - $api_path = str_replace("jjpg", "jpg", $api_path); - $path_parts = explode('?', basename($api_path)); - $path = current($path_parts); - $ext_parts = explode('.', $path); - $ext = end($ext_parts); - - // Workaround for some broken extensions - if ($ext == "jjpg") $ext = "jpg"; - - // Failsafe for weird urls - if (strlen($ext) > 3) return $api_path; - - $cached_image = "{$series_slug}.{$ext}"; - $cached_path = "{$this->config->img_cache_path}/{$type}/{$cached_image}"; - - // Cache the file if it doesn't already exist - if ( ! file_exists($cached_path)) - { - if (ini_get('allow_url_fopen')) - { - copy($api_path, $cached_path); - } - elseif (function_exists('curl_init')) - { - $ch = curl_init($api_path); - $fp = fopen($cached_path, 'wb'); - curl_setopt_array($ch, [ - CURLOPT_FILE => $fp, - CURLOPT_HEADER => 0 - ]); - curl_exec($ch); - curl_close($ch); - fclose($ch); - } - else - { - throw new DomainException("Couldn't cache images because they couldn't be downloaded."); - } - - // Resize the image - if ($type == 'anime') - { - $resize_width = 220; - $resize_height = 319; - $this->_resize($cached_path, $resize_width, $resize_height); - } - } - - return "/public/images/{$type}/{$cached_image}"; - } - - /** - * Resize an image - * - * @codeCoverageIgnore - * @param string $path - * @param string $width - * @param string $height - */ - private function _resize($path, $width, $height) - { - $img = new SimpleImage($path); - $img->resize($width,$height)->save(); - } -} -// End of BaseModel.php \ No newline at end of file diff --git a/app/Base/Router.php b/app/Base/Router.php deleted file mode 100644 index 754bf6bc..00000000 --- a/app/Base/Router.php +++ /dev/null @@ -1,232 +0,0 @@ -config = $config; - $this->router = $router; - $this->request = $request; - $this->web = [$request, $response]; - - $this->output_routes = $this->_setup_routes(); - } - - /** - * Get the current route object, if one matches - * - * @return object - */ - public function get_route() - { - global $defaultHandler; - - $raw_route = parse_url($this->request->server->get('REQUEST_URI'), \PHP_URL_PATH); - $route_path = str_replace([$this->config->anime_path, $this->config->manga_path], '', $raw_route); - $route_path = "/" . trim($route_path, '/'); - - /*$defaultHandler->addDataTable('Route Info', [ - 'route_path' => $route_path - ]);*/ - - $route = $this->router->match($route_path, $_SERVER); - - return $route; - } - - /** - * Get list of routes applied - * - * @return array - */ - public function get_output_routes() - { - return $this->output_routes; - } - - /** - * Handle the current route - * - * @codeCoverageIgnore - * @param [object] $route - * @return void - */ - public function dispatch($route = NULL) - { - global $defaultHandler; - - if (is_null($route)) - { - $route = $this->get_route(); - } - - if ( ! $route) - { - $failure = $this->router->getFailedRoute(); - $defaultHandler->addDataTable('failed_route', (array)$failure); - } - else - { - list($controller_name, $action_method) = $route->params['action']; - $params = (isset($route->params['params'])) ? $route->params['params'] : []; - - if ( ! empty($route->tokens)) - { - foreach($route->tokens as $key => $v) - { - if (array_key_exists($key, $route->params)) - { - $params[$key] = $route->params[$key]; - } - } - } - } - - $controller = new $controller_name($this->config, $this->web); - - // Run the appropriate controller method - $defaultHandler->addDataTable('controller_args', $params); - call_user_func_array([$controller, $action_method], $params); - } - - /** - * Get the type of route, to select the current controller - * - * @return string - */ - public function get_route_type() - { - $route_type = $this->config->default_list; - - $host = $this->request->server->get("HTTP_HOST"); - $request_uri = $this->request->server->get('REQUEST_URI'); - - // Host-based controller selection - if ($this->config->route_by === "host") - { - if (strtolower($host) === strtolower($this->config->anime_host)) - { - $route_type = "anime"; - } - - if (strtolower($host) === strtolower($this->config->manga_host)) - { - $route_type = "manga"; - } - } - - // Path-based controller selection - if ($this->config->route_by === "path") - { - $path = trim($request_uri, '/'); - - if (stripos($path, trim($this->config->anime_path, '/')) === 0) - { - $route_type = "anime"; - } - - if (stripos($path, trim($this->config->manga_path, '/')) === 0) - { - $route_type = "manga"; - } - } - - return $route_type; - } - - /** - * Select controller based on the current url, and apply its relevent routes - * - * @return array - */ - public function _setup_routes() - { - $route_map = [ - 'anime' => '\\AnimeClient\\Controller\\Anime', - 'manga' => '\\AnimeClient\\Controller\\Manga', - ]; - - $output_routes = []; - - $route_type = $this->get_route_type(); - - // Return early if invalid route array - if ( ! array_key_exists($route_type, $this->config->routes)) return []; - - $applied_routes = array_merge($this->config->routes['common'], $this->config->routes[$route_type]); - - // Add routes - foreach($applied_routes as $name => &$route) - { - $path = $route['path']; - unset($route['path']); - - // Prepend the controller to the route parameters - array_unshift($route['action'], $route_map[$route_type]); - - // Select the appropriate router method based on the http verb - $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)) - { - $output_routes[] = $this->router->$add($name, $path)->addValues($route); - } - else - { - $tokens = $route['tokens']; - unset($route['tokens']); - - $output_routes[] = $this->router->$add($name, $path) - ->addValues($route) - ->addTokens($tokens); - } - } - - return $output_routes; - } -} -// End of Router.php \ No newline at end of file diff --git a/app/Base/functions.php b/app/Base/functions.php deleted file mode 100644 index fa9d81ce..00000000 --- a/app/Base/functions.php +++ /dev/null @@ -1,68 +0,0 @@ - '/watching{/view}', - 'Plan to Watch' => '/plan_to_watch{/view}', - 'On Hold' => '/on_hold{/view}', - 'Dropped' => '/dropped{/view}', - 'Completed' => '/completed{/view}', - 'Collection' => '/collection/view{/view}', - 'All' => '/all{/view}' - ]; - - /** - * Constructor - */ - public function __construct(Config $config, Array $web) - { - parent::__construct($config, $web); - - if ($this->config->show_anime_collection === FALSE) - { - unset($this->nav_routes['Collection']); - } - - $this->model = new AnimeModel($config); - $this->collection_model = new AnimeCollectionModel($config); - $this->base_data = [ - 'message' => '', - 'url_type' => 'anime', - 'other_type' => 'manga', - 'nav_routes' => $this->nav_routes, - 'config' => $this->config, - ]; - } - - /** - * Search for anime - * - * @return void - */ - public function search() - { - $query = $this->request->query->get('query'); - $this->outputJSON($this->model->search($query)); - } - - /** - * Show a portion, or all of the anime list - * - * @param string $type - The section of the list - * @param string $title - The title of the page - * @return void - */ - public function anime_list($type, $title, $view) - { - $view_map = [ - '' => 'cover', - 'list' => 'list' - ]; - - $data = ($type != 'all') - ? $this->model->get_list($type) - : $this->model->get_all_lists(); - - $this->outputHTML('anime/' . $view_map[$view], [ - 'title' => $title, - 'sections' => $data - ]); - } - - /** - * Show the anime collection page - * - * @return void - */ - public function collection($view) - { - $view_map = [ - '' => 'collection', - 'list' => 'collection_list' - ]; - - $data = $this->collection_model->get_collection(); - - $this->outputHTML('anime/' . $view_map[$view], [ - 'title' => WHOSE . " Anime Collection", - 'sections' => $data, - 'genres' => $this->collection_model->get_genre_list() - ]); - } - - /** - * Show the anime collection add/edit form - * - * @param int $id - * @return void - */ - public function collection_form($id=NULL) - { - $action = (is_null($id)) ? "Add" : "Edit"; - - $this->outputHTML('anime/collection_' . strtolower($action), [ - 'action' => $action, - 'action_url' => $this->config->full_url("collection/" . strtolower($action)), - 'title' => WHOSE . " Anime Collection · {$action}", - 'media_items' => $this->collection_model->get_media_type_list(), - 'item' => ($action === "Edit") ? $this->collection_model->get($id) : [] - ]); - } - - /** - * Update a collection item - * - * @return void - */ - public function collection_edit() - { - $data = $this->request->post->get(); - if ( ! array_key_exists('hummingbird_id', $data)) - { - $this->redirect("collection/view", 303, "anime"); - } - - $this->collection_model->update($data); - - $this->redirect("collection/view", 303, "anime"); - } - - /** - * Add a collection item - * - * @return void - */ - public function collection_add() - { - $data = $this->request->post->get(); - if ( ! array_key_exists('id', $data)) - { - $this->redirect("collection/view", 303, "anime"); - } - - $this->collection_model->add($data); - - $this->redirect("collection/view", 303, "anime"); - } - - /** - * Update an anime item - * - * @return bool - */ - public function update() - { - $this->outputJSON($this->model->update($this->request->post->get())); - } -} -// End of AnimeController.php \ No newline at end of file diff --git a/app/Controller/Manga.php b/app/Controller/Manga.php deleted file mode 100644 index e23eb1b0..00000000 --- a/app/Controller/Manga.php +++ /dev/null @@ -1,92 +0,0 @@ - '/reading{/view}', - 'Plan to Read' => '/plan_to_read{/view}', - 'On Hold' => '/on_hold{/view}', - 'Dropped' => '/dropped{/view}', - 'Completed' => '/completed{/view}', - 'All' => '/all{/view}' - ]; - - /** - * Constructor - */ - public function __construct(Config $config, Array $web) - { - parent::__construct($config, $web); - $this->model = new MangaModel($config); - $this->base_data = [ - 'config' => $this->config, - 'url_type' => 'manga', - 'other_type' => 'anime', - 'nav_routes' => $this->nav_routes - ]; - } - - /** - * Update an anime item - * - * @return bool - */ - public function update() - { - $this->outputJSON($this->model->update($this->request->post->get())); - } - - /** - * Get a section of the manga list - * - * @param string $status - * @param string $title - * @param string $view - * @return void - */ - public function manga_list($status, $title, $view) - { - $view_map = [ - '' => 'cover', - 'list' => 'list' - ]; - - $data = ($status !== 'all') - ? [$status => $this->model->get_list($status)] - : $this->model->get_all_lists(); - - $this->outputHTML('manga/' . $view_map[$view], [ - 'title' => $title, - 'sections' => $data - ]); - } -} -// End of MangaController.php \ No newline at end of file diff --git a/app/Model/Anime.php b/app/Model/Anime.php deleted file mode 100644 index b7e2ab3d..00000000 --- a/app/Model/Anime.php +++ /dev/null @@ -1,248 +0,0 @@ -client->post("libraries/{$data['id']}", [ - 'body' => $data - ]); - - return $result->json(); - } - - /** - * Get the full set of anime lists - * - * @return array - */ - public function get_all_lists() - { - $output = [ - 'Watching' => [], - 'Plan to Watch' => [], - 'On Hold' => [], - 'Dropped' => [], - 'Completed' => [], - ]; - - $data = $this->_get_list(); - - foreach($data as $datum) - { - switch($datum['status']) - { - case "completed": - $output['Completed'][] = $datum; - break; - - case "plan-to-watch": - $output['Plan to Watch'][] = $datum; - break; - - case "dropped": - $output['Dropped'][] = $datum; - break; - - case "on-hold": - $output['On Hold'][] = $datum; - break; - - case "currently-watching": - $output['Watching'][] = $datum; - break; - } - } - - // Sort anime by name - foreach($output as &$status_list) - { - $this->sort_by_name($status_list); - } - - return $output; - } - - /** - * Get a category out of the full list - * - * @param string $status - * @return array - */ - public function get_list($status) - { - $map = [ - 'currently-watching' => 'Watching', - 'plan-to-watch' => 'Plan to Watch', - 'on-hold' => 'On Hold', - 'dropped' => 'Dropped', - 'completed' => 'Completed', - ]; - - $data = $this->_get_list($status); - $this->sort_by_name($data); - - $output = []; - $output[$map[$status]] = $data; - - return $output; - } - - /** - * Get information about an anime from its id - * - * @param string $anime_id - * @return array - */ - public function get_anime($anime_id) - { - $config = [ - 'query' => [ - 'id' => $anime_id - ] - ]; - - $response = $this->client->get("anime/{$anime_id}", $config); - - return $response->json(); - } - - /** - * Search for anime by name - * - * @param string $name - * @return array - */ - public function search($name) - { - global $defaultHandler; - - $config = [ - 'query' => [ - 'query' => $name - ] - ]; - - $response = $this->client->get('search/anime', $config); - $defaultHandler->addDataTable('anime_search_response', (array)$response); - - if ($response->getStatusCode() != 200) - { - throw new RuntimeException($response->getEffectiveUrl()); - } - - return $response->json(); - } - - /** - * Actually retreive the data from the api - * - * @param string $status - Status to filter by - * @return array - */ - private function _get_list($status="all") - { - global $defaultHandler; - - $cache_file = "{$this->config->data_cache_path}/anime-{$status}.json"; - - $config = [ - 'allow_redirects' => FALSE - ]; - - if ($status != "all") - { - $config['query']['status'] = $status; - } - - $response = $this->client->get("users/{$this->config->hummingbird_username}/library", $config); - - $defaultHandler->addDataTable('anime_list_response', (array)$response); - - if ($response->getStatusCode() != 200) - { - if ( ! file_exists($cache_file)) - { - throw new DomainException($response->getEffectiveUrl()); - } - else - { - $output = json_decode(file_get_contents($cache_file), TRUE); - } - } - else - { - $output = $response->json(); - $output_json = json_encode($output); - - if (( ! file_exists($cache_file)) || file_get_contents($cache_file) !== $output_json) - { - // Attempt to create the cache folder if it doesn't exist - if ( ! is_dir($this->config->data_cache_path)) - { - mkdir($this->config->data_cache_path); - } - // Cache the call in case of downtime - file_put_contents($cache_file, json_encode($output)); - } - } - - foreach($output as &$row) - { - $row['anime']['cover_image'] = $this->get_cached_image($row['anime']['cover_image'], $row['anime']['slug'], 'anime'); - } - - return $output; - } - - /** - * Sort the list by title - * - * @param array $array - * @return void - */ - private function sort_by_name(&$array) - { - $sort = array(); - - foreach($array as $key => $item) - { - $sort[$key] = $item['anime']['title']; - } - - array_multisort($sort, SORT_ASC, $array); - } -} -// End of AnimeModel.php \ No newline at end of file diff --git a/app/Model/AnimeCollection.php b/app/Model/AnimeCollection.php deleted file mode 100644 index 418b6e42..00000000 --- a/app/Model/AnimeCollection.php +++ /dev/null @@ -1,372 +0,0 @@ -db = \Query($this->db_config['collection']); - $this->anime_model = new AnimeModel($config); - - // Is database valid? If not, set a flag so the - // app can be run without a valid database - $db_file = file_get_contents($this->db_config['collection']['file']); - $this->valid_database = (strpos($db_file, 'SQLite format 3') === 0); - - - // Do an import if an import file exists - $this->json_import(); - } - - /** - * Get genres for anime collection items - * - * @param array $filter - * @return array - */ - public function get_genre_list($filter=[]) - { - $this->db->select('hummingbird_id, genre') - ->from('genre_anime_set_link gl') - ->join('genres g', 'g.id=gl.genre_id', 'left'); - - - if ( ! empty($filter)) $this->db->where_in('hummingbird_id', $filter); - - $query = $this->db->order_by('hummingbird_id') - ->order_by('genre') - ->get(); - - $output = []; - - foreach($query->fetchAll(\PDO::FETCH_ASSOC) as $row) - { - $id = $row['hummingbird_id']; - $genre = $row['genre']; - - // Empty genre names aren't useful - if (empty($genre)) continue; - - - if (array_key_exists($id, $output)) - { - array_push($output[$id], $genre); - } - else - { - $output[$id] = [$genre]; - } - } - - return $output; - } - - /** - * Get collection from the database, and organize by media type - * - * @return array - */ - public function get_collection() - { - $raw_collection = $this->_get_collection(); - - $collection = []; - - foreach($raw_collection as $row) - { - if (array_key_exists($row['media'], $collection)) - { - $collection[$row['media']][] = $row; - } - else - { - $collection[$row['media']] = [$row]; - } - } - - return $collection; - } - - /** - * Get list of media types - * - * @return array - */ - public function get_media_type_list() - { - $output = array(); - - $query = $this->db->select('id, type') - ->from('media') - ->get(); - - foreach($query->fetchAll(\PDO::FETCH_ASSOC) as $row) - { - $output[$row['id']] = $row['type']; - } - - return $output; - } - - /** - * Get item from collection for editing - * - * @param int $id - * @return array - */ - public function get_collection_entry($id) - { - $query = $this->db->from('anime_set') - ->where('hummingbird_id', (int) $id) - ->get(); - - return $query->fetch(\PDO::FETCH_ASSOC); - } - - /** - * Get full collection from the database - * - * @return array - */ - private function _get_collection() - { - if ( ! $this->valid_database) return []; - - $query = $this->db->select('hummingbird_id, slug, title, alternate_title, show_type, age_rating, episode_count, episode_length, cover_image, notes, media.type as media') - ->from('anime_set a') - ->join('media', 'media.id=a.media_id', 'inner') - ->order_by('media') - ->order_by('title') - ->get(); - - return $query->fetchAll(\PDO::FETCH_ASSOC); - } - - /** - * Add an item to the anime collection - * - * @param array $data - * @return void - */ - public function add($data) - { - $anime = (object) $this->anime_model->get_anime($data['id']); - - $this->db->set([ - 'hummingbird_id' => $data['id'], - 'slug' => $anime->slug, - 'title' => $anime->title, - 'alternate_title' => $anime->alternate_title, - 'show_type' => $anime->show_type, - 'age_rating' => $anime->age_rating, - 'cover_image' => basename($this->get_cached_image($anime->cover_image, $anime->slug, 'anime')), - 'episode_count' => $anime->episode_count, - 'episode_length' => $anime->episode_length, - 'media_id' => $data['media_id'], - 'notes' => $data['notes'] - ])->insert('anime_set'); - - $this->update_genre($data['id']); - } - - /** - * Update a collection item - * - * @param array $data - * @return void - */ - public function update($data) - { - // If there's no id to update, don't update - if ( ! array_key_exists('hummingbird_id', $data)) return; - - $id = $data['hummingbird_id']; - unset($data['hummingbird_id']); - - $this->db->set($data) - ->where('hummingbird_id', $id) - ->update('anime_set'); - } - - /** - * Get the details of a collection item - * - * @param int $hummingbird_id - * @return array - */ - public function get($hummingbird_id) - { - $query = $this->db->from('anime_set') - ->where('hummingbird_id', $hummingbird_id) - ->get(); - - return $query->fetch(\PDO::FETCH_ASSOC); - } - - /** - * Import anime into collection from a json file - * - * @return void - */ - private function json_import() - { - if ( ! file_exists('import.json')) return; - if ( ! $this->valid_database) return; - - $anime = json_decode(file_get_contents("import.json")); - - foreach($anime as $item) - { - $this->db->set([ - 'hummingbird_id' => $item->id, - 'slug' => $item->slug, - 'title' => $item->title, - 'alternate_title' => $item->alternate_title, - 'show_type' => $item->show_type, - 'age_rating' => $item->age_rating, - 'cover_image' => basename($this->get_cached_image($item->cover_image, $item->slug, 'anime')), - 'episode_count' => $item->episode_count, - 'episode_length' => $item->episode_length - ])->insert('anime_set'); - } - - // Delete the import file - unlink('import.json'); - - // Update genre info - $this->update_genres(); - } - - /** - * Update genre information for selected anime - * - * @return void - */ - private function update_genre($anime_id) - { - $genre_info = $this->get_genre_data(); - extract($genre_info); - - // Get api information - $anime = $this->anime_model->get_anime($anime_id); - - foreach($anime['genres'] as $genre) - { - // Add genres that don't currently exist - if ( ! in_array($genre['name'], $genres)) - { - $this->db->set('genre', $genre['name']) - ->insert('genres'); - - $genres[] = $genre['name']; - } - - // Update link table - // Get id of genre to put in link table - $flipped_genres = array_flip($genres); - - $insert_array = [ - 'hummingbird_id' => $anime['id'], - 'genre_id' => $flipped_genres[$genre['name']] - ]; - - if (array_key_exists($anime['id'], $links)) - { - if ( ! in_array($flipped_genres[$genre['name']], $links[$anime['id']])) - { - $this->db->set($insert_array)->insert('genre_anime_set_link'); - } - } - else - { - $this->db->set($insert_array)->insert('genre_anime_set_link'); - } - } - } - - /** - * Get list of existing genres - * - * @return array - */ - private function get_genre_data() - { - $genres = []; - $links = []; - - // Get existing genres - $query = $this->db->select('id, genre') - ->from('genres') - ->get(); - foreach($query->fetchAll(\PDO::FETCH_ASSOC) as $genre) - { - $genres[$genre['id']] = $genre['genre']; - } - - // Get existing link table entries - $query = $this->db->select('hummingbird_id, genre_id') - ->from('genre_anime_set_link') - ->get(); - foreach($query->fetchAll(\PDO::FETCH_ASSOC) as $link) - { - if (array_key_exists($link['hummingbird_id'], $links)) - { - $links[$link['hummingbird_id']][] = $link['genre_id']; - } - else - { - $links[$link['hummingbird_id']] = [$link['genre_id']]; - } - } - - return [ - 'genres' => $genres, - 'links' => $links - ]; - } - - /** - * Update genre information for the entire collection - * - * @return void - */ - private function update_genres() - { - // Get the anime collection - $collection = $this->_get_collection(); - foreach($collection as $anime) - { - // Get api information - $this->update_genre($anime['hummingbird_id']); - } - } -} -// End of AnimeCollectionModel.php \ No newline at end of file diff --git a/app/Model/Manga.php b/app/Model/Manga.php deleted file mode 100644 index 2fe270ac..00000000 --- a/app/Model/Manga.php +++ /dev/null @@ -1,201 +0,0 @@ -client->put("manga_library_entries/{$id}", [ - 'cookies' => ['token' => $_SESSION['hummingbird_anime_token']], - 'json' => ['manga_library_entry' => $data] - ]); - - return $result->json(); - } - - /** - * Get the full set of anime lists - * - * @return array - */ - public function get_all_lists() - { - $data = $this->_get_list(); - - foreach ($data as $key => &$val) - { - $this->sort_by_name($val); - } - - return $data; - } - - /** - * Get a category out of the full list - * - * @param string $status - * @return array - */ - public function get_list($status) - { - $data = $this->_get_list($status); - - $this->sort_by_name($data); - - return $data; - } - - /** - * Massage the list of manga entries into something more usable - * - * @param string $status - * @return array - */ - private function _get_list($status="all") - { - global $defaultHandler; - - $cache_file = _dir($this->config->data_cache_path, 'manga.json'); - - $config = [ - 'query' => [ - 'user_id' => $this->config->hummingbird_username - ], - 'allow_redirects' => FALSE - ]; - - $response = $this->client->get('manga_library_entries', $config); - - $defaultHandler->addDataTable('response', (array)$response); - - if ($response->getStatusCode() != 200) - { - if ( ! file_exists($cache_file)) - { - throw new DomainException($response->getEffectiveUrl()); - } - else - { - $raw_data = json_decode(file_get_contents($cache_file), TRUE); - } - } - else - { - // Reorganize data to be more usable - $raw_data = $response->json(); - - // Attempt to create the cache dir if it doesn't exist - if ( ! is_dir($this->config->data_cache_path)) - { - mkdir($this->config->data_cache_path); - } - - // Cache data in case of downtime - file_put_contents($cache_file, json_encode($raw_data)); - } - - // Bail out early if there isn't any manga data - if ( ! array_key_exists('manga', $raw_data)) return []; - - $data = [ - 'Reading' => [], - 'Plan to Read' => [], - 'On Hold' => [], - 'Dropped' => [], - 'Completed' => [], - ]; - $manga_data = []; - - // Massage the two lists into one - foreach($raw_data['manga'] as $manga) - { - $manga_data[$manga['id']] = $manga; - } - - // Filter data by status - foreach($raw_data['manga_library_entries'] as &$entry) - { - $entry['manga'] = $manga_data[$entry['manga_id']]; - - // Cache poster images - $entry['manga']['poster_image'] = $this->get_cached_image($entry['manga']['poster_image'], $entry['manga_id'], 'manga'); - - switch($entry['status']) - { - case "Plan to Read": - $data['Plan to Read'][] = $entry; - break; - - case "Dropped": - $data['Dropped'][] = $entry; - break; - - case "On Hold": - $data['On Hold'][] = $entry; - break; - - case "Currently Reading": - $data['Reading'][] = $entry; - break; - - case "Completed": - default: - $data['Completed'][] = $entry; - break; - } - } - - return (array_key_exists($status, $data)) ? $data[$status] : $data; - } - - /** - * Sort the manga entries by their title - * - * @param array $array - * @return void - */ - private function sort_by_name(&$array) - { - $sort = array(); - - foreach($array as $key => $item) - { - $sort[$key] = $item['manga']['romaji_title']; - } - - array_multisort($sort, SORT_ASC, $array); - } -} -// End of MangaModel.php \ No newline at end of file diff --git a/app/config/routes.php b/app/config/routes.php index 92e46c47..1060ddf2 100644 --- a/app/config/routes.php +++ b/app/config/routes.php @@ -70,6 +70,25 @@ return [ 'code' => '301' ] ], + 'login_form' => [ + 'path' => '/anime/login', + 'action' => ['login'], + 'verb' => 'get' + ], + 'login_action' => [ + 'path' => '/anime/login', + 'action' => ['login_action'], + 'verb' => 'post' + ], + 'logout' => [ + 'path' => '/anime/logout', + 'action' => ['logout'] + ], + 'update' => [ + 'path' => '/anime/update', + 'action' => ['update'], + 'verb' => 'post' + ], 'search' => [ 'path' => '/anime/search', 'action' => ['search'], diff --git a/src/Base/Router.php b/src/Base/Router.php index cd46b811..c33413f2 100644 --- a/src/Base/Router.php +++ b/src/Base/Router.php @@ -149,7 +149,10 @@ class Router extends RoutingBase { $segments = explode('/', $path); $controller = reset($segments); - //$controller_class = '\\AnimeClient\\Controller\\' . ucfirst($controller); + if (empty($controller)) + { + $controller = $route_type; + } return $controller; } diff --git a/src/views/anime/list.php b/src/views/anime/list.php index 3067fcd0..87877b26 100644 --- a/src/views/anime/list.php +++ b/src/views/anime/list.php @@ -44,4 +44,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/views/collection/list.php b/src/views/collection/list.php index ee4065bd..5dcfae5a 100644 --- a/src/views/collection/list.php +++ b/src/views/collection/list.php @@ -1,6 +1,6 @@
-[Add Item] +[Add Item]

There's nothing here!

@@ -43,7 +43,7 @@ - [">Edit] + [">Edit] @@ -53,4 +53,4 @@
- \ No newline at end of file + \ No newline at end of file diff --git a/src/views/header.php b/src/views/header.php index 431d3e9b..e1209b97 100644 --- a/src/views/header.php +++ b/src/views/header.php @@ -18,9 +18,9 @@ - [">Logout] + [">Logout] - ["> Login] + ["> Login] diff --git a/src/views/manga/list.php b/src/views/manga/list.php index 89cddde7..40248c82 100644 --- a/src/views/manga/list.php +++ b/src/views/manga/list.php @@ -34,4 +34,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/tests/Base/RouterTest.php b/tests/Base/RouterTest.php index 072c3bfb..5b77b217 100644 --- a/tests/Base/RouterTest.php +++ b/tests/Base/RouterTest.php @@ -205,5 +205,6 @@ class RouterTest extends AnimeClient_TestCase { $this->_set_up($config, "/", "localhost"); $this->assertEquals('//localhost/manga/all', $this->urlGenerator->default_url('manga'), "Incorrect default url"); $this->assertEquals('//localhost/anime/watching', $this->urlGenerator->default_url('anime'), "Incorrect default url"); + $this->assertEquals('', $this->urlGenerator->default_url('foo'), "Incorrect default url"); } } \ No newline at end of file