API client for Kitsu.io, with optional Anime collection, and optional Anilist syncing.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Anime.php 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. <?php declare(strict_types=1);
  2. /**
  3. * Hummingbird Anime List Client
  4. *
  5. * An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
  6. *
  7. * PHP version 7
  8. *
  9. * @package HummingbirdAnimeClient
  10. * @author Timothy J. Warren <tim@timshomepage.net>
  11. * @copyright 2015 - 2018 Timothy J. Warren
  12. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  13. * @version 4.0
  14. * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
  15. */
  16. namespace Aviat\AnimeClient\Controller;
  17. use Aviat\AnimeClient\Controller as BaseController;
  18. use Aviat\AnimeClient\API\Kitsu\{
  19. Enum\AnimeWatchingStatus as KitsuWatchingStatus,
  20. Transformer\AnimeListTransformer
  21. };
  22. use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
  23. use Aviat\Ion\Di\ContainerInterface;
  24. use Aviat\Ion\Json;
  25. use Aviat\Ion\StringWrapper;
  26. /**
  27. * Controller for Anime-related pages
  28. */
  29. class Anime extends BaseController {
  30. use StringWrapper;
  31. /**
  32. * The anime list model
  33. * @var object $model
  34. */
  35. protected $model;
  36. /**
  37. * Data to be sent to all routes in this controller
  38. * @var array $baseData
  39. */
  40. protected $baseData;
  41. /**
  42. * Data cache
  43. * @var \Psr\Cache\CachePoolInterface
  44. */
  45. protected $cache;
  46. /**
  47. * Constructor
  48. *
  49. * @param ContainerInterface $container
  50. */
  51. public function __construct(ContainerInterface $container)
  52. {
  53. parent::__construct($container);
  54. $this->model = $container->get('anime-model');
  55. $this->baseData = array_merge($this->baseData, [
  56. 'menu_name' => 'anime_list',
  57. 'url_type' => 'anime',
  58. 'other_type' => 'manga',
  59. 'config' => $this->config,
  60. ]);
  61. $this->cache = $container->get('cache');
  62. }
  63. /**
  64. * Show a portion, or all of the anime list
  65. *
  66. * @param string|int $type - The section of the list
  67. * @param string $view - List or cover view
  68. * @return void
  69. */
  70. public function index($type = KitsuWatchingStatus::WATCHING, string $view = NULL)
  71. {
  72. $title = (array_key_exists($type, AnimeWatchingStatus::ROUTE_TO_TITLE))
  73. ? $this->formatTitle(
  74. $this->config->get('whose_list') . "'s Anime List",
  75. AnimeWatchingStatus::ROUTE_TO_TITLE[$type]
  76. )
  77. : '';
  78. $viewMap = [
  79. '' => 'cover',
  80. 'list' => 'list'
  81. ];
  82. $data = ($type !== 'all')
  83. ? $this->model->getList(AnimeWatchingStatus::ROUTE_TO_KITSU[$type])
  84. : $this->model->getAllLists();
  85. $this->outputHTML('anime/' . $viewMap[$view], [
  86. 'title' => $title,
  87. 'sections' => $data
  88. ]);
  89. }
  90. /**
  91. * Form to add an anime
  92. *
  93. * @return void
  94. */
  95. public function addForm()
  96. {
  97. $this->setSessionRedirect();
  98. $this->outputHTML('anime/add', [
  99. 'title' => $this->formatTitle(
  100. $this->config->get('whose_list') . "'s Anime List",
  101. 'Add'
  102. ),
  103. 'action_url' => $this->url->generate('anime.add.post'),
  104. 'status_list' => AnimeWatchingStatus::KITSU_TO_TITLE
  105. ]);
  106. }
  107. /**
  108. * Add an anime to the list
  109. *
  110. * @return void
  111. */
  112. public function add()
  113. {
  114. $data = $this->request->getParsedBody();
  115. if ( ! array_key_exists('id', $data))
  116. {
  117. $this->redirect("anime/add", 303);
  118. }
  119. $result = $this->model->createLibraryItem($data);
  120. if ($result)
  121. {
  122. $this->setFlashMessage('Added new anime to list', 'success');
  123. $this->cache->clear();
  124. }
  125. else
  126. {
  127. $this->setFlashMessage('Failed to add new anime to list', 'error');
  128. }
  129. $this->sessionRedirect();
  130. }
  131. /**
  132. * Form to edit details about a series
  133. *
  134. * @param int $id
  135. * @param string $status
  136. * @return void
  137. */
  138. public function edit($id, $status = "all")
  139. {
  140. $item = $this->model->getLibraryItem($id, $status);
  141. $this->setSessionRedirect();
  142. $this->outputHTML('anime/edit', [
  143. 'title' => $this->formatTitle(
  144. $this->config->get('whose_list') . "'s Anime List",
  145. 'Edit'
  146. ),
  147. 'item' => $item,
  148. 'statuses' => AnimeWatchingStatus::KITSU_TO_TITLE,
  149. 'action' => $this->url->generate('update.post', [
  150. 'controller' => 'anime'
  151. ]),
  152. ]);
  153. }
  154. /**
  155. * Search for anime
  156. *
  157. * @return void
  158. */
  159. public function search()
  160. {
  161. $queryParams = $this->request->getQueryParams();
  162. $query = $queryParams['query'];
  163. $this->outputJSON($this->model->search($query));
  164. }
  165. /**
  166. * Update an anime item via a form submission
  167. *
  168. * @return void
  169. */
  170. public function formUpdate()
  171. {
  172. $data = $this->request->getParsedBody();
  173. // Do some minor data manipulation for
  174. // large form-based updates
  175. $transformer = new AnimeListTransformer();
  176. $postData = $transformer->untransform($data);
  177. $fullResult = $this->model->updateLibraryItem($postData);
  178. if ($fullResult['statusCode'] === 200)
  179. {
  180. $this->setFlashMessage("Successfully updated.", 'success');
  181. $this->cache->clear();
  182. }
  183. else
  184. {
  185. $this->setFlashMessage('Failed to update anime.', 'error');
  186. }
  187. $this->sessionRedirect();
  188. }
  189. /**
  190. * Update an anime item
  191. *
  192. * @return void
  193. */
  194. public function update()
  195. {
  196. if (stripos($this->request->getHeader('content-type')[0], 'application/json') !== FALSE)
  197. {
  198. $data = Json::decode((string)$this->request->getBody());
  199. }
  200. else
  201. {
  202. $data = $this->request->getParsedBody();
  203. }
  204. $response = $this->model->updateLibraryItem($data, $data);
  205. $this->cache->clear();
  206. $this->outputJSON($response['body'], $response['statusCode']);
  207. }
  208. /**
  209. * Remove an anime from the list
  210. *
  211. * @return void
  212. */
  213. public function delete()
  214. {
  215. $body = $this->request->getParsedBody();
  216. $response = $this->model->deleteLibraryItem($body['id'], $body['mal_id']);
  217. if ((bool)$response === TRUE)
  218. {
  219. $this->setFlashMessage("Successfully deleted anime.", 'success');
  220. $this->cache->clear();
  221. }
  222. else
  223. {
  224. $this->setFlashMessage('Failed to delete anime.', 'error');
  225. }
  226. $this->sessionRedirect();
  227. }
  228. /**
  229. * View details of an anime
  230. *
  231. * @param string $animeId
  232. * @return void
  233. */
  234. public function details(string $animeId)
  235. {
  236. $data = $this->model->getAnime($animeId);
  237. $characters = [];
  238. if (empty($data))
  239. {
  240. return $this->notFound(
  241. $this->config->get('whose_list') .
  242. "'s Anime List &middot; Anime &middot; " .
  243. 'Anime not found',
  244. 'Anime Not Found'
  245. );
  246. }
  247. if (array_key_exists('characters', $data['included']))
  248. {
  249. foreach($data['included']['characters'] as $id => $character)
  250. {
  251. $characters[$id] = $character['attributes'];
  252. }
  253. }
  254. $this->outputHTML('anime/details', [
  255. 'title' => $this->formatTitle(
  256. $this->config->get('whose_list') . "'s Anime List",
  257. 'Anime',
  258. $data['titles'][0]
  259. ),
  260. 'characters' => $characters,
  261. 'data' => $data,
  262. ]);
  263. }
  264. }
  265. // End of AnimeController.php