From 1e6d7f5291410a65539e76775cf5a704f1154390 Mon Sep 17 00:00:00 2001 From: Irfan Date: Thu, 7 Jul 2022 23:44:21 +0500 Subject: [PATCH] add anime videos episodes --- src/Model/Anime/AnimeVideosEpisodes.php | 74 +++++++++++++++ src/MyAnimeList/MalClient.php | 18 ++++ src/Parser/Anime/VideosParser.php | 92 ++++++++++++++++++- .../Anime/AnimeVideosEpisodesRequest.php | 58 ++++++++++++ src/Request/Anime/AnimeVideosRequest.php | 4 +- 5 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 src/Model/Anime/AnimeVideosEpisodes.php create mode 100644 src/Request/Anime/AnimeVideosEpisodesRequest.php diff --git a/src/Model/Anime/AnimeVideosEpisodes.php b/src/Model/Anime/AnimeVideosEpisodes.php new file mode 100644 index 00000000..bc24ec41 --- /dev/null +++ b/src/Model/Anime/AnimeVideosEpisodes.php @@ -0,0 +1,74 @@ +results = $parser->getEpisodes(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); + + return $instance; + } + + /** + * @return static + */ + public static function mock() : self + { + return new self(); + } + + /** + * @return bool + */ + public function hasNextPage(): bool + { + return $this->hasNextPage; + } + + /** + * @return int + */ + public function getLastVisiblePage(): int + { + return $this->lastVisiblePage; + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->results; + } +} diff --git a/src/MyAnimeList/MalClient.php b/src/MyAnimeList/MalClient.php index 7c89f20a..2edad457 100644 --- a/src/MyAnimeList/MalClient.php +++ b/src/MyAnimeList/MalClient.php @@ -113,6 +113,24 @@ public function getAnimeVideos(Request\Anime\AnimeVideosRequest $request): Model } } + /** + * @param Request\Anime\AnimeVideosEpisodesRequest $request + * @return Model\Anime\AnimeVideosEpisodes + * @throws BadResponseException + * @throws ParserException + */ + public function getAnimeVideosEpisodes(Request\Anime\AnimeVideosEpisodesRequest $request): Model\Anime\AnimeVideosEpisodes + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Anime\VideosParser($crawler); + + return $parser->getResultsModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + /** * @param Request\Manga\MangaRequest $request * @return Model\Manga\Manga diff --git a/src/Parser/Anime/VideosParser.php b/src/Parser/Anime/VideosParser.php index 1b73d8fd..9b81c808 100644 --- a/src/Parser/Anime/VideosParser.php +++ b/src/Parser/Anime/VideosParser.php @@ -3,6 +3,7 @@ namespace Jikan\Parser\Anime; use Jikan\Model\Anime\AnimeVideos; +use Jikan\Model\Anime\AnimeVideosEpisodes; use Jikan\Model\Anime\PromoListItem; use Jikan\Parser\ParserInterface; use Symfony\Component\DomCrawler\Crawler; @@ -17,7 +18,7 @@ class VideosParser implements ParserInterface /** * @var Crawler */ - private $crawler; + private Crawler $crawler; /** * EpisodesParser constructor. @@ -72,6 +73,85 @@ function (Crawler $crawler) { ); } + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $node = $this->crawler + ->filterXPath('//div[contains(@class, "video-block episode-video")]//div[contains(@class, "pagination")]/a[text()[contains(.,"More")]]'); + + if ($node->count()) { + return true; + } + + return false; + } + + /** + * @return int + */ + public function getLastPage(): int + { + $node = $this->crawler + ->filterXPath('//div[contains(@class, "video-block episode-video")]//div[contains(@class, "pagination")]/a[text()[contains(.,"Last")]]'); + + // All pages except the last page returns "Last" button + if ($node->count()) { + parse_str( + parse_url($node->attr('href'), PHP_URL_QUERY), + $params + ); + + return (int) $params['p']; + } + + // Fallback 1 + // The second last page doesn't return "Last" and only returns "More" as an indicator + // for the next or last page + $node = $this->crawler + ->filterXPath('//div[contains(@class, "video-block episode-video")]//div[contains(@class, "pagination")]/a[text()[contains(.,"More")]]'); + + if ($node->count()) { + parse_str( + parse_url($node->attr('href'), PHP_URL_QUERY), + $params + ); + + return (int) $params['p']; + } + + // Fallback 2 + // The last page only indicates the last page through a span element + $node = $this->crawler + ->filterXPath('//div[contains(@class, "video-block episode-video")]//div[contains(@class, "pagination")]/*[position()=last()]'); + + // Fallback 3 + // The user has exceeded the pagination + // MAL still generates pagination here for some reason + // So we'll check other properties to see whether the page has ended or not + // otherwise fallback 2 will keep returning the generated page + $hasReachedTheEnd = $this->crawler + ->filterXPath('//div[contains(@class, "video-block episode-video")]//p[text()[contains(.,"No episode video has been added to this title")]]'); + + if ($hasReachedTheEnd->count()) { + // there is no way for us to know + // what the last accessible page is + // e.g https://myanimelist.net/anime/21/One_Piece/video?p=300 + return 1; + } + + + if ($node->count()) { + // this element is not clickable and is returned as text + + return (int) $node->text(); + } + + // if anything breaks + return 1; + } + /** * Return the model * @@ -81,4 +161,14 @@ public function getModel(): AnimeVideos { return AnimeVideos::fromParser($this); } + + /** + * Return the results based model + * + * @throws \InvalidArgumentException + */ + public function getResultsModel(): AnimeVideosEpisodes + { + return AnimeVideosEpisodes::fromParser($this); + } } diff --git a/src/Request/Anime/AnimeVideosEpisodesRequest.php b/src/Request/Anime/AnimeVideosEpisodesRequest.php new file mode 100644 index 00000000..50d6d706 --- /dev/null +++ b/src/Request/Anime/AnimeVideosEpisodesRequest.php @@ -0,0 +1,58 @@ +id = $id; + $this->page = $page; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/anime/%d/_/video?p=%d', $this->id, $this->page); + } + + /** + * @return int + */ + public function getId(): int + { + return $this->id; + } + + /** + * @return int + */ + public function getPage(): int + { + return $this->page; + } +} diff --git a/src/Request/Anime/AnimeVideosRequest.php b/src/Request/Anime/AnimeVideosRequest.php index 1e6cb755..ad794f32 100644 --- a/src/Request/Anime/AnimeVideosRequest.php +++ b/src/Request/Anime/AnimeVideosRequest.php @@ -5,7 +5,7 @@ use Jikan\Request\RequestInterface; /** - * Class AnimeVideos + * Class AnimeVideosRequest * * @package Jikan\Request */ @@ -14,7 +14,7 @@ class AnimeVideosRequest implements RequestInterface /** * @var int */ - private $id; + private int $id; /** * AnimeVideosRequest constructor.