diff --git a/.gitignore b/.gitignore index e244eda0..5ede35ba 100755 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /vendor/ -/.idea/ \ No newline at end of file +/.idea/ +/composer.lock +/test.php +/jikan-fixtures diff --git a/.travis.yml b/.travis.yml old mode 100755 new mode 100644 index 1ebde19a..4b4eb63e --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,30 @@ language: php + php: - - '7.0' - - '7.1' - - '7.2' + - 7.1 + - 7.2 + - nightly + +env: + matrix: + - +# - DEPENDENCIES=--prefer-lowest + +cache: + directories: + - .composer/cache + +matrix: + fast_finish: true + allow_failures: + - php: nightly + +before_install: + - alias composer=composer\ --no-interaction && composer selfupdate + - composer global require hirak/prestissimo + +install: + - travis_retry composer update --no-progress --profile --no-scripts --no-suggest $DEPENDENCIES -before_script: - - composer install -script: php travis.php \ No newline at end of file +script: + - vendor/bin/grumphp run \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..23dd9305 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,51 @@ +build: false +shallow_clone: false +platform: + - x86 + - x64 +clone_folder: c:\projects\jikan + +environment: + matrix: + - PHP_VERSION: 7.1 + - PHP_VERSION: 7.2 + +cache: + - '%APPDATA%\Composer' + - c:\tools\php -> appveyor.yml +init: + - SET PATH=C:\Program Files\OpenSSL;c:\tools\php;%PATH% + - SET COMPOSER_NO_INTERACTION=1 + - SET PHP=1 + - SET ANSICON=121x90 (121x90) + +install: + - IF EXIST c:\tools\php (SET PHP=0) + - ps: Set-Service wuauserv -StartupType Manual + + # Install PHP here + - ps: appveyor-retry cinst --params '""/InstallDir:C:\tools\php""' --ignore-checksums -y php --version ((choco search php --exact --all-versions -r | select-string -pattern $env:PHP_VERSION | sort { [version]($_ -split '\|' | select -last 1) } -Descending | Select-Object -first 1) -replace '[php|]','') + # - IF %PHP%==1 cinst -y OpenSSL.Light + # - IF %PHP%==1 cinst -y php -version %PHP_VERSION% + # - cd C:\tools\php71 + - cd c:\tools\php + - IF %PHP%==1 copy php.ini-production php.ini + - IF %PHP%==1 echo date.timezone="UTC" >> php.ini + - IF %PHP%==1 echo memory_limit=1024M >> php.ini + - IF %PHP%==1 echo extension_dir=ext >> php.ini + - IF %PHP%==1 echo extension=php_curl.dll >> php.ini + - IF %PHP%==1 echo extension=php_mbstring.dll >> php.ini + - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini + - IF %PHP%==1 echo @php %%~dp0composer.phar %%* > composer.bat + + # Download + - cd C:\tools + - appveyor-retry appveyor DownloadFile https://getcomposer.org/composer.phar + +before_test: + - cd C:\projects\jikan + - php C:\tools\composer.phar update --no-progress --profile --prefer-dist --no-scripts --no-interaction --no-suggest + +test_script: + - cd c:\projects\jikan + - vendor\bin\phpunit --colors=always diff --git a/composer.json b/composer.json index 51751385..92d5b019 100755 --- a/composer.json +++ b/composer.json @@ -9,8 +9,7 @@ "email": "irfan@jikan.moe" } ], - "minimum-stability": "dev", - "require": {}, + "minimum-stability": "stable", "autoload": { "psr-4": { "Jikan\\": [ @@ -18,6 +17,25 @@ ] } }, + "autoload-dev": { + "psr-4": { + "Jikan\\": [ + "test/JikanTest" + ] + } + }, + "require": { + "fabpot/goutte": "^3.2", + "php": "^7.1" + }, "require-dev": { + "phpunit/phpunit": "^6.3", + "php-vcr/php-vcr": "~1.3.2", + "php-vcr/phpunit-testlistener-vcr": "^3.0", + "squizlabs/php_codesniffer": "^3.3", + "phpro/grumphp": "^0.14.1", + "jakub-onderka/php-parallel-lint": "^1.0", + "doctrine/collections": "^1.5", + "jikan-me/jikan-fixtures": "dev-master" } } diff --git a/examples/anime.php b/examples/anime.php deleted file mode 100755 index b71001af..00000000 --- a/examples/anime.php +++ /dev/null @@ -1,12 +0,0 @@ -Anime(21); -//$jikan->Anime(1, [EPISODES, CHARACTERS_STAFF]); // get episodes + characters+staff -//$jikan->Anime(21, [EPISODES=>2]); // get all the episodes from page 2 of the episode list - -var_dump($jikan->response); -?> \ No newline at end of file diff --git a/examples/character.php b/examples/character.php deleted file mode 100755 index 983a79a2..00000000 --- a/examples/character.php +++ /dev/null @@ -1,9 +0,0 @@ -Character(1); - -var_dump($jikan->response); -?> \ No newline at end of file diff --git a/examples/manga.php b/examples/manga.php deleted file mode 100755 index 14a9aa45..00000000 --- a/examples/manga.php +++ /dev/null @@ -1,11 +0,0 @@ -Manga(1); -//$jikan->Manga(1, [CHARACTERS]); // get the characters too - -var_dump($jikan->response); -?> \ No newline at end of file diff --git a/examples/person.php b/examples/person.php deleted file mode 100755 index 7800c559..00000000 --- a/examples/person.php +++ /dev/null @@ -1,9 +0,0 @@ -Person(1); - -var_dump($jikan->response); -?> \ No newline at end of file diff --git a/examples/schedule.php b/examples/schedule.php deleted file mode 100755 index 55a24e45..00000000 --- a/examples/schedule.php +++ /dev/null @@ -1,15 +0,0 @@ -Schedule(); - -$jikan->response['monday']; // anime airing on monday -$jikan->response['tuesday']; // anime airing on tuesday -//$jikan->response[$day]; -$jikan->response['sunday']; // all the way upto sunday - -var_dump($jikan->response); -?> \ No newline at end of file diff --git a/examples/search.php b/examples/search.php deleted file mode 100755 index ffbe76a9..00000000 --- a/examples/search.php +++ /dev/null @@ -1,110 +0,0 @@ -Search(query, type[, page, config]) - * - * `query` : string (must be atleast 3 characters) - * `type` : CONSTANT [ANIME, MANGA, PEOPLE, PERSON (alias), CHARACTER] - * `page` : integer // search result page - * `config` : Helper\SearchConfig OBJECT - */ - -// Basic Search -$jikan->Search('Code Geass', ANIME); -var_dump($jikan->response['result']); // Search results for 'Code Geass' that are Anime -$pages = $jikan->response['result_last_page']; // Number of pages of search results. You can use this for pagination - -/* - * NOTE: Response is stored in `$jikan->response` - * Search results are in `$jikan->response['result']` (array) - * No# of pages `$jikan->response['result_last_page']` (integer) - */ - -var_dump( - $jikan->Search('Sword Art Online', MANGA)->response['result']; // All manga search results for 'Sword Art Online' -); - -$jikan->Search('Makise', CHARACTER, 2); // 2nd page of the search results for 'Makise' -$jikan->Search('Sawano', PEOPLE); // you get it by now - - -/* - * Advanced Search - */ - -// Call the SearchConfig Helper to build the config for the query. -// Only Argument is the SearchConfig Type. Only Legal values are ANIME and MANGA -// There are no advanced search options for CHARACTER or PEOPLE -// ALL CONSTANTS ARE DEFINED IN `src/config.php` -$config = new Jikan\Helper\SearchConfig(ANIME); - -// NOTE: If it isn't obvious, All these flags are optional. -// NOTE2: These methods can be chained - -/* Types - * CONSTANTS ARE DEFINED IN `src/config.php` - */ -$config->setType(TYPE_MOVIE); - -/* Score (integer) 1-10 - * Minimum Score in results - */ -$config->setScore(5); - -/* Status - * e.g finished, airing, publishing, etc - * CONSTANTS ARE DEFINED IN `src/config.php` - */ -$config->setStatus(FINISHED_AIRING); - -/* Rated - * PG, PG13, R17, etc - * CONSTANTS ARE DEFINED IN `src/config.php` - */ -$config->setRated(PG13); - -/* Start Date - * setStartDate(day (int), month (int), year (int)) - */ -$config->setStartDate(5, 10, 2004); - -/* End Date - * setEndDate(day (int), month (int), year (int)) - */ -$config->setStartDate(27, 3, 2012); - -/* Genre - * CONSTANTS ARE DEFINED IN `src/config.php` - */ - -// You can set one by one -$config->setGenre(ACTION); -$config->setGenre(COMEDY); - -// or in bulk -$config->setGenre([ACTION, COMEDY, SUPER_POWER, SUPERNATURAL, SHOUNEN]); -// Don't worry about duplicates, they're removed automatically - -/* Genre Include Or Exclude - * The genre that are defined above this - * You have the option of having the results either - * - Include anime/manga with them - * - Exclude anime/manga with them - * - * NOTE: THIS IS `TRUE` BY DEFAULT - */ - -$config->setGenreInclude(true); // This will Include the results with these genre (default) - -$config->setGenreInclude(false); // Exclude - -// Pass the object as an argument -$jikan->Search('Bleach', ANIME, 1, $config); - -var_dump($jikan->response); -?> \ No newline at end of file diff --git a/examples/seasonal.php b/examples/seasonal.php deleted file mode 100755 index d78254d4..00000000 --- a/examples/seasonal.php +++ /dev/null @@ -1,13 +0,0 @@ -Seasonal(season (constant), year (string)); -// season : WINTER, SPRING, SUMMER, FALL -// CONSTANTS ARE DEFINED IN `src/config.php` -$jikan->Seasonal(WINTER, 2017); - -var_dump($jikan->response); -?> \ No newline at end of file diff --git a/examples/test.php b/examples/test.php deleted file mode 100755 index 4b2b1523..00000000 --- a/examples/test.php +++ /dev/null @@ -1,43 +0,0 @@ -setGenre(1, 2); - -$jikan->Search(NULL, ANIME, 1, $config); - -$time_end = microtime(true); -$execution_time = ($time_end - $time_start); - -//execution time of the script -echo 'Total Execution Time: '.$execution_time.' s

'; - -//var_dump(); -foreach ($jikan->response['result'] as $key => $value) { - var_dump($value); -} - -//$jikan->Anime(21); -//sleep(5); -//$jikan->Anime(21, [EPISODES]); -//sleep(5); -//$jikan->Anime(21, [EPISODES, CHARACTERS_STAFF]); -//sleep(5); -//$jikan->Manga(1); -//sleep(5); -//$jikan->Manga(1, [CHARACTERS]); -//sleep(5); -//$jikan->Person(1); -//sleep(5); -//$jikan->Character(1); -// \ No newline at end of file diff --git a/grumphp.yml b/grumphp.yml new file mode 100644 index 00000000..4f1bb9ff --- /dev/null +++ b/grumphp.yml @@ -0,0 +1,20 @@ +parameters: + git_dir: . + bin_dir: ./vendor/bin + process_timeout: 180 + tasks: + phpcs: + standard: 'PSR2' + ignore_patterns: + - 'test/*.php' + - 'src/Jikan.php' + git_blacklist: + keywords: + - 'var_dump' + - 'exit' + - 'else' + - 'ini_set' + - 'error_reporting' + - 'die' + phpunit: ~ + phplint: ~ \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 00000000..b344bddb --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,18 @@ + + + + + + + ./test/JikanTest + + + ./test/JikanTest/JikanTest.php + + + + + src + + + \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 00000000..83cbf5c3 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,15 @@ + + + + + + + ./test/JikanTest + + + + + src + + + \ No newline at end of file diff --git a/readme.md b/readme.md index bfd07a3e..19d4635f 100755 --- a/readme.md +++ b/readme.md @@ -1,38 +1,31 @@ ![Jikan](http://i.imgur.com/ctoJ3Jp.png) -# Jikan - The Unofficial MyAnimeList.net PHP API -[![build](https://travis-ci.org/jikan-me/jikan.svg?branch=master)](https://travis-ci.org/jikan-me/jikan?branch=master) [![stable](https://img.shields.io/badge/jikanPHP-v1.15.15-blue.svg?style=flat)]() [![stable](https://img.shields.io/packagist/v/jikan-me/jikan.svg?style=flat)](https://packagist.org/packages/jikan-me/jikan) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/jikan-me/jikan.svg)](http://isitmaintained.com/project/jikan-me/jikan "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/jikan-me/jikan.svg)](http://isitmaintained.com/project/jikan-me/jikan "Percentage of issues still open") [![stable](https://img.shields.io/badge/PHP->=%207.0-blue.svg?style=flat)]() +# Jikan - Unofficial MyAnimeList.net PHP API +[![build](https://travis-ci.org/jikan-me/jikan.svg?branch=master)](https://travis-ci.org/jikan-me/jikan?branch=master) [![build](https://ci.appveyor.com/api/projects/status/github/irfan-dahir/jikan?branch=2.0.0-dev&svg=true)](https://ci.appveyor.com/project/irfan-dahir/jikan) [![stable](https://img.shields.io/packagist/v/jikan-me/jikan.svg?style=flat)](https://packagist.org/packages/jikan-me/jikan) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/jikan-me/jikan.svg)](http://isitmaintained.com/project/jikan-me/jikan "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/jikan-me/jikan.svg)](http://isitmaintained.com/project/jikan-me/jikan "Percentage of issues still open") [![stable](https://img.shields.io/badge/PHP-^%207.1-blue.svg?style=flat)]() [![Discord Server](https://img.shields.io/discord/460491088004907029.svg?style=flat&logo=discord)](https://discord.gg/4q8E4Gg) -Jikan is a **depenency free**, PHP API with easy-to-use syntax that scrapes and parses requests from [MyAnimeList.net](https://myanimelist.net). +Jikan is a PHP API with scrapes and parses requests from [MyAnimeList.net](https://myanimelist.net). The raison d'être of Jikan is to help developers easily get the data they need for their apps and projects without having to depend on the lackluster official API, unstable APIs, or sidetracking their projects to develop parsers. The word _Jikan_ literally translates to _Time_ in Japanese (**時間**). And that's what this API saves you of. ;) -### Getting Started +## Getting Started 1. `composer require jikan-me/jikan` -2. [Documentation](https://jikan.moe/docs) +2. [Documentation](https://docs.jikan.moe) +## Jikan REST API +There's a REST service available, as well as a few wrappers built around it. -## Jikan REST API [![REST PHP](https://img.shields.io/badge/JikanPHP-1.15.15-blue.svg?style=flat)](https://jikan.moe) -If you don't want to handle PHP, you're in luck! Jikan has it's own RESTful API service (CORS enabled + JSON response) hosted by [Hibiki](https://github.com/assintates) +- **[REST DOCUMENTATION](https://jikan.docs.apiary.io)** +- **[See which apps are using JikanREST](https://jikan.moe/showcase)** +- **[Want to host your own instance of Jikan REST?](https://github.com/jikan-me/jikan-rest)** -**[REST DOCUMENTATION](https://jikan.docs.apiary.io)** - -**[See which apps are using JikanREST](https://jikan.moe/showcase)** - -### WARNING: BULK REQUESTS -If your use of the API is **NOT** for an app/bot/etc that makes consistent amount of requests but **rather** for the sake of making bulk requests, keep in mind to have a **3-4 second delay between EACH request** otherwise **your IP will be blacklisted**. - -Remember, you're not the only one using the API. Be responsible. - -## Wrappers +### Wrappers - **[.NET]** [Jikan.net](https://github.com/Ervie/jikan.net) by Ervie - **[Python]** [JikanPy](https://github.com/AWConant/jikanpy) by Andrew Conant & Abhinav Kasamsetty - **[Ruby]** [Jikan.rb](https://github.com/Zerocchi/jikan.rb) by Zerocchi - -Contributions to Jikan by making wrappers in programming languages of your choice are much appreciated! Do let me know if you've made one and I'll include it here. +- **[JavaScript]** [JikanJS](https://github.com/zuritor/jikanjs) by Zuritor ## Features - Anime Parsing @@ -55,57 +48,38 @@ Contributions to Jikan by making wrappers in programming languages of your choic - Pictures - People Parsing - Pictures -- Search (Anime/Manga/Character/Person) - - Filters (Advanced Search) +- Search + - Anime + - Manga + - Character + - Person - Pagination Support - - No.# of pages + - Advanced Search (Filters) - Seasonal Anime (Season + Year) - Anime Scheduling (for current season) - Top - Anime - Manga - - Sub Types & Pagination Support - -- Modular scraping methods for developers to easily extend the API -- JSON format! ლ( ͡⎚ ͜ʖ ͡⎚ ლ) - -## Roadmap -- Most Favorited - Characters - People -- User Profile -- Command Line Usage -- [PThreads](https://github.com/krakjoe/pthreads) (Multi-threaded) Support (CLI ONLY!) + - Sub Types & Pagination Support +- Genre + - Anime + - Manga +- Producers (Anime Listing) +- Magazines (Manga Listing) +- User + - Profile + - Friends + - History ## Changelog -### 1.15.14 stable - May 26, 18 -- **[Anime, Manga, Extended]** - - Fix Some parsing methods were not parsing correctly [#148](/../../issues/148) -- **[Person]** - - Add information about roles [#146](/../../issues/146) -- **[Seasonal]** - - Add `season_name` and `season_year` data - -**[Read More](https://github.com/jikan-me/jikan/tree/master/changelog.md)** -## Usage -- [.NET](https://github.com/Ervie/jikan.net/wiki) -- [PHP](https://github.com/jikan-me/jikan/tree/master/examples) -- [Python](https://github.com/jikan-me/jikanpy#jikanpy) -- [Ruby](https://github.com/jikan-me/jikan.rb#usage) -## Contributions -I would like to thank these 3 for graciously hosting Jikan REST for free! -* [Hibiki](https://twitter.com/Assintates) -* [Sif](https://myanimelist.net/profile/ArtoriasMoreder) -* [BroHosting](https://brohosting.eu) +## Dependencies +- [Goutte](https://github.com/FriendsOfPHP/Goutte) +- PHP ^7.1 ## DISCLAIMER -- Jikan is in no way affiliated with MyAnimeList. -- I am not responsible for what you do with this library, so use it responsibly as per MyAnimeList's [TOS](https://myanimelist.net/about/terms_of_use) -- Use the REST API responsibly, bulk requesting data for building your own database/datasets is only allowed under conditions. [Read More](https://jikan.docs.apiary.io/#introduction/information/rate-limiting) - -## [Donate](https://liberapay.com/Nekomata/donate) -If you found this useful, please feel free to donate to help with development! - -[![Donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/Nekomata/donate "Donate using Liberapay") \ No newline at end of file +- Jikan is not affiliated with MyAnimeList.net +- I am not responsible for how you do use this library. Please be respectful towards MyAnimeList's [Terms Of Service](https://myanimelist.net/about/terms_of_use) diff --git a/src/Exception/ParserException.php b/src/Exception/ParserException.php new file mode 100644 index 00000000..5d0fd8e4 --- /dev/null +++ b/src/Exception/ParserException.php @@ -0,0 +1,26 @@ +getPath()); + + return new self($message, $previous->getCode(), $previous); + } +} diff --git a/src/Get/Anime.php b/src/Get/Anime.php deleted file mode 100755 index 08ad8908..00000000 --- a/src/Get/Anime.php +++ /dev/null @@ -1,151 +0,0 @@ -id = $id; - - $this->parser = new AnimeParse; - $this->parser->setPath( - ( - is_int($this->id) || ctype_digit($this->id) - ) ? BASE_URL . ANIME_ENDPOINT . $this->id : $this->id - ); - $this->parser->loadFile(); - - $this->response['code'] = $this->parser->status; - $this->response = array_merge($this->response, $this->parser->parse()); - - $this->canonical_path = $this->parser->model->get('Anime', 'link_canonical'); - - - - if (!empty($extend)) { - $this->extend = $extend; - - foreach ($this->extend as $key => $extend) { - - if (is_string($key)) { - $this->extend = $key; - $this->extendArgs = $extend; - - if (!in_array($this->extend, $this->validExtends)) { - throw new \Exception('Unsupported parse request'); - } - - $this->{$this->extend}($this->extendArgs); - } elseif (is_int($key)) { - $this->extend = $extend; - - if (!in_array($this->extend, $this->validExtends)) { - throw new \Exception('Unsupported parse request'); - } - - $this->{$this->extend}(); - } - } - } - - } - - private function episodes($page=1) { - $page = ($page < 1) ? $page = 1 : $page; - $this->parser = new AnimeEpisodeParse; - //echo $this->canonical_path.'?offset='.(($page-1)*100); - - $this->parser->setPath($this->canonical_path.'/episode?offset='.(($page-1)*100)); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - - } - - private function charactersStaff() { - $this->parser = new AnimeCharacterStaffParse; - - $this->parser->setPath($this->canonical_path.'/characters'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - private function news() { - $this->parser = new AnimeNewsParse; - - $this->parser->setPath($this->canonical_path.'/news'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - private function videos() { - $this->parser = new AnimeVideoParse; - - $this->parser->setPath($this->canonical_path.'/video'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - private function stats() { - $this->parser = new AnimeStatsParse; - - $this->parser->setPath($this->canonical_path.'/stats'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - private function pictures() { - $this->parser = new AnimePicturesParse; - - $this->parser->setPath($this->canonical_path.'/pics'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - private function forum() { - $this->parser = new AnimeForumParse; - - $this->parser->setPath($this->canonical_path.'/forum'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - private function moreInfo() { - $this->parser = new AnimeMoreInfoParse; - - $this->parser->setPath($this->canonical_path.'/moreinfo'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - -} \ No newline at end of file diff --git a/src/Get/Character.php b/src/Get/Character.php deleted file mode 100755 index 968bccfe..00000000 --- a/src/Get/Character.php +++ /dev/null @@ -1,74 +0,0 @@ -id = $id; - - $this->parser = new CharacterParse; - $this->parser->setPath( - ( - is_int($this->id) || ctype_digit($this->id) - ) ? BASE_URL . CHARACTER_ENDPOINT . $this->id : $this->id - ); - $this->parser->loadFile(); - - $this->response['code'] = $this->parser->status; - $this->response = array_merge($this->response, $this->parser->parse()); - - $this->canonical_path = $this->parser->model->get('Character', 'link_canonical'); - - if (!empty($extend)) { - $this->extend = $extend; - - foreach ($this->extend as $key => $extend) { - - if (is_string($key)) { - $this->extend = $key; - $this->extendArgs = $extend; - - if (!in_array($this->extend, $this->validExtends)) { - throw new \Exception('Unsupported parse request'); - } - - $this->{$this->extend}($this->extendArgs); - } elseif (is_int($key)) { - $this->extend = $extend; - - if (!in_array($this->extend, $this->validExtends)) { - throw new \Exception('Unsupported parse request'); - } - - $this->{$this->extend}(); - } - } - } - - } - - private function pictures() { - $this->parser = new CharacterPicturesParse; - - $this->parser->setPath($this->canonical_path.'/pictures'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - -} \ No newline at end of file diff --git a/src/Get/Get.php b/src/Get/Get.php deleted file mode 100755 index 0bb5fcd2..00000000 --- a/src/Get/Get.php +++ /dev/null @@ -1,17 +0,0 @@ -id = $id; - - $this->parser = new MangaParse; - $this->parser->setPath( - ( - is_int($this->id) || ctype_digit($this->id) - ) ? BASE_URL . MANGA_ENDPOINT . $this->id : $this->id - ); - $this->parser->loadFile(); - - $this->response['code'] = $this->parser->status; - $this->response = array_merge($this->response, $this->parser->parse()); - - $this->canonical_path = $this->parser->model->get('Manga', 'link_canonical'); - - - if (!empty($extend)) { - $this->extend = $extend; - - foreach ($this->extend as $key => $extend) { - - if (is_string($key)) { - $this->extend = $key; - $this->extendArgs = $extend; - - if (!in_array($this->extend, $this->validExtends)) { - throw new \Exception('Unsupported parse request'); - } - - $this->{$this->extend}($this->extendArgs); - } elseif (is_int($key)) { - $this->extend = $extend; - - if (!in_array($this->extend, $this->validExtends)) { - throw new \Exception('Unsupported parse request'); - } - - $this->{$this->extend}(); - } - } - } - - } - - private function characters() { - $this->parser = new MangaCharacterParse; - - $this->parser->setPath($this->canonical_path.'/characters'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - private function news() { - $this->parser = new MangaNewsParse; - - $this->parser->setPath($this->canonical_path.'/news'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - private function stats() { - $this->parser = new MangaStatsParse; - - $this->parser->setPath($this->canonical_path.'/stats'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - private function pictures() { - $this->parser = new MangaPicturesParse; - - $this->parser->setPath($this->canonical_path.'/pics'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - private function forum() { - $this->parser = new MangaForumParse; - - $this->parser->setPath($this->canonical_path.'/forum'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - - private function moreInfo() { - $this->parser = new MangaMoreInfoParse; - - $this->parser->setPath($this->canonical_path.'/moreinfo'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - -} \ No newline at end of file diff --git a/src/Get/Person.php b/src/Get/Person.php deleted file mode 100755 index b216dfc6..00000000 --- a/src/Get/Person.php +++ /dev/null @@ -1,75 +0,0 @@ -id = $id; - - $this->parser = new PersonParse; - $this->parser->setPath( - ( - is_int($this->id) || ctype_digit($this->id) - ) ? BASE_URL . PEOPLE_ENDPOINT . $this->id : $this->id - ); - $this->parser->loadFile(); - - $this->response['code'] = $this->parser->status; - $this->response = array_merge($this->response, $this->parser->parse()); - - $this->canonical_path = $this->parser->model->get('Person', 'link_canonical'); - - - if (!empty($extend)) { - $this->extend = $extend; - - foreach ($this->extend as $key => $extend) { - - if (is_string($key)) { - $this->extend = $key; - $this->extendArgs = $extend; - - if (!in_array($this->extend, $this->validExtends)) { - throw new \Exception('Unsupported parse request'); - } - - $this->{$this->extend}($this->extendArgs); - } elseif (is_int($key)) { - $this->extend = $extend; - - if (!in_array($this->extend, $this->validExtends)) { - throw new \Exception('Unsupported parse request'); - } - - $this->{$this->extend}(); - } - } - } - - } - - private function pictures() { - $this->parser = new PersonPicturesParse; - - $this->parser->setPath($this->canonical_path.'/pictures'); - $this->parser->loadFile(); - - $this->response = array_merge($this->response, $this->parser->parse()); - } - -} \ No newline at end of file diff --git a/src/Get/Schedule.php b/src/Get/Schedule.php deleted file mode 100755 index cfcdedb5..00000000 --- a/src/Get/Schedule.php +++ /dev/null @@ -1,26 +0,0 @@ -parser = new ScheduleParse; - - $link = BASE_URL . 'anime/season/schedule'; - - $this->parser->setPath($link); - $this->parser->loadFile(); - - $this->response['code'] = $this->parser->status; - $this->response = array_merge($this->response, $this->parser->parse()); - } - -} \ No newline at end of file diff --git a/src/Get/Search.php b/src/Get/Search.php deleted file mode 100755 index ae2e3970..00000000 --- a/src/Get/Search.php +++ /dev/null @@ -1,60 +0,0 @@ -validNullQueries)) { - if (is_null($query)) { - throw new \Exception('No Query Given'); - } - } - - $this->query = is_null($query) ? "" : urlencode($query); - - $this->parser = new SearchParse; - - $link = BASE_URL; - - switch ($type) { - case ANIME: - $link .= 'anime.php?q=' . $this->query . ($page > 1 ? '&show=' . ($page-1)*50 : '' ) . '&c[]=a&c[]=b&c[]=c&c[]=f'; - break; - case MANGA: - $link .= 'manga.php?q=' . $this->query . ($page > 1 ? '&show=' . ($page-1)*50 : '' ) . '&c[]=a&c[]=b&c[]=c&c[]=f'; - break; - case CHARACTER: - $link .= 'character.php?q=' . $this->query . ($page > 1 ? '&show=' . ($page-1)*50 : '' ); - break; - case PERSON: - $link .= 'people.php?q=' . $this->query . ($page > 1 ? '&show=' . ($page-1)*50 : '' ); - break; - - default: - throw new \Exception('Invalid Search Type'); - break; - } - - if (!is_null($config)) { - if ($type == ANIME || $type == MANGA) { - $link .= "&".$config->build(); - } - } - - $this->parser->setPath($link); - $this->parser->loadFile(); - - $this->response['code'] = $this->parser->status; - $this->response = array_merge($this->response, $this->parser->parse($type, $this->parser->status)); - } - -} \ No newline at end of file diff --git a/src/Get/Seasonal.php b/src/Get/Seasonal.php deleted file mode 100755 index 61b5456a..00000000 --- a/src/Get/Seasonal.php +++ /dev/null @@ -1,31 +0,0 @@ -parser = new SeasonalParse; - - $link = BASE_URL . 'anime/season'; - - if (!is_null($season) && !is_null($year)) { - $link .= '/' . $year . '/' . $season; - } - - - $this->parser->setPath($link); - $this->parser->loadFile(); - - $this->response['code'] = $this->parser->status; - $this->response = array_merge($this->response, $this->parser->parse()); - } - -} \ No newline at end of file diff --git a/src/Get/Top.php b/src/Get/Top.php deleted file mode 100755 index dbedcdc9..00000000 --- a/src/Get/Top.php +++ /dev/null @@ -1,43 +0,0 @@ -parser = new TopParse; - - $link = BASE_URL . 'top'.$type.'.php?limit=' . ($page-1)*50; - - if (!is_null($subtype)) { - $link .= '&type=' . $subtype; - } - - - $this->parser->setPath($link); - - $this->parser->loadFile(); - - $this->response['code'] = $this->parser->status; - $this->response = array_merge($this->response, $this->parser->parse($type)); - } - -} \ No newline at end of file diff --git a/src/Get/UserList.php b/src/Get/UserList.php deleted file mode 100644 index 965ba4a0..00000000 --- a/src/Get/UserList.php +++ /dev/null @@ -1,41 +0,0 @@ -parser = new UserListParse; - - $link = BASE_URL . $type.'list/' . $username; - - - - - // $this->parser->setPath($link); - - // $this->parser->loadFile(); - - // $this->response['code'] = $this->parser->status; - // $this->response = array_merge($this->response, $this->parser->parse($type)); - } - -} \ No newline at end of file diff --git a/src/Helper/Constants.php b/src/Helper/Constants.php new file mode 100644 index 00000000..a601f99c --- /dev/null +++ b/src/Helper/Constants.php @@ -0,0 +1,49 @@ +', '
', '
'], '\n', $string) + ), + ENT_QUOTES + ) + ); + } + + /** + * @param string $string + * + * @return string + */ + public static function UTF8NbspTrim(string $string): string + { + return trim($string, \chr(0xC2).\chr(0xA0)); + } +} diff --git a/src/Helper/MalUrlExtractor.php b/src/Helper/MalUrlExtractor.php new file mode 100644 index 00000000..e0fa74e1 --- /dev/null +++ b/src/Helper/MalUrlExtractor.php @@ -0,0 +1,75 @@ +crawler = clone $crawler; + $this->type = $type; + $this->imageLinks = $imageLinks; + } + + /** + * Extract all mal urls that begin with BASE_URL/$type + * + * @return \Jikan\Model\Common\MalUrl[] + * @throws \InvalidArgumentException + */ + public function getMalUrls(): array + { + if (!$this->imageLinks) { + $this->crawler->filterXPath('//a/img')->each( + function (Crawler $c) { + $node = $c->parents()->first()->getNode(0); + /** @noinspection NullPointerExceptionInspection */ + $node->parentNode->removeChild($node); + } + ); + } + + $xpath = sprintf('//a[contains(@href, "%s/%s")]', Constants::BASE_URL, $this->type); + + return $this->crawler + ->filterXPath($xpath) + ->each( + function (Crawler $c) { + return (new MalUrlParser($c))->getModel(); + } + ); + } +} diff --git a/src/Helper/Parser.php b/src/Helper/Parser.php new file mode 100644 index 00000000..0d2ac4e0 --- /dev/null +++ b/src/Helper/Parser.php @@ -0,0 +1,138 @@ +count()) { + return $crawler; + } + $crawler->children()->each( + function (Crawler $crawler) { + $node = $crawler->getNode(0); + if ($node === null || $node->nodeType === 3 || \in_array($node->nodeName, self::ALLOWED_NODES, true)) { + return; + } + $node->parentNode->removeChild($node); + } + ); + + return $crawler; + } + + /** + * Extract the id from a mal url + * + * @param string $url + * + * @return int + */ + public static function idFromUrl(string $url): int + { + return (int)preg_replace('#https://myanimelist.net(/\w+/)(\d+).*#', '$2', $url); + } + + /** + * @param string $date + * + * @return \DateTimeImmutable|null + */ + public static function parseForumDate(string $date): ?\DateTimeImmutable + { + if (!preg_match('/\d{4}/', $date)) { + $date .= ', '.date('Y'); + } + + return self::parseDate($date); + } + + /** + * @param string $date + * + * @return \DateTimeImmutable|null + */ + public static function parseDate(string $date): ?\DateTimeImmutable + { + if (preg_match('/^\d{4}$/', $date)) { + return \DateTimeImmutable::createFromFormat('Y-m-d', $date.'-01-01', new \DateTimeZone('UTC')); + } + try { + return new \DateTimeImmutable($date, new \DateTimeZone('UTC')); + } catch (\Exception $e) { + return null; + } + } + + /** + * @param string $date + * + * @return \DateTimeImmutable|null + */ + public static function parseDateMDY(string $date): ?\DateTimeImmutable + { + if ($date === '-') { + return null; + } + + $dateArray = explode('-', $date); + + if ($dateArray[0] === '??' && $dateArray[1] === '??' && $dateArray[2] === date('y')) { + return null; + } + + $date = str_replace('??', '01', $date); + + return \DateTimeImmutable::createFromFormat('!m-d-y', $date, new \DateTimeZone('UTC')) ?: null; + } + + /** + * @param string $date + * + * @return \DateTimeImmutable|null + * @throws \Exception + */ + public static function parseDateMDYReadable(string $date): ?\DateTimeImmutable + { + $date = str_replace(' ', ' ', $date); + + if (preg_match('~[a-zA-z]+ \d+, \d{4}~', $date)) { + return new \DateTimeImmutable($date, new \DateTimeZone('UTC')); + } + + return null; + } + + /** + * @param Crawler $crawler + * + * @return null|string + * @throws \InvalidArgumentException + */ + public static function textOrNull(Crawler $crawler): ?string + { + if (!$crawler->count()) { + return null; + } + + return $crawler->text(); + } +} diff --git a/src/Helper/SearchConfig.php b/src/Helper/SearchConfig.php deleted file mode 100755 index 208bacf3..00000000 --- a/src/Helper/SearchConfig.php +++ /dev/null @@ -1,123 +0,0 @@ -type = $type; - - return $this; - } - - public function build() { - $query = ""; - // Type - $query .= "type=".$this->subType; - // Score - $query .= "&score=".$this->score; - // Status - $query .= "&status=".$this->status; - // Rated - $query .= "&r=".$this->rated; - // Start Date ISO8601 - $query .= "&sd=".$this->startDate[0]; - $query .= "&sm=".$this->startDate[1]; - $query .= "&sy=".$this->startDate[2]; - // End Date ISO8601 - $query .= "&ed=".$this->endDate[0]; - $query .= "&em=".$this->endDate[1]; - $query .= "&ey=".$this->endDate[2]; - // Genre Include - $query .= "&gx=".($this->genreInclude ? "0" : "1"); - // Genre - if (!empty($this->genre)) { - foreach ($this->genre as $key => $genre) { - $query .= "&genre[]=".$genre; - } - } - - return $query; - } - - public function setType($subType) { - $this->subType = in_array($subType, self::VALID_SUB_TYPES) ? $subType : 0; - - return $this; - } - - public function setScore($score) { - $this->score = $score; - - return $this; - } - - public function setStatus($status) { - $this->status = in_array($status, self::VALID_STATUS) ? $status : 0; - - return $this; - } - - public function setRated($rated) { - $this->rated = in_array($rated, self::VALID_RATING) ? $rated : 0; - - return $this; - } - - public function setStartDate($day, $month, $year) { - $this->startDate = [ - ltrim((string)$year, '0'), - ltrim((string)$month, '0'), - ltrim((string)$day, '0') - ]; - - return $this; - } - - public function setEndDate($day, $month, $year) { - $this->endDate = [ - ltrim((string)$year, '0'), - ltrim((string)$month, '0'), - ltrim((string)$day, '0') - ]; - - return $this; - } - - public function setGenreInclude(Bool $bool) { - $this->genreInclude = $bool; - - return $this; - } - - public function setGenre(...$genre) { - if (is_array($genre)) { - $this->genre = !empty($genre) ? array_unique(array_merge($this->genre, $genre)) : []; - } else { - $this->genre[] = $genre; - $this->genre = array_unique($this->genre); - } - - return $this; - } - -} \ No newline at end of file diff --git a/src/Helper/Utils.php b/src/Helper/Utils.php deleted file mode 100755 index 491d52ab..00000000 --- a/src/Helper/Utils.php +++ /dev/null @@ -1,24 +0,0 @@ -filePath, FILTER_VALIDATE_URL) ? true : false); - return preg_match('`^http(s)?://`', $url) ? true : false; - } - - static public function existsURL($status) { - return ($status == 200 || $status == 303) ? true : false; - } - - static public function getStatus($url) { - return substr(get_headers($url)[0], 9, 3); - } - - static public function trim(&$item, $key) { $item = trim($item); } - -} diff --git a/src/Jikan.php b/src/Jikan.php index a76296fc..d2051c6a 100755 --- a/src/Jikan.php +++ b/src/Jikan.php @@ -1,128 +1,581 @@ myanimelist = new MalClient($guzzle); + } + + /** + * @param int $id + * + * @return \Jikan\Model\Anime\Anime + * @throws ParserException + */ + public function Anime(int $id): Model\Anime\Anime + { + return $this->myanimelist->getAnime( + new Request\Anime\AnimeRequest($id) + ); + } + + /** + * @param int $id + * + * @return \Jikan\Model\Anime\AnimeCharactersAndStaff + * @throws ParserException + */ + public function AnimeCharactersAndStaff(int $id): Model\Anime\AnimeCharactersAndStaff + { + return $this->myanimelist->getAnimeCharactersAndStaff( + new Request\Anime\AnimeCharactersAndStaffRequest($id) + ); + } + + /** + * @param int $id + * @param int $page + * + * @return \Jikan\Model\Anime\Episodes + * @throws ParserException + */ + public function AnimeEpisodes(int $id, int $page = 1): Model\Anime\Episodes + { + return $this->myanimelist->getAnimeEpisodes( + new Request\Anime\AnimeEpisodesRequest($id, $page) + ); + } + + /** + * @param int $id + * + * @return \Jikan\Model\Anime\AnimeVideos + * @throws ParserException + */ + public function AnimeVideos(int $id): Model\Anime\AnimeVideos + { + return $this->myanimelist->getAnimeVideos( + new Request\Anime\AnimeVideosRequest($id) + ); + } + + /** + * @param int $id + * + * @return \Jikan\Model\Common\Picture[] + * @throws ParserException + */ + public function AnimePictures(int $id): array + { + return $this->myanimelist->getAnimePictures( + new Request\Anime\AnimePicturesRequest($id) + ); + } - public function __construct() { - return $this; - } - private function setStatus() { - $this->status = $this->response['code']; - unset($this->response['code']); + /** + * @param int $id + * + * @return Model\News\NewsListItem[] + * @throws ParserException + */ + public function AnimeNews(int $id): array + { + return $this->myanimelist->getNewsList( + new Request\Anime\AnimeNewsRequest($id) + ); } - /* - * Anime - */ - public function Anime($id = null, Array $extend = []) { - $this->response = (array) (new Get\Anime($id, $extend))->response; - $this->setStatus(); + /** + * @param int $id + * + * @return Model\Forum\ForumTopic[] + * @throws ParserException + */ + public function AnimeForum(int $id): array + { + return $this->myanimelist->getAnimeForum( + new Request\Anime\AnimeForumRequest($id) + ); + } - return $this; + /** + * @param int $id + * + * @return Model\Anime\AnimeStats + * @throws ParserException + */ + public function AnimeStats(int $id): Model\Anime\AnimeStats + { + return $this->myanimelist->getAnimeStats( + new Request\Anime\AnimeStatsRequest($id) + ); } - /* - * Manga + /** + * @param int $id + * + * @return string|null + * @throws ParserException */ - public function Manga($id = null, Array $extend = []) { - $this->response = (array) (new Get\Manga($id, $extend))->response; - $this->setStatus(); + public function AnimeMoreInfo(int $id): ?string + { + return $this->myanimelist->getAnimeMoreInfo( + new Request\Anime\AnimeMoreInfoRequest($id) + ); + } - return $this; + /** + * @param int $id + * + * @return \Jikan\Model\Manga\Manga + * @throws ParserException + */ + public function Manga(int $id): Model\Manga\Manga + { + return $this->myanimelist->getManga( + new Request\Manga\MangaRequest($id) + ); } - /* - * Character + /** + * @param int $id + * + * @return Model\Manga\CharacterListItem[] + * @throws ParserException */ - public function Character($id = null, Array $extend = []) { - $this->response = (array) (new Get\Character($id, $extend))->response; - $this->setStatus(); + public function MangaCharacters(int $id): array + { + return $this->myanimelist->getMangaCharacters( + new Request\Manga\MangaCharactersRequest($id) + ); + } - return $this; + /** + * @param int $id + * + * @return \Jikan\Model\Common\Picture[] + * @throws ParserException + */ + public function MangaPictures(int $id): array + { + return $this->myanimelist->getMangaPictures( + new Request\Manga\MangaPicturesRequest($id) + ); } - /* - * Person + /** + * @param int $id + * + * @return Model\News\NewsListItem[] + * @throws ParserException */ - public function Person($id = null, Array $extend = []) { - $this->response = (array) (new Get\Person($id, $extend))->response; - $this->setStatus(); + public function MangaNews(int $id): array + { + return $this->myanimelist->getNewsList( + new Request\Manga\MangaNewsRequest($id) + ); + } - return $this; + /** + * @param int $id + * + * @return Model\Forum\ForumTopic[] + * @throws ParserException + */ + public function MangaForum(int $id): array + { + return $this->myanimelist->getMangaForum( + new Request\Manga\MangaForumRequest($id) + ); } - /* - * Search + /** + * @param int $id + * + * @return Model\Manga\MangaStats + * @throws ParserException */ - public function Search(string $query = null, string $type = ANIME, int $page = 1, SearchConfig $config = null) { - $this->response = (array) (new Get\Search($query, $type, $page, $config))->response; - $this->setStatus(); + public function MangaStats(int $id): Model\Manga\MangaStats + { + return $this->myanimelist->getMangaStats( + new Request\Manga\MangaStatsRequest($id) + ); + } - return $this; + /** + * @param int $id + * + * @return string|null + * @throws ParserException + */ + public function MangaMoreInfo(int $id): ?string + { + return $this->myanimelist->getMangaMoreInfo( + new Request\Manga\MangaMoreInfoRequest($id) + ); } - /* - * Seasonal Anime + /** + * @param int $id + * + * @return \Jikan\Model\Character\Character + * @throws ParserException */ - public function Seasonal(string $season = null, int $year = null) { - $this->response = (array) (new Get\Seasonal($season, $year))->response; - $this->setStatus(); + public function Character(int $id): Model\Character\Character + { + return $this->myanimelist->getCharacter( + new Request\Character\CharacterRequest($id) + ); + } - return $this; + /** + * @param int $id + * + * @return \Jikan\Model\Common\Picture[] + * @throws ParserException + */ + public function CharacterPictures(int $id): array + { + return $this->myanimelist->getCharacterPictures( + new Request\Character\CharacterPicturesRequest($id) + ); } - /* - * Anime Schedule For Current Season + /** + * @param int $id + * + * @return \Jikan\Model\Person\Person + * @throws ParserException */ - public function Schedule() { - $this->response = (array) (new Get\Schedule())->response; - $this->setStatus(); + public function Person(int $id): Model\Person\Person + { + return $this->myanimelist->getPerson( + new Request\Person\PersonRequest($id) + ); + } - return $this; + /** + * @param int $id + * + * @return \Jikan\Model\Common\Picture[] + * @throws ParserException + */ + public function PersonPictures(int $id): array + { + return $this->myanimelist->getPersonPictures( + new Request\Person\PersonPicturesRequest($id) + ); } - /* - * Top Anime/Manga + /** + * @param int $year + * @param string $season + * + * @return \Jikan\Model\Seasonal\Seasonal + * @throws ParserException */ - public function Top(string $type, int $page, string $subtype = null) { - $this->response = (array) (new Get\Top($type, $page, $subtype))->response; - $this->setStatus(); + public function Seasonal(int $year, string $season): Model\Seasonal\Seasonal + { + return $this->myanimelist->getSeasonal( + new Request\Seasonal\SeasonalRequest($year, $season) + ); + } - return $this; + /** + * + * @return array + * @throws ParserException + */ + public function SeasonList(): array + { + return $this->myanimelist->getSeasonList( + new Request\SeasonList\SeasonListRequest() + ); } - /* - * User List - * + /** + * + * @return \Jikan\Model\Shedule\Schedule + * @throws ParserException */ -/* public function UserList(string $username, string $type, int $status = null) { - $this->response = (array) (new Get\User($username, $type, $status))->response; - $this->setStatus(); + public function Schedule(): Model\Shedule\Schedule + { + return $this->myanimelist->getSchedule( + new Request\Schedule\ScheduleRequest() + ); + } - return $this; - }*/ + /** + * @param int $id + * @param int $page + * + * @return \Jikan\Model\Producer\Producer + * @throws ParserException + */ + public function Producer(int $id, int $page): Model\Producer\Producer + { + return $this->myanimelist->getProducer( + new Request\Producer\ProducerRequest($id, $page) + ); + } -} \ No newline at end of file + /** + * @param int $id + * @param int $page + * + * @return \Jikan\Model\Magazine\Magazine + * @throws ParserException + */ + public function Magazine(int $id, int $page): Model\Magazine\Magazine + { + return $this->myanimelist->getMagazine( + new Request\Magazine\MagazineRequest($id, $page) + ); + } + + /** + * @param int $id + * @param int $page + * + * @return \Jikan\Model\Genre\AnimeGenre + * @throws ParserException + */ + public function AnimeGenre(int $id, int $page): Model\Genre\AnimeGenre + { + return $this->myanimelist->getAnimeGenre( + new Request\Genre\AnimeGenreRequest($id, $page) + ); + } + + /** + * @param int $id + * @param int $page + * + * @return \Jikan\Model\Genre\MangaGenre + * @throws ParserException + */ + public function MangaGenre(int $id, int $page): Model\Genre\MangaGenre + { + return $this->myanimelist->getMangaGenre( + new Request\Genre\MangaGenreRequest($id, $page) + ); + } + + /** + * @param int $page + * @param string|null $type + * + * @return Model\Top\TopAnime[] + * @throws ParserException + */ + public function TopAnime(int $page, ?string $type = null): array + { + return $this->myanimelist->getTopAnime( + new Request\Top\TopAnimeRequest($page, $type) + ); + } + + /** + * @param int $page + * @param string|null $type + * + * @return Model\Top\TopManga[] + * @throws ParserException + */ + public function TopManga(int $page, ?string $type = null): array + { + return $this->myanimelist->getTopManga( + new Request\Top\TopMangaRequest($page, $type) + ); + } + + /** + * @param int $page + * + * @return Model\Top\TopCharacter[] + * @throws ParserException + */ + public function TopCharacters(int $page = 1): array + { + return $this->myanimelist->getTopCharacters( + new Request\Top\TopCharactersRequest($page) + ); + } + + /** + * @param int $page + * + * @return Model\Top\TopPerson[] + * @throws ParserException + */ + public function TopPeople(int $page = 1): array + { + return $this->myanimelist->getTopPeople( + new Request\Top\TopPeopleRequest($page) + ); + } + + /** + * @param string|null $query + * @param int $page + * @param null|Request\Search\AnimeSearchRequest $request + * + * @return Model\Search\AnimeSearch + * @throws ParserException + */ + public function AnimeSearch( + ?string $query, + int $page = 1, + ?Request\Search\AnimeSearchRequest $request = null + ): Model\Search\AnimeSearch { + return $this->myanimelist->getAnimeSearch( + null !== $request + ? $request + ->setQuery($query) + ->setPage($page) + : new Request\Search\AnimeSearchRequest($query, $page) + ); + } + + /** + * @param string|null $query + * @param int $page + * @param null|Request\Search\MangaSearchRequest $request + * + * @return Model\Search\MangaSearch + * @throws ParserException + */ + public function MangaSearch( + ?string $query, + int $page = 1, + ?Request\Search\MangaSearchRequest $request = null + ): Model\Search\MangaSearch { + return $this->myanimelist->getMangaSearch( + null !== $request + ? $request + ->setQuery($query) + ->setPage($page) + : new Request\Search\MangaSearchRequest($query, $page) + ); + } + + /** + * @param string|null $query + * @param int $page + * @param null|Request\Search\CharacterSearchRequest $request + * + * @return Model\Search\CharacterSearch + * @throws ParserException + */ + public function CharacterSearch( + ?string $query, + int $page = 1, + ?Request\Search\CharacterSearchRequest $request = null + ): Model\Search\CharacterSearch { + return $this->myanimelist->getCharacterSearch( + null !== $request + ? $request + ->setQuery($query) + ->setPage($page) + : new Request\Search\CharacterSearchRequest($query, $page) + ); + } + + /** + * @param string|null $query + * @param int $page + * @param Request\Search\CharacterSearchRequest|Request\Search\PersonSearchRequest|null $request + * + * @return Model\Search\PersonSearch + */ + public function PersonSearch( + ?string $query, + int $page = 1, + ?Request\Search\CharacterSearchRequest $request = null + ): Model\Search\PersonSearch { + return $this->myanimelist->getPersonSearch( + null !== $request + ? $request + ->setQuery($query) + ->setPage($page) + : new Request\Search\PersonSearchRequest($query, $page) + ); + } + + /** + * @param string $username + * + * @return \Jikan\Model\User\Profile + * @throws ParserException + */ + public function UserProfile(string $username): Model\User\Profile + { + return $this->myanimelist->getUserProfile( + new Request\User\UserProfileRequest($username) + ); + } + + /** + * @param string $username + * @param int $page + * + * @return Model\User\Friend[] + * @throws ParserException + */ + public function UserFriends(string $username, int $page = 1): array + { + return $this->myanimelist->getUserFriends( + new Request\User\UserFriendsRequest($username, $page) + ); + } + + /** + * @param string $username + * @param null|string $type + * + * @return array + * @throws ParserException + */ + public function UserHistory(string $username, ?string $type = null): array + { + return $this->myanimelist->getUserHistory( + new Request\User\UserHistoryRequest($username, $type) + ); + } +} diff --git a/src/Lib/Parser/AnimeCharacterStaffParse.php b/src/Lib/Parser/AnimeCharacterStaffParse.php deleted file mode 100755 index 266a4a86..00000000 --- a/src/Lib/Parser/AnimeCharacterStaffParse.php +++ /dev/null @@ -1,147 +0,0 @@ -match as TemplateParse provides that option now - -namespace Jikan\Lib\Parser; - -use Jikan\Model\AnimeCharacterStaff as AnimeCharacterStaffModel; - -class AnimeCharacterStaffParse extends TemplateParse -{ - - private $return = []; - - public function parse() : Array - { - - - - $this->model = new AnimeCharacterStaffModel(); - - /* - * Rules - */ - - $this->addRule('character', '~Characters & Voice Actors~', function() { - $running = true; - $i = 0; - $characters = []; - while ($running) { - if (preg_match('~~', $this->file[$this->lineNo + $i])) { - $running = false; - } - - $character = []; - - if (preg_match('~~', $this->file[$this->lineNo + $i])) { - $i += 3; - $image = array(); - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $image); - $character['image_url'] = trim(substr(explode(",", $image[3])[1], 0, -3)); - - $i += 5; - $name = array(); - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $name); - preg_match('~myanimelist.net/(.+)/(.*)/~', $name[1], $this->matches); - $character['mal_id'] = (int) $this->matches[2]; - $character['url'] = $name[1]; - $character['name'] = $name[2]; - - $i += 2; - $role = array(); - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $role); - $character['role'] = $role[1]; - - - - $running2 = true; - $character['voice_actor'] = array(); - while ($running2) { - if (preg_match('~~', $this->file[$this->lineNo + $i])) { - $running2 = false; - } - - if (preg_match('~~', $this->file[$this->lineNo + $i])) { - $i++; - $name = array(); - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $name); - $i++; - $role = array(); - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $role); - $i += 5; - $image = array(); - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $image); - - preg_match('~myanimelist.net/(.+)/(.*)/~', $name[1], $this->matches); - - $character['voice_actor'][] = array( - 'mal_id' => (int) $this->matches[2], - 'name' => $name[2], - 'url' => $name[1], - 'language' => $role[1], - 'image_url' => trim(substr(explode(",", $image[3])[1], 0, -3)) - ); - } - - $i++; - } - $characters[] = $character; - } - - $i++; - } - - $this->model->set('AnimeCharacterStaff', 'character', $characters); - }); - - - $this->addRule('staff', '~~', function() { - $running = true; - $i = 0; - $staff = array(); - while ($running) { - $person = array(); - if (preg_match('~
~', $this->file[$this->lineNo + $i])) { - $running = false; - } - - if (preg_match('~~', $this->file[$this->lineNo + $i])) { - $i += 5; - $match = array(); - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $match); - $person['image_url'] = trim(substr(explode(",", $match[3])[1], 0, -3)); - $i += 5; - $match = array(); - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $match); - preg_match('~myanimelist.net/(.+)/(.*)/~', $match[1], $this->matches); - $person['mal_id'] = (int) $this->matches[2]; - $person['url'] = $match[1]; - $person['name'] = $match[2]; - $i += 2; - $match = array(); - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $match); - $person['role'] = $match[1]; - - $staff[] = $person; - } - - $i++; - } - - $this->model->set('AnimeCharacterStaff', 'staff', $staff); - }); - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/AnimeEpisodeParse.php b/src/Lib/Parser/AnimeEpisodeParse.php deleted file mode 100755 index 7cf61179..00000000 --- a/src/Lib/Parser/AnimeEpisodeParse.php +++ /dev/null @@ -1,103 +0,0 @@ -model = new AnimeEpisodeModel; - - /* - * Rules - */ - - - $this->addRule('last_page', '~~', function() { - preg_match_all('~(.*?)~', $this->line, $this->matches); - - $this->model->set('AnimeEpisode', 'episode_last_page', ((int)substr(end($this->matches[2]), -3))/100); - }); - - - $this->addRule('episode', '~
~', function() { - $running = true; - $i = 1; - - while ($running) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~
~', $line)) { - $running = false; - } - - if (preg_match('~~', $line)) { - $i++; - $epMeta = []; - - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - $epMeta['id'] = (int) $this->matches[1]; - $i++; - - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - $epMeta['video_url'] = (!empty($this->matches)) ? $this->matches[1] : null; - $i++; - - preg_match('~(Filler|Recap|)(.*)~', $this->file[$this->lineNo + $i], $this->matches); - $epMeta['title'] = $this->matches[3]; - - $epMeta['filler'] = preg_match('~Filler~', $this->file[$this->lineNo + $i]) ? true : false; - $epMeta['recap'] = preg_match('~Recap~', $this->file[$this->lineNo + $i]) ? true : false; - $i++; - - preg_match('~
(.*) (.*)~', $this->file[$this->lineNo + $i], $this->matches); - $epMeta['title_japanese'] = !empty($this->matches) ? $this->matches[2] : null; - $epMeta['title_romanji'] = !empty($this->matches) ? $this->matches[1] : null; - $i += 2; - - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - $epMeta['aired'] = $this->matches[1] != 'N/A' ? $this->matches[1] : false; - $i += 2; - - preg_match('~Forum~', $this->file[$this->lineNo + $i], $this->matches); - $epMeta['forum_url'] = !empty($this->matches) ? $this->matches[1] : null; - - $this->return[] = [ - 'id' => (int) $epMeta['id'], - 'title' => htmlspecialchars_decode($epMeta['title']), - 'title_japanese' => $epMeta['title_japanese'], - 'title_romanji' => $epMeta['title_romanji'], - 'aired' => $epMeta['aired'], - 'filler' => (bool) $epMeta['filler'], - 'recap' => (bool) $epMeta['recap'], - 'video_url' => $epMeta['video_url'], - 'forum_url' => $epMeta['forum_url'] - ]; - } - - $i++; - } - - $this->model->set('AnimeEpisode','episode', $this->return); - - }); - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/AnimeForumParse.php b/src/Lib/Parser/AnimeForumParse.php deleted file mode 100755 index 863994ae..00000000 --- a/src/Lib/Parser/AnimeForumParse.php +++ /dev/null @@ -1,99 +0,0 @@ -model = new AnimeForumModel; - - /* - * Rules - */ - - $this->addRule('topic', '~~', function() { - $i = 0; - $topics = []; - - while (true) { - $line = $this->file[$this->lineNo + $i]; - - if (preg_match('~~', $line)) { - $i += 2; - - $topic = [ - 'topic_id' => null, - 'url' => null, - 'title' => null, - 'date_posted' => null, - 'author_name' => null, - 'author_url' => null, - 'replies' => 0, - 'last_post' => [ - 'url' => null, - 'author_name' => null, - 'author_url' => null, - 'date_relative' => null, - ] - ]; - - preg_match('~~', $this->file[$this->lineNo + $i], $this->matches); - - - $topic['url'] = BASE_URL . $this->matches[3]; - $topic['title'] = $this->matches[4]; - $topic['author_name'] = $this->matches[7]; - $topic['author_url'] = BASE_URL . $this->matches[6]; - $topic['date_posted'] = @date_format(date_create($this->matches[8]), 'o-m-d'); - - preg_match('~forum/\?topicid=(.*)~', $this->matches[3], $this->matches); - $topic['topic_id'] = (int) $this->matches[1]; - - $i++; - preg_match('~~', $this->file[$this->lineNo+$i], $this->matches); - $topic['replies'] = (int) $this->matches[2]; - - $i++; - preg_match('~~', $this->file[$this->lineNo+$i], $this->matches); - $topic['last_post']['author_url'] = BASE_URL . $this->matches[2]; - $topic['last_post']['author_name'] = BASE_URL . $this->matches[3]; - $topic['last_post']['url'] = BASE_URL . $this->matches[4]; - $topic['last_post']['date_relative'] = $this->matches[5]; - - $topics[] = $topic; - } - - $i++; - } - - - $this->model->set('AnimeForum', 'topic', $topics); - }); - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/AnimeMoreInfoParse.php b/src/Lib/Parser/AnimeMoreInfoParse.php deleted file mode 100755 index edfb2aaa..00000000 --- a/src/Lib/Parser/AnimeMoreInfoParse.php +++ /dev/null @@ -1,58 +0,0 @@ -model = new AnimeMoreInfoModel; - - /* - * Rules - */ - - $this->addRule('moreinfo', '~

More Info

~', function() { - $i = 0; - $capture = ""; - - while(true) { - if (preg_match('~
file[$this->lineNo + $i])) { - $capture .= $this->file[$this->lineNo + $i]; - break; - } - - $capture .= $this->file[$this->lineNo + $i]; - - $i++; - } - - - $capture = trim(str_replace(['

More Info

', '
'], '', $capture)); - $capture = strip_tags(str_replace(['
', '
', '
'], '\n', $capture)); - - $this->model->set('AnimeMoreInfo', 'more_info', $capture); - - }); - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/AnimeNewsParse.php b/src/Lib/Parser/AnimeNewsParse.php deleted file mode 100755 index e01854f7..00000000 --- a/src/Lib/Parser/AnimeNewsParse.php +++ /dev/null @@ -1,78 +0,0 @@ -model = new AnimeNewsModel; - - /* - * Rules - */ - - - $this->addRule('news', '~

News

~', function() { - $running = true; - $i = 0; - - $news = []; - while ($running) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~
(Poll: |) (.*) (.*?)
(.*) - (.*)
(.*)by (.*) »»
(.*)
~', $line)) { - $running = false; - } - - if (preg_match('~
(
(.*)
|)

(.*)

~', $line, $this->matches)) { - - $tmp = [ - 'url' => BASE_URL . $this->matches[6], - 'image_url' => !empty($this->matches[5]) ? trim(substr(explode(",", $this->matches[5])[1], 0, -3)) : null, - 'forum_url' => null, - 'comments' => 0, - 'title' => $this->matches[8], - 'date' => null, - 'author_url' => null, - 'author' => null - ]; - if (preg_match('~
~', $this->file[$this->lineNo + $i + 2], $this->matches)) { - - $tmp['date'] = trim($this->matches[1]); - $tmp['author_url'] = BASE_URL . $this->matches[2]; - $tmp['author'] = $this->matches[3]; - $tmp['forum_url'] = BASE_URL . $this->matches[4]; - $tmp['comments'] = (int) $this->matches[5]; - } - - $news[] = $tmp; - } - - $this->model->set('AnimeNews', 'news', $news); - - $i++; - } - }); - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/AnimeParse.php b/src/Lib/Parser/AnimeParse.php deleted file mode 100755 index 2ecb6dc7..00000000 --- a/src/Lib/Parser/AnimeParse.php +++ /dev/null @@ -1,331 +0,0 @@ -model = new AnimeModel; - - /* - * Rules - */ - - $this->addRule('link_canonical', '~~', function() { - $this->model->set('Anime', 'link_canonical', $this->matches[1]); - - preg_match('~myanimelist.net/(.+)/(.*)/~', $this->model->get('Anime', 'link_canonical'), $this->matches); - $this->model->set('Anime', 'mal_id', (int) $this->matches[2]); - }); - - $this->addRule('title', '~

(.*)

~', function() { - $this->model->set('Anime', 'title', htmlspecialchars_decode($this->matches[1])); - }); - - $this->addRule('title_english', '~English: (.*)~', function() { - $this->model->set('Anime', 'title_english', htmlspecialchars_decode($this->matches[1])); - }); - - $this->addRule('title_synonyms', '~Synonyms: (.*)~', function() { - $this->model->set('Anime', 'title_synonyms', htmlspecialchars_decode($this->matches[1])); - }); - - $this->addRule('title_japanese', '~Japanese: (.*)~', function() { - $this->model->set('Anime', 'title_japanese', htmlspecialchars_decode($this->matches[1])); - }); - - $this->addRule('image_url', '~(.*)~', function() { - $this->model->set('Anime', 'image_url', $this->matches[1]); - }); - - $this->addRule('type', '~Type:~', function() { - preg_match('~((.*?)|(.*))~', $this->file[$this->lineNo + 1], $this->matches); - $this->model->set('Anime', 'type', (empty($this->matches[3]) ? $this->matches[4] : $this->matches[3])); - }); - - $this->addRule('episodes', '~Episodes:~', function() { - $this->model->set('Anime', 'episodes', (int) $this->file[$this->lineNo + 1]); - }); - - $this->addRule('status', '~Status:~', function() { - $this->model->set('Anime', 'status', $this->file[$this->lineNo + 1]); - - if (strpos($this->model->get('Anime', 'status'), "Currently Airing") !== false) - $this->model->set('Anime', 'airing', true); - }); - - $this->addRule('aired', '~Aired:~', function() { - $this->model->set('Anime', 'aired_string', $this->file[$this->lineNo + 1]); - - - if (!empty($this->model->get('Anime', 'aired_string')) && $this->model->get('Anime', 'aired_string') != 'Not available') { - if (strpos($this->model->get('Anime', 'aired_string'), 'to')) { - preg_match('~(.*) to (.*)~', $this->model->get('Anime', 'aired_string'), $this->matches); - $this->model->set('Anime', 'aired', [ - 'from' => (strpos($this->matches[1], '?') !== false) ? null : @date_format(date_create($this->matches[1]), 'o-m-d'), - 'to' => (strpos($this->matches[2], '?') !== false) ? null : @date_format(date_create($this->matches[2]), 'o-m-d') - ]); - } else { - - if (preg_match('~^[0-9]{4}$~', $this->model->get('Anime', 'aired_string')) || - preg_match('~^[A-Za-z]{1,}, [0-9]{4}$~', $this->model->get('Anime', 'aired_string'))) { - $this->model->set('Anime', 'aired', [ - 'from' => null, - 'to' => null - ]); - } else { - $this->model->set('Anime', 'aired', [ - 'from' => (strpos($this->model->get('Anime', 'aired_string'), '?') !== false) ? null : @date_format(date_create($this->model->get('Anime', 'aired_string')), 'o-m-d'), - 'to' => (strpos($this->model->get('Anime', 'aired_string'), '?') !== false) ? null : @date_format(date_create($this->model->get('Anime', 'aired_string')), 'o-m-d') - ]); - } - } - } else { - $this->model->set('Anime', 'aired', [ - 'from' => null, - 'to' => null - ]); - } - }); - - $this->addRule('premiered', '~Premiered:~', function() { - if (preg_match('~(.*)~', $this->file[$this->lineNo + 1], $this->matches)) { - $this->model->set('Anime', 'premiered', $this->matches[2]); - } - }); - - $this->addRule('broadcast', '~Broadcast:~', function() { - $this->model->set('Anime', 'broadcast', $this->file[$this->lineNo + 1]); - }); - - $this->addRule('producer', '~Producers:~', function() { - $return = []; - if (!preg_match('~None found~', $this->file[$this->lineNo + 1])) { - $array = explode("", $this->file[$this->lineNo + 1]); - // producers can contain commas, so we can't use that as delimiter. e.g; "Kanetsu Co., LTD." //anime/16067/anime/32951 - - foreach ($array as $key => $value) { - if (preg_match('~([\s\S]*)(|)~', $value)) { - preg_match('~([\s\S]*)(|)~', $value, $this->matches); - $return[] = [ - 'url' => BASE_URL . $this->matches[1], - 'name' => strip_tags($this->matches[2]) - ]; - } - } - } - - $this->model->set('Anime', 'producer', $return); - }); - - $this->addRule('licensor', '~Licensors:~', function() { - $return = []; - if (!preg_match('~None found~', $this->file[$this->lineNo + 1])) { - $array = explode("", $this->file[$this->lineNo + 1]); - // licensors can contain commas, so we can't use that as delimiter. e.g; "NIS America, Inc." //anime/16067 - - foreach ($array as $key => $value) { - if (preg_match('~([\s\S]*)(|)~', $value)) { - preg_match('~([\s\S]*)(|)~', $value, $this->matches); - $return[] = [ - 'url' => BASE_URL . $this->matches[1], - 'name' => strip_tags($this->matches[2]) - ]; - } - } - } - - $this->model->set('Anime', 'licensor', $return); - }); - - $this->addRule('studio', '~Studios:~', function() { - $return = []; - if (!preg_match('~None found~', $this->file[$this->lineNo + 1])) { - $array = explode("", $this->file[$this->lineNo + 1]); - - foreach ($array as $key => $value) { - preg_match('~([\s\S]*)(|)~', $value, $this->matches); - - if (!empty($this->matches)) { - $return[] = [ - 'url' => BASE_URL . $this->matches[1], - 'name' => strip_tags($this->matches[2]) - ]; - } - } - } - - $this->model->set('Anime', 'studio', $return); - }); - - $this->addRule('source', '~Source:~', function() { - $this->model->set('Anime', 'source', $this->file[$this->lineNo + 1]); - }); - - $this->addRule('genre', '~Genres:~', function() { - $return = []; - if (!preg_match('~No genres have been added yet~', $this->file[$this->lineNo + 1])) { - $array = explode(",", $this->file[$this->lineNo + 1]); - - foreach ($array as $key => $value) { - preg_match('~([\s\S]*)(|)~', $value, $this->matches); - $return[] = [ - 'url' => BASE_URL . $this->matches[1], - 'name' => strip_tags($this->matches[2]) - ]; - } - } - - $this->model->set('Anime', 'genre', $return); - }); - - $this->addRule('duration', '~Duration:~', function() { - $this->model->set('Anime', 'duration', $this->file[$this->lineNo + 1]); - }); - - $this->addRule('rating', '~Rating:~', function() { - $this->model->set('Anime', 'rating', htmlspecialchars_decode($this->file[$this->lineNo + 1])); - }); - - $this->addRule('score', '~Score:~', function(){ - preg_match('~(.*)1 \(scored by (.*) users\)~', $this->file[$this->lineNo + 1], $this->matches); - - $this->model->set('Anime', 'score', (float) $this->matches[2]); - $this->model->set('Anime', 'scored_by', (int) str_replace(",", "", $this->matches[4])); - }); - - $this->addRule('rank', '~Ranked:~', function() { - if (!preg_match('~N/A2~', $this->file[$this->lineNo + 1], $this->matches)) { - preg_match('~#(.*)2~', $this->file[$this->lineNo + 1], $this->matches); - - $this->model->set('Anime', 'rank', (int) $this->matches[1]); - } - }); - - $this->addRule('popularity', '~Popularity:~', function() { - preg_match('~#(.*)~', $this->file[$this->lineNo + 1], $this->matches); - - $this->model->set('Anime', 'popularity', (int) $this->matches[1]); - }); - - $this->addRule('members', '~Members:~', function() { - $this->model->set('Anime', 'members', (int) str_replace(",", "", $this->file[$this->lineNo + 1])); - }); - - $this->addRule('favorites', '~Favorites:~', function() { - $this->model->set('Anime', 'favorites', (int) str_replace(",", "", $this->file[$this->lineNo + 1])); - }); - - $this->addRule('synopsis', '~~', function() { - $this->model->set('Anime', 'synopsis', htmlspecialchars_decode($this->matches[1])); - }); - - $this->addRule('related', '~file[$this->lineNo]; - $line = substr($line, strpos($line, '') + 4); - $line = substr($line, 0, strpos($line, '')); - $line = str_replace('', ',,,,', $line); - $related = explode(',,,,', $line); - - - $title = ''; - foreach ($related as $key => $value) { - - if (!empty($value)) { - if (preg_match('~(.*)~', $value, $this->matches)) { - $title = str_replace(":", "", $this->matches[1]); - $return[$title] = []; - } else { - $links = explode("", $value); - foreach ($links as $key2 => $value2) { - if (preg_match('~(.*)(|)~', $value2, $this->matches)) { - $return[$title][] = [ - 'mal_id' => (int) $this->matches[2], - 'type' => preg_match('~/(.*)~', $this->matches[1], $_type) ? $_type[1] : null, - 'url' => BASE_URL . substr($this->matches[1], 1) . '/' . $this->matches[2] . '/' . $this->matches[3], - 'title' => htmlspecialchars_decode(strip_tags($this->matches[4])) - ]; - } - } - } - } - - } - - $this->model->set('Anime', 'related', $return); - }); - - $this->addRule('background', '~Background~', function() { - if (!preg_match('~No background information has been added to this title.~', $this->line)) { - if (preg_match('~Background([\s\S]*)
file[$this->lineNo + $i]) || - preg_match('~~', $this->file[$this->lineNo + $i]) ) - { - $running = false; - } - - $string .= $this->file[$this->lineNo + $i]; - $i++; - } - - if (strpos($string, '')) { - $string = substr($string, 0, strpos($string, '')); - } - if (strpos($string, '
model->set('Anime', 'background', htmlspecialchars_decode(strip_tags($string))); - } - } - }); - - $this->addRule('opening_theme', '~
([\s\S]*)
~', function() { - preg_match_all('~(.*?)~', $this->matches[1], $this->matches); - foreach ($this->matches[1] as $key => &$value) { $value = htmlspecialchars_decode($value); } - - $this->model->set('Anime', 'opening_theme', $this->matches[1]); - }); - - $this->addRule('ending_theme', '~
([\s\S]*)
~', function() { - preg_match_all('~(.*?)~', $this->matches[1], $this->matches); - foreach ($this->matches[1] as $key => &$value) { $value = htmlspecialchars_decode($value); } - - $this->model->set('Anime', 'ending_theme', $this->matches[1]); - }); - - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - - } - - -} \ No newline at end of file diff --git a/src/Lib/Parser/AnimePicturesParse.php b/src/Lib/Parser/AnimePicturesParse.php deleted file mode 100755 index cb29a1f4..00000000 --- a/src/Lib/Parser/AnimePicturesParse.php +++ /dev/null @@ -1,60 +0,0 @@ -model = new AnimePicturesModel; - - /* - * Rules - */ - - $this->addRule('images', '~

~', function() { - $i = 1; - - while(true) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~
~', $line)) { - break; - } - - if (preg_match_all('~
(.*?)
~', $line, $this->matches)) { - $this->model->set( - 'AnimePictures', - 'image', - array_merge( - $this->model->get('AnimePictures', 'image'), - (is_array($this->matches[3]) ? $this->matches[3] : [$this->matches[3]]) - ) - ); - } - - $i++; - } - }); - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/AnimeStatsParse.php b/src/Lib/Parser/AnimeStatsParse.php deleted file mode 100755 index cce286e6..00000000 --- a/src/Lib/Parser/AnimeStatsParse.php +++ /dev/null @@ -1,117 +0,0 @@ -model = new AnimeStats; - - /* - * Rules - */ - - - $this->addRule('watching', '~
Watching: (.*)
~', function() { - $this->model->set('AnimeStats', 'watching', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - $this->addRule('completed', '~
Completed: (.*)
~', function() { - $this->model->set('AnimeStats', 'completed', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - $this->addRule('on_hold', '~
On-Hold: (.*)
~', function() { - $this->model->set('AnimeStats', 'on_hold', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - $this->addRule('dropped', '~
Dropped: (.*)
~', function() { - $this->model->set('AnimeStats', 'dropped', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - $this->addRule('plan_to_watch', '~
Plan to Watch: (.*)
~', function() { - $this->model->set('AnimeStats', 'plan_to_watch', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - $this->addRule('total', '~
Total: (.*)
~', function() { - $this->model->set('AnimeStats', 'total', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - - $this->addRule('score_stats', '~

Score Stats

~', function() { - $score = [ - 1 => ['percentage' => null, 'votes' => null], - 2 => ['percentage' => null, 'votes' => null], - 3 => ['percentage' => null, 'votes' => null], - 4 => ['percentage' => null, 'votes' => null], - 5 => ['percentage' => null, 'votes' => null], - 6 => ['percentage' => null, 'votes' => null], - 7 => ['percentage' => null, 'votes' => null], - 8 => ['percentage' => null, 'votes' => null], - 9 => ['percentage' => null, 'votes' => null], - 10 => ['percentage' => null, 'votes' => null] - ]; - - - $i = 0; - while (true) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~

All MembersRecently Updated By

~', $line)) { - break; - } - - - if (preg_match('~(.*?)~', $line, $this->matches)) { - $_score = (int) $this->matches[1]; - $i++; - preg_match('~
 (.*?)% \((.*?) votes\)
~', $this->file[$this->lineNo + $i], $this->matches); - - $score[ $_score ] = [ - 'percentage' => (float) $this->matches[2], - 'votes' => (int) $this->matches[3] - ]; - - } - - $i++; - } - - - - $this->model->set('AnimeStats', 'score_stats', $score); - }); - - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - - } - - -} \ No newline at end of file diff --git a/src/Lib/Parser/AnimeVideoParse.php b/src/Lib/Parser/AnimeVideoParse.php deleted file mode 100755 index 1cccea90..00000000 --- a/src/Lib/Parser/AnimeVideoParse.php +++ /dev/null @@ -1,87 +0,0 @@ -model = new AnimeVideoModel; - - /* - * Rules - */ - - - - $this->addRule('episode', '~

~', function() { - $parsingLine = $this->file[$this->lineNo + 10]; - preg_match_all('~
(.*?)
~', $parsingLine, $this->matches); - - $episode = []; - if (!empty($this->matches)) { - foreach ($this->matches[1] as $key => $value) { - preg_match('~
(.*)
(.*)
~', $value, $this->matches); - - $episode[] = [ - 'url' => $this->matches[1], - 'image_url' => $this->matches[3], - 'episode' => $this->matches[7], - 'title' => $this->matches[8] - ]; - } - } - - $this->model->set('AnimeVideos', 'episode', $episode); - }); - - $this->addRule('promo', '~
~', function() { - $running = true; - $i = 1; - - $promo = []; - while($running) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~~', $line)) { - $running = false; - } - - if (preg_match('~
(.*)
(play|)
~', $line, $this->matches)) { - - $promo[] = [ - 'video_url' => $this->matches[1], - 'image_url' => $this->matches[3], - 'title' => $this->matches[7] - ]; - - } - - $i++; - } - - $this->model->set('AnimeVideos', 'promo', $promo); - }); - - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/CharacterParse.php b/src/Lib/Parser/CharacterParse.php deleted file mode 100755 index b6ced45d..00000000 --- a/src/Lib/Parser/CharacterParse.php +++ /dev/null @@ -1,202 +0,0 @@ -model = new CharacterModel; - - /* - * Rules - */ - - $this->addRule('link_canonical', '~~', function() { - $this->model->set('Character', 'link_canonical', $this->matches[1]); - - preg_match('~myanimelist.net/(.+)/(.*)/~', $this->model->get('Character', 'link_canonical'), $this->matches); - $this->model->set('Character', 'mal_id', (int) $this->matches[2]); - }); - - $this->addRule('name', '~
(.*) ((.*)|)
~', function() { - - $this->model->set('Character', 'name', trim($this->matches[1])); - if (!empty($this->matches[2])) { - $this->model->set('Character', 'name_kanji', $this->matches[3]); - } - }); - - $this->addRule('nicknames', '~
~', function() { - preg_match('~

(.*)

~', $this->file[$this->lineNo+1], $this->matches); - - $this->model->set('Character', 'nicknames', trim($this->matches[1])); - }); - - $this->addRule('about', '~
(.*) ((.*)|)
(.*?)
~', function() { - $match = []; - $match[] = $this->matches[4]; - - $finding = true; - $i = $this->lineNo; - while ($finding) { - if (preg_match('~
Voice Actors
~', $this->file[$i])) { - $finding = false; - } else { - $i++; - $match[] = $this->file[$i]; - } - } - - //filter out the residue - $about = implode(' ', $match); - $about = str_replace('
', "\n", $about); - $about = str_replace('
Voice Actors
', '', $about); - $about = str_replace('
', '', $about); - $about = htmlspecialchars_decode($about, ENT_QUOTES); - - $this->model->set('Character', 'about', $about); - }); - - $this->addRule('animeography', '~
Animeography
~', function() { - $running = true; - $i = 1; - $animeography = []; - while ($running) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~~', $line)) { - $running = false; - } - - if (preg_match('~~', $line)) { - $i++; - $this->matches = []; - preg_match('~
~', $this->file[$this->lineNo + $i], $animeMeta); - $i++; - $animeName = []; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $animeName); - $i++; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - - $animeography[] = [ - 'mal_id' => (int) $animeName[4], - 'name' => $animeName[6], - 'url' => $animeMeta[1], - 'image_url' => $animeMeta[2], - 'role' => $this->matches[1] - ]; - } - $i++; - } - - $this->model->set('Character', 'animeography', $animeography); - }); - - $this->addRule('mangaography', '~
Mangaography
~', function() { - $running = true; - $i = 1; - $mangaography = []; - while ($running) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~~', $line)) { - $running = false; - } - - if (preg_match('~~', $line)) { - $i++; - $mangaMeta = array(); - preg_match('~
~', $this->file[$this->lineNo + $i], $mangaMeta); - $i++; - $mangaName = array(); - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $mangaName); - $i++; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - - $mangaography[] = [ - 'mal_id' => (int) $mangaName[4], - 'name' => $mangaName[6], - 'url' => $mangaMeta[1], - 'image_url' => $mangaMeta[2], - 'role' => $this->matches[1] - ]; - } - $i++; - } - - $this->model->set('Character', 'mangaography', $mangaography); - }); - - $this->addRule('voice_actors', '~
Voice Actors
~', function() { - $running = true; - $i = 1; - $voiceActors = []; - while ($running) { - $line = $this->file[$this->lineNo + $i]; // bugs - if ( - preg_match('~

~', $line) || - preg_match('~
~', $line) || - preg_match('~
~', $this->file[$this->lineNo]) - ) { - $running = false; - } - - if (preg_match('~~', $line)) { - $i++; - $personMeta = []; - preg_match('~
~', $this->file[$this->lineNo + $i], $personMeta); - $i++; - $personName = []; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $personName); - $i++; - $personType = []; - preg_match('~
(.*)
~', $this->file[$this->lineNo + $i], $personType); - - $voiceActors[] = [ - 'mal_id' => (int) $personName[4], - 'name' => $personName[6], - 'url' => $personMeta[1], - 'image_url' => $personMeta[2], - 'language' => $personType[1] - ]; - } - $i++; - } - - $this->model->set('Character', 'voice_actor', $voiceActors); - }); - - $this->addRule('member_favorites', '~Member Favorites: (.*)~', function() { - - $this->model->set('Character', 'member_favorites', - (int) str_replace(',', '', trim($this->matches[1])) - ); - }); - - $this->addRule('image_url', '~~', function() { - - $this->model->set('Character', 'image_url', $this->matches[3]); - }); - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - - } - - -} \ No newline at end of file diff --git a/src/Lib/Parser/CharacterPicturesParse.php b/src/Lib/Parser/CharacterPicturesParse.php deleted file mode 100755 index f74f34cf..00000000 --- a/src/Lib/Parser/CharacterPicturesParse.php +++ /dev/null @@ -1,60 +0,0 @@ -model = new CharacterPicturesModel; - - /* - * Rules - */ - - $this->addRule('images', '~

~', function() { - $i = 0; - - while(true) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~
~', $line)) { - break; - } - - if (preg_match_all('~
(.*?)
~', $line, $this->matches)) { - $this->model->set( - 'CharacterPictures', - 'image', - array_merge( - $this->model->get('CharacterPictures', 'image'), - (is_array($this->matches[4]) ? $this->matches[4] : [$this->matches[4]]) - ) - ); - } - - $i++; - } - }); - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/MangaCharacterParse.php b/src/Lib/Parser/MangaCharacterParse.php deleted file mode 100755 index 490cc7d2..00000000 --- a/src/Lib/Parser/MangaCharacterParse.php +++ /dev/null @@ -1,74 +0,0 @@ -model = new MangaCharacterModel(); - - /* - * Rules - */ - - - $this->addRule('character', '~

Characters

~', function() { - $running = true; - $i = 0; - $characters = []; - while ($running) { - if (preg_match('~
~', $this->file[$this->lineNo + $i])) { - $running = false; - } - - $character = []; - - if (preg_match('~~', $this->file[$this->lineNo + $i])) { - $i += 3; - $image = []; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $image); - $character['image_url'] = trim(substr(explode(",", $image[3])[1], 0, -3)); - - $i += 5; - $name = []; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $name); - preg_match('~myanimelist.net/(.+)/(.*)/~', $name[1], $this->matches); - $character['mal_id'] = (int) $this->matches[2]; - $character['url'] = $name[1]; - $character['name'] = $name[2]; - $i += 2; - $role = []; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $role); - $character['role'] = $role[1]; - $characters[] = $character; - } - - $i++; - } - - $this->model->set('MangaCharacter', 'character', $characters); - }); - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/MangaForumParse.php b/src/Lib/Parser/MangaForumParse.php deleted file mode 100755 index 3c68b06b..00000000 --- a/src/Lib/Parser/MangaForumParse.php +++ /dev/null @@ -1,99 +0,0 @@ -model = new MangaForumModel; - - /* - * Rules - */ - - $this->addRule('topic', '~~', function() { - $i = 0; - $topics = []; - - while (true) { - $line = $this->file[$this->lineNo + $i]; - - if (preg_match('~~', $line)) { - $i += 2; - - $topic = [ - 'topic_id' => null, - 'url' => null, - 'title' => null, - 'date_posted' => null, - 'author_name' => null, - 'author_url' => null, - 'replies' => 0, - 'last_post' => [ - 'url' => null, - 'author_name' => null, - 'author_url' => null, - 'date_relative' => null, - ] - ]; - - preg_match('~~', $this->file[$this->lineNo + $i], $this->matches); - - - $topic['url'] = BASE_URL . $this->matches[3]; - $topic['title'] = $this->matches[4]; - $topic['author_name'] = $this->matches[7]; - $topic['author_url'] = BASE_URL . $this->matches[6]; - $topic['date_posted'] = @date_format(date_create($this->matches[8]), 'o-m-d'); - - preg_match('~forum/\?topicid=(.*)~', $this->matches[3], $this->matches); - $topic['topic_id'] = (int) $this->matches[1]; - - $i++; - preg_match('~~', $this->file[$this->lineNo+$i], $this->matches); - $topic['replies'] = (int) $this->matches[2]; - - $i++; - preg_match('~~', $this->file[$this->lineNo+$i], $this->matches); - $topic['last_post']['author_url'] = BASE_URL . $this->matches[2]; - $topic['last_post']['author_name'] = BASE_URL . $this->matches[3]; - $topic['last_post']['url'] = BASE_URL . $this->matches[4]; - $topic['last_post']['date_relative'] = $this->matches[5]; - - $topics[] = $topic; - } - - $i++; - } - - - $this->model->set('MangaForum', 'topic', $topics); - }); - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/MangaMoreInfoParse.php b/src/Lib/Parser/MangaMoreInfoParse.php deleted file mode 100755 index c9303bb8..00000000 --- a/src/Lib/Parser/MangaMoreInfoParse.php +++ /dev/null @@ -1,60 +0,0 @@ -model = new MangaMoreInfoModel; - - /* - * Rules - */ - - - $this->addRule('moreinfo', '~

More Info

~', function() { - $i = 0; - $capture = ""; - - while(true) { - if (preg_match('~
file[$this->lineNo + $i])) { - $capture .= $this->file[$this->lineNo + $i]; - break; - } - - $capture .= $this->file[$this->lineNo + $i]; - - $i++; - } - - - $capture = trim(str_replace(['

More Info

', '
'], '', $capture)); - $capture = strip_tags(str_replace(['
', '
', '
'], '\n', $capture)); - - $this->model->set('MangaMoreInfo', 'more_info', $capture); - - }); - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/MangaNewsParse.php b/src/Lib/Parser/MangaNewsParse.php deleted file mode 100755 index 59f31297..00000000 --- a/src/Lib/Parser/MangaNewsParse.php +++ /dev/null @@ -1,78 +0,0 @@ -model = new MangaNewsModel; - - /* - * Rules - */ - - - $this->addRule('news', '~

News

~', function() { - $running = true; - $i = 0; - - $news = []; - while ($running) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~
(Poll: |) (.*) (.*?)
(.*) - (.*)
(.*)by (.*) »»
(.*)
~', $line)) { - $running = false; - } - - if (preg_match('~
(
(.*)
|)

(.*)

~', $line, $this->matches)) { - - $tmp = [ - 'url' => BASE_URL . $this->matches[2], - 'image_url' => !empty($this->matches[5]) ? trim(substr(explode(",", $this->matches[5])[1], 0, -3)) : null, - 'forum_url' => null, - 'comments' => 0, - 'title' => $this->matches[6], - 'date' => null, - 'author_url' => null, - 'author' => null - ]; - if (preg_match('~
~', $this->file[$this->lineNo + $i + 2], $this->matches)) { - - $tmp['date'] = trim($this->matches[1]); - $tmp['author_url'] = BASE_URL . $this->matches[2]; - $tmp['author'] = $this->matches[3]; - $tmp['forum_url'] = BASE_URL . $this->matches[4]; - $tmp['comments'] = (int) $this->matches[5]; - } - - $news[] = $tmp; - } - - $this->model->set('MangaNews', 'news', $news); - - $i++; - } - }); - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/MangaParse.php b/src/Lib/Parser/MangaParse.php deleted file mode 100755 index 9f78870d..00000000 --- a/src/Lib/Parser/MangaParse.php +++ /dev/null @@ -1,297 +0,0 @@ -model = new MangaModel; - - /* - * Rules - */ - - $this->addRule('link_canonical', '~~', function() { - $this->model->set('Manga', 'link_canonical', $this->matches[1]); - - preg_match('~myanimelist.net/(.+)/(.*)/~', $this->model->get('Manga', 'link_canonical'), $this->matches); - $this->model->set('Manga', 'mal_id', (int) $this->matches[2]); - }); - - $this->addRule('title', '~

(.*)

~', function(){ - $this->model->set('Manga', 'title', htmlspecialchars_decode($this->matches[1])); - }); - - $this->addRule('title_english', '~English: (.*?)
~', function(){ - $this->model->set('Manga', 'title_english', htmlspecialchars_decode($this->matches[1])); - }); - - $this->addRule('title_synonyms', '~Synonyms: (.*)
Japanese:~', function(){ - $this->model->set('Manga', 'title_synonyms', htmlspecialchars_decode($this->matches[1])); - }); - - $this->addRule('title_japanese', '~Japanese:(.*?)
~', function(){ - $this->model->set('Manga', 'title_japanese', htmlspecialchars_decode(trim($this->matches[1]))); - }); - - $this->addRule('status', '~
Status: (.*)
~', function(){ - $this->model->set('Manga', 'status', $this->matches[1]); - - if (strpos($this->model->get('Manga', 'status'), "Publishing") !== false) - $this->model->set('Manga', 'publishing', true); - }); - - $this->addRule('image_url', '~(.*)~', function(){ - $this->model->set('Manga', 'image_url', $this->matches[1]); - }); - - $this->addRule('type', '~Type: (.*?)
~', function(){ - $this->model->set('Manga', 'type', $this->matches[2]); - }); - - $this->addRule('volumes', '~Volumes: (.*)$~', function(){ - $this->model->set('Manga', 'volumes', - ($this->matches[1] != 'Unknown') ? (int) trim($this->matches[1]) : $this->matches[1] - ); - }); - - $this->addRule('chapters', '~Chapters: (.*)$~', function(){ - $this->model->set('Manga', 'chapters', - ($this->matches[1] != 'Unknown') ? (int) trim($this->matches[1]) : $this->matches[1] - ); - }); - - $this->addRule('published', '~Published:(.*)
~', function(){ - $this->model->set('Manga', 'published_string', trim($this->matches[1])); - - if (!empty($this->model->get('Manga', 'published_string')) && $this->model->get('Manga', 'published_string') != 'Not available') { - if (strpos($this->model->get('Manga', 'published_string'), 'to')) { - preg_match('~(.*) to (.*)~', $this->model->get('Manga', 'published_string'), $this->matches); - $this->model->set('Manga', 'published', [ - 'from' => (strpos($this->matches[1], '?') !== false) ? null : @date_format(date_create($this->matches[1]), 'o-m-d'), - 'to' => (strpos($this->matches[2], '?') !== false) ? null : @date_format(date_create($this->matches[2]), 'o-m-d') - ]); - } else { - if (preg_match('~^[0-9]{4}$~', $this->model->get('Manga', 'published_string'))) { - $this->model->set('Manga', 'published_string', [ - 'from' => null, - 'to' => null - ]); - } else { - $this->model->set('Manga', 'published', [ - 'from' => (strpos($this->model->get('Manga', 'published_string'), '?') !== false) ? null : @date_format(date_create($this->model->get('Manga', 'published_string')), 'o-m-d'), - 'to' => (strpos($this->model->get('Manga', 'published_string'), '?') !== false) ? null : @date_format(date_create($this->model->get('Manga', 'published_string')), 'o-m-d') - ]); - } - } - } else { - $this->model->set('Manga', 'published', [ - 'from' => null, - 'to' => null - ]); - } - }); - - $this->addRule('rank', '~Ranked:<\/span> #(.*[[:alnum:]])~', function(){ - $this->model->set('Manga', 'rank', - ($this->matches[1] == "N/A" ? -1 : (int) $this->matches[1]) - ); - }); - - $this->addRule('score', '~Score: (.*)1 \(scored by (.*) users\)~', function(){ - - if (is_null($this->model->get('Manga', 'score'))) { - $this->model->set('Manga', 'score', (float) $this->matches[1]); - $this->model->set('Manga', 'scored_by', (int) str_replace(",", "", $this->matches[2])); - } - }); - - $this->addRule('score2', '~
Score: (.*)1 \(scored by (.*) users\)~', function() { - - if (is_null($this->model->get('Manga', 'score'))) { - $this->model->set('Manga', 'score', (float) $this->matches[1]); - $this->model->set('Manga', 'scored_by', (int) str_replace(",", "", $this->matches[2])); - } - }); - - - $this->addRule('popularity', '~Popularity:<\/span> #(.*[[:alnum:]])<\/div>~', function(){ - $this->model->set('Manga', 'popularity', - ($this->matches[1] == "N/A" ? -1 : (int) $this->matches[1]) - ); - }); - - $this->addRule('members', '~Members:(.*)
~', function(){ - $this->model->set('Manga', 'members', - (int) str_replace(",", "", trim($this->matches[1])) - ); - }); - - $this->addRule('favorites', '~
Favorites: (.*)
~', function(){ - $this->model->set('Manga', 'favorites', - (int) str_replace(",", "", trim($this->matches[1])) - ); - }); - - $this->addRule('synopsis', '~~', function(){ - $this->model->set('Manga', 'synopsis', - htmlspecialchars_decode(strip_tags($this->matches[1])) - ); - }); - - $this->addRule('background', '~
Background

~', function(){ - if (!preg_match('~No background information has been added to this title.~', $this->line)) { - if (preg_match('~
Background([\s\S]*)
file[$this->lineNo + $i]) || - preg_match('~~', $this->file[$this->lineNo + $i]) ) - { - $running = false; - } - - $string .= $this->file[$this->lineNo + $i]; - $i++; - } - - if (strpos($string, '')) { - $string = substr($string, 0, strpos($string, '')); - } - if (strpos($string, '
model->set('Manga', 'background', htmlspecialchars_decode(strip_tags($string))); - } - } - }); - - $this->addRule('related', '~file[$this->lineNo]; - $line = substr($line, strpos($line, '') + 4); - $line = substr($line, 0, strpos($line, '')); - $line = str_replace('', ',,,,', $line); - $related = explode(',,,,', $line); - - - $title = ''; - foreach ($related as $key => $value) { - - if (!empty($value)) { - if (preg_match('~(.*)~', $value, $this->matches)) { - $title = str_replace(":", "", $this->matches[1]); - $return[$title] = []; - } else { - $links = explode("", $value); - foreach ($links as $key2 => $value2) { - if (preg_match('~(.*)(|)~', $value2, $this->matches)) { - $return[$title][] = [ - 'mal_id' => (int) $this->matches[2], - 'type' => $this->matches[1], - 'url' => BASE_URL . $this->matches[1] . '/' . $this->matches[2] . '/' . $this->matches[3], - 'title' => strip_tags($this->matches[4]) - ]; - } - } - } - } - - } - - $this->model->set('Manga', 'related', $return); - }); - - $this->addRule('genre', '~Genres:~', function() { - $return = []; - if (!preg_match('~No genres have been added yet~', $this->file[$this->lineNo + 1])) { - $array = explode(",", $this->file[$this->lineNo + 1]); - - foreach ($array as $key => $value) { - preg_match('~(.*)~', $value, $this->matches); - $return[] = [ - 'url' => BASE_URL . $this->matches[1], - 'name' => strip_tags($this->matches[2]) - ]; - } - } - - $this->model->set('Manga', 'genre', $return); - }); - - $this->addRule('author', '~Authors:~', function(){ - $return = []; - if (!preg_match("~None~", $this->file[$this->lineNo + 1])) { - $_authors = array(); - preg_match('`^(.*?)
`', trim($this->file[$this->lineNo + 1]), $_authors); - - $authors = explode("),", $_authors[1]); - - foreach ($authors as $key => $value) { - if (!strpos($value, ')')) {$value .= ')'; } - $break = array(); - preg_match('`(.*)`', $value, $break); - $return[] = array( - 'url' => BASE_URL . $break[1], - 'name' => strip_tags($break[2]) - ); - } - } - - $this->model->set('Manga', 'author', $return); - }); - - $this->addRule('serialization', '~Serialization:~', function(){ - $return = []; - if (!preg_match('~None~', $this->file[$this->lineNo + 1])) { - $array = explode("", $this->file[$this->lineNo + 1]); - - - foreach ($array as $key => $value) { - //preg_match('~([\s\S]*)(|)~', $value, $this->matches); - preg_match('~(.*)(|)~', $value, $this->matches); - - if (!empty($this->matches)) { - $return[] = [ - 'url' => BASE_URL . $this->matches[1], - 'name' => strip_tags($this->matches[2]) - ]; - } - } - } - - $this->model->set('Manga', 'serialization', $return); - }); - - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - - } - - -} \ No newline at end of file diff --git a/src/Lib/Parser/MangaPicturesParse.php b/src/Lib/Parser/MangaPicturesParse.php deleted file mode 100755 index c0577e95..00000000 --- a/src/Lib/Parser/MangaPicturesParse.php +++ /dev/null @@ -1,60 +0,0 @@ -model = new MangaPicturesModel; - - /* - * Rules - */ - - $this->addRule('images', '~

~', function() { - $i = 1; - - while(true) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~
~', $line)) { - break; - } - - if (preg_match_all('~
(.*?)
~', $line, $this->matches)) { - $this->model->set( - 'MangaPictures', - 'image', - array_merge( - $this->model->get('MangaPictures', 'image'), - (is_array($this->matches[4]) ? $this->matches[4] : [$this->matches[4]]) - ) - ); - } - - $i++; - } - }); - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/MangaStatsParse.php b/src/Lib/Parser/MangaStatsParse.php deleted file mode 100755 index 9de24970..00000000 --- a/src/Lib/Parser/MangaStatsParse.php +++ /dev/null @@ -1,117 +0,0 @@ -model = new MangaStats; - - /* - * Rules - */ - - - $this->addRule('reading', '~
Reading: (.*)
~', function() { - $this->model->set('MangaStats', 'reading', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - $this->addRule('completed', '~
Completed: (.*)
~', function() { - $this->model->set('MangaStats', 'completed', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - $this->addRule('on_hold', '~
On-Hold: (.*)
~', function() { - $this->model->set('MangaStats', 'on_hold', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - $this->addRule('dropped', '~
Dropped: (.*)
~', function() { - $this->model->set('MangaStats', 'dropped', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - $this->addRule('plan_to_watch', '~
Plan to Read: (.*)
~', function() { - $this->model->set('MangaStats', 'plan_to_read', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - $this->addRule('total', '~
Total: (.*)
~', function() { - $this->model->set('MangaStats', 'total', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - - $this->addRule('score_stats', '~

Score Stats

~', function() { - $score = [ - 1 => ['percentage' => null, 'votes' => null], - 2 => ['percentage' => null, 'votes' => null], - 3 => ['percentage' => null, 'votes' => null], - 4 => ['percentage' => null, 'votes' => null], - 5 => ['percentage' => null, 'votes' => null], - 6 => ['percentage' => null, 'votes' => null], - 7 => ['percentage' => null, 'votes' => null], - 8 => ['percentage' => null, 'votes' => null], - 9 => ['percentage' => null, 'votes' => null], - 10 => ['percentage' => null, 'votes' => null] - ]; - - - $i = 0; - while (true) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~

All MembersRecently Updated By

~', $line)) { - break; - } - - - if (preg_match('~(.*?)~', $line, $this->matches)) { - $_score = (int) $this->matches[1]; - $i++; - preg_match('~
 (.*?)% \((.*?) votes\)
~', $this->file[$this->lineNo + $i], $this->matches); - - $score[ $_score ] = [ - 'percentage' => (float) $this->matches[2], - 'votes' => (int) $this->matches[3] - ]; - - } - - $i++; - } - - - - $this->model->set('MangaStats', 'score_stats', $score); - }); - - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - - } - - -} \ No newline at end of file diff --git a/src/Lib/Parser/PersonParse.php b/src/Lib/Parser/PersonParse.php deleted file mode 100755 index 6ba60a62..00000000 --- a/src/Lib/Parser/PersonParse.php +++ /dev/null @@ -1,228 +0,0 @@ -model = new PersonModel; - - /* - * Rules - */ - - $this->addRule('link_canonical', '~~', function() { - $this->model->set('Person', 'link_canonical', $this->matches[1]); - - preg_match('~myanimelist.net/(.+)/(.*)/~', $this->model->get('Person', 'link_canonical'), $this->matches); - $this->model->set('Person', 'mal_id', (int) $this->matches[2]); - }); - - $this->addRule('name', '~~', function() { - - $this->model->set('Person', 'name', $this->matches[1]); - }); - - $this->addRule('given_name', '~
Given name: (.*)
~', function() { - - $this->model->set('Person', 'given_name', $this->matches[1]); - }); - - $this->addRule('family_name', '~Family name: (.*)
Alternate names:~', function() { - - $this->model->set('Person', 'family_name', $this->matches[1]); - }); - - $this->addRule('alternate_name', '~Alternate names: (.*)
~', function() { - $alternateNames = $this->matches[1]; - if (strpos($alternateNames, ",")) { - $alternateNames = explode(",", $alternateNames); - foreach ($alternateNames as $key => &$value) { - $value = trim($value); - } - } - $this->model->set('Person', 'alternate_name', $alternateNames); - }); - - $this->addRule('birthday', '~Birthday: (.*)
Website:~', function() { - - $this->model->set('Person', 'birthday', $this->matches[1]); - }); - - $this->addRule('website_url', '~Website: (.*)~', function() { - - $this->model->set('Person', 'website_url', $this->matches[1]); - }); - - $this->addRule('member_favorites', '~
Member Favorites: (.*)
~', function() { - - $this->model->set('Person', 'member_favorites', - (int) str_replace(',', '', $this->matches[1]) - ); - }); - - $this->addRule('more', '~
(.*)?~', function() { - $more = str_replace("
", "", $this->matches[1]); - - $running = true; - $i = 0; - - while ($running) { - $i++; - $line = $this->file[$this->lineNo + $i]; - if (strpos($line, '') !== false) { - $running = false; break; - } - - $more .= $line; - } - - $this->model->set('Person', 'more', - htmlspecialchars_decode(strip_tags(str_replace(["
", "
"], "\\n", $more))) - ); - }); - - $this->addRule('voice_acting_role', '~
Voice Acting Roles
~', function() { - $running = true; - $i = 1; - $voiceActingRoles = []; - while ($running) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~Anime Staff Positions~', $line)) { - $running = false; - } - - if (preg_match('~~', $line)) { - $i++; - $animeMeta = []; - preg_match('~
~', $this->file[$this->lineNo + $i], $animeMeta); - $i++; - $animeName = []; - preg_match('~(.*)
~', $this->file[$this->lineNo + $i], $animeName); - $i += 2; - $char = []; - preg_match('~(.*) 
(.*) 
~', $this->file[$this->lineNo + $i], $char); - $i++; - $charMeta = []; - preg_match('~
(.*)
~', $this->file[$this->lineNo + $i], $charMeta); - - $voiceActingRoles[] = [ - 'anime' => [ - 'mal_id' => (int) $animeName[4], - 'name' => $animeName[6], - 'url' => $animeMeta[1], - 'image_url' => $animeMeta[2] - ], - 'character' => [ - 'mal_id' => (int) $char[4], - 'name' => $char[6], - 'url' => $charMeta[1], - 'image_url' => $charMeta[2], - 'role' => htmlspecialchars_decode($char[7]) - ], - ]; - } - $i++; - } - - $this->model->set('Person', 'voice_acting_role', $voiceActingRoles); - }); - - $this->addRule('anime_staff_position', '~Anime Staff Positions
~', function() { - $running = true; - $i = 1; - $animeStaffPositions = []; - while ($running) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~Published Manga~', $line)) { - $running = false; - } - - if (preg_match('~~', $line)) { - $i++; - $animeMeta = []; - preg_match('~
~', $this->file[$this->lineNo + $i], $animeMeta); - $i++; - $animeName = []; - preg_match('~(.*)
~', $this->file[$this->lineNo + $i], $animeName); - $i++; - $role = []; - preg_match('~add (.*)~', $this->file[$this->lineNo + $i], $role); - $animeStaffPositions[] = [ - 'anime' => [ - 'mal_id' => (int) $animeName[4], - 'name' => $animeName[6], - 'url' => $animeMeta[1], - 'image_url' => $animeMeta[2] - ], - 'role' => htmlspecialchars_decode($role[2]) - ]; - } - $i++; - } - - $this->model->set('Person', 'anime_staff_position', $animeStaffPositions); - }); - - $this->addRule('published_manga', '~Published Manga
~', function() { - $running = true; - $i = 1; - $publsihedManga = []; - while ($running) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~~', $line)) { - $running = false; - } - - if (preg_match('~~', $line)) { - $i++; - $mangaMeta = []; - preg_match('~
~', $this->file[$this->lineNo + $i], $mangaMeta); - $i++; - $mangaName = []; - preg_match('~(.*)
~', $this->file[$this->lineNo + $i], $mangaName); - $i++; - $role = []; - preg_match('~add (.*)~', $this->file[$this->lineNo + $i], $role); - $publsihedManga[] = [ - 'manga' => [ - 'mal_id' => (int) $mangaName[4], - 'name' => $mangaName[6], - 'url' => $mangaMeta[1], - 'image_url' => $mangaMeta[2] - ], - 'role' => htmlspecialchars_decode($role[2]) - ]; - } - $i++; - } - - $this->model->set('Person', 'published_manga', $publsihedManga); - }); - - $this->addRule('image_url', '~
((.*)|
Add Picture
)
~', function() { - - $this->model->set('Person', 'image_url', $this->matches[3]); - }); - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - - } - - -} \ No newline at end of file diff --git a/src/Lib/Parser/PersonPicturesParse.php b/src/Lib/Parser/PersonPicturesParse.php deleted file mode 100755 index 81457908..00000000 --- a/src/Lib/Parser/PersonPicturesParse.php +++ /dev/null @@ -1,60 +0,0 @@ -model = new PersonPicturesModel; - - /* - * Rules - */ - - $this->addRule('images', '~

~', function() { - $i = 0; - - while(true) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~
~', $line)) { - break; - } - - if (preg_match_all('~
(.*?)
~', $line, $this->matches)) { - $this->model->set( - 'PersonPictures', - 'image', - array_merge( - $this->model->get('PersonPictures', 'image'), - (is_array($this->matches[4]) ? $this->matches[4] : [$this->matches[4]]) - ) - ); - } - - $i++; - } - }); - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/ScheduleParse.php b/src/Lib/Parser/ScheduleParse.php deleted file mode 100755 index ba7a64a1..00000000 --- a/src/Lib/Parser/ScheduleParse.php +++ /dev/null @@ -1,199 +0,0 @@ -model = new ScheduleModel(); - - - /* - * Rules - */ - - $this->addRule('monday', '~
Monday
~', function() { - $this->model->set('Schedule', 'monday', $this->parseTo('
Tuesday
')); - }); - - $this->addRule('tuesday', '~
Tuesday
~', function() { - $this->model->set('Schedule', 'tuesday', $this->parseTo('
Wednesday
')); - }); - - $this->addRule('wednesday', '~
Wednesday
~', function() { - $this->model->set('Schedule', 'wednesday', $this->parseTo('
Thursday
')); - }); - - $this->addRule('thursday', '~
Thursday
~', function() { - $this->model->set('Schedule', 'thursday', $this->parseTo('
Friday
')); - }); - - $this->addRule('friday', '~
Friday
~', function() { - $this->model->set('Schedule', 'friday', $this->parseTo('
Saturday
')); - }); - - $this->addRule('saturday', '~
Saturday
~', function() { - $this->model->set('Schedule', 'saturday', $this->parseTo('
Sunday
')); - }); - - $this->addRule('sunday', '~
Sunday
~', function() { - $this->model->set('Schedule', 'sunday', $this->parseTo('
file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } - - - private function parseTo($next) { - $i = 1; - $seasonal = []; - - while (true) { - if (preg_match('~'.$next.'~', $this->file[$this->lineNo + $i])) { - break; - } - - if (preg_match('~
file[$this->lineNo + $i], $this->matches)) { - - $anime = [ - 'mal_id' => null, - 'url' => null, - 'title' => null, - 'image_url' => null, - 'synopsis' => null, - 'producer' => [], - 'licensor' => [], - 'episodes' => null, - 'source' => null, - 'genre' => [], - 'airing_start' => null, - 'score' => null, - 'members' => null, - 'kids' => false, - 'r18_plus' => false - ]; - - $anime['kids'] = strpos($this->matches[1], 'kids') ? true : false; - $anime['r18_plus'] = strpos($this->matches[1], 'r18') ? true : false; - - $i += 3; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - - - $anime['mal_id'] = (int) $this->matches[2]; - $anime['url'] = $this->matches[1]; - $anime['title'] = $this->matches[4]; - - $i += 5; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - $producers = explode("", $this->matches[1]); - foreach ($producers as $key => $value) { - if (preg_match('~([\s\S]*)(|)~', $value)) { - preg_match('~([\s\S]*)(|)~', $value, $this->matches); - $anime['producer'][] = [ - 'url' => BASE_URL . $this->matches[1], - 'name' => strip_tags($this->matches[2]) - ]; - } - } - - $i += 2; - preg_match('~(.*) ep(s|)~', $this->file[$this->lineNo +$i], $this->matches); - $anime['episodes'] = $this->matches[2] == '?' ? null : (int) $this->matches[2]; - - $i += 4; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - $anime['source'] = $this->matches[1]; - - $i += 5; - if (preg_match('~
file[$this->lineNo + $i])) { - while (true) { - if (preg_match('~
~', $this->file[$this->lineNo + $i])) { break; } - if (preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches)) { - $anime['genre'][] = [ - 'url' => BASE_URL . $this->matches[1], - 'name' => $this->matches[3] - ]; - } - $i++; - } - } - - if (preg_match('~
(.*?) data-src=~', $this->file[$this->lineNo + $i], $this->matches) || - preg_match('~(.*?)~', $this->file[$this->lineNo + $i], $this->matches) - ) { - $anime['image_url'] = trim(substr(explode(",", $this->matches[5])[1], 0, -3)); - } - - while (!preg_match('~
~', $this->file[$this->lineNo + $i])){$i++;} // haxing MAL's inconsistencies - - $i++; - $synopsis = ""; - if (preg_match('~~', $this->file[$this->lineNo + $i])) { - - while (true) { - if (preg_match('~

file[$this->lineNo + $i])) { - break; - } - - $synopsis .= $this->file[$this->lineNo + $i]; - - $i++; - } - - - $anime['synopsis'] = trim(htmlspecialchars_decode(strip_tags($synopsis))); - } - - if (preg_match('~

~', $this->file[$this->lineNo + $i], $this->matches)) { - $licensors = explode(',', $this->matches[1]); - foreach ($licensors as $key => $value) { - $value = trim($value); - - if (!empty($value)) { - $anime['licensor'][] = $value; - } - } - } - - while (!preg_match('~~', $this->file[$this->lineNo + $i])){$i++;} // haxing MAL's inconsistencies - - $i++; - $anime['airing_start'] = trim(strip_tags($this->file[$this->lineNo + $i])); - - while (!preg_match('~~', $this->file[$this->lineNo + $i])){$i++;} // haxing MAL's inconsistencies - $i++; - $anime['members'] = (int) trim(str_replace(',', '', $this->file[$this->lineNo + $i])); - - while (!preg_match('~~', $this->file[$this->lineNo + $i])){$i++;} // haxing MAL's inconsistencies - $i++; - $anime['score'] = trim($this->file[$this->lineNo + $i]) == 'N/A' ? null : (float) trim($this->file[$this->lineNo + $i]); - - $seasonal[] = $anime; - - } - - $i++; - } - return $seasonal; - } -} diff --git a/src/Lib/Parser/SearchParse.php b/src/Lib/Parser/SearchParse.php deleted file mode 100755 index 010885d1..00000000 --- a/src/Lib/Parser/SearchParse.php +++ /dev/null @@ -1,334 +0,0 @@ -type = $type; - $this->model = new SearchModel(); - - - /* - * Rules - */ - - switch ($type) { - case ANIME: - case MANGA: - - $this->addRule('title', '~~', function() { - $results = []; - $result = [ - 'mal_id' => null, - 'url' => null, - 'image_url' => null, - 'title' => null, - 'description' => null, - 'type' => null, - 'score' => null - ]; - - $i = 0; - while(true) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~
~', $line, $this->matches)) { - $result['title'] = $this->matches[1]; - } - - if (preg_match('~~', $line, $this->matches)) { - $result['image_url'] = $this->matches[1]; - } - - if (preg_match('~~', $line, $this->matches)) { - $result['url'] = $this->matches[1]; - preg_match('~https://myanimelist.net/(anime|manga)/(.*)/(.*)~', $this->matches[1], $this->matches); - $result['mal_id'] = (int) $this->matches[2]; - } - - if (preg_match('~~', $line, $this->matches)) { - $result['description'] = $this->matches[1]; - } - - if (preg_match('~Type:~', $line)) { - preg_match('~((.*?)|(.*))
~', $this->file[$this->lineNo + $i + 1], $this->matches); - $result['type'] = (empty($this->matches[3]) ? $this->matches[4] : $this->matches[3]); - } - - if (preg_match('~Score:~', $line)) { - preg_match('~(.*)
1 \(scored by (.*)
users\)~', $this->file[$this->lineNo + $i + 1], $this->matches); - $result['score'] = (float) $this->matches[2]; - } - - $i++; - } - - $results[] = $result; - $this->model->set('Search', 'result', $results); - }); - - $this->addRule('result', '~
~', function() { - $i = 1; - $results = []; - while (true) { - $result = [ - 'mal_id' => null, - 'url' => null, - 'image_url' => null, - 'title' => null, - 'description' => null, - 'type' => null, - 'score' => null - ]; - $line = $this->file[$this->lineNo + $i]; - - if (preg_match('~~', $line)) { - break; - } - - if (preg_match('~^$~', $line)) { - $i += 2; - - preg_match('~~', $this->file[$this->lineNo + $i], $this->matches); - $result['mal_id'] = (int) $this->matches[3]; - $result['url'] = $this->matches[1]; - - $i++; - - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - $result['image_url'] = trim(substr(explode(",", $this->matches[3])[1], 0, -3)); - $result['title'] = $this->matches[1]; - - - ($this->type == ANIME ? $i += 8 : $i += 10); - - if (preg_match('~~', $this->file[$this->lineNo + $i], $this->matches)) { - $result['description'] = utf8_encode(trim(htmlspecialchars_decode($this->matches[1], ENT_QUOTES))); - } - - $i += 2; - $result['type'] = trim($this->file[$this->lineNo + $i]); - $i += 2; - $result[($this->type == ANIME ? 'episodes' : 'volumes')] = (int) trim($this->file[$this->lineNo + $i]); - $i += 2; - $result['score'] = (float) trim($this->file[$this->lineNo + $i]); - $i += 2; - $result['members'] = (int) str_replace(',', '', trim($this->file[$this->lineNo + $i])); - - $results[] = $result; - } - - $i++; - } - - $this->model->set('Search', 'result', $results); - }); - - break; - case CHARACTER: - $this->addRule('result', '~Search Results~', function() { - $i = 0; - $results = []; - while (true) { - $result = [ - 'mal_id' => null, - 'url' => null, - 'image_url' => null, - 'name' => null, - 'nicknames' => null, - 'anime' => [], - 'manga' => [] - ]; - $line = $this->file[$this->lineNo + $i]; - - if (preg_match('~~', $line)) { - break; - } - - if (preg_match('~
~', $line, $this->matches)) { - - $result['mal_id'] = (int) $this->matches[4]; - $result['url'] = $this->matches[2]; - $result['image_url'] = $this->matches[6]; - - $i += 3; - - preg_match('~(.*?)(
(.*)|)~', $this->file[$this->lineNo + $i], $this->matches); - $result['name'] = $this->matches[2]; - (isset($this->matches[4]) && !empty($this->matches[4])) ? - $result['nicknames'] = str_replace(['(', ')'], '', trim($this->matches[4])) - : $result['nicknames'] = null ; - - $i += 2; - // :uh: i give up finding a pattern here, let's just do it the nasty way - if ( - preg_match('~ Anime: (.*)
Manga: (.*)
~', $this->file[$this->lineNo + $i], $this->matches) - || preg_match('~ Anime: (.*)~', $this->file[$this->lineNo + $i], $this->matches) - || preg_match('~
Manga: (.*)
~', $this->file[$this->lineNo + $i], $this->matches) - ) - { - - - if (isset($this->matches[2])) { - $_anime = explode(',', $this->matches[2]); - foreach ($_anime as $key => &$value) { - preg_match('~(.*)~', $value, $value); - if (!empty($value[5])) { - if ($value[2] == 'anime' || $value[2] == 'manga') { - $result[$value[2]][] = [ - 'mal_id' => (int) $value[3], - 'url' => BASE_URL . substr($value[1], 1), - 'title' => htmlspecialchars_decode($value[5]) - ]; - } - } - } - } - - if (isset($this->matches[3])) { - $_anime = explode(',', $this->matches[3]); - foreach ($_anime as $key => &$value) { - preg_match('~(.*)~', $value, $value); - if (!empty($value[5])) { - if ($value[2] == 'anime' || $value[2] == 'manga') { - $result[$value[2]][] = [ - 'mal_id' => (int) $value[3], - 'url' => BASE_URL . substr($value[1], 1), - 'title' => htmlspecialchars_decode($value[5]) - ]; - } - } - } - } - - - } - - - $results[] = $result; - } - - $i++; - } - - $this->model->set('Search', 'result', $results); - }); - - break; - case PERSON: - - $this->addRule('title', '~~', function() { - $results = []; - $result = [ - 'mal_id' => null, - 'url' => null, - 'image_url' => null, - 'name' => null, - 'nicknames' => null, - ]; - - $i = 0; - while(true) { - $line = $this->file[$this->lineNo + $i]; - if (preg_match('~
~', $line, $this->matches)) { - $result['name'] = trim($this->matches[1]); - } - - if (preg_match('~~', $line, $this->matches)) { - $result['image_url'] = $this->matches[1]; - } - - if (preg_match('~~', $line, $this->matches)) { - $result['url'] = $this->matches[1]; - preg_match('~https://myanimelist.net/people/(.*)/(.*)~', $this->matches[1], $this->matches); - $result['mal_id'] = (int) $this->matches[1]; - } - - - $i++; - } - - $results[] = $result; - $this->model->set('Search', 'result', $results); - }); - - $this->addRule('result', '~Search Results~', function() { - $i = 0; - $results = []; - while (true) { - $result = [ - 'mal_id' => null, - 'url' => null, - 'image_url' => null, - 'name' => null, - 'nicknames' => null, - ]; - $line = $this->file[$this->lineNo + $i]; - - if (preg_match('~~', $line)) { - break; - } - - if (preg_match('~
~', $line, $this->matches)) { - - $result['mal_id'] = (int) $this->matches[3]; - $result['url'] = BASE_URL . $this->matches[1]; - $result['image_url'] = $this->matches[5]; - - $i++; - preg_match('~(.*)(
(.*)|)~', $this->file[$this->lineNo + $i], $this->matches); - $result['name'] = $this->matches[2]; - (isset($this->matches[4]) && !empty($this->matches[4])) ? - $result['nicknames'] = str_replace(['(', ')'], '', trim($this->matches[4])) - : $result['nicknames'] = null ; - - $results[] = $result; - } - - $i++; - } - - $this->model->set('Search', 'result', $results); - }); - - break; - } - - - $this->addRule('result_last_page', '~
~', function() { - preg_match_all('~(.*?)~', $this->line, $this->matches); - - if (!empty($this->matches[2])) { - $this->model->set('Search', 'result_last_page', (int) end($this->matches[2])); - } - }); - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/SeasonalParse.php b/src/Lib/Parser/SeasonalParse.php deleted file mode 100755 index e0c2022d..00000000 --- a/src/Lib/Parser/SeasonalParse.php +++ /dev/null @@ -1,188 +0,0 @@ -model = new SeasonalModel(); - - - /* - * Rules - */ - - $this->addRule('season_meta', '~~', function() { - $season_meta = explode(" ", trim($this->matches[1])); - $this->model->set('Seasonal', 'season_name', $season_meta[0]); - $this->model->set('Seasonal', 'season_year', (int) $season_meta[1]); - }); - - $this->addRule('seasonal', '~
~', function() { - - $i = 1; - $seasonal = []; - $continued = false; - - while (true) { - if (preg_match('~
file[$this->lineNo + $i])) { - break; - } - - if (preg_match('~
TV \(Continuing\)
~', $this->file[$this->lineNo + $i])) {$continued = true;} - if (preg_match('~
ONA
~', $this->file[$this->lineNo + $i])) {$continued = false;} - - if (preg_match('~
file[$this->lineNo + $i], $this->matches)) { - - $anime = [ - 'mal_id' => null, - 'url' => null, - 'title' => null, - 'image_url' => null, - 'type' => null, - 'synopsis' => null, - 'producer' => [], - 'licensor' => [], - 'episodes' => null, - 'source' => null, - 'genre' => [], - 'airing_start' => null, - 'score' => null, - 'members' => null, - 'kids' => false, - 'r18_plus' => false, - 'continued' => false - ]; - - $anime['kids'] = strpos($this->matches[1], 'kids') ? true : false; - $anime['r18_plus'] = strpos($this->matches[1], 'r18') ? true : false; - $anime['continued'] = $continued; - - $i += 3; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - - - $anime['mal_id'] = (int) $this->matches[2]; - $anime['url'] = $this->matches[1]; - $anime['title'] = $this->matches[4]; - - $i += 5; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - $producers = explode("", $this->matches[1]); - foreach ($producers as $key => $value) { - if (preg_match('~([\s\S]*)(|)~', $value)) { - preg_match('~([\s\S]*)(|)~', $value, $this->matches); - $anime['producer'][] = [ - 'url' => BASE_URL . $this->matches[1], - 'name' => strip_tags($this->matches[2]) - ]; - } - } - - $i += 2; - preg_match('~(.*) ep(s|)~', $this->file[$this->lineNo +$i], $this->matches); - $anime['episodes'] = $this->matches[2] == '?' ? null : (int) $this->matches[2]; - - $i += 4; - preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches); - $anime['source'] = $this->matches[1]; - - $i += 5; - if (preg_match('~
file[$this->lineNo + $i])) { - while (true) { - if (preg_match('~
~', $this->file[$this->lineNo + $i])) { break; } - if (preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches)) { - $anime['genre'][] = [ - 'url' => BASE_URL . $this->matches[1], - 'name' => $this->matches[3] - ]; - } - $i++; - } - } - - if (preg_match('~
(.*?) data-src=~', $this->file[$this->lineNo + $i], $this->matches) || - preg_match('~(.*?)~', $this->file[$this->lineNo + $i], $this->matches) - ) { - $anime['image_url'] = trim(substr(explode(",", $this->matches[5])[1], 0, -3)); - } - - while (!preg_match('~
~', $this->file[$this->lineNo + $i])){$i++;} // haxing MAL's inconsistencies - - $i++; - $synopsis = ""; - if (preg_match('~~', $this->file[$this->lineNo + $i])) { - - while (true) { - if (preg_match('~

file[$this->lineNo + $i])) { - break; - } - - $synopsis .= $this->file[$this->lineNo + $i]; - - $i++; - } - - - $anime['synopsis'] = trim(htmlspecialchars_decode(strip_tags($synopsis))); - } - - if (preg_match('~

~', $this->file[$this->lineNo + $i], $this->matches)) { - $licensors = explode(',', $this->matches[1]); - foreach ($licensors as $key => $value) { - $value = trim($value); - - if (!empty($value)) { - $anime['licensor'][] = $value; - } - } - } - - while (!preg_match('~
~', $this->file[$this->lineNo + $i])){$i++;} // haxing MAL's inconsistencies - $i++; - $type = $this->file[$this->lineNo + $i]; - $anime['type'] = trim(str_replace('-', '', $type)); - - while (!preg_match('~~', $this->file[$this->lineNo + $i])){$i++;} // haxing MAL's inconsistencies - $i++; - $anime['airing_start'] = trim(strip_tags($this->file[$this->lineNo + $i])); - - while (!preg_match('~~', $this->file[$this->lineNo + $i])){$i++;} // haxing MAL's inconsistencies - $i++; - $anime['members'] = (int) trim(str_replace(',', '', $this->file[$this->lineNo + $i])); - - while (!preg_match('~~', $this->file[$this->lineNo + $i])){$i++;} // haxing MAL's inconsistencies - $i++; - $anime['score'] = trim($this->file[$this->lineNo + $i]) == 'N/A' ? null : (float) trim($this->file[$this->lineNo + $i]); - - $seasonal[] = $anime; - - } - - $i++; - } - - - $this->model->set('Seasonal', 'season', $seasonal); - }); - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Lib/Parser/TemplateParse.php b/src/Lib/Parser/TemplateParse.php deleted file mode 100755 index 263a5591..00000000 --- a/src/Lib/Parser/TemplateParse.php +++ /dev/null @@ -1,92 +0,0 @@ -filePath = $filePath; - } - - public function setStatus($status) { - $this->status = (int) $status; - } - - public function loadFile() { - if (!is_null($this->filePath)) { - - if (Util::isURL($this->filePath)) { - $this->setStatus(Util::getStatus($this->filePath)); - if (!Util::existsURL($this->status)) { - - - http_response_code($this->status); - - if ($this->status == 429) { - throw new \Exception("MyAnimeList Rate Limit reached"); - } - - throw new \Exception("File does not exist"); - } - } else { - if (!file_exists($this->filePath)) { - throw new \Exception("File does not exist"); - } - } - - $this->file = @file($this->filePath); - - if (!is_bool($this->file)) { - array_walk($this->file, Util::class.'::trim'); // bystanders begone! - } else { - throw new \Exception("MyAnimeList Rate Limit reached"); - } - - } else { - throw new \Exception("File path is null"); - } - } - - public function find() { - foreach ($this->rules as $index => $value) { - if (!$value['found']) { - if (preg_match($value['regex'], $this->line, $this->matches)) { - if ($value['merge']) { - $this->rules[$index] = array_merge($this->rules[$index], ($value['args'] !== false) ? $value['callback'](...$value['args']) : $value['callback']()); - } else { - $this->rules[$index] = ($value['args'] !== false) ? $value['callback'](...$value['args']) : $value['callback'](); - } - - $this->rules[$index]['found'] = true; - } - } - } - } - - public function addRule(String $index, String $regex, Callable $callback, $args = null, Bool $merge = false) { - $args = $args ?? false; // The reason you need PHP 7.1+ - $this->rules[$index] = [ - 'regex' => $regex, - 'callback' => $callback, - 'args' => $args, - 'merge' => $merge, - 'found' => false - ]; - } - - -} \ No newline at end of file diff --git a/src/Lib/Parser/TopParse.php b/src/Lib/Parser/TopParse.php deleted file mode 100755 index daacf067..00000000 --- a/src/Lib/Parser/TopParse.php +++ /dev/null @@ -1,137 +0,0 @@ -model = new TopModel(); - - /* - * Rules - */ - $this->addRule('top', '~

(.*?)

~', function($type) { - $top = []; - $i = 0; - - while (true) { - if (preg_match('~
~', $this->file[$this->lineNo + $i])) { - - $item = [ - 'mal_id' => null, - 'rank' => null, - 'url' => null, - 'image_url' => null, - 'title' => null, - 'type' => null, - 'score' => null, - 'members' => null, - ]; - - if ($type == ANIME) { - $item['airing_start'] = null; - $item['airing_end'] = null; - $item['episodes'] = 0; - } - if ($type == MANGA) { - $item['publishing_start'] = null; - $item['publishing_end'] = null; - $item['volumes'] = 0; - } - - $i+=2; - if (preg_match('~(.*?)~', $this->file[$this->lineNo + $i], $this->matches)) { - $item['rank'] = (int) $this->matches[2]; - } - - $i+=3; - if (preg_match('~~', $this->file[$this->lineNo + $i], $this->matches)) { - $item['url'] = $this->matches[1]; - $item['mal_id'] = (int) $this->matches[3]; - } - - $i++; - if (preg_match('~(.*?)~', $this->file[$this->lineNo + $i], $this->matches)) { - $item['image_url'] = trim(substr(explode(",", $this->matches[2])[1], 0, -3)); - } - - - if ($type == ANIME) {$i+=6;} - if ($type == MANGA) {$i+=7;} - if (preg_match('~(.*?)~', $this->file[$this->lineNo + $i], $this->matches)) { - $item['title'] = $this->matches[5]; - } - - if ($type == ANIME) { - $i+=1; - if (preg_match('~(.*) \((.*) eps\)
~', $this->file[$this->lineNo + $i], $this->matches)) { - $item['type'] = $this->matches[1]; - $item['episodes'] = (int) $this->matches[2]; - } - } - if ($type == MANGA) { - $i+=2; - if (preg_match('~(.*) \((.*) vols\)
~', $this->file[$this->lineNo + $i], $this->matches)) { - $item['type'] = $this->matches[1]; - $item['volumes'] = (int) $this->matches[2]; - } - } - - $i++; - if (preg_match('~(.*) - (.*)
~', $this->file[$this->lineNo + $i], $this->matches)) { - if ($type == ANIME) { - $item['airing_start'] = !empty(trim($this->matches[1])) ? $this->matches[1] : null; - $item['airing_end'] = !empty(trim($this->matches[2])) ? $this->matches[2] : null; - } - if ($type == MANGA) { - $item['publishing_start'] = !empty(trim($this->matches[1])) ? $this->matches[1] : null; - $item['publishing_end'] = !empty(trim($this->matches[2])) ? $this->matches[2] : null; - } - } - - $i++; - if (preg_match('~(.*) (members|favorites)~', $this->file[$this->lineNo + $i], $this->matches)) { - $item['members'] = (int) str_replace(',', '', $this->matches[1]); - } - - if ($type == ANIME) {$i+=4;} - if ($type == MANGA) {$i+=6;} - if (preg_match('~(.*)~', $this->file[$this->lineNo + $i], $this->matches)) { - $item['score'] = (float) $this->matches[1]; - } - - $top[] = $item; - - } - - $i++; - } - - $this->model->set('Top', 'top', $top); - }, [$type]); - - - /* - * Parsing - */ - - foreach ($this->file as $lineNo => $line) { - $this->line = $line; - $this->lineNo = $lineNo; - - $this->find(); - } - - return (array) $this->model; - } -} diff --git a/src/Model/Anime.php b/src/Model/Anime.php deleted file mode 100755 index 648f023f..00000000 --- a/src/Model/Anime.php +++ /dev/null @@ -1,78 +0,0 @@ - null, - 'to' => null - ]; - - public $duration; - - public $rating; - - public $score; - - public $scored_by; - - public $rank; - - public $popularity; - - public $members; - - public $favorites; - - public $synopsis; - - public $background; - - public $premiered; - - public $broadcast; - - public $related = []; - - public $producer = []; - - public $licensor = []; - - public $studio = []; - - public $genre = []; - - public $opening_theme = []; - - public $ending_theme = []; - -} \ No newline at end of file diff --git a/src/Model/Anime/Anime.php b/src/Model/Anime/Anime.php new file mode 100755 index 00000000..f4193d72 --- /dev/null +++ b/src/Model/Anime/Anime.php @@ -0,0 +1,509 @@ +previewVideoUrl = $parser->getPreview(); + $instance->title = $parser->getTitle(); + $instance->url = $parser->getURL(); + $instance->malId = $parser->getId(); + $instance->imageUrl = $parser->getImageURL(); + $instance->synopsis = $parser->getSynopsis(); + $instance->titleEnglish = $parser->getTitleEnglish(); + $instance->titleSynonyms = $parser->getTitleSynonyms(); + $instance->titleJapanese = $parser->getTitleJapanese(); + $instance->type = $parser->getType(); + $instance->episodes = $parser->getEpisodes(); + $instance->episodesUnknown = $instance->episodes === 0; + $instance->status = $parser->getStatus(); + $instance->airing = $instance->status === 'Currently Airing'; + $instance->aired = $parser->getAired(); + $instance->premiered = $parser->getPremiered(); + $instance->broadcast = $parser->getBroadcast(); + $instance->producers = $parser->getProducers(); + $instance->licensors = $parser->getLicensors(); + $instance->studios = $parser->getStudios(); + $instance->source = $parser->getSource(); + $instance->genres = $parser->getGenres(); + $instance->duration = $parser->getDuration(); + $instance->rating = $parser->getRating(); + $instance->score = $parser->getScore(); + $instance->scoredBy = $parser->getScoredBy(); + $instance->rank = $parser->getRank(); + $instance->popularity = $parser->getPopularity(); + $instance->members = $parser->getMembers(); + $instance->favorites = $parser->getFavorites(); + $instance->related = $parser->getRelated(); + $instance->openingTheme = $parser->getOpeningThemes(); + $instance->endingTheme = $parser->getEndingThemes(); + $instance->background = $parser->getBackground(); + + return $instance; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getTitleEnglish(): string + { + return $this->titleEnglish; + } + + /** + * @return string + */ + public function getTitleJapanese(): string + { + return $this->titleJapanese; + } + + /** + * @return string[] + */ + public function getTitleSynonyms(): array + { + return $this->titleSynonyms; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return null|string + */ + public function getPreviewVideoUrl(): ?string + { + return $this->previewVideoUrl; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @return string + */ + public function getSource(): string + { + return $this->source; + } + + /** + * @return string + */ + public function getEpisodes(): string + { + return $this->episodes; + } + + /** + * @return bool + * @todo shouldn't we return null if its unknow and drop this funtion? + */ + public function isEpisodesUnknown(): bool + { + return $this->episodesUnknown; + } + + /** + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * @return bool + */ + public function isAiring(): bool + { + return $this->airing; + } + + /** + * @return \Jikan\Model\Common\DateRange + */ + public function getAired(): DateRange + { + return $this->aired; + } + + /** + * @return string + */ + public function getDuration(): string + { + return $this->duration; + } + + /** + * @return string + */ + public function getRating(): string + { + return $this->rating; + } + + /** + * @return string + */ + public function getScore(): string + { + return $this->score; + } + + /** + * @return string + */ + public function getScoredBy(): string + { + return $this->scoredBy; + } + + /** + * @return string + */ + public function getRank(): string + { + return $this->rank; + } + + /** + * @return string + */ + public function getPopularity(): string + { + return $this->popularity; + } + + /** + * @return string + */ + public function getMembers(): string + { + return $this->members; + } + + /** + * @return string + */ + public function getFavorites(): string + { + return $this->favorites; + } + + /** + * @return string + */ + public function getSynopsis(): string + { + return $this->synopsis; + } + + /** + * @return string + */ + public function getBackground(): string + { + return $this->background; + } + + /** + * @return string + */ + public function getPremiered(): string + { + return $this->premiered; + } + + /** + * @return string + */ + public function getBroadcast(): string + { + return $this->broadcast; + } + + /** + * @return MalUrl[] + */ + public function getRelated(): array + { + return $this->related; + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + */ + public function getProducers(): array + { + return $this->producers; + } + + /** + * @return MalUrl[] + */ + public function getLicensors(): array + { + return $this->licensors; + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + */ + public function getStudios(): array + { + return $this->studios; + } + + /** + * @return MalUrl[] + */ + public function getGenres(): array + { + return $this->genres; + } + + /** + * @return string[] + */ + public function getOpeningTheme(): array + { + return $this->openingTheme; + } + + /** + * @return string[] + */ + public function getEndingTheme(): array + { + return $this->endingTheme; + } +} diff --git a/src/Model/Anime/AnimeCharactersAndStaff.php b/src/Model/Anime/AnimeCharactersAndStaff.php new file mode 100644 index 00000000..0c9c370d --- /dev/null +++ b/src/Model/Anime/AnimeCharactersAndStaff.php @@ -0,0 +1,56 @@ +characters = $parser->getCharacters(); + $instance->staff = $parser->getStaff(); + + return $instance; + } + + /** + * @return \Jikan\Model\Character\CharacterListItem[] + */ + public function getCharacters(): array + { + return $this->characters; + } + + /** + * @return StaffListItem[] + */ + public function getStaff(): array + { + return $this->staff; + } +} diff --git a/src/Model/Anime/AnimeMoreInfo.php b/src/Model/Anime/AnimeMoreInfo.php new file mode 100644 index 00000000..1664e28a --- /dev/null +++ b/src/Model/Anime/AnimeMoreInfo.php @@ -0,0 +1,41 @@ +moreInfo = $parser->getMoreInfo(); + + return $instance; + } + + /** + * @return string|null + */ + public function getMoreInfo(): ?string + { + return $this->moreInfo; + } +} diff --git a/src/Model/Anime/AnimeStats.php b/src/Model/Anime/AnimeStats.php new file mode 100644 index 00000000..92de1bc4 --- /dev/null +++ b/src/Model/Anime/AnimeStats.php @@ -0,0 +1,124 @@ +watching = $parser->getWatching(); + $instance->completed = $parser->getCompleted(); + $instance->onHold = $parser->getOnHold(); + $instance->dropped = $parser->getDropped(); + $instance->planToWatch = $parser->getPlanToWatch(); + $instance->total = $parser->getTotal(); + $instance->scores = $parser->getScores(); + + return $instance; + } + + /** + * @return int + */ + public function getWatching(): int + { + return $this->watching; + } + + /** + * @return int + */ + public function getCompleted(): int + { + return $this->completed; + } + + /** + * @return int + */ + public function getOnHold(): int + { + return $this->onHold; + } + + /** + * @return int + */ + public function getDropped(): int + { + return $this->dropped; + } + + /** + * @return int + */ + public function getPlanToWatch(): int + { + return $this->planToWatch; + } + + /** + * @return int + */ + public function getTotal(): int + { + return $this->total; + } + + /** + * @return int + */ + public function getScores(): int + { + return $this->scores; + } +} diff --git a/src/Model/Anime/AnimeVideos.php b/src/Model/Anime/AnimeVideos.php new file mode 100644 index 00000000..00cd490b --- /dev/null +++ b/src/Model/Anime/AnimeVideos.php @@ -0,0 +1,54 @@ +episodes = $parser->getEpisodes(); + $instance->promo = $parser->getPromos(); + + return $instance; + } + + /** + * @return PromoListItem[] + */ + public function getPromos(): array + { + return $this->promo; + } + + /** + * @return StreamEpisodeListItem[] + */ + public function getEpisodes(): array + { + return $this->episodes; + } +} diff --git a/src/Model/Anime/EpisodeListItem.php b/src/Model/Anime/EpisodeListItem.php new file mode 100644 index 00000000..4badeeb2 --- /dev/null +++ b/src/Model/Anime/EpisodeListItem.php @@ -0,0 +1,153 @@ +episodeId = $parser->getEpisodeId(); + $instance->title = $parser->getTitle(); + $instance->titleJapanese = $parser->getTitleJapanese(); + $instance->titleRomanji = $parser->getTitleRomanji(); + $instance->aired = $parser->getAired(); + $instance->filler = $parser->getFiller(); + $instance->recap = $parser->getRecap(); + $instance->videoUrl = $parser->getVideoUrl(); + $instance->forumUrl = $parser->getForumUrl(); + + return $instance; + } + + /** + * @return int + */ + public function getEpisodeId(): int + { + return $this->episodeId; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getTitleJapanese(): string + { + return $this->titleJapanese; + } + + /** + * @return string + */ + public function getTitleRomanji(): string + { + return $this->titleRomanji; + } + + /** + * @return DateRange|null + */ + public function getAired(): ?DateRange + { + return $this->aired; + } + + /** + * @return bool + */ + public function isFiller(): bool + { + return $this->filler; + } + + /** + * @return bool + */ + public function isRecap(): bool + { + return $this->recap; + } + + /** + * @return string + */ + public function getVideoUrl(): string + { + return $this->videoUrl; + } + + /** + * @return string + */ + public function getForumUrl(): string + { + return $this->forumUrl; + } +} diff --git a/src/Model/Anime/Episodes.php b/src/Model/Anime/Episodes.php new file mode 100644 index 00000000..004b07ef --- /dev/null +++ b/src/Model/Anime/Episodes.php @@ -0,0 +1,54 @@ +episodes = $parser->getEpisodes(); + $instance->episodesLastPage = $parser->getEpisodesLastPage(); + + return $instance; + } + + /** + * @return EpisodeListItem[] + */ + public function getEpisodes(): array + { + return $this->episodes; + } + + /** + * @return int + */ + public function getEpisodesLastPage(): int + { + return $this->episodesLastPage; + } +} diff --git a/src/Model/Anime/PromoListItem.php b/src/Model/Anime/PromoListItem.php new file mode 100644 index 00000000..140b7714 --- /dev/null +++ b/src/Model/Anime/PromoListItem.php @@ -0,0 +1,68 @@ +title = $parser->getTitle(); + $instance->videoUrl = $parser->getVideoUrl(); + $instance->imageUrl = $parser->getImageUrl(); + + return $instance; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getVideoUrl(): string + { + return $this->videoUrl; + } +} diff --git a/src/Model/Anime/StaffListItem.php b/src/Model/Anime/StaffListItem.php new file mode 100755 index 00000000..8d84b0e4 --- /dev/null +++ b/src/Model/Anime/StaffListItem.php @@ -0,0 +1,96 @@ +positions = $parser->getPositions(); + $instance->malId = $parser->getMalId(); + $instance->url = $parser->getUrl(); + $instance->name = $parser->getName(); + $instance->imageUrl = $parser->getImage(); + + return $instance; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string[] + */ + public function getPositions(): array + { + return $this->positions; + } +} diff --git a/src/Model/Anime/StreamEpisodeListItem.php b/src/Model/Anime/StreamEpisodeListItem.php new file mode 100644 index 00000000..68e8042b --- /dev/null +++ b/src/Model/Anime/StreamEpisodeListItem.php @@ -0,0 +1,82 @@ +title = $parser->getTitle(); + $instance->episode = $parser->getEpisode(); + $instance->url = $parser->getUrl(); + $instance->imageUrl = $parser->getImageUrl(); + + return $instance; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getEpisode(): string + { + return $this->episode; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } +} diff --git a/src/Model/AnimeArticles.php b/src/Model/AnimeArticles.php deleted file mode 100755 index feacf197..00000000 --- a/src/Model/AnimeArticles.php +++ /dev/null @@ -1,11 +0,0 @@ -animeography = $parser->getAnimeography(); + $instance->mangaography = $parser->getMangaography(); + $instance->voiceActors = $parser->getVoiceActors(); + $instance->malId = $parser->getMalId(); + $instance->url = $parser->getCharacterUrl(); + $instance->name = $parser->getName(); + $instance->nameKanji = $parser->getNameKanji(); + $instance->nicknames = $parser->getNameNicknames(); + $instance->about = $parser->getAbout(); + $instance->memberFavorites = $parser->getMemberFavorites(); + $instance->imageUrl = $parser->getImage(); + + return $instance; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getCharacterUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return string + */ + public function getNameKanji(): string + { + return $this->nameKanji; + } + + /** + * @return array + */ + public function getNicknames(): array + { + return $this->nicknames; + } + + /** + * @return string + */ + public function getAbout(): string + { + return $this->about; + } + + /** + * @return int + */ + public function getMemberFavorites(): int + { + return $this->memberFavorites; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return Animeography[] + */ + public function getAnimeography(): array + { + return $this->animeography; + } + + /** + * @return Mangaography[] + */ + public function getMangaography(): array + { + return $this->mangaography; + } + + /** + * @return VoiceActor[] + */ + public function getVoiceActors(): array + { + return $this->voiceActors; + } +} diff --git a/src/Model/Character/CharacterListItem.php b/src/Model/Character/CharacterListItem.php new file mode 100755 index 00000000..d6ce0543 --- /dev/null +++ b/src/Model/Character/CharacterListItem.php @@ -0,0 +1,119 @@ +voiceActors = $parser->getVoiceActors(); + $instance->malId = $parser->getMalId(); + $instance->url = $parser->getCharacterUrl(); + $instance->name = $parser->getName(); + $instance->role = $parser->getRole(); + $instance->imageUrl = $parser->getImage(); + + return $instance; + } + + /** + * @return string + */ + public function __toString() + { + return $this->name; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return string + */ + public function getRole(): string + { + return $this->role; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return VoiceActor[] + */ + public function getVoiceActors(): array + { + return $this->voiceActors; + } +} diff --git a/src/Model/Character/Mangaography.php b/src/Model/Character/Mangaography.php new file mode 100644 index 00000000..88b55d76 --- /dev/null +++ b/src/Model/Character/Mangaography.php @@ -0,0 +1,28 @@ +malId = $parser->getMalId(); + $instance->url = $parser->getUrl(); + $instance->name = $parser->getName(); + $instance->imageUrl = $parser->getImage(); + $instance->language = $parser->getLanguage(); + $instance->url = $parser->getUrl(); + + return $instance; + } + + /** + * @return string + */ + public function __toString() + { + return $this->getName(); + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getLanguage(): string + { + return $this->language; + } +} diff --git a/src/Model/CharacterArticles.php b/src/Model/CharacterArticles.php deleted file mode 100755 index 470eabb6..00000000 --- a/src/Model/CharacterArticles.php +++ /dev/null @@ -1,11 +0,0 @@ -malId = $parser->getMalId(); + $instance->url = $parser->getAnimeUrl(); + $instance->title = $parser->getTitle(); + $instance->imageUrl = $parser->getAnimeImage(); + $instance->synopsis = $parser->getDescription(); + $instance->type = $parser->getType(); + $instance->airingStart = $parser->getAirDates(); + $instance->episodes = $parser->getEpisodes(); + $instance->members = $parser->getMembers(); + $instance->genres = $parser->getGenres(); + $instance->source = $parser->getSource(); + $instance->producers = $parser->getProducer(); + $instance->score = $parser->getAnimeScore(); + $instance->licensors = $parser->getLicensors(); + $instance->r18 = $parser->isR18(); + $instance->kids = $parser->isKids(); + } + + /** + * @return string + */ + public function __toString() + { + return (string)$this->url; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getSynopsis(): string + { + return $this->synopsis; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @return \DateTimeImmutable|null + */ + public function getAiringStart(): ?\DateTimeImmutable + { + return $this->airingStart; + } + + /** + * @return int|null + */ + public function getEpisodes(): ?int + { + return $this->episodes; + } + + /** + * @return int + */ + public function getMembers(): int + { + return $this->members; + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + */ + public function getGenres(): array + { + return $this->genres; + } + + /** + * @return string + */ + public function getSource(): string + { + return $this->source; + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + */ + public function getProducers(): array + { + return $this->producers; + } + + /** + * @return float|null + */ + public function getScore(): ?float + { + return $this->score; + } + + /** + * @return string[]|null + */ + public function getLicensors(): ?array + { + return $this->licensors; + } + + /** + * @return bool + */ + public function isR18(): bool + { + return $this->r18; + } + + /** + * @return bool + */ + public function isKids(): bool + { + return $this->kids; + } +} diff --git a/src/Model/Common/AnimeMeta.php b/src/Model/Common/AnimeMeta.php new file mode 100644 index 00000000..e94693d5 --- /dev/null +++ b/src/Model/Common/AnimeMeta.php @@ -0,0 +1,13 @@ +aired = $aired; + } + + /** + * @return string + */ + public function __toString() + { + return $this->aired; + } + + /** + * @return \DateTimeImmutable|null + */ + public function getFrom(): ?\DateTimeImmutable + { + $aired = $this->aired; + if ($aired === 'Not available') { + return null; + } + if (strpos($aired, ' to ') !== false || strpos($aired, ' to ?') !== false) { + $aired = explode(' to ', $aired)[0]; + } + + return Parser::parseDate($aired); + } + + /** + * @return \DateTimeImmutable|null + */ + public function getUntil(): ?\DateTimeImmutable + { + $aired = $this->aired; + if (strpos($aired, ' to ') === false || strpos($aired, ' to ?') !== false) { + return null; + } + $aired = explode(' to ', $aired)[1]; + + return Parser::parseDate($aired); + } +} diff --git a/src/Model/Common/ItemMeta.php b/src/Model/Common/ItemMeta.php new file mode 100644 index 00000000..f8a167cb --- /dev/null +++ b/src/Model/Common/ItemMeta.php @@ -0,0 +1,89 @@ +url = $url; + $this->imageUrl = $imageUrl; + $this->name = $name; + + $this->malId = Parser::idFromUrl($this->url); + } + + /** + * @return string + */ + public function __toString() + { + return $this->name; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } +} diff --git a/src/Model/Common/MalUrl.php b/src/Model/Common/MalUrl.php new file mode 100644 index 00000000..bc55d7a8 --- /dev/null +++ b/src/Model/Common/MalUrl.php @@ -0,0 +1,81 @@ +name = $name; + $this->url = $url; + } + + /** + * @return string + */ + public function __toString() + { + return $this->name; + } + + /** + * @return int + */ + public function getMalId(): int + { + return (int)preg_replace('#https://myanimelist.net/\w+/(\d+)/.*#', '$1', $this->url); + } + + /** + * @return string + */ + public function getType(): string + { + return preg_replace('#https://myanimelist.net/(\w+)/.*#', '', $this->url); + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->name; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } +} diff --git a/src/Model/Common/MangaCard.php b/src/Model/Common/MangaCard.php new file mode 100644 index 00000000..9bac6de2 --- /dev/null +++ b/src/Model/Common/MangaCard.php @@ -0,0 +1,230 @@ +malId = $parser->getMalId(); + $instance->url = $parser->getMangaUrl(); + $instance->title = $parser->getTitle(); + $instance->imageUrl = $parser->getMangaImage(); + $instance->synopsis = $parser->getDescription(); + $instance->type = $parser->getType(); + $instance->publishingStart = $parser->getPublishDates(); + $instance->volumes = $parser->getVolumes(); + $instance->members = $parser->getMembers(); + $instance->genres = $parser->getGenres(); + $instance->type = $parser->getType(); + $instance->authors = $parser->getAuthor(); + $instance->score = $parser->getMangaScore(); + $instance->serialization = $parser->getSerialization(); + } + + /** + * @return string + */ + public function __toString() + { + return (string)$this->url; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getSynopsis(): string + { + return $this->synopsis; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @return \DateTimeImmutable|null + */ + public function getPublishingStart(): ?\DateTimeImmutable + { + return $this->publishingStart; + } + + /** + * @return int|null + */ + public function getVolumes(): ?int + { + return $this->volumes; + } + + /** + * @return int + */ + public function getMembers(): int + { + return $this->members; + } + + /** + * @return MalUrl[] + */ + public function getGenres(): array + { + return $this->genres; + } + + /** + * @return MalUrl[] + */ + public function getAuthors(): array + { + return $this->authors; + } + + /** + * @return float|null + */ + public function getScore(): ?float + { + return $this->score; + } + + /** + * @return string[]|null + */ + public function getSerialization(): ?array + { + return $this->serialization; + } +} diff --git a/src/Model/Common/MangaMeta.php b/src/Model/Common/MangaMeta.php new file mode 100644 index 00000000..ca3dad16 --- /dev/null +++ b/src/Model/Common/MangaMeta.php @@ -0,0 +1,13 @@ +malId = $parser->getMalId(); + $instance->url = $parser->getUrl(); + $instance->name = $parser->getName(); + $instance->imageUrl = $parser->getImage(); + $instance->role = $parser->getRole(); + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getRole(): string + { + return $this->role; + } +} diff --git a/src/Model/Common/PersonMeta.php b/src/Model/Common/PersonMeta.php new file mode 100644 index 00000000..42a83265 --- /dev/null +++ b/src/Model/Common/PersonMeta.php @@ -0,0 +1,13 @@ +large = $parser->getLarge(); + $instance->small = $parser->getSmall(); + + return $instance; + } + + /** + * @return string + */ + public function getLarge(): string + { + return $this->large; + } + + /** + * @return string + */ + public function getSmall(): string + { + return $this->small; + } +} diff --git a/src/Model/Forum/ForumPost.php b/src/Model/Forum/ForumPost.php new file mode 100644 index 00000000..f507bbd1 --- /dev/null +++ b/src/Model/Forum/ForumPost.php @@ -0,0 +1,80 @@ +url = $url; + $this->authorName = $authorName; + $this->authorUrl = $authorUrl; + $this->relativeDate = $relativeDate; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getAuthorName(): string + { + return $this->authorName; + } + + /** + * @return string + */ + public function getAuthorUrl(): string + { + return $this->authorUrl; + } + + /** + * @return \DateTimeImmutable|null + */ + public function getRelativeDate(): ?\DateTimeImmutable + { + return $this->relativeDate; + } +} diff --git a/src/Model/Forum/ForumTopic.php b/src/Model/Forum/ForumTopic.php new file mode 100644 index 00000000..8e34a341 --- /dev/null +++ b/src/Model/Forum/ForumTopic.php @@ -0,0 +1,146 @@ +topicId = $parser->getTopicId(); + $instance->url = $parser->getUrl(); + $instance->title = $parser->getTitle(); + $instance->datePosted = $parser->getPostDate(); + $instance->replies = $parser->getReplies(); + $instance->authorName = $parser->getAuthorName(); + $instance->authorUrl = $parser->getAuthorUrl(); + $instance->lastPost = $parser->getLastPost(); + + return $instance; + } + + /** + * @return string + */ + public function __toString() + { + return $this->title; + } + + /** + * @return int + */ + public function getTopicId(): int + { + return $this->topicId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return \DateTimeImmutable + */ + public function getDatePosted(): \DateTimeImmutable + { + return $this->datePosted; + } + + /** + * @return string + */ + public function getAuthorName(): string + { + return $this->authorName; + } + + /** + * @return string + */ + public function getAuthorUrl(): string + { + return $this->authorUrl; + } + + /** + * @return int + */ + public function getReplies(): int + { + return $this->replies; + } + + /** + * @return ForumPost + */ + public function getLastPost(): ForumPost + { + return $this->lastPost; + } +} diff --git a/src/Model/Genre/AnimeGenre.php b/src/Model/Genre/AnimeGenre.php new file mode 100644 index 00000000..a2c4113e --- /dev/null +++ b/src/Model/Genre/AnimeGenre.php @@ -0,0 +1,99 @@ +url = $parser->getUrl(); + $instance->malId = $parser->getMalId(); + $instance->name = $parser->getName(); + $instance->count = $parser->getCount(); + $instance->anime = $parser->getGenreAnime(); + + return $instance; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return int + */ + public function getCount(): int + { + return $this->count; + } + + /** + * @return array|AnimeCard[] + */ + public function getAnime(): array + { + return $this->anime; + } +} diff --git a/src/Model/Genre/MangaGenre.php b/src/Model/Genre/MangaGenre.php new file mode 100644 index 00000000..2d85f23d --- /dev/null +++ b/src/Model/Genre/MangaGenre.php @@ -0,0 +1,98 @@ +url = $parser->getUrl(); + $instance->malId = $parser->getMalId(); + $instance->name = $parser->getName(); + $instance->count = $parser->getCount(); + $instance->manga = $parser->getGenreManga(); + + return $instance; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return int + */ + public function getCount(): int + { + return $this->count; + } + + /** + * @return array|MangaGenre[] + */ + public function getManga(): array + { + return $this->manga; + } +} diff --git a/src/Model/Magazine/Magazine.php b/src/Model/Magazine/Magazine.php new file mode 100644 index 00000000..358b09c0 --- /dev/null +++ b/src/Model/Magazine/Magazine.php @@ -0,0 +1,57 @@ +malUrl = $parser->getUrl(); + $instance->manga = $parser->getMagazineManga(); + + return $instance; + } + + /** + * @return \Jikan\Model\Common\MalUrl + */ + public function getMalUrl(): MalUrl + { + return $this->malUrl; + } + + /** + * @return array|MagazineManga[] + */ + public function getManga(): array + { + return $this->manga; + } +} diff --git a/src/Model/Magazine/MagazineManga.php b/src/Model/Magazine/MagazineManga.php new file mode 100644 index 00000000..5243c0b0 --- /dev/null +++ b/src/Model/Magazine/MagazineManga.php @@ -0,0 +1,29 @@ +role = $parser->getRole(); + $instance->malId = $parser->getMalId(); + $instance->url = $parser->getCharacterUrl(); + $instance->name = $parser->getName(); + $instance->imageUrl = $parser->getImage(); + + return $instance; + } + + /** + * @return string + */ + public function __toString() + { + return $this->name; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getRole(): string + { + return $this->role; + } +} diff --git a/src/Model/Manga/Manga.php b/src/Model/Manga/Manga.php new file mode 100755 index 00000000..942ba206 --- /dev/null +++ b/src/Model/Manga/Manga.php @@ -0,0 +1,418 @@ +title = $parser->getMangaTitle(); + $instance->url = $parser->getMangaURL(); + $instance->malId = $parser->getMangaId(); + $instance->imageUrl = $parser->getMangaImageURL(); + $instance->synopsis = $parser->getMangaSynopsis(); + $instance->titleEnglish = $parser->getMangaTitleEnglish(); + $instance->titleSynonyms = $parser->getMangaTitleSynonyms(); + $instance->titleJapanese = $parser->getMangaTitleJapanese(); + $instance->type = $parser->getMangaType(); + $instance->chapters = $parser->getMangaChapters(); + $instance->volumes = $parser->getMangaVolumes(); + $instance->chaptersUnknown = $instance->chapters === 0; + $instance->volumesUnknown = $instance->volumes === 0; + $instance->status = $parser->getMangaStatus(); + $instance->publishing = $instance->status === 'Publishing'; + $instance->published = $parser->getPublished(); + $instance->genres = $parser->getMangaGenre(); + $instance->score = $parser->getMangaScore(); + $instance->scoredBy = $parser->getMangaScoredBy(); + $instance->rank = $parser->getMangaRank(); + $instance->popularity = $parser->getMangaPopularity(); + $instance->members = $parser->getMangaMembers(); + $instance->favorites = $parser->getMangaFavorites(); + $instance->related = $parser->getMangaRelated(); + $instance->background = $parser->getMangaBackground(); + $instance->authors = $parser->getMangaAuthors(); + $instance->serializations = $parser->getMangaSerialization(); + + return $instance; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getTitleEnglish(): string + { + return $this->titleEnglish; + } + + /** + * @return string[] + */ + public function getTitleSynonyms(): array + { + return $this->titleSynonyms; + } + + /** + * @return string + */ + public function getTitleJapanese(): string + { + return $this->titleJapanese; + } + + /** + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @return int + */ + public function getVolumes(): int + { + return $this->volumes; + } + + /** + * @return bool + */ + public function isVolumesUnknown(): bool + { + return $this->volumesUnknown; + } + + /** + * @return int + */ + public function getChapters(): int + { + return $this->chapters; + } + + /** + * @return bool + */ + public function isChaptersUnknown(): bool + { + return $this->chaptersUnknown; + } + + /** + * @return bool + */ + public function isPublishing(): bool + { + return $this->publishing; + } + + /** + * @return DateRange + */ + public function getPublished(): DateRange + { + return $this->published; + } + + /** + * @return int + */ + public function getRank(): int + { + return $this->rank; + } + + /** + * @return float + */ + public function getScore(): float + { + return $this->score; + } + + /** + * @return int + */ + public function getScoredBy(): int + { + return $this->scoredBy; + } + + /** + * @return int + */ + public function getPopularity(): int + { + return $this->popularity; + } + + /** + * @return int + */ + public function getMembers(): int + { + return $this->members; + } + + /** + * @return int + */ + public function getFavorites(): int + { + return $this->favorites; + } + + /** + * @return string + */ + public function getSynopsis(): string + { + return $this->synopsis; + } + + /** + * @return string + */ + public function getBackground(): string + { + return $this->background; + } + + /** + * @return MalUrl[] + */ + public function getRelated(): array + { + return $this->related; + } + + /** + * @return MalUrl[] + */ + public function getGenres(): array + { + return $this->genres; + } + + /** + * @return MalUrl[] + */ + public function getAuthors(): array + { + return $this->authors; + } + + /** + * @return MalUrl[] + */ + public function getSerializations(): array + { + return $this->serializations; + } +} diff --git a/src/Model/Manga/MangaMoreInfo.php b/src/Model/Manga/MangaMoreInfo.php new file mode 100644 index 00000000..70c5b033 --- /dev/null +++ b/src/Model/Manga/MangaMoreInfo.php @@ -0,0 +1,41 @@ +moreInfo = $parser->getMoreInfo(); + + return $instance; + } + + /** + * @return string + */ + public function getMoreInfo(): ?string + { + return $this->moreInfo; + } +} diff --git a/src/Model/Manga/MangaStats.php b/src/Model/Manga/MangaStats.php new file mode 100644 index 00000000..a02ff1fc --- /dev/null +++ b/src/Model/Manga/MangaStats.php @@ -0,0 +1,124 @@ +reading = $parser->getReading(); + $instance->completed = $parser->getCompleted(); + $instance->onHold = $parser->getOnHold(); + $instance->dropped = $parser->getDropped(); + $instance->planToRead = $parser->getPlanToRead(); + $instance->total = $parser->getTotal(); + $instance->scores = $parser->getScores(); + + return $instance; + } + + /** + * @return int + */ + public function getReading(): int + { + return $this->reading; + } + + /** + * @return int + */ + public function getCompleted(): int + { + return $this->completed; + } + + /** + * @return int + */ + public function getOnHold(): int + { + return $this->onHold; + } + + /** + * @return int + */ + public function getDropped(): int + { + return $this->dropped; + } + + /** + * @return int + */ + public function getPlanToRead(): int + { + return $this->planToRead; + } + + /** + * @return int + */ + public function getTotal(): int + { + return $this->total; + } + + /** + * @return int + */ + public function getScores(): int + { + return $this->scores; + } +} diff --git a/src/Model/MangaArticles.php b/src/Model/MangaArticles.php deleted file mode 100755 index a52a06c9..00000000 --- a/src/Model/MangaArticles.php +++ /dev/null @@ -1,11 +0,0 @@ -{$key} = $value; - } - } - - public function get($class, $key) { - if (property_exists('Jikan\Model\\'.$class, $key)) { - return $this->{$key}; - } - } - - public function insert($class, $key_array, $value, $key=null) { - if (property_exists('Jikan\Model\\'.$class, $key)) { - if (is_null($key)) { - $this->{$key_array}[] = $value; - } else { - $this->{$key_array}[$key] = $value; - } - } - } - -} \ No newline at end of file diff --git a/src/Model/News/NewsListItem.php b/src/Model/News/NewsListItem.php new file mode 100644 index 00000000..070d4e70 --- /dev/null +++ b/src/Model/News/NewsListItem.php @@ -0,0 +1,125 @@ +url = $parser->getUrl(); + $instance->title = $parser->getTitle(); + $instance->date = $parser->getDate(); + $instance->author = $parser->getAuthor(); + $instance->forumUrl = $parser->getDiscussionLink(); + $instance->imageUrl = $parser->getImage(); + $instance->intro = $parser->getIntro(); + + return $instance; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return \DateTimeImmutable + */ + public function getDate(): \DateTimeImmutable + { + return $this->date; + } + + /** + * @return MalUrl + */ + public function getAuthor(): MalUrl + { + return $this->author; + } + + /** + * @return string + */ + public function getForumUrl(): string + { + return $this->forumUrl; + } + + /** + * @return string|null + */ + public function getImageUrl(): ?string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getIntro(): string + { + return $this->intro; + } +} diff --git a/src/Model/Person.php b/src/Model/Person.php deleted file mode 100755 index c2005408..00000000 --- a/src/Model/Person.php +++ /dev/null @@ -1,36 +0,0 @@ -position = $parser->getPosition(); + $instance->animeMeta = $parser->getAnimeMeta(); + + return $instance; + } + + /** + * @return string + */ + public function getPosition(): string + { + return $this->position; + } + + /** + * @return AnimeMeta + */ + public function getAnimeMeta(): AnimeMeta + { + return $this->animeMeta; + } +} diff --git a/src/Model/Person/Person.php b/src/Model/Person/Person.php new file mode 100755 index 00000000..d5b9dde6 --- /dev/null +++ b/src/Model/Person/Person.php @@ -0,0 +1,248 @@ +malId = $parser->getPersonId(); + $instance->url = $parser->getPersonURL(); + $instance->imageUrl = $parser->getPersonImageUrl(); + $instance->name = $parser->getPersonName(); + $instance->givenName = $parser->getPersonGivenName(); + $instance->familyName = $parser->getPersonFamilyName(); + $instance->alternateNames = $parser->getPersonAlternateNames(); + $instance->websiteUrl = $parser->getPersonWebsite(); + $instance->birthday = $parser->getPersonBirthday(); + $instance->about = $parser->getPersonAbout(); + $instance->memberFavorites = $parser->getPersonFavorites(); + $instance->voiceActingRoles = $parser->getPersonVoiceActingRoles(); + $instance->animeStaffPositions = $parser->getPersonAnimeStaffPositions(); + $instance->publishedManga = $parser->getPersonPublishedManga(); + + return $instance; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getWebsiteUrl(): string + { + return $this->websiteUrl; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return string + */ + public function getGivenName(): string + { + return $this->givenName; + } + + /** + * @return string + */ + public function getFamilyName(): string + { + return $this->familyName; + } + + /** + * @return string[] + */ + public function getAlternateNames(): array + { + return $this->alternateNames; + } + + /** + * @return \DateTimeImmutable|null + */ + public function getBirthday(): ?\DateTimeImmutable + { + return $this->birthday; + } + + /** + * @return int + */ + public function getMemberFavorites(): int + { + return $this->memberFavorites; + } + + /** + * @return string + */ + public function getAbout(): string + { + return $this->about; + } + + /** + * @return VoiceActingRole[] + */ + public function getVoiceActingRoles(): array + { + return $this->voiceActingRoles; + } + + /** + * @param VoiceActingRole[] $voiceActingRoles + */ + public function setVoiceActingRoles(array $voiceActingRoles): void + { + $this->voiceActingRoles = $voiceActingRoles; + } + + /** + * @return AnimeStaffPosition[] + */ + public function getAnimeStaffPositions(): array + { + return $this->animeStaffPositions; + } + + /** + * @param AnimeStaffPosition[] $animeStaffPositions + */ + public function setAnimeStaffPositions(array $animeStaffPositions): void + { + $this->animeStaffPositions = $animeStaffPositions; + } + + /** + * @return PublishedManga[] + */ + public function getPublishedManga(): array + { + return $this->publishedManga; + } + + /** + * @param PublishedManga[] $publishedManga + */ + public function setPublishedManga(array $publishedManga): void + { + $this->publishedManga = $publishedManga; + } +} diff --git a/src/Model/Person/PublishedManga.php b/src/Model/Person/PublishedManga.php new file mode 100644 index 00000000..656dfffc --- /dev/null +++ b/src/Model/Person/PublishedManga.php @@ -0,0 +1,57 @@ +position = $parser->getPosition(); + $instance->mangaMeta = $parser->getMangaMeta(); + + return $instance; + } + + /** + * @return string + */ + public function getPosition(): string + { + return $this->position; + } + + /** + * @return mangaMeta + */ + public function getMangaMeta(): MangaMeta + { + return $this->mangaMeta; + } +} diff --git a/src/Model/Person/VoiceActingRole.php b/src/Model/Person/VoiceActingRole.php new file mode 100644 index 00000000..635916ce --- /dev/null +++ b/src/Model/Person/VoiceActingRole.php @@ -0,0 +1,71 @@ +role = $parser->getRole(); + $instance->animeMeta = $parser->getAnimeMeta(); + $instance->characterMeta = $parser->getCharacterMeta(); + + return $instance; + } + + /** + * @return string + */ + public function getRole(): string + { + return $this->role; + } + + /** + * @return AnimeMeta + */ + public function getAnimeMeta(): AnimeMeta + { + return $this->animeMeta; + } + + /** + * @return CharacterMeta + */ + public function getCharacterMeta(): CharacterMeta + { + return $this->characterMeta; + } +} diff --git a/src/Model/PersonNews.php b/src/Model/PersonNews.php deleted file mode 100755 index 0480783a..00000000 --- a/src/Model/PersonNews.php +++ /dev/null @@ -1,11 +0,0 @@ -malUrl = $parser->getUrl(); + $instance->anime = $parser->getProducerAnime(); + + return $instance; + } + + /** + * @return MalUrl + */ + public function getMalUrl(): MalUrl + { + return $this->malUrl; + } + + /** + * @return array|ProducerAnime[] + */ + public function getAnime(): array + { + return $this->anime; + } +} diff --git a/src/Model/Producer/ProducerAnime.php b/src/Model/Producer/ProducerAnime.php new file mode 100644 index 00000000..5cc7bd44 --- /dev/null +++ b/src/Model/Producer/ProducerAnime.php @@ -0,0 +1,29 @@ +results = $parser->getResults(); + $instance->lastPage = $parser->getLastPage(); + + return $instance; + } + + /** + * @return AnimeSearchListItem[] + */ + public function getResults(): array + { + return $this->results; + } + + /** + * @return int + */ + public function getLastPage(): int + { + return $this->lastPage; + } +} diff --git a/src/Model/Search/AnimeSearchListItem.php b/src/Model/Search/AnimeSearchListItem.php new file mode 100644 index 00000000..b1c479af --- /dev/null +++ b/src/Model/Search/AnimeSearchListItem.php @@ -0,0 +1,237 @@ +malUrl = $parser->getUrl(); + $instance->imageUrl = $parser->getImageUrl(); + $instance->title = $parser->getTitle(); + $instance->synopsis = $parser->getSynopsis(); + $instance->type = $parser->getType(); + $instance->episodes = $parser->getEpisodes(); + $instance->score = $parser->getScore(); + $instance->startDateString = $parser->getStartDateString(); + $instance->endDateString = $parser->getEndDateString(); + $instance->startDate = $parser->getStartDate(); + $instance->endDate = $parser->getEndDate(); + $instance->members = $parser->getMembers(); + $instance->rated = $parser->getRated(); + $instance->airing = + null === $instance->endDate + && null !== $instance->startDate + && + ( + new \DateTimeImmutable( + 'now', + new \DateTimeZone('UTC') + ) > $instance->startDate + ); + + return $instance; + } + + + /** + * @return \Jikan\Model\Common\MalUrl + */ + public function getMalUrl(): MalUrl + { + return $this->malUrl; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getSynopsis(): string + { + return $this->synopsis; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @return int + */ + public function getEpisodes(): int + { + return $this->episodes; + } + + /** + * @return float + */ + public function getScore(): float + { + return $this->score; + } + + /** + * @return \DateTimeImmutable|null + */ + public function getStartDate(): ?\DateTimeImmutable + { + return $this->startDate; + } + + /** + * @return \DateTimeImmutable|null + */ + public function getEndDate(): ?\DateTimeImmutable + { + return $this->endDate; + } + + /** + * @return int + */ + public function getMembers(): int + { + return $this->members; + } + + /** + * @return string|null + */ + public function getRated(): ?string + { + return $this->rated; + } + + /** + * @return string|null + */ + public function getStartDateString(): ?string + { + return $this->startDateString; + } + + /** + * @return string|null + */ + public function getEndDateString(): ?string + { + return $this->endDateString; + } + + /** + * @return bool + */ + public function isAiring(): bool + { + return $this->airing; + } +} diff --git a/src/Model/Search/CharacterSearch.php b/src/Model/Search/CharacterSearch.php new file mode 100644 index 00000000..63d27ec2 --- /dev/null +++ b/src/Model/Search/CharacterSearch.php @@ -0,0 +1,58 @@ +results = $parser->getResults(); + $instance->lastPage = $parser->getLastPage(); + + return $instance; + } + + /** + * @return CharacterSearchListItem[] + */ + public function getResults(): array + { + return $this->results; + } + + /** + * @return int + */ + public function getLastPage(): int + { + return $this->lastPage; + } +} diff --git a/src/Model/Search/CharacterSearchListItem.php b/src/Model/Search/CharacterSearchListItem.php new file mode 100644 index 00000000..03ca5f8f --- /dev/null +++ b/src/Model/Search/CharacterSearchListItem.php @@ -0,0 +1,115 @@ +malUrl = $parser->getUrl(); + $instance->imageUrl = $parser->getImageUrl(); + $instance->name = $parser->getName(); + $instance->alternativeNames = $parser->getAlternativeNames(); + $instance->anime = $parser->getAnime(); + $instance->manga = $parser->getManga(); + + return $instance; + } + + + /** + * @return \Jikan\Model\Common\MalUrl + */ + public function getMalUrl(): MalUrl + { + return $this->malUrl; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return array + */ + public function getAlternativeNames(): array + { + return $this->alternativeNames; + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + */ + public function getAnime(): array + { + return $this->anime; + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + */ + public function getManga(): array + { + return $this->manga; + } +} diff --git a/src/Model/Search/MangaSearch.php b/src/Model/Search/MangaSearch.php new file mode 100644 index 00000000..a3361ed1 --- /dev/null +++ b/src/Model/Search/MangaSearch.php @@ -0,0 +1,59 @@ +results = $parser->getResults(); + $instance->lastPage = $parser->getLastPage(); + + return $instance; + } + + /** + * @return MangaSearchListItem[] + */ + public function getResults(): array + { + return $this->results; + } + + /** + * @return int + */ + public function getLastPage(): int + { + return $this->lastPage; + } +} diff --git a/src/Model/Search/MangaSearchListItem.php b/src/Model/Search/MangaSearchListItem.php new file mode 100644 index 00000000..1a300234 --- /dev/null +++ b/src/Model/Search/MangaSearchListItem.php @@ -0,0 +1,238 @@ +malUrl = $parser->getUrl(); + $instance->imageUrl = $parser->getImageUrl(); + $instance->title = $parser->getTitle(); + $instance->synopsis = $parser->getSynopsis(); + $instance->type = $parser->getType(); + $instance->volumes = $parser->getVolumes(); + $instance->chapters = $parser->getChapters(); + $instance->score = $parser->getScore(); + $instance->startDateString = $parser->getStartDateString(); + $instance->endDateString = $parser->getEndDateString(); + $instance->startDate = $parser->getStartDate(); + $instance->endDate = $parser->getEndDate(); + $instance->members = $parser->getMembers(); + $instance->publishing = + null === $instance->endDate + && null !== $instance->startDate + && + ( + new \DateTimeImmutable( + 'now', + new \DateTimeZone('UTC') + ) > $instance->startDate + ); + + return $instance; + } + + + /** + * @return MalUrl + */ + public function getMalUrl(): MalUrl + { + return $this->malUrl; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getSynopsis(): string + { + return $this->synopsis; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @return int + */ + public function getChapters(): int + { + return $this->chapters; + } + + /** + * @return int + */ + public function getVolumes(): int + { + return $this->volumes; + } + + /** + * @return float + */ + public function getScore(): float + { + return $this->score; + } + + /** + * @return \DateTimeImmutable|null ?\DateTimeImmutable + */ + public function getStartDate(): ?\DateTimeImmutable + { + return $this->startDate; + } + + /** + * @return \DateTimeImmutable|null ?\DateTimeImmutable + */ + public function getEndDate(): ?\DateTimeImmutable + { + return $this->endDate; + } + + /** + * @return int + */ + public function getMembers(): int + { + return $this->members; + } + + /** + * @return null|string ?string + */ + public function getStartDateString(): ?string + { + return $this->startDateString; + } + + /** + * @return null|string ?string + */ + public function getEndDateString(): ?string + { + return $this->endDateString; + } + + /** + * @return bool + */ + public function isPublishing(): bool + { + return $this->publishing; + } +} diff --git a/src/Model/Search/PersonSearch.php b/src/Model/Search/PersonSearch.php new file mode 100644 index 00000000..71b4cd2b --- /dev/null +++ b/src/Model/Search/PersonSearch.php @@ -0,0 +1,59 @@ +results = $parser->getResults(); + $instance->lastPage = $parser->getLastPage(); + + return $instance; + } + + /** + * @return PersonSearchListItem[] + */ + public function getResults(): array + { + return $this->results; + } + + /** + * @return int + */ + public function getLastPage(): int + { + return $this->lastPage; + } +} diff --git a/src/Model/Search/PersonSearchListItem.php b/src/Model/Search/PersonSearchListItem.php new file mode 100644 index 00000000..34c6758d --- /dev/null +++ b/src/Model/Search/PersonSearchListItem.php @@ -0,0 +1,87 @@ +malUrl = $parser->getUrl(); + $instance->imageUrl = $parser->getImageUrl(); + $instance->name = $parser->getName(); + $instance->alternativeNames = $parser->getAlternativeNames(); + + return $instance; + } + + + /** + * @return \Jikan\Model\Common\MalUrl + */ + public function getMalUrl(): MalUrl + { + return $this->malUrl; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return array + */ + public function getAlternativeNames(): array + { + return $this->alternativeNames; + } +} diff --git a/src/Model/Search/Search.php b/src/Model/Search/Search.php new file mode 100755 index 00000000..91623394 --- /dev/null +++ b/src/Model/Search/Search.php @@ -0,0 +1,16 @@ +year = $parser->getYear(); + $instance->seasons = $parser->getSeasons(); + + return $instance; + } + + /** + * @return int + */ + public function getYear(): int + { + return $this->year; + } + + /** + * @return string[] + */ + public function getSeasons(): array + { + return $this->seasons; + } +} diff --git a/src/Model/Seasonal.php b/src/Model/Seasonal.php deleted file mode 100755 index c9688e72..00000000 --- a/src/Model/Seasonal.php +++ /dev/null @@ -1,15 +0,0 @@ -season = $parser->getSeason(); + $instance->anime = $parser->getSeasonalAnime(); + + return $instance; + } + + /** + * @return string + */ + public function getSeason(): string + { + return $this->season; + } + + /** + * @return array|SeasonalAnime[] + */ + public function getAnime(): array + { + return $this->anime; + } +} diff --git a/src/Model/Seasonal/SeasonalAnime.php b/src/Model/Seasonal/SeasonalAnime.php new file mode 100755 index 00000000..52342859 --- /dev/null +++ b/src/Model/Seasonal/SeasonalAnime.php @@ -0,0 +1,43 @@ +continuing = $parser->isContinuing(); + + return $instance; + } + + /** + * @return bool + */ + public function isContinuing(): bool + { + return $this->continuing; + } +} diff --git a/src/Model/Shedule/Schedule.php b/src/Model/Shedule/Schedule.php new file mode 100755 index 00000000..a8a76b14 --- /dev/null +++ b/src/Model/Shedule/Schedule.php @@ -0,0 +1,155 @@ +monday = $parser->getShedule('monday'); + $instance->tuesday = $parser->getShedule('tuesday'); + $instance->wednesday = $parser->getShedule('wednesday'); + $instance->thursday = $parser->getShedule('thursday'); + $instance->friday = $parser->getShedule('friday'); + $instance->saturday = $parser->getShedule('saturday'); + $instance->sunday = $parser->getShedule('sunday'); + $instance->other = $parser->getShedule('other'); + $instance->unknown = $parser->getShedule('unknown'); + + return $instance; + } + + /** + * @return AnimeCard[] + */ + public function getMonday(): array + { + return $this->monday; + } + + /** + * @return AnimeCard[] + */ + public function getTuesday(): array + { + return $this->tuesday; + } + + /** + * @return AnimeCard[] + */ + public function getWednesday(): array + { + return $this->wednesday; + } + + /** + * @return AnimeCard[] + */ + public function getThursday(): array + { + return $this->thursday; + } + + /** + * @return AnimeCard[] + */ + public function getFriday(): array + { + return $this->friday; + } + + /** + * @return AnimeCard[] + */ + public function getSaturday(): array + { + return $this->saturday; + } + + /** + * @return AnimeCard[] + */ + public function getSunday(): array + { + return $this->sunday; + } + + /** + * @return AnimeCard[] + */ + public function getOther(): array + { + return $this->other; + } + + /** + * @return AnimeCard[] + */ + public function getUnknown(): array + { + return $this->unknown; + } +} diff --git a/src/Model/Top.php b/src/Model/Top.php deleted file mode 100755 index bf2bae9f..00000000 --- a/src/Model/Top.php +++ /dev/null @@ -1,11 +0,0 @@ -rank = $parser->getRank(); + $instance->malUrl = $parser->getMalUrl(); + $instance->type = $parser->getType(); + $instance->episodes = $parser->getEpisodes(); + $instance->startDate = $parser->getStartDate(); + $instance->endDate = $parser->getEndDate(); + $instance->members = $parser->getMembers(); + $instance->rating = $parser->getRating(); + $instance->imageUrl = $parser->getImage(); + + return $instance; + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->malUrl->getName(); + } + + /** + * @return int + */ + public function getRank(): int + { + return $this->rank; + } + + /** + * @return MalUrl + */ + public function getMalUrl(): MalUrl + { + return $this->malUrl; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @return int + */ + public function getEpisodes(): int + { + return $this->episodes; + } + + /** + * @return string + */ + public function getStartDate(): string + { + return $this->startDate; + } + + /** + * @return string + */ + public function getEndDate(): string + { + return $this->endDate; + } + + /** + * @return int + */ + public function getMembers(): int + { + return $this->members; + } + + /** + * @return float + */ + public function getRating(): float + { + return $this->rating; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } +} diff --git a/src/Model/Top/TopCharacter.php b/src/Model/Top/TopCharacter.php new file mode 100755 index 00000000..ed47605f --- /dev/null +++ b/src/Model/Top/TopCharacter.php @@ -0,0 +1,136 @@ +rank = $parser->getRank(); + $instance->malUrl = $parser->getMalUrl(); + $instance->nameKanji = $parser->getKanjiName(); + $instance->animeography = $parser->getAnimeography(); + $instance->mangaography = $parser->getMangaography(); + $instance->favorites = $parser->getFavorites(); + $instance->imageUrl = $parser->getImage(); + + return $instance; + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->malUrl->getName(); + } + + /** + * @return int + */ + public function getRank(): int + { + return $this->rank; + } + + /** + * @return MalUrl + */ + public function getMalUrl(): MalUrl + { + return $this->malUrl; + } + + /** + * @return string|null + */ + public function getNameKanji(): ?string + { + return $this->nameKanji; + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + */ + public function getAnimeography(): array + { + return $this->animeography; + } + + /** + * @return MalUrl[] + */ + public function getMangaography(): array + { + return $this->mangaography; + } + + /** + * @return int + */ + public function getFavorites(): int + { + return $this->favorites; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } +} diff --git a/src/Model/Top/TopManga.php b/src/Model/Top/TopManga.php new file mode 100755 index 00000000..93a295d9 --- /dev/null +++ b/src/Model/Top/TopManga.php @@ -0,0 +1,164 @@ +rank = $parser->getRank(); + $instance->malUrl = $parser->getMalUrl(); + $instance->type = $parser->getType(); + $instance->volumes = $parser->getVolumes(); + $instance->startDate = $parser->getStartDate(); + $instance->endDate = $parser->getEndDate(); + $instance->members = $parser->getMembers(); + $instance->rating = $parser->getRating(); + $instance->imageUrl = $parser->getImage(); + + return $instance; + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->malUrl->getName(); + } + + /** + * @return int + */ + public function getRank(): int + { + return $this->rank; + } + + /** + * @return MalUrl + */ + public function getMalUrl(): MalUrl + { + return $this->malUrl; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @return int|null + */ + public function getVolumes(): ?int + { + return $this->volumes; + } + + /** + * @return string + */ + public function getStartDate(): string + { + return $this->startDate; + } + + /** + * @return string + */ + public function getEndDate(): string + { + return $this->endDate; + } + + /** + * @return int + */ + public function getMembers(): int + { + return $this->members; + } + + /** + * @return float + */ + public function getRating(): float + { + return $this->rating; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } +} diff --git a/src/Model/Top/TopPerson.php b/src/Model/Top/TopPerson.php new file mode 100755 index 00000000..fb3ea8cc --- /dev/null +++ b/src/Model/Top/TopPerson.php @@ -0,0 +1,135 @@ +rank = $parser->getRank(); + $instance->malUrl = $parser->getMalUrl(); + $instance->nameKanji = $parser->getKanjiName(); + $instance->favorites = $parser->getPeopleFavorites(); + $instance->image = $parser->getImage(); + $instance->birthday = $parser->getBirthday(); + + return $instance; + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->malUrl->getName(); + } + + /** + * @return int + */ + public function getRank(): int + { + return $this->rank; + } + + /** + * @return \Jikan\Model\Common\MalUrl + */ + public function getMalUrl(): MalUrl + { + return $this->malUrl; + } + + /** + * @return string|null + */ + public function getNameKanji(): ?string + { + return $this->nameKanji; + } + + /** + * @return int + */ + public function getFavorites(): int + { + return $this->favorites; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return \DateTimeImmutable|null + */ + public function getBirthday(): ?\DateTimeImmutable + { + return $this->birthday; + } + + /** + * @return null|string + */ + public function getImage(): ?string + { + return $this->image; + } +} diff --git a/src/Model/User/AnimeStats.php b/src/Model/User/AnimeStats.php new file mode 100644 index 00000000..31a51f29 --- /dev/null +++ b/src/Model/User/AnimeStats.php @@ -0,0 +1,167 @@ +daysWatched = $parser->getDaysWatched(); + $instance->meanScore = $parser->getMeanScore(); + $instance->watching = $parser->getWatching(); + $instance->completed = $parser->getCompleted(); + $instance->onHold = $parser->getOnHold(); + $instance->dropped = $parser->getDropped(); + $instance->planToWatch = $parser->getPlanToWatch(); + $instance->totalEntries = $parser->getTotalEntries(); + $instance->rewatched = $parser->getRewatched(); + $instance->episodesWatched = $parser->getEpisodesWatched(); + + + return $instance; + } + + /** + * @return float + */ + public function getDaysWatched(): float + { + return $this->daysWatched; + } + + /** + * @return float + */ + public function getMeanScore(): float + { + return $this->meanScore; + } + + /** + * @return int + */ + public function getWatching(): int + { + return $this->watching; + } + + /** + * @return int + */ + public function getCompleted(): int + { + return $this->completed; + } + + /** + * @return int + */ + public function getOnHold(): int + { + return $this->onHold; + } + + /** + * @return int + */ + public function getDropped(): int + { + return $this->dropped; + } + + /** + * @return int + */ + public function getPlanToWatch(): int + { + return $this->planToWatch; + } + + /** + * @return int + */ + public function getTotalEntries(): int + { + return $this->totalEntries; + } + + /** + * @return int + */ + public function getRewatched(): int + { + return $this->rewatched; + } + + /** + * @return int + */ + public function getEpisodesWatched(): int + { + return $this->episodesWatched; + } +} diff --git a/src/Model/User/Favorites.php b/src/Model/User/Favorites.php new file mode 100644 index 00000000..7969f7c2 --- /dev/null +++ b/src/Model/User/Favorites.php @@ -0,0 +1,83 @@ +anime = $parser->getAnime(); + $instance->manga = $parser->getManga(); + $instance->characters = $parser->getCharacters(); + $instance->people = $parser->getPeople(); + + return $instance; + } + + /** + * @return array + */ + public function getAnime(): array + { + return $this->anime; + } + + /** + * @return array + */ + public function getManga(): array + { + return $this->manga; + } + + /** + * @return array + */ + public function getCharacters(): array + { + return $this->characters; + } + + /** + * @return array + */ + public function getPeople(): array + { + return $this->people; + } +} diff --git a/src/Model/User/Friend.php b/src/Model/User/Friend.php new file mode 100644 index 00000000..f5f3f11e --- /dev/null +++ b/src/Model/User/Friend.php @@ -0,0 +1,105 @@ +url = $parser->getUrl(); + $instance->username = $parser->getName(); + $instance->imageUrl = $parser->getAvatar(); + $instance->friendsSince = $parser->getFriendsSince(); + $instance->lastOnline = $parser->getLastOnline(); + + return $instance; + } + + /** + * @return string + */ + public function __toString() + { + return $this->username; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getUsername(): string + { + return $this->username; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @return \DateTimeImmutable + */ + public function getLastOnline(): \DateTimeImmutable + { + return $this->lastOnline; + } + + /** + * @return \DateTimeImmutable + */ + public function getFriendsSince(): \DateTimeImmutable + { + return $this->friendsSince; + } +} diff --git a/src/Model/User/History.php b/src/Model/User/History.php new file mode 100644 index 00000000..8a04b5fd --- /dev/null +++ b/src/Model/User/History.php @@ -0,0 +1,73 @@ +malUrl = $parser->getUrl(); + $instance->increment = $parser->getIncrement(); + $instance->date = $parser->getDate(); + + return $instance; + } + + + /** + * @return MalUrl + */ + public function getMalUrl(): MalUrl + { + return $this->malUrl; + } + + /** + * @return int + */ + public function getIncrement(): int + { + return $this->increment; + } + + /** + * @return \DateTimeImmutable + */ + public function getDate(): \DateTimeImmutable + { + return $this->date; + } +} diff --git a/src/Model/User/MangaStats.php b/src/Model/User/MangaStats.php new file mode 100644 index 00000000..a44d259b --- /dev/null +++ b/src/Model/User/MangaStats.php @@ -0,0 +1,180 @@ +daysRead = $parser->getDaysRead(); + $instance->meanScore = $parser->getMeanScore(); + $instance->reading = $parser->getReading(); + $instance->completed = $parser->getCompleted(); + $instance->onHold = $parser->getOnHold(); + $instance->dropped = $parser->getDropped(); + $instance->planToRead = $parser->getPlanToRead(); + $instance->totalEntries = $parser->getTotalEntries(); + $instance->reread = $parser->getReread(); + $instance->chaptersRead = $parser->getChaptersRead(); + $instance->volumesRead = $parser->getVolumesRead(); + + return $instance; + } + + /** + * @return float + */ + public function getDaysRead(): float + { + return $this->daysRead; + } + + /** + * @return float + */ + public function getMeanScore(): float + { + return $this->meanScore; + } + + /** + * @return int + */ + public function getReading(): int + { + return $this->reading; + } + + /** + * @return int + */ + public function getCompleted(): int + { + return $this->completed; + } + + /** + * @return int + */ + public function getOnHold(): int + { + return $this->onHold; + } + + /** + * @return int + */ + public function getDropped(): int + { + return $this->dropped; + } + + /** + * @return int + */ + public function getPlanToRead(): int + { + return $this->planToRead; + } + + /** + * @return int + */ + public function getTotalEntries(): int + { + return $this->totalEntries; + } + + /** + * @return int + */ + public function getReread(): int + { + return $this->reread; + } + + /** + * @return int + */ + public function getChaptersRead(): int + { + return $this->chaptersRead; + } + + /** + * @return int + */ + public function getVolumesRead(): int + { + return $this->volumesRead; + } +} diff --git a/src/Model/User/Profile.php b/src/Model/User/Profile.php new file mode 100644 index 00000000..907c75ae --- /dev/null +++ b/src/Model/User/Profile.php @@ -0,0 +1,196 @@ +username = $parser->getUsername(); + $instance->url = $parser->getProfileUrl(); + $instance->imageUrl = $parser->getImageUrl(); + $instance->joined = $parser->getJoinDate(); + $instance->lastOnline = $parser->getLastOnline(); + $instance->gender = $parser->getGender(); + $instance->birthday = $parser->getBirthday(); + $instance->location = $parser->getLocation(); + $instance->animeStats = $parser->getAnimeStats(); + $instance->mangaStats = $parser->getMangaStats(); + $instance->about = $parser->getAbout(); + $instance->favorites = $parser->getFavorites(); + + return $instance; + } + + /** + * @return string + */ + public function getUsername(): string + { + return $this->username; + } + + /** + * @return \DateTimeImmutable + */ + public function getLastOnline(): \DateTimeImmutable + { + return $this->lastOnline; + } + + /** + * @return string + */ + public function getGender(): string + { + return $this->gender; + } + + /** + * @return \DateTimeImmutable|null + */ + public function getBirthday(): ?\DateTimeImmutable + { + return $this->birthday; + } + + /** + * @return string + */ + public function getLocation(): string + { + return $this->location; + } + + /** + * @return \DateTimeImmutable|null + */ + public function getJoined(): ?\DateTimeImmutable + { + return $this->joined; + } + + /** + * @return AnimeStats + */ + public function getAnimeStats(): AnimeStats + { + return $this->animeStats; + } + + /** + * @return MangaStats + */ + public function getMangaStats(): MangaStats + { + return $this->mangaStats; + } + + /** + * @return Favorites + */ + public function getFavorites(): Favorites + { + return $this->favorites; + } + + /** + * @return string + */ + public function getAbout(): string + { + return $this->about; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return null|string + */ + public function getImageUrl(): ?string + { + return $this->imageUrl; + } +} diff --git a/src/MyAnimeList/MalClient.php b/src/MyAnimeList/MalClient.php new file mode 100644 index 00000000..8ec4daad --- /dev/null +++ b/src/MyAnimeList/MalClient.php @@ -0,0 +1,712 @@ +ghoutte = new Client(); + if ($guzzle !== null) { + $this->ghoutte->setClient($guzzle); + } + } + + /** + * @param Request\Anime\AnimeRequest $request + * + * @return Model\Anime\Anime + * @throws ParserException + */ + public function getAnime(Request\Anime\AnimeRequest $request): Model\Anime\Anime + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Anime\AnimeParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Anime\AnimeEpisodesRequest $request + * + * @return Model\Anime\Episodes + * @throws ParserException + */ + public function getAnimeEpisodes(Request\Anime\AnimeEpisodesRequest $request): Model\Anime\Episodes + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Anime\EpisodesParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Anime\AnimeVideosRequest $request + * + * @return Model\Anime\AnimeVideos + * @throws ParserException + */ + public function getAnimeVideos(Request\Anime\AnimeVideosRequest $request): Model\Anime\AnimeVideos + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Anime\VideosParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Manga\MangaRequest $request + * + * @return Model\Manga\Manga + * @throws ParserException + */ + public function getManga(Request\Manga\MangaRequest $request): Model\Manga\Manga + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Manga\MangaParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Character\CharacterRequest $request + * + * @return Model\Character\Character + * @throws ParserException + */ + public function getCharacter(Request\Character\CharacterRequest $request): Model\Character\Character + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Character\CharacterParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Person\PersonRequest $request + * + * @return Model\Person\Person + * @throws ParserException + */ + public function getPerson(Request\Person\PersonRequest $request): Model\Person\Person + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Person\PersonParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\User\UserProfileRequest $request + * + * @return Model\User\Profile + * @throws ParserException + */ + public function getUserProfile(Request\User\UserProfileRequest $request): Model\User\Profile + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\User\Profile\UserProfileParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\User\UserFriendsRequest $request + * + * @return Model\User\Friend[] + * @throws ParserException + */ + public function getUserFriends(Request\User\UserFriendsRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\User\Friends\FriendsParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Seasonal\SeasonalRequest $request + * + * @return Model\Seasonal\Seasonal + * @throws ParserException + */ + public function getSeasonal(Request\Seasonal\SeasonalRequest $request): Model\Seasonal\Seasonal + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Seasonal\SeasonalParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Producer\ProducerRequest $request + * + * @return Model\Producer\Producer + * @throws ParserException + */ + public function getProducer(Request\Producer\ProducerRequest $request): Model\Producer\Producer + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Producer\ProducerParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Magazine\MagazineRequest $request + * + * @return Model\Magazine\Magazine + * @throws ParserException + */ + public function getMagazine(Request\Magazine\MagazineRequest $request): Model\Magazine\Magazine + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Magazine\MagazineParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Genre\AnimeGenreRequest $request + * + * @return Model\Genre\AnimeGenre + * @throws ParserException + */ + public function getAnimeGenre(Request\Genre\AnimeGenreRequest $request): Model\Genre\AnimeGenre + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Genre\AnimeGenreParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Genre\MangaGenreRequest $request + * + * @return Model\Genre\MangaGenre + * @throws ParserException + */ + public function getMangaGenre(Request\Genre\MangaGenreRequest $request): Model\Genre\MangaGenre + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Genre\MangaGenreParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Schedule\ScheduleRequest $request + * + * @return Model\Shedule\Schedule + * @throws ParserException + */ + public function getSchedule(Request\Schedule\ScheduleRequest $request): Model\Shedule\Schedule + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Schedule\ScheduleParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Anime\AnimeCharactersAndStaffRequest $request + * + * @return Model\Anime\AnimeCharactersAndStaff + * @throws ParserException + */ + public function getAnimeCharactersAndStaff( + Request\Anime\AnimeCharactersAndStaffRequest $request + ): Model\Anime\AnimeCharactersAndStaff { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Anime\CharactersAndStaffParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Anime\AnimePicturesRequest $request + * + * @return Model\Common\Picture[] + * @throws ParserException + */ + public function getAnimePictures(Request\Anime\AnimePicturesRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Common\PicturesPageParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Manga\MangaPicturesRequest $request + * + * @return Model\Common\Picture[] + * @throws ParserException + */ + public function getMangaPictures(Request\Manga\MangaPicturesRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Common\PicturesPageParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Character\CharacterPicturesRequest $request + * + * @return Model\Common\Picture[] + * @throws ParserException + */ + public function getCharacterPictures(Request\Character\CharacterPicturesRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Common\PicturesPageParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Person\PersonPicturesRequest $request + * + * @return Model\Common\Picture[] + * @throws ParserException + */ + public function getPersonPictures(Request\Person\PersonPicturesRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Common\PicturesPageParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\RequestInterface $request + * + * @return Model\News\NewsListItem[] + * @throws ParserException + */ + public function getNewsList(Request\RequestInterface $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\News\NewsListParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Search\AnimeSearchRequest $request + * + * @return Model\Search\AnimeSearch + * @throws ParserException + */ + public function getAnimeSearch(Request\Search\AnimeSearchRequest $request): Model\Search\AnimeSearch + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Search\AnimeSearchParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Search\MangaSearchRequest $request + * + * @return Model\Search\MangaSearch + * @throws ParserException + */ + public function getMangaSearch(Request\Search\MangaSearchRequest $request): Model\Search\MangaSearch + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Search\MangaSearchParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Search\CharacterSearchRequest $request + * + * @return Model\Search\CharacterSearch + * @throws ParserException + */ + public function getCharacterSearch(Request\Search\CharacterSearchRequest $request): Model\Search\CharacterSearch + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Search\CharacterSearchParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Search\PersonSearchRequest $request + * + * @return Model\Search\PersonSearch + * @throws ParserException + */ + public function getPersonSearch(Request\Search\PersonSearchRequest $request): Model\Search\PersonSearch + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Search\PersonSearchParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Manga\MangaCharactersRequest $request + * + * @return Model\Manga\CharacterListItem[] + * @throws ParserException + */ + public function getMangaCharacters(Request\Manga\MangaCharactersRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Manga\CharactersParser($crawler); + + return $parser->getCharacters(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Top\TopAnimeRequest $request + * + * @return Model\Top\TopAnime[] + * @throws ParserException + */ + public function getTopAnime(Request\Top\TopAnimeRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Top\TopAnimeParser($crawler); + + return $parser->getTopAnime(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Top\TopMangaRequest $request + * + * @return Model\Top\TopManga[] + * @throws ParserException + */ + public function getTopManga(Request\Top\TopMangaRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Top\TopMangaParser($crawler); + + return $parser->getTopManga(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Top\TopCharactersRequest $request + * + * @return Model\Top\TopCharacter[] + * @throws ParserException + */ + public function getTopCharacters(Request\Top\TopCharactersRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Top\TopCharactersParser($crawler); + + return $parser->getTopCharacters(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Top\TopPeopleRequest $request + * + * @return Model\Top\TopPerson[] + * @throws ParserException + */ + public function getTopPeople(Request\Top\TopPeopleRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Top\TopPeopleParser($crawler); + + return $parser->getTopPeople(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Anime\AnimeStatsRequest $request + * + * @return Model\Anime\AnimeStats + * @throws ParserException + */ + public function getAnimeStats(Request\Anime\AnimeStatsRequest $request): Model\Anime\AnimeStats + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Anime\AnimeStatsParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Manga\MangaStatsRequest $request + * + * @return Model\Manga\MangaStats + * @throws ParserException + */ + public function getMangaStats(Request\Manga\MangaStatsRequest $request): Model\Manga\MangaStats + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Manga\MangaStatsParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Anime\AnimeForumRequest $request + * + * @return Model\Forum\ForumTopic[] + * @throws ParserException + */ + public function getAnimeForum(Request\Anime\AnimeForumRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Forum\ForumPageParser($crawler); + + return $parser->getTopics(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Manga\MangaForumRequest $request + * + * @return Model\Forum\ForumTopic[] + * @throws ParserException + */ + public function getMangaForum(Request\Manga\MangaForumRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Forum\ForumPageParser($crawler); + + return $parser->getTopics(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Anime\AnimeMoreInfoRequest $request + * + * @return null|string + * @throws ParserException + */ + public function getAnimeMoreInfo(Request\Anime\AnimeMoreInfoRequest $request): ?string + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Anime\MoreInfoParser($crawler); + + return $parser->getModel()->getMoreInfo(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\Manga\MangaMoreInfoRequest $request + * + * @return null|string + * @throws ParserException + */ + public function getMangaMoreInfo(Request\Manga\MangaMoreInfoRequest $request): ?string + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\Manga\MoreInfoParser($crawler); + + return $parser->getModel()->getMoreInfo(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\SeasonList\SeasonListRequest $request + * + * @return Model\SeasonList\SeasonListItem[] An array of SeasonListItem instances + * @throws ParserException + */ + public function getSeasonList(Request\SeasonList\SeasonListRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\SeasonList\SeasonListParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } + + /** + * @param Request\User\UserHistoryRequest $request + * + * @return Model\User\History[] + * @throws ParserException + */ + public function getUserHistory(Request\User\UserHistoryRequest $request): array + { + $crawler = $this->ghoutte->request('GET', $request->getPath()); + try { + $parser = new Parser\User\History\HistoryParser($crawler); + + return $parser->getModel(); + } catch (\Exception $e) { + throw ParserException::fromRequest($request, $e); + } + } +} diff --git a/src/Parser/Anime/AnimeParser.php b/src/Parser/Anime/AnimeParser.php new file mode 100644 index 00000000..d8c61793 --- /dev/null +++ b/src/Parser/Anime/AnimeParser.php @@ -0,0 +1,593 @@ +crawler = $crawler; + } + + /** + * @return Anime + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Anime + { + return Anime::fromParser($this); + } + + /** + * @return int + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getId(): int + { + return Parser::idFromUrl($this->getURL()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getURL(): string + { + return $this->crawler->filterXPath('//meta[@property=\'og:url\']')->attr('content'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getTitle(): string + { + return $this->crawler->filterXPath('//meta[@property=\'og:title\']')->attr('content'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImageURL(): string + { + return $this->crawler->filterXPath('//meta[@property=\'og:image\']')->attr('content'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getSynopsis(): string + { + return JString::cleanse( + $this->crawler->filterXPath('//meta[@property=\'og:description\']')->attr('content') + ); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getTitleEnglish(): ?string + { + $title = $this->crawler->filterXPath('//span[text()="English:"]'); + if (!$title->count()) { + return null; + } + + return JString::cleanse( + str_replace($title->text(), '', $title->parents()->text()) + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getTitleSynonyms(): array + { + $title = $this->crawler + ->filterXPath('//span[text()="Synonyms:"]'); + + if (!$title->count()) { + return []; + } + + $titles = str_replace($title->text(), '', $title->parents()->text()); + $titles = explode(',', $titles); + + foreach ($titles as &$title) { + $title = JString::cleanse($title); + } + + return $titles; + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getTitleJapanese(): ?string + { + $title = $this->crawler + ->filterXPath('//span[text()="Japanese:"]'); + if (!$title->count()) { + return null; + } + + return JString::cleanse( + str_replace($title->text(), '', $title->parents()->text()) + ); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getType(): ?string + { + $type = $this->crawler + ->filterXPath('//span[text()="Type:"]'); + if (!$type->count()) { + return null; + } + + return JString::cleanse( + str_replace($type->text(), '', $type->parents()->text()) + ); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getEpisodes(): ?int + { + $episodes = $this->crawler + ->filterXPath('//span[text()="Episodes:"]'); + + if (!$episodes->count()) { + return null; + } + + return (str_replace($episodes->text(), '', $episodes->parents()->text()) === 'Unknown') ? 0 : (int)str_replace( + $episodes->text(), + '', + $episodes->parents()->text() + ); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getStatus(): ?string + { + $status = $this->crawler + ->filterXPath('//span[text()="Status:"]'); + if (!$status->count()) { + return null; + } + + return JString::cleanse( + str_replace($status->text(), '', $status->parents()->text()) + ); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getPremiered(): ?string + { + $premiered = $this->crawler + ->filterXPath('//span[text()="Premiered:"]'); + + if (!$premiered->count()) { + return null; + } + + return JString::cleanse( + str_replace($premiered->text(), '', $premiered->parents()->text()) + ); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getBroadcast(): ?string + { + $broadcast = $this->crawler + ->filterXPath('//span[text()="Broadcast:"]'); + + if (!$broadcast->count()) { + return null; + } + + return JString::cleanse( + str_replace($broadcast->text(), '', $broadcast->parents()->text()) + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getProducers(): array + { + $producer = $this->crawler + ->filterXPath('//span[text()="Producers:"]'); + + if ($producer->count() && strpos($producer->parents()->text(), 'None found') === false) { + return $producer->parents()->first()->filterXPath('//a')->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + return []; // If `None found` + } + + /** + * @return array + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getLicensors(): array + { + $licensor = $this->crawler + ->filterXPath('//span[text()="Licensors:"]'); + + if ($licensor->count() && strpos($licensor->parents()->text(), 'None found') === false) { + return $licensor->parents()->first()->filterXPath('//a')->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + return []; // If `None found` + } + + /** + * @return array + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getStudios(): array + { + $studio = $this->crawler->filterXPath('//span[text()="Studios:"]'); + + if ($studio->count() && strpos($studio->parents()->text(), 'None found') === false) { + return $studio->parents()->first()->filterXPath('//a')->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + return []; // If `None found` + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getSource(): ?string + { + $source = $this->crawler + ->filterXPath('//span[text()="Source:"]'); + + if (!$source->count()) { + return null; + } + + return JString::cleanse( + str_replace($source->text(), '', $source->parents()->text()) + ); + } + + /** + * @return MalUrl[] + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getGenres(): array + { + $genre = $this->crawler + ->filterXPath('//span[text()="Genres:"]'); + + if ($genre->count() && strpos($genre->parents()->text(), 'No genres have been added yet') === false) { + return $genre->parents()->first()->filterXPath('//a')->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + return []; // If `No genres have been added yet` + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getDuration(): ?string + { + $duration = $this->crawler + ->filterXPath('//span[text()="Duration:"]'); + + if (!$duration->count()) { + return null; + } + + return JString::cleanse( + str_replace( + '.', + '', + str_replace($duration->text(), '', $duration->parents()->text()) + ) + ); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getRating(): ?string + { + $rating = $this->crawler + ->filterXPath('//span[text()="Rating:"]'); + + if (!$rating->count()) { + return null; + } + + return JString::cleanse( + str_replace($rating->text(), '', $rating->parents()->text()) + ); + } + + /** + * @return float + * @throws \InvalidArgumentException + */ + public function getScore(): ?float + { + return Parser::textOrNull($this->crawler->filterXPath('//span[@itemprop="ratingValue"]')); + } + + /** + * @return float + * @throws \InvalidArgumentException + */ + public function getScoredBy(): ?float + { + $rating = Parser::textOrNull($this->crawler->filterXPath('//span[@itemprop="ratingCount"]')); + if ($rating === null) { + return $rating; + } + + return str_replace(',', '', $rating); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getRank(): ?int + { + $rank = $this->crawler + ->filterXPath('//span[text()="Ranked:"]'); + + if (!$rank->count()) { + return null; + } + + $ranked = str_replace( + '#', + '', + substr( + explode("\n", trim(str_replace($rank->text(), '', $rank->parents()->text())))[0], + 0, + -1 + ) + ); + + return $ranked !== 'N/A' ? $ranked : null; + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getPopularity(): ?int + { + $popularity = $this->crawler + ->filterXPath('//span[text()="Popularity:"]'); + + if (!$popularity->count()) { + return null; + } + + return JString::cleanse( + str_replace([$popularity->text(), '#'], '', $popularity->parents()->text()) + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMembers(): ?int + { + $member = $this->crawler + ->filterXPath('//span[text()="Members:"]'); + + if (!$member->count()) { + return null; + } + + return JString::cleanse( + str_replace([$member->text(), ','], '', $member->parents()->text()) + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getFavorites(): ?int + { + $favorite = $this->crawler + ->filterXPath('//span[text()="Favorites:"]'); + + if (!$favorite->count()) { + return null; + } + + return JString::cleanse( + str_replace([$favorite->text(), ','], '', $favorite->parents()->text()) + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getRelated(): array + { + $related = []; + $this->crawler + ->filterXPath('//table[contains(@class, "anime_detail_related_anime")]/tr') + ->each( + function (Crawler $c) use (&$related) { + $related[JString::cleanse( + str_replace(':', '', $c->filterXPath('//td[1]')->text()) + )] = $c->filterXPath('//td[2]/a') + ->each( + function (Crawler $c) { + return (new MalUrlParser($c))->getModel(); + } + ); + } + ); + + return $related; + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getBackground(): ?string + { + $background = Parser::removeChildNodes($this->crawler->filterXPath('//span[@itemprop="description"]/..')); + if (!$background->count()) { + return null; + } + $background = $background->text(); + if (preg_match('~No background information has been added to this title~', $background)) { + return null; + } + + return JString::cleanse($background); + } + + /** + * @return array + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getOpeningThemes(): array + { + return array_filter( + preg_split( + '/\s?#\d+:\s/m', + $this->crawler->filterXPath('//div[@class="theme-songs js-theme-songs opnening"]')->text() + ) + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getEndingThemes(): array + { + return array_filter( + preg_split( + '/\s?#\d+:\s/m', + $this->crawler->filterXPath('//div[@class="theme-songs js-theme-songs ending"]')->text() + ) + ); + } + + /** + * @return \Jikan\Model\Common\DateRange + * @throws \InvalidArgumentException + */ + public function getAired(): DateRange + { + return new DateRange($this->getAnimeAiredString()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getAnimeAiredString(): ?string + { + $aired = $this->crawler->filterXPath('//span[contains(text(), "Aired")]/..')->text(); + $aired = explode("\n", trim($aired))[1]; + + return trim($aired); + } + + /** + * @return null|string + * @throws \InvalidArgumentException + */ + public function getPreview(): ?string + { + $video = $this->crawler->filterXPath('//div[contains(@class, "video-promotion")]/a'); + if (!$video->count()) { + return null; + } + + return $video->attr('href'); + } +} diff --git a/src/Parser/Anime/AnimeStatsParser.php b/src/Parser/Anime/AnimeStatsParser.php new file mode 100644 index 00000000..b3f8eab9 --- /dev/null +++ b/src/Parser/Anime/AnimeStatsParser.php @@ -0,0 +1,167 @@ +crawler = $crawler; + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getWatching(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'Watching:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @param $input + * + * @return int + */ + private function sanitize($input): int + { + return (int)preg_replace('/\D/', '', $input); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getCompleted(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'Completed:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getOnHold(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'On-Hold:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getDropped(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'Dropped:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getPlanToWatch(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'Plan to Watch:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getTotal(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'Total:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getScores(): array + { + $table = $this->crawler->filterXPath('//h2[text()="Score Stats"]/following-sibling::table'); + $voteCounts = $table->filterXPath('//small[contains(text(), \'votes\')]'); + + $scores = []; + $score = 10; + + $voteCounts->each( + function (Crawler $crawler) use (&$scores, &$score) { + $scores[$score] = [ + 'votes' => $this->sanitize($crawler->text()), + 'percentage' => (double)preg_replace( + '/[^0-9,.]/', + '', + substr( + $completeText = $crawler->parents()->getNode(0)->textContent, + 0, + strpos($completeText, '%') + ) + ), + ]; + + $score--; + } + ); + + return $scores; + } + + /** + * @return AnimeStats + * @throws \InvalidArgumentException + */ + public function getModel(): AnimeStats + { + return AnimeStats::fromParser($this); + } +} diff --git a/src/Parser/Anime/CharactersAndStaffParser.php b/src/Parser/Anime/CharactersAndStaffParser.php new file mode 100644 index 00000000..5a93e935 --- /dev/null +++ b/src/Parser/Anime/CharactersAndStaffParser.php @@ -0,0 +1,88 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Character\CharacterListItem[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getCharacters(): array + { + return $this->crawler + ->filterXPath('//h2[text()="Characters & Voice Actors"]/following-sibling::table') + ->reduce( + function (Crawler $crawler) { + return (bool)$crawler->filterXPath( + '//a[contains(@href, "https://myanimelist.net/character")]' + )->count(); + } + ) + ->each( + function (Crawler $crawler) { + return (new CharacterListItemParser($crawler))->getModel(); + } + ); + } + + /** + * Return the model + * + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): AnimeCharactersAndStaff + { + return AnimeCharactersAndStaff::fromParser($this); + } + + /** + * @return StaffListItem[] + * @throws \InvalidArgumentException + */ + public function getStaff(): array + { + return $this->crawler + ->filterXPath('//h2/div/../following-sibling::table') + ->reduce( + function (Crawler $crawler) { + return !(bool)$crawler->filterXPath( + '//a[contains(@href, "https://myanimelist.net/character")]' + )->count(); + } + ) + ->each( + function (Crawler $crawler) { + return (new StaffListItemParser($crawler))->getModel(); + } + ); + } +} diff --git a/src/Parser/Anime/EpisodeListItemParser.php b/src/Parser/Anime/EpisodeListItemParser.php new file mode 100644 index 00000000..f975fbfd --- /dev/null +++ b/src/Parser/Anime/EpisodeListItemParser.php @@ -0,0 +1,186 @@ +crawler = $crawler; + } + + /** + * @return EpisodeListItem + * @throws \InvalidArgumentException + */ + public function getModel(): EpisodeListItem + { + return EpisodeListItem::fromParser($this); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getEpisodeId(): int + { + return (int)$this->crawler->filterXPath('//td[contains(@class, \'episode-number\')]')->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getEpisodeUrl(): string + { + return $this->crawler->filterXPath('//td[@class="episode-title"]/a')->attr('href'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getTitle(): string + { + return $this->crawler->filterXPath('//td[@class="episode-title"]/a')->text(); + } + + /** + * @return null|string + * @throws \InvalidArgumentException + */ + public function getTitleJapanese(): ?string + { + $title = $this->crawler->filterXPath('//td[@class="episode-title"]/span[@class=\'di-ib\']')->text(); + + if (empty($title)) { + return null; + } + + preg_match('~(.*)\((.*)\)~', $title, $matches); + + return $matches[2]; + } + + /** + * @return null|string + * @throws \InvalidArgumentException + */ + public function getTitleRomanji(): ?string + { + $title = $this->crawler->filterXPath('//td[@class="episode-title"]/span[@class=\'di-ib\']')->text(); + + if (empty($title)) { + return null; + } + + preg_match('~(.*)\((.*)\)~', $title, $matches); + + return (!empty($matches[1]) ? $matches[1] : null); + } + + /** + * @return DateRange|null ?DateRange + * @throws \InvalidArgumentException + */ + public function getAired(): ?DateRange + { + $aired = $this->crawler->filterXPath('//td[contains(@class, \'episode-aired\')]')->text(); + + if ($aired === 'N/A') { + return null; + } + + return new DateRange($aired); + } + + /** + * @return bool + */ + public function getFiller(): bool + { + $filler = $this->crawler->filterXPath( + '//td + [ + @class="episode-title"] + /span[contains(@class, \'icon-episode-type-bg\') and contains(text(), \'Filler\') + ]' + ); + + if (!$filler->count()) { + return false; + } + + return true; + } + + /** + * @return bool + */ + public function getRecap(): bool + { + $recap = $this->crawler->filterXPath( + '//td + [ + @class="episode-title"] + /span[contains(@class, \'icon-episode-type-bg\') and contains(text(), \'Recap\') + ]' + ); + + if (!$recap->count()) { + return false; + } + + return true; + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getVideoUrl(): ?string + { + $video = $this->crawler->filterXPath('//td[contains(@class, \'episode-video\')]/a'); + + if (!$video->count()) { + return null; + } + + return $video->attr('href'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getForumUrl(): ?string + { + $forum = $this->crawler->filterXPath('//td[contains(@class, \'episode-forum\')]/a'); + + if (!$forum->count()) { + return null; + } + + return $forum->attr('href'); + } +} diff --git a/src/Parser/Anime/EpisodesParser.php b/src/Parser/Anime/EpisodesParser.php new file mode 100644 index 00000000..808d01de --- /dev/null +++ b/src/Parser/Anime/EpisodesParser.php @@ -0,0 +1,101 @@ +crawler = $crawler; + } + + /** + * @return EpisodeListItem[] + * @throws \InvalidArgumentException + */ + public function getEpisodes(): array + { + $episodes = $this->crawler + ->filterXPath('//table[contains(@class, \'js-watch-episode-list ascend\')]/tr[1]'); + + if (!$episodes->count()) { + return []; + } + + return $episodes->nextAll() + ->each( + function (Crawler $crawler) { + return (new EpisodeListItemParser($crawler))->getModel(); + } + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getEpisodesLastPage(): int + { + $episodesLastPage = $this->crawler + ->filterXPath('//div[contains(@class, \'pagination\')]'); + + if (!$episodesLastPage->count()) { + return 1; + } + + $episodesLastPage = $episodesLastPage->children(); + + + if ($episodesLastPage->getNode(1)->tagName === 'span') { + $episodesLastPage = $episodesLastPage + ->filterXPath('//a') + ->last(); + + preg_match('~(\d+) - (\d+)~', $episodesLastPage->text(), $matches); + + return ceil((int)$matches[2] / 100); + } + + $episodesLastPage = $this->crawler + ->filterXPath('//div[contains(@class, \'pagination\')]/a') + ->last(); + + if (!$episodesLastPage->count()) { + return 1; + } + + preg_match('~(\d+) - (\d+)~', $episodesLastPage->text(), $matches); + + return ceil((int)$matches[2] / 100); + } + + /** + * Return the model + * + * @throws \InvalidArgumentException + */ + public function getModel(): Episodes + { + return Episodes::fromParser($this); + } +} diff --git a/src/Parser/Anime/MoreInfoParser.php b/src/Parser/Anime/MoreInfoParser.php new file mode 100644 index 00000000..c829aad0 --- /dev/null +++ b/src/Parser/Anime/MoreInfoParser.php @@ -0,0 +1,62 @@ +crawler = $crawler; + } + + /** + * Return the model + * + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): AnimeMoreInfo + { + return AnimeMoreInfo::fromParser($this); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getMoreInfo(): ?string + { + $moreinfo = JString::cleanse( + Parser::removeChildNodes( + $this->crawler->filterXPath('//div[@class="js-scrollfix-bottom-rel"]') + )->text() + ); + + if (empty($moreinfo)) { + return null; + } + + return $moreinfo; + } +} diff --git a/src/Parser/Anime/PromoListItemParser.php b/src/Parser/Anime/PromoListItemParser.php new file mode 100644 index 00000000..0b6faa4c --- /dev/null +++ b/src/Parser/Anime/PromoListItemParser.php @@ -0,0 +1,67 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Anime\PromoListItem + * @throws \InvalidArgumentException + */ + public function getModel(): PromoListItem + { + return PromoListItem::fromParser($this); + } + + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getTitle(): string + { + return $this->crawler->filterXPath('//a/div/span')->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImageUrl(): string + { + return $this->crawler->filterXPath('//a/img')->attr('data-src'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getVideoUrl(): string + { + return $this->crawler->filterXPath('//a')->attr('href'); + } +} diff --git a/src/Parser/Anime/StaffListItemParser.php b/src/Parser/Anime/StaffListItemParser.php new file mode 100644 index 00000000..4416a107 --- /dev/null +++ b/src/Parser/Anime/StaffListItemParser.php @@ -0,0 +1,106 @@ +crawler = $crawler; + } + + /** + * @return string[] + * @throws \InvalidArgumentException + */ + public function getPositions(): array + { + return explode(', ', $this->crawler->filterXPath('//small')->text()); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMalId(): int + { + return Parser::idFromUrl($this->getUrl()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getUrl(): string + { + return $this->getMalUrl()->getUrl(); + } + + /** + * @return \Jikan\Model\Common\MalUrl + * @throws \InvalidArgumentException + */ + public function getMalUrl(): MalUrl + { + $link = $this->crawler->filterXPath('//a') + ->reduce( + function (Crawler $c) { + return !$c->filterXPath('//img')->count(); + } + ) + ->first(); + + return (new MalUrlParser($link))->getModel(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getName(): string + { + return $this->getMalUrl()->getName(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImage(): string + { + return $this->crawler->filterXPath('//img')->attr('data-src'); + } + + /** + * Return the model + * + * @throws \InvalidArgumentException + */ + public function getModel(): StaffListItem + { + return StaffListItem::fromParser($this); + } +} diff --git a/src/Parser/Anime/StreamEpisodeListItemParser.php b/src/Parser/Anime/StreamEpisodeListItemParser.php new file mode 100644 index 00000000..0dcd68e6 --- /dev/null +++ b/src/Parser/Anime/StreamEpisodeListItemParser.php @@ -0,0 +1,76 @@ +crawler = $crawler; + } + + /** + * @return StreamEpisodeListItem + * @throws \InvalidArgumentException + */ + public function getModel(): StreamEpisodeListItem + { + return StreamEpisodeListItem::fromParser($this); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getTitle(): string + { + return $this->crawler->filterXPath('//a/div/span/span[@class="episode-title"]')->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getEpisode(): string + { + return Parser::removeChildNodes($this->crawler->filterXPath('//a/div/span[@class="title"]'))->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getUrl(): string + { + return $this->crawler->filterXPath('//a')->attr('href'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImageUrl(): string + { + return $this->crawler->filterXPath('//a/img')->attr('data-src'); + } +} diff --git a/src/Parser/Anime/VideosParser.php b/src/Parser/Anime/VideosParser.php new file mode 100644 index 00000000..2b4e9607 --- /dev/null +++ b/src/Parser/Anime/VideosParser.php @@ -0,0 +1,84 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Anime\StreamEpisodeListItem[] + * @throws \InvalidArgumentException + */ + public function getEpisodes(): array + { + $episodes = $this->crawler + ->filterXPath('//div[@class="js-video-list-content"]/div[contains(@class, "video-list-outer")]'); + + if (!$episodes->count()) { + return []; + } + + return $episodes + ->each( + function (Crawler $crawler) { + return (new StreamEpisodeListItemParser($crawler))->getModel(); + } + ); + } + + /** + * @return PromoListItem[] + * @throws \InvalidArgumentException + */ + public function getPromos(): array + { + $promos = $this->crawler + ->filterXPath('//div[contains(@class, "video-block promotional-video")]/section/div'); + + if (!$promos->count()) { + return []; + } + + + return $promos + ->each( + function (Crawler $crawler) { + return (new PromoListItemParser($crawler))->getModel(); + } + ); + } + + /** + * Return the model + * + * @throws \InvalidArgumentException + */ + public function getModel(): AnimeVideos + { + return AnimeVideos::fromParser($this); + } +} diff --git a/src/Parser/Character/AnimeographyParser.php b/src/Parser/Character/AnimeographyParser.php new file mode 100644 index 00000000..85179729 --- /dev/null +++ b/src/Parser/Character/AnimeographyParser.php @@ -0,0 +1,25 @@ +crawler = $crawler; + } + + /** + * @return VoiceActor[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getVoiceActors(): array + { + return $this->crawler->filterXPath('//table[2]/tr')->each( + function (Crawler $c) { + return (new VoiceActorParser($c))->getModel(); + } + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMalId(): int + { + return Parser::idFromUrl($this->getCharacterUrl()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getCharacterUrl(): string + { + return $this->crawler->filterXPath('//td[2]/a')->attr('href'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getName(): string + { + return $this->crawler->filterXPath('//td[2]/a')->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImage(): string + { + return $this->crawler->filterXPath('//img[1]')->attr('data-src'); + } + + /** + * @return \Jikan\Model\Character\CharacterListItem + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): CharacterListItem + { + return CharacterListItem::fromParser($this); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getRole(): string + { + //echo $this->crawler->filterXPath('//td[2]/div/small')->text(); + return $this->crawler->filterXPath('//td[2]/div/small')->text(); + } +} diff --git a/src/Parser/Character/CharacterParser.php b/src/Parser/Character/CharacterParser.php new file mode 100644 index 00000000..c871d447 --- /dev/null +++ b/src/Parser/Character/CharacterParser.php @@ -0,0 +1,182 @@ +crawler = $crawler; + } + + /** + * Return the model + * + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Model\Character\Character + { + return Model\Character\Character::fromParser($this); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMalId(): int + { + return Parser::idFromUrl($this->getCharacterUrl()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getCharacterUrl(): string + { + return $this->crawler->filterXPath('//meta[@property="og:url"]')->attr('content'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getName(): string + { + return $this->crawler->filterXPath('//meta[@property="og:title"]')->attr('content'); + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getNameKanji(): string + { + $kanji = $this->crawler->filterXPath('//div[contains(@class,"breadcrumb")]') + ->nextAll()->filter('small') + ->text(); + + return str_replace(['(', ')'], '', $kanji); + } + + /** + * @return string[] + * @throws \InvalidArgumentException + */ + public function getNameNicknames(): array + { + $aliases = preg_replace( + '/^.*"(.*)".*$/', + '$1', + $this->crawler->filterXPath('//h1')->text(), + -1, + $count + ); + if (!$count) { + return []; + } + + return explode(', ', $aliases); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getAbout(): string + { + $crawler = Parser::removeChildNodes($this->crawler->filterXPath('//*[@id="content"]/table/tr/td[2]')); + + return JString::cleanse($crawler->text()); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMemberFavorites(): int + { + $crawler = $this->crawler->filterXPath('//*[@id="content"]/table/tr/td[1]'); + $crawler = Parser::removeChildNodes($crawler); + + return (int)preg_replace('/\D/', '', $crawler->text()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImage(): string + { + return $this->crawler->filterXPath('//meta[@property="og:image"]')->attr('content'); + } + + /** + * @return \Jikan\Model\Character\Animeography[] + * @throws \InvalidArgumentException + */ + public function getAnimeography(): array + { + return $this->crawler + ->filterXPath('//div[contains(text(), \'Animeography\')]/../table[1]/tr') + ->each( + function (Crawler $c) { + return (new AnimeographyParser($c))->getModel(); + } + ); + } + + /** + * @return \Jikan\Model\Character\Mangaography[] + * @throws \InvalidArgumentException + */ + public function getMangaography(): array + { + return $this->crawler + ->filterXPath('//div[contains(text(), \'Mangaography\')]/../table[2]/tr') + ->each( + function (Crawler $c) { + return (new MangaographyParser($c))->getModel(); + } + ); + } + + /** + * @return \Jikan\Model\Character\VoiceActor[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getVoiceActors(): array + { + return $this->crawler + ->filterXPath('//div[contains(text(), \'Voice Actors\')]/../table/tr') + ->each( + function (Crawler $c) { + return (new VoiceActorParser($c))->getModel(); + } + ); + } +} diff --git a/src/Parser/Character/MangaographyParser.php b/src/Parser/Character/MangaographyParser.php new file mode 100644 index 00000000..e0da52c2 --- /dev/null +++ b/src/Parser/Character/MangaographyParser.php @@ -0,0 +1,25 @@ +crawler = $crawler; + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMalId(): int + { + return (int)preg_replace('#https://myanimelist.net/\w+/(\d+).*#', '$1', $this->getUrl()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getUrl(): string + { + return $this->crawler->filterXPath('//td/a')->attr('href'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getName(): string + { + return $this->crawler->filterXPath('//td/a')->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImage(): string + { + return $this->crawler->filterXPath('//img')->attr('src'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getRole(): string + { + return $this->crawler->filterXPath('//small')->last()->text(); + } +} diff --git a/src/Parser/Character/VoiceActorParser.php b/src/Parser/Character/VoiceActorParser.php new file mode 100644 index 00000000..cef6d2ab --- /dev/null +++ b/src/Parser/Character/VoiceActorParser.php @@ -0,0 +1,115 @@ +crawler = $crawler; + } + + /** + * Return the model + * + * @return \Jikan\Model\Character\VoiceActor + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Model\Character\VoiceActor + { + return Model\Character\VoiceActor::fromParser($this); + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getName(): string + { + return $this->crawler->filterXPath('//a') + ->reduce( + function (Crawler $crawler) { + return !$crawler->filter('img')->count(); + } + )->text(); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMalId(): int + { + return Helper\Parser::idFromUrl($this->getUrl()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getUrl(): string + { + return $this->crawler->filterXPath('//a')->attr('href'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImage(): string + { + + $img = $this->crawler->filterXPath('//img'); + + return $img->attr('src') ?? $img->attr('data-src'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getLanguage(): string + { + return $this->crawler->filterXPath('//small')->last()->text(); + } + + /** + * @return \Jikan\Model\Common\MalUrl + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getPerson(): Model\Common\MalUrl + { + return (new MalUrlParser( + $this->crawler->filterXPath('//a') + ->reduce( + function (Crawler $crawler) { + return !$crawler->filter('img')->count(); + } + ) + ))->getModel(); + } +} diff --git a/src/Parser/Common/AnimeCardParser.php b/src/Parser/Common/AnimeCardParser.php new file mode 100644 index 00000000..fc649043 --- /dev/null +++ b/src/Parser/Common/AnimeCardParser.php @@ -0,0 +1,293 @@ +crawler = $crawler; + } + + /** + * @return Model\Common\AnimeCard + */ + public function getModel(): Model\Common\AnimeCard + { + return Model\Common\AnimeCard::parseAnimeCard($this); + } + + /** + * @return \Jikan\Model\Seasonal\SeasonalAnime + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getSeasonalModel(): Model\Seasonal\SeasonalAnime + { + return Model\Seasonal\SeasonalAnime::parseSeasonalAnime($this); + } + + /** + * @return int + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getMalId(): int + { + return Parser::idFromUrl($this->getAnimeUrl()); + } + + /** + * @return string + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getAnimeUrl(): string + { + return $this->crawler->filterXPath('//div[contains(@class, "title")]/p/a')->attr('href'); + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getProducer(): array + { + return $this->crawler + ->filterXPath('//span[contains(@class, "producer")]/a') + ->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + /** + * @return int|null + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getEpisodes(): ?int + { + + $eps = $this->crawler->filterXPath('//div[contains(@class, "eps")]')->text(); + $eps = JString::cleanse($eps); + str_replace(' eps', '', $eps); + + return $eps === '?' ? null : (int)$eps; + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getSource(): string + { + return $this->crawler->filterXPath('//span[contains(@class, "source")]')->text(); + } + + /** + * @return array|\Jikan\Model\Common\MalUrl[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getGenres(): array + { + return $this->crawler->filterXPath('//span[contains(@class, "genre")]/a') + ->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getDescription(): string + { + return $this->crawler->filterXPath('//div[contains(@class, "synopsis")]/span')->text(); + } + + /** + * @return string|null + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getType(): ?string + { + $text = $this->crawler->filterXPath('//div[contains(@class, "info")]'); + + if (!$text->count()) { + return null; + } + + $text = JString::cleanse($text->text()); + preg_match('/^([\w\.]+)/', $text, $matches); + + return $matches[1]; + } + + /** + * @return \DateTimeImmutable|null ?\DateTimeImmutable + * @throws \InvalidArgumentException + */ + public function getAirDates(): ?\DateTimeImmutable + { + $date = str_replace( + '(JST)', + '', + JString::cleanse($this->crawler->filterXPath('//span[contains(@class, "remain-time")]')->text()) + ); + + try { + return (new \DateTimeImmutable($date, new \DateTimeZone('JST'))) + ->setTimezone(new \DateTimeZone('UTC')); + } catch (\Exception $e) { + return null; + } + } + + /** + * @return int + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getMembers(): int + { + $count = $this->crawler->filterXPath('//div[contains(@class, "scormem")]/span')->text(); + $count = JString::cleanse($count); + + return (int)str_replace(',', '', $count); + } + + /** + * @return \Jikan\Model\Common\AnimeMeta + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getAnimeMeta(): Model\Common\AnimeMeta + { + return new Model\Common\AnimeMeta( + $this->getTitle(), + $this->getAnimeUrl(), + $this->getAnimeImage() + ); + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getTitle(): string + { + return $this->crawler->filterXPath('//p[contains(@class,"title-text")]/a')->text(); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getAnimeImage(): ?string + { + //bypass lazyloading + $image = $this->crawler->filterXPath('//div[contains(@class, "image")]/img')->first()->attr('src'); + + if (null !== $image) { + return $image; + } + + return $this->crawler->filterXPath('//div[contains(@class, "image")]/img')->first()->attr('data-src'); + } + + /** + * @return float|null + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getAnimeScore(): ?float + { + $score = JString::cleanse($this->crawler->filterXPath('//span[contains(@class, "score")]')->text()); + if ($score === 'N/A') { + return null; + } + + return (float)$score; + } + + /** + * @return string[] + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getLicensors(): array + { + $licensors = $this->crawler->filterXPath('//p[contains(@class, "licensors")]'); + + if (!$licensors->count()) { + return []; + } + $licensors = JString::cleanse($licensors->attr('data-licensors')); + $licensors = explode(',', $licensors); + + return array_filter($licensors); + } + + /** + * @return bool + * @throws \InvalidArgumentException + */ + public function isR18(): bool + { + $classes = explode(' ', $this->crawler->attr('class')); + + return \in_array('r18', $classes, true); + } + + /** + * @return bool + * @throws \InvalidArgumentException + */ + public function isKids(): bool + { + $classes = explode(' ', $this->crawler->attr('class')); + + return \in_array('kids', $classes, true); + } + + /** + * @return bool + * @throws \InvalidArgumentException + */ + public function isContinuing(): bool + { + return strpos($this->crawler->parents()->text(), '(Continuing)') !== false; + } +} diff --git a/src/Parser/Common/ItemMetaParser.php b/src/Parser/Common/ItemMetaParser.php new file mode 100644 index 00000000..edf36437 --- /dev/null +++ b/src/Parser/Common/ItemMetaParser.php @@ -0,0 +1,64 @@ +crawler = $crawler; + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getMalId(): ?int + { + return (int)preg_replace('#https://myanimelist.net/\w+/(\d+).*#', '$1', $this->getUrl()); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getUrl(): ?string + { + return $this->crawler->filterXPath('//a')->attr('href'); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getName(): ?string + { + return $this->crawler->filterXPath('//a')->text(); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getImage(): ?string + { + return $this->crawler->filterXPath('//img')->attr('data-src'); + } +} diff --git a/src/Parser/Common/MalUrlParser.php b/src/Parser/Common/MalUrlParser.php new file mode 100644 index 00000000..074b8b62 --- /dev/null +++ b/src/Parser/Common/MalUrlParser.php @@ -0,0 +1,44 @@ +crawler = $crawler; + } + + /** + * @return MalUrl + * @throws \InvalidArgumentException + */ + public function getModel(): MalUrl + { + $href = $this->crawler->attr('href'); + $href = str_replace('https://myanimelist.net', '', $href); + + return new MalUrl( + $this->crawler->text(), + 'https://myanimelist.net'.$href + ); + } +} diff --git a/src/Parser/Common/MangaCardParser.php b/src/Parser/Common/MangaCardParser.php new file mode 100644 index 00000000..2344a83f --- /dev/null +++ b/src/Parser/Common/MangaCardParser.php @@ -0,0 +1,238 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Common\MangaCard + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Model\Common\MangaCard + { + return Model\Common\MangaCard::parseMangaCard($this); + } + + /** + * @return int + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getMalId(): int + { + return Parser::idFromUrl($this->getMangaUrl()); + } + + /** + * @return string + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getMangaUrl(): string + { + return $this->crawler->filterXPath('//div[contains(@class, "title")]/p/a')->attr('href'); + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getAuthor(): array + { + return $this->crawler + ->filterXPath('//span[contains(@class, "producer")]/a') + ->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + /** + * @return int|null + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getVolumes(): ?int + { + + $eps = $this->crawler->filterXPath('//div[contains(@class, "eps")]')->text(); + $eps = JString::cleanse($eps); + str_replace(' eps', '', $eps); + + return $eps === '?' ? null : (int)$eps; + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getType(): string + { + return JString::cleanse($this->crawler->filterXPath('//span[contains(@class, "source")]')->text()); + } + + /** + * @return array|\Jikan\Model\Common\MalUrl[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getGenres(): array + { + return $this->crawler->filterXPath('//span[contains(@class, "genre")]/a') + ->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getDescription(): string + { + return $this->crawler->filterXPath('//div[contains(@class, "synopsis")]/span')->text(); + } + + /** + * @return \DateTimeImmutable|null ?\DateTimeImmutable + * @throws \InvalidArgumentException + */ + public function getPublishDates(): ?\DateTimeImmutable + { + $date = str_replace( + '(JST)', + '', + JString::cleanse($this->crawler->filterXPath('//span[contains(@class, "remain-time")]')->text()) + ); + + try { + return (new \DateTimeImmutable($date, new \DateTimeZone('JST'))) + ->setTimezone(new \DateTimeZone('UTC')) + ->setTime(0, 0); + } catch (\Exception $e) { + return null; + } + } + + /** + * @return int + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getMembers(): int + { + $count = $this->crawler->filterXPath('//div[contains(@class, "scormem")]/span')->text(); + $count = JString::cleanse($count); + + return (int)str_replace(',', '', $count); + } + + /** + * @return \Jikan\Model\Common\MangaMeta + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getMangaMeta(): Model\Common\MangaMeta + { + return new Model\Common\MangaMeta( + $this->getTitle(), + $this->getMangaUrl(), + $this->getMangaImage() + ); + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getTitle(): string + { + return $this->crawler->filterXPath('//p[contains(@class,"title-text")]/a')->text(); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getMangaImage(): ?string + { + //bypass lazyloading + $image = $this->crawler->filterXPath('//div[contains(@class, "image")]/img')->first()->attr('src'); + + if (null !== $image) { + return $image; + } + + return $this->crawler->filterXPath('//div[contains(@class, "image")]/img')->first()->attr('data-src'); + } + + /** + * @return float|null + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getMangaScore(): ?float + { + $score = JString::cleanse($this->crawler->filterXPath('//span[contains(@class, "score")]')->text()); + if ($score === 'N/A') { + return null; + } + + return (float)$score; + } + + /** + * @return null|string[] + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getSerialization(): ?array + { + $serialization = $this->crawler->filterXPath('//p[contains(@class, "serialization")]/a'); + + if (!$serialization->count()) { + return []; + } + + return $serialization->each( + function (Crawler $c) { + return $c->text(); + } + ); + } +} diff --git a/src/Parser/Common/PictureParser.php b/src/Parser/Common/PictureParser.php new file mode 100644 index 00000000..691489a1 --- /dev/null +++ b/src/Parser/Common/PictureParser.php @@ -0,0 +1,57 @@ +crawler = $crawler; + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getLarge(): string + { + return $this->crawler->filterXPath('//a')->attr('href'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getSmall(): string + { + return $this->crawler->filterXPath('//img')->attr('src'); + } + + /** + * @return Picture + * @throws \InvalidArgumentException + */ + public function getModel(): Picture + { + return Picture::fromParser($this); + } +} diff --git a/src/Parser/Common/PicturesPageParser.php b/src/Parser/Common/PicturesPageParser.php new file mode 100644 index 00000000..610aaa65 --- /dev/null +++ b/src/Parser/Common/PicturesPageParser.php @@ -0,0 +1,45 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Common\Picture[] + * @throws \InvalidArgumentException + */ + public function getModel(): array + { + return $this->crawler + ->filterXPath('//a[@class="js-picture-gallery"]') + ->each( + function (Crawler $crawler) { + return Picture::fromParser(new PictureParser($crawler)); + } + ); + } +} diff --git a/src/Parser/Forum/ForumPageParser.php b/src/Parser/Forum/ForumPageParser.php new file mode 100644 index 00000000..8b6bbe89 --- /dev/null +++ b/src/Parser/Forum/ForumPageParser.php @@ -0,0 +1,44 @@ +crawler = $crawler; + } + + /** + * @return ForumTopic[] + * @throws \InvalidArgumentException + */ + public function getTopics(): array + { + return $this->crawler + ->filterXPath('//tr[contains(@id, "topicRow")]') + ->each( + function (Crawler $crawler) { + return ForumTopic::fromParser(new ForumTopicParser($crawler)); + } + ); + } +} diff --git a/src/Parser/Forum/ForumTopicParser.php b/src/Parser/Forum/ForumTopicParser.php new file mode 100644 index 00000000..a93b0927 --- /dev/null +++ b/src/Parser/Forum/ForumTopicParser.php @@ -0,0 +1,115 @@ +crawler = $crawler; + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getTopicId(): int + { + $query = parse_query(explode('?', $this->getUrl())[1]); + + return (int)$query['topicid']; + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getUrl(): string + { + return Constants::BASE_URL.$this->crawler->filterXPath('//a[2]')->attr('href'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getTitle(): string + { + return $this->crawler->filterXPath('//a[2]')->text(); + } + + /** + * @return \DateTimeImmutable + * @throws \InvalidArgumentException + */ + public function getPostDate(): \DateTimeImmutable + { + return Parser::parseForumDate($this->crawler->filterXPath('//td[2]/span[@class="lightLink"]')->text()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getAuthorName(): string + { + return $this->crawler->filterXPath('//span[@class="forum_postusername"]/a')->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getAuthorUrl(): string + { + return Constants::BASE_URL.$this->crawler->filterXPath('//span[@class="forum_postusername"]/a')->attr('href'); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getReplies(): int + { + return (int)$this->crawler->filterXPath('//td[3]')->text(); + } + + /** + * @return ForumPost + * @throws \InvalidArgumentException + */ + public function getLastPost(): ForumPost + { + $authorName = $this->crawler->filterXPath('//td[4]/a[1]')->text(); + $authorUrl = Constants::BASE_URL.$this->crawler->filterXPath('//td[4]/a[1]')->attr('href'); + $url = Constants::BASE_URL.$this->crawler->filterXPath('//td[4]/a[2]')->attr('href'); + $date = Parser::removeChildNodes($this->crawler->filterXPath('//td[4]'))->text(); + $date = JString::cleanse($date); + $date = str_replace('by ', '', $date); + $date = Parser::parseDate($date); + + return new ForumPost($url, $authorName, $authorUrl, $date); + } +} diff --git a/src/Parser/Genre/AnimeGenreParser.php b/src/Parser/Genre/AnimeGenreParser.php new file mode 100644 index 00000000..a3ef7f85 --- /dev/null +++ b/src/Parser/Genre/AnimeGenreParser.php @@ -0,0 +1,105 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Genre\AnimeGenre + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Model\Genre\AnimeGenre + { + return Model\Genre\AnimeGenre::fromParser($this); + } + + /** + * @return array|\Jikan\Model\Genre\AnimeGenre[] + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getGenreAnime(): array + { + return $this->crawler + ->filter('div.seasonal-anime') + ->each( + function (Crawler $animeCrawler) { + return (new AnimeCardParser($animeCrawler))->getModel(); + } + ); + } + + /** + * @return int + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getMalId(): int + { + return (int)preg_replace('#https://myanimelist.net(/\w+/\w+/)(\d+).*#', '$2', $this->getUrl()); + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getUrl(): string + { + return $this->crawler->filterXPath('//meta[@property="og:url"]')->attr('content'); + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getName(): string + { + return JString::cleanse( + Parser::removeChildNodes($this->crawler->filterXPath('//span[@class=\'di-ib mt4\']'))->text() + ); + } + + /** + * @return int + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getCount(): int + { + return (int)preg_replace( + '/\D/', + '', + $this->crawler->filterXPath('//span[@class=\'di-ib mt4\']/span')->text() + ); + } +} diff --git a/src/Parser/Genre/MangaGenreParser.php b/src/Parser/Genre/MangaGenreParser.php new file mode 100644 index 00000000..5e79fada --- /dev/null +++ b/src/Parser/Genre/MangaGenreParser.php @@ -0,0 +1,105 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Genre\MangaGenre + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Model\Genre\MangaGenre + { + return Model\Genre\MangaGenre::fromParser($this); + } + + /** + * @return array|\Jikan\Model\Genre\MangaGenre[] + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getGenreManga(): array + { + return $this->crawler + ->filter('div.seasonal-anime') + ->each( + function (Crawler $MangaCrawler) { + return (new MangaCardParser($MangaCrawler))->getModel(); + } + ); + } + + /** + * @return int + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getMalId(): int + { + return (int)preg_replace('#https://myanimelist.net(/\w+/\w+/)(\d+).*#', '$2', $this->getUrl()); + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getUrl(): string + { + return $this->crawler->filterXPath('//meta[@property="og:url"]')->attr('content'); + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getName(): string + { + return JString::cleanse( + Parser::removeChildNodes($this->crawler->filterXPath('//span[@class=\'di-ib mt4\']'))->text() + ); + } + + /** + * @return int + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getCount(): int + { + return (int)preg_replace( + '/\D/', + '', + $this->crawler->filterXPath('//span[@class=\'di-ib mt4\']/span')->text() + ); + } +} diff --git a/src/Parser/Magazine/MagazineParser.php b/src/Parser/Magazine/MagazineParser.php new file mode 100644 index 00000000..bad51e04 --- /dev/null +++ b/src/Parser/Magazine/MagazineParser.php @@ -0,0 +1,74 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Magazine\Magazine + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Model\Magazine\Magazine + { + return Model\Magazine\Magazine::fromParser($this); + } + + /** + * @return array|\Jikan\Model\Magazine\MagazineManga[] + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getMagazineManga(): array + { + return $this->crawler + ->filter('div.seasonal-anime') + ->each( + function (Crawler $MangaCrawler) { + return (new MangaCardParser($MangaCrawler))->getModel(); + } + ); + } + + /** + * @return \Jikan\Model\Common\MalUrl + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getUrl(): Model\Common\MalUrl + { + return new Model\Common\MalUrl( + JString::cleanse( + Parser::removeChildNodes($this->crawler->filterXPath('//span[@class=\'di-ib mt4\']'))->text() + ), + $this->crawler->filterXPath('//meta[@property="og:url"]')->attr('content') + ); + } +} diff --git a/src/Parser/Manga/CharactersParser.php b/src/Parser/Manga/CharactersParser.php new file mode 100644 index 00000000..ea4091e4 --- /dev/null +++ b/src/Parser/Manga/CharactersParser.php @@ -0,0 +1,52 @@ +crawler = $crawler; + } + + /** + * @return CharacterListItem[] + * @throws \InvalidArgumentException + */ + public function getCharacters(): array + { + return $this->crawler + ->filterXPath('//h2[text()="Characters"]/following-sibling::table') + ->reduce( + function (Crawler $crawler) { + return (bool)$crawler->filterXPath( + '//a[contains(@href, "https://myanimelist.net/character")]' + )->count(); + } + ) + ->each( + function (Crawler $crawler) { + return CharacterListItem::fromParser(new CharacterListItemParser($crawler)); + } + ); + } +} diff --git a/src/Parser/Manga/MangaParser.php b/src/Parser/Manga/MangaParser.php new file mode 100644 index 00000000..76f37a22 --- /dev/null +++ b/src/Parser/Manga/MangaParser.php @@ -0,0 +1,473 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Manga\Manga + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Manga + { + return Manga::fromParser($this); + } + + /** + * @return int + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getMangaId(): int + { + preg_match('#https?://myanimelist.net/manga/(\d+)#', $this->getMangaURL(), $matches); + + return (int)$matches[1]; + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getMangaURL(): string + { + return $this->crawler->filterXPath('//meta[@property=\'og:url\']')->attr('content'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getMangaTitle(): string + { + return $this->crawler->filterXPath('//meta[@property=\'og:title\']')->attr('content'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getMangaImageURL(): string + { + return $this->crawler->filterXPath('//meta[@property=\'og:image\']')->attr('content'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getMangaSynopsis(): string + { + return JString::cleanse( + $this->crawler->filterXPath('//meta[@property=\'og:description\']')->attr('content') + ); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getMangaTitleEnglish(): ?string + { + $title = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="English:"]'); + if (!$title->count()) { + return null; + } + + return JString::cleanse( + str_replace($title->text(), '', $title->parents()->text()) + ); + } + + /** + * @return string[] + * @throws \InvalidArgumentException + */ + public function getMangaTitleSynonyms(): array + { + $title = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="Synonyms:"]'); + + if (!$title->count()) { + return []; + } + + $titles = str_replace($title->text(), '', $title->parents()->text()); + $titles = explode(',', $titles); + + foreach ($titles as &$title) { + $title = JString::cleanse($title); + } + + return $titles; + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getMangaTitleJapanese(): ?string + { + $title = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="Japanese:"]'); + if (!$title->count()) { + return null; + } + + return JString::cleanse( + str_replace($title->text(), '', $title->parents()->text()) + ); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getMangaType(): ?string + { + $type = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="Type:"]'); + if (!$type->count()) { + return null; + } + + return JString::cleanse( + str_replace($type->text(), '', $type->parents()->text()) + ); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getMangaChapters(): ?int + { + $chapters = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="Chapters:"]'); + + if (!$chapters->count()) { + return null; + } + + return (str_replace($chapters->text(), '', $chapters->parents()->text()) === 'Unknown') ? 0 : (int)str_replace( + $chapters->text(), + '', + $chapters->parents()->text() + ); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getMangaVolumes(): ?int + { + $chapters = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="Volumes:"]'); + + if (!$chapters->count()) { + return null; + } + + return (str_replace($chapters->text(), '', $chapters->parents()->text()) === 'Unknown') ? 0 : (int)str_replace( + $chapters->text(), + '', + $chapters->parents()->text() + ); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getMangaStatus(): ?string + { + $status = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="Status:"]'); + if (!$status->count()) { + return null; + } + + return JString::cleanse( + str_replace($status->text(), '', $status->parents()->text()) + ); + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getMangaAuthors(): array + { + return $this->crawler + ->filterXPath('//span[text()="Authors:"]/following-sibling::a') + ->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + /** + * @return MalUrl[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getMangaSerialization(): array + { + return $this->crawler + ->filterXPath('//span[text()="Serialization:"]/following-sibling::a')->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + /** + * @return MalUrl[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getMangaGenre(): array + { + return $this->crawler + ->filterXPath('//span[text()="Genres:"]/following-sibling::a')->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + /** + * @return float + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getMangaScore(): ?float + { + $score = $this->crawler + ->filter('span[itemprop="ratingValue"]'); + + if (!$score->count()) { + return null; + } + + if (strpos($score->text(), 'N/A')) { + return null; + } + + return (float)$score->text(); + } + + /** + * @return int + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getMangaScoredBy(): ?int + { + $scoredBy = $this->crawler + ->filter('span[itemprop="ratingCount"]'); + + if (!$scoredBy->count()) { + return null; + } + + return (int)$scoredBy->text(); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMangaRank(): ?int + { + $rank = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="Ranked:"]'); + + if (!$rank->count()) { + return null; + } + + $rank = Parser::removeChildNodes($rank->parents()); + $ranked = trim( + str_replace( + '#', + '', + $rank->text() + ) + ); + + return $ranked !== 'N/A' ? (int)$ranked : null; + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMangaPopularity(): ?int + { + $popularity = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="Popularity:"]'); + + if (!$popularity->count()) { + return null; + } + + return JString::cleanse( + str_replace([$popularity->text(), '#'], '', $popularity->parents()->text()) + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMangaMembers(): ?int + { + $member = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="Members:"]'); + + if (!$member->count()) { + return null; + } + + return JString::cleanse( + str_replace([$member->text(), ','], '', $member->parents()->text()) + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMangaFavorites(): ?int + { + $favorite = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="Favorites:"]'); + + if (!$favorite->count()) { + return null; + } + + return JString::cleanse( + str_replace([$favorite->text(), ','], '', $favorite->parents()->text()) + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getMangaRelated(): array + { + $related = []; + $this->crawler + ->filterXPath('//table[contains(@class, "anime_detail_related_anime")]/tr') + ->each( + function (Crawler $c) use (&$related) { + $related[JString::cleanse( + str_replace(':', '', $c->filterXPath('//td[1]')->text()) + )] = $c->filterXPath('//td[2]/a') + ->each( + function (Crawler $c) { + return (new MalUrlParser($c))->getModel(); + } + ); + } + ); + + return $related; + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getMangaBackground(): ?string + { + $background = Parser::removeChildNodes($this->crawler->filterXPath('//span[@itemprop="description"]/..')); + if (!$background->count()) { + return null; + } + $background = $background->text(); + if (preg_match('~No background information has been added to this title~', $background)) { + return null; + } + + return JString::cleanse($background); + } + + /** + * @return DateRange + * @throws \InvalidArgumentException + */ + public function getPublished(): DateRange + { + return new DateRange($this->getMangaPublishedString()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getMangaPublishedString(): ?string + { + $aired = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filterXPath('//span[text()="Published:"]'); + + if (!$aired->count()) { + return null; + } + + return JString::cleanse( + str_replace($aired->text(), '', $aired->parents()->text()) + ); + } +} diff --git a/src/Parser/Manga/MangaStatsParser.php b/src/Parser/Manga/MangaStatsParser.php new file mode 100644 index 00000000..ffa5db01 --- /dev/null +++ b/src/Parser/Manga/MangaStatsParser.php @@ -0,0 +1,167 @@ +crawler = $crawler; + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getReading(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'Reading:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @param $input + * + * @return int + */ + private function sanitize($input): int + { + return (int)preg_replace('/\D/', '', $input); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getCompleted(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'Completed:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getOnHold(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'On-Hold:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getDropped(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'Dropped:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getPlanToRead(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'Plan to Read:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getTotal(): int + { + return $this->sanitize( + $this->crawler + ->filterXPath('//div[@class="spaceit_pad"]/span[contains(text(), \'Total:\')]') + ->parents() + ->getNode(0)->textContent + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getScores(): array + { + $table = $this->crawler->filterXPath('//h2[text()="Score Stats"]/following-sibling::table'); + $voteCounts = $table->filterXPath('//small[contains(text(), \'votes\')]'); + + $scores = []; + $score = 10; + + $voteCounts->each( + function (Crawler $crawler) use (&$scores, &$score) { + $scores[$score] = [ + 'votes' => $this->sanitize($crawler->text()), + 'percentage' => (double)preg_replace( + '/[^0-9,.]/', + '', + substr( + $completeText = $crawler->parents()->getNode(0)->textContent, + 0, + strpos($completeText, '%') + ) + ), + ]; + + $score--; + } + ); + + return $scores; + } + + /** + * @return MangaStats + * @throws \InvalidArgumentException + */ + public function getModel(): MangaStats + { + return MangaStats::fromParser($this); + } +} diff --git a/src/Parser/Manga/MoreInfoParser.php b/src/Parser/Manga/MoreInfoParser.php new file mode 100644 index 00000000..8b0b0c5c --- /dev/null +++ b/src/Parser/Manga/MoreInfoParser.php @@ -0,0 +1,62 @@ +crawler = $crawler; + } + + /** + * Return the model + * + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): MangaMoreInfo + { + return MangaMoreInfo::fromParser($this); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getMoreInfo(): ?string + { + $moreinfo = JString::cleanse( + Parser::removeChildNodes( + $this->crawler->filterXPath('//div[@class="js-scrollfix-bottom-rel"]') + )->text() + ); + + if (empty($moreinfo)) { + return null; + } + + return $moreinfo; + } +} diff --git a/src/Parser/News/NewsListItemParser.php b/src/Parser/News/NewsListItemParser.php new file mode 100644 index 00000000..e7c8a131 --- /dev/null +++ b/src/Parser/News/NewsListItemParser.php @@ -0,0 +1,113 @@ +crawler = $crawler; + } + + /** + * @return NewsListItem + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): NewsListItem + { + return NewsListItem::fromParser($this); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getTitle(): string + { + return $this->crawler->filterXPath('//p/a/strong')->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getUrl(): string + { + return Constants::BASE_URL.$this->crawler->filterXPath('//p/a/strong/..')->attr('href'); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getImage(): ?string + { + $image = $this->crawler->filterXPath('//img[1]'); + + if (!$image->count()) { + return null; + } + + return $image->attr('data-src'); + } + + /** + * @return \DateTimeImmutable + * @throws \InvalidArgumentException + */ + public function getDate(): ?\DateTimeImmutable + { + return Parser::parseDate(explode(' by', $this->crawler->filterXPath('//p[last()]')->text())[0]); + } + + /** + * @return MalUrl + * @throws \InvalidArgumentException + */ + public function getAuthor(): MalUrl + { + return (new MalUrlParser($this->crawler->filterXPath('//a[contains(@href, "profile")][1]')))->getModel(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getDiscussionLink(): string + { + return Constants::BASE_URL.$this->crawler->filterXPath('//a[last()]')->attr('href'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getIntro(): string + { + return Parser::removeChildNodes($this->crawler->filterXPath('//p[2]'))->text(); + } +} diff --git a/src/Parser/News/NewsListParser.php b/src/Parser/News/NewsListParser.php new file mode 100644 index 00000000..1fb806b6 --- /dev/null +++ b/src/Parser/News/NewsListParser.php @@ -0,0 +1,46 @@ +crawler = $crawler; + } + + /** + * @return NewsListItem[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): array + { + return $this->crawler + ->filterXPath('//div[@class="js-scrollfix-bottom-rel"]/div[@class="clearfix"]') + ->each( + function (Crawler $crawler) { + return (new NewsListItemParser($crawler))->getModel(); + } + ); + } +} diff --git a/src/Parser/ParserInterface.php b/src/Parser/ParserInterface.php new file mode 100644 index 00000000..a84deb84 --- /dev/null +++ b/src/Parser/ParserInterface.php @@ -0,0 +1,16 @@ +crawler = $crawler; + } + + /** + * Return the model + * + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Model\Person\AnimeStaffPosition + { + return Model\Person\AnimeStaffPosition::fromParser($this); + } + + /** + * @return string + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getPosition(): string + { + return JString::cleanse( + $this->crawler + ->filterXPath('//small') + ->text() + ); + } + + /** + * @return \Jikan\Model\Common\AnimeMeta + * @throws \InvalidArgumentException + */ + public function getAnimeMeta(): Model\Common\AnimeMeta + { + return new Model\Common\AnimeMeta( + $this->crawler->filterXPath('//td[position() = 2]/a')->text(), + $this->crawler->filterXPath('//td[position() = 2]/a')->attr('href'), + $this->crawler->filterXPath('//td[position() = 1]/div/a/img')->attr('data-src') + ); + } +} diff --git a/src/Parser/Person/PersonParser.php b/src/Parser/Person/PersonParser.php new file mode 100644 index 00000000..aeced0f7 --- /dev/null +++ b/src/Parser/Person/PersonParser.php @@ -0,0 +1,328 @@ +crawler = $crawler; + } + + /** + * Return the model + * + * @throws \RuntimeException + * @throws \InvalidArgumentException + * @throws \Exception + * @throws \Exception + */ + public function getModel(): Model\Person\Person + { + return Model\Person\Person::fromParser($this); + } + + + /** + * @return int + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getPersonId(): int + { + preg_match('#https?://myanimelist.net/people/(\d+)#', $this->getPersonURL(), $matches); + + return (int)$matches[1]; + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getPersonURL(): string + { + return $this->crawler->filterXPath('//meta[@property=\'og:url\']')->attr('content'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getPersonName(): string + { + return JString::cleanse($this->crawler->filterXPath('//meta[@property=\'og:title\']')->attr('content')); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getPersonImageUrl(): string + { + return $this->crawler->filterXPath('//meta[@property=\'og:image\']')->attr('content'); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getPersonGivenName(): ?string + { + $node = $this->crawler + ->filterXPath('//span[text()="Given name:"]'); + + if (!$node->count()) { + return null; + } + + return JString::cleanse( + str_replace($node->text(), '', $node->parents()->text()) + ); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getPersonFamilyName(): ?string + { + $node = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]/span[text()="Family name:"]'); + + if (!$node->count()) { + return null; + } + + // MAL screwed up the HTML here + preg_match( + '~Family name:(.*?)(Alternate names|Birthday|Website|Member Favorites|More)~', + $node->parents()->text(), + $matches + ); + + if (empty($matches)) { + return null; + } + + $familyName = JString::cleanse($matches[1]); + + if (empty($familyName)) { // MAL has it empty at some places + return null; + } + + return $familyName; + } + + /** + * @return array|null + * @throws \InvalidArgumentException + */ + public function getPersonAlternateNames(): array + { + $node = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]/div/span[text()="Alternate names:"]'); + + if (!$node->count()) { + return []; + } + + $names = explode( + ',', + str_replace($node->text(), '', $node->parents()->text()) + ); + + foreach ($names as &$name) { + $name = JString::cleanse($name); + } + + return $names; + } + + /** + * @return string|null + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getPersonWebsite(): ?string + { + $node = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]/span[text()="Website:"]'); + + + $website = $node->nextAll()->filter('a'); + + if (!$website->count()) { + return null; + } + + // MAL returns an empty `` when there's no website + if (empty($website->text())) { + return null; + } + + + return $website->attr('href'); + } + + /** + * @return \DateTimeImmutable|null + * @throws \RuntimeException + * @throws \InvalidArgumentException + * @throws \Exception + */ + public function getPersonBirthday(): ?\DateTimeImmutable + { + $node = $this->crawler + ->filterXPath('//span[text()="Birthday:"]'); + + if (!$node->count()) { + return null; + } + + return Parser::parseDateMDYReadable( + JString::cleanse( + str_replace($node->text(), '', $node->parents()->text()) + ) + ); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getPersonFavorites(): ?int + { + $node = $this->crawler + ->filterXPath('//span[text()="Member Favorites:"]'); + + + if (!$node->count()) { + return null; + } + + return (int)JString::cleanse( + str_replace([$node->text(), ','], '', $node->parents()->text()) + ); + } + + /** + * @return string|null + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getPersonAbout(): ?string + { + $node = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[@class="borderClass"]') + ->filter('.people-informantion-more'); + + if (!$node->count()) { + return null; + } + + if (empty($node->text())) { + return null; + } + + return JString::cleanse( + $node->html() + ); + } + + + /** + * @return \Jikan\Model\Person\VoiceActingRole[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getPersonVoiceActingRoles(): array + { + $node = $this->crawler + ->filterXPath('//div[contains(text(), \'Voice Acting Roles\')]'); + + if (strpos($node->parents()->text(), 'No voice acting roles have been added to this person.')) { + return []; + } + + if (!$node->count()) { + return []; + } + + return $node->nextAll()->children()->each( + function (Crawler $c) { + return (new VoiceActingRoleParser($c))->getModel(); + } + ); + } + + /** + * @return \Jikan\Model\Person\AnimeStaffPosition[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getPersonAnimeStaffPositions(): array + { + $node = $this->crawler + ->filterXPath('//div[contains(text(), \'Anime Staff Positions\')]'); + + if (strpos($node->parents()->text(), 'No staff positions have been added to this person.')) { + return []; + } + + if (!$node->count()) { + return []; + } + + return $node->nextAll()->children()->each( + function (Crawler $c) { + return (new AnimeStaffPositionParser($c))->getModel(); + } + ); + } + + /** + * @return \Jikan\Model\Person\PublishedManga[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getPersonPublishedManga(): array + { + $node = $this->crawler + ->filterXPath('//div[contains(text(), \'Published Manga\')]'); + + if (strpos($node->parents()->text(), 'No published manga have been added to this person.')) { + return []; + } + + if (!$node->count()) { + return []; + } + + return $node->nextAll()->children()->each( + function (Crawler $c) { + return (new PublishedMangaParser($c))->getModel(); + } + ); + } +} diff --git a/src/Parser/Person/PublishedMangaParser.php b/src/Parser/Person/PublishedMangaParser.php new file mode 100644 index 00000000..4f4035e1 --- /dev/null +++ b/src/Parser/Person/PublishedMangaParser.php @@ -0,0 +1,69 @@ +crawler = $crawler; + } + + /** + * Return the model + * + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getModel(): Model\Person\PublishedManga + { + return Model\Person\PublishedManga::fromParser($this); + } + + /** + * @return string + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getPosition(): string + { + return JString::cleanse( + $this->crawler + ->filterXPath('//small') + ->text() + ); + } + + /** + * @return \Jikan\Model\Common\MangaMeta + * @throws \InvalidArgumentException + */ + public function getMangaMeta(): Model\Common\MangaMeta + { + return new Model\Common\MangaMeta( + $this->crawler->filterXPath('//td[position() = 2]/a')->text(), + $this->crawler->filterXPath('//td[position() = 2]/a')->attr('href'), + $this->crawler->filterXPath('//td[position() = 1]/div/a/img')->attr('data-src') + ); + } +} diff --git a/src/Parser/Person/VoiceActingRoleParser.php b/src/Parser/Person/VoiceActingRoleParser.php new file mode 100644 index 00000000..af16192b --- /dev/null +++ b/src/Parser/Person/VoiceActingRoleParser.php @@ -0,0 +1,88 @@ +crawler = $crawler; + } + + /** + * Return the model + * + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getModel(): Model\Person\VoiceActingRole + { + return Model\Person\VoiceActingRole::fromParser($this); + } + + + /** + * @return string + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getRole(): ?string + { + $role = $this->crawler + ->filterXPath('//td[3]/div') + ->text(); + + return JString::UTF8NbspTrim( + JString::cleanse( + $role + ) + ); + } + + /** + * @return \Jikan\Model\Common\AnimeMeta + * @throws \InvalidArgumentException + */ + public function getAnimeMeta(): Model\Common\AnimeMeta + { + return new Model\Common\AnimeMeta( + $this->crawler->filterXPath('//td[position() = 2]/a')->text(), + $this->crawler->filterXPath('//td[position() = 2]/a')->attr('href'), + $this->crawler->filterXPath('//td[position() = 1]/div/a/img')->attr('data-src') + ); + } + + + /** + * @return \Jikan\Model\Common\CharacterMeta + * @throws \InvalidArgumentException + */ + public function getCharacterMeta(): Model\Common\CharacterMeta + { + return new Model\Common\CharacterMeta( + $this->crawler->filterXPath('//td[position() = 3]/a')->text(), + $this->crawler->filterXPath('//td[position() = 3]/a')->attr('href'), + $this->crawler->filterXPath('//td[position() = 4]/div/a/img')->attr('data-src') + ); + } +} diff --git a/src/Parser/Producer/ProducerParser.php b/src/Parser/Producer/ProducerParser.php new file mode 100644 index 00000000..481974bd --- /dev/null +++ b/src/Parser/Producer/ProducerParser.php @@ -0,0 +1,74 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Producer\Producer + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Model\Producer\Producer + { + return Model\Producer\Producer::fromParser($this); + } + + /** + * @return array|\Jikan\Model\Producer\ProducerAnime[] + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getProducerAnime(): array + { + return $this->crawler + ->filter('div.seasonal-anime') + ->each( + function (Crawler $animeCrawler) { + return (new AnimeCardParser($animeCrawler))->getModel(); + } + ); + } + + /** + * @return \Jikan\Model\Common\MalUrl + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getUrl(): Model\Common\MalUrl + { + return new Model\Common\MalUrl( + JString::cleanse( + Parser::removeChildNodes($this->crawler->filterXPath('//span[@class=\'di-ib mt4\']'))->text() + ), + $this->crawler->filterXPath('//meta[@property="og:url"]')->attr('content') + ); + } +} diff --git a/src/Parser/Schedule/ScheduleParser.php b/src/Parser/Schedule/ScheduleParser.php new file mode 100644 index 00000000..f35cd4c8 --- /dev/null +++ b/src/Parser/Schedule/ScheduleParser.php @@ -0,0 +1,64 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Shedule\Schedule + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Model\Shedule\Schedule + { + return Model\Shedule\Schedule::fromParser($this); + } + + /** + * @param string $day + * + * @return array + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getShedule(string $day = 'all'): array + { + $parts = ['/']; + if ($day !== 'all') { + $parts[] = sprintf('div[contains(@class, "js-seasonal-anime-list-key-%s")]', $day); + } + $parts[] = 'div[contains(@class, "seasonal-anime")]'; + $query = implode('/', $parts); + + return $this->crawler->filterXPath($query)->each( + function (Crawler $c) { + return (new AnimeCardParser($c))->getModel(); + } + ); + } +} diff --git a/src/Parser/Search/AnimeSearchListItemParser.php b/src/Parser/Search/AnimeSearchListItemParser.php new file mode 100644 index 00000000..02ad8096 --- /dev/null +++ b/src/Parser/Search/AnimeSearchListItemParser.php @@ -0,0 +1,203 @@ +crawler = $crawler; + } + + /** + * @return AnimeSearchListItem + * @throws \Exception + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): AnimeSearchListItem + { + return AnimeSearchListItem::fromParser($this); + } + + /** + * @return \Jikan\Model\Common\MalUrl + * @throws \InvalidArgumentException + */ + public function getUrl(): MalUrl + { + return new MalUrl( + $this->getTitle(), + $this->crawler->filterXPath('//td[2]/a')->attr('href') + ); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getTitle(): string + { + return $this->crawler->filterXPath('//td[2]/a/strong')->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImageUrl(): string + { + return $this->crawler->filterXPath('//td[1]/div/a/img')->attr('data-src'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getSynopsis(): string + { + return JString::cleanse( + Parser::removeChildNodes( + $this->crawler->filterXPath('//td[2]/div[@class="pt4"]') + )->text() + ); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getType(): string + { + return JString::cleanse( + $this->crawler->filterXPath('//td[3]')->text() + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getEpisodes(): int + { + return (int)$this->crawler->filterXPath('//td[4]')->text(); + } + + /** + * @return float + * @throws \InvalidArgumentException + */ + public function getScore(): float + { + return (float)$this->crawler->filterXPath('//td[5]')->text(); + } + + /** + * @return \DateTimeImmutable|null + * @throws \InvalidArgumentException + */ + public function getStartDate(): ?\DateTimeImmutable + { + $date = $this->getStartDateString(); + + if (null === $date) { + return null; + } + + return Parser::parseDateMDY($date); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getStartDateString(): ?string + { + $date = JString::cleanse($this->crawler->filterXPath('//td[6]')->text()); + + if ($date === '-') { + return null; + } + + return $date; + } + + /** + * @return \DateTimeImmutable|null + * @throws \InvalidArgumentException + */ + public function getEndDate(): ?\DateTimeImmutable + { + $date = $this->getEndDateString(); + + if (null === $date) { + return null; + } + + return Parser::parseDateMDY($date); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getEndDateString(): ?string + { + $date = JString::cleanse($this->crawler->filterXPath('//td[7]')->text()); + + if ($date === '-') { + return null; + } + + return $date; + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMembers(): int + { + return (int)str_replace( + ',', + '', + $this->crawler->filterXPath('//td[8]')->text() + ); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getRated(): ?string + { + $rated = JString::cleanse($this->crawler->filterXPath('//td[9]')->text()); + + if ($rated === '-') { + return null; + } + + return $rated; + } +} diff --git a/src/Parser/Search/AnimeSearchParser.php b/src/Parser/Search/AnimeSearchParser.php new file mode 100644 index 00000000..0029c670 --- /dev/null +++ b/src/Parser/Search/AnimeSearchParser.php @@ -0,0 +1,75 @@ +crawler = $crawler; + } + + /** + * @return AnimeSearch + * @throws \Exception + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): AnimeSearch + { + return AnimeSearch::fromParser($this); + } + + /** + * @return AnimeSearchListItem[] + * @throws \Exception + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getResults(): array + { + return $this->crawler + ->filterXPath('//div[contains(@class, "js-categories-seasonal")]/table/tr[1]') + ->nextAll() + ->each( + function (Crawler $c) { + return (new AnimeSearchListItemParser($c))->getModel(); + } + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//div[contains(@class, "normal_header")]/div/div/span/a'); + + if (!$pages->count()) { + return 1; + } + + return (int)$pages->last()->text(); + } +} diff --git a/src/Parser/Search/CharacterSearchListItemParser.php b/src/Parser/Search/CharacterSearchListItemParser.php new file mode 100644 index 00000000..3443272e --- /dev/null +++ b/src/Parser/Search/CharacterSearchListItemParser.php @@ -0,0 +1,143 @@ +crawler = $crawler; + } + + /** + * @return CharacterSearchListItem + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): CharacterSearchListItem + { + return CharacterSearchListItem::fromParser($this); + } + + /** + * @return MalUrl + * @throws \InvalidArgumentException + */ + public function getUrl(): MalUrl + { + return new MalUrl( + $this->getName(), + $this->crawler->filterXPath('//td[2]/a')->attr('href') + ); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getName(): string + { + return $this->crawler->filterXPath('//td[2]/a')->text(); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getAlternativeNames(): array + { + $names = $this->crawler->filterXPath('//td[2]/small'); + + if (!$names->count()) { + return []; + } + + $names = str_replace(['(', ')'], '', $names->text()); + $names = explode(',', $names); + + foreach ($names as &$name) { + $name = JString::cleanse($name); + } + + return $names; + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImageUrl(): string + { + return $this->crawler->filterXPath('//td[1]/div/a/img')->attr('src'); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getAnime(): array + { + $anime = Parser::removeChildNodes( + $this->crawler + ->filterXPath('//td[3]/small/a') + ); + + if (!$anime->count()) { + return []; + } + + return $anime->each( + function (Crawler $c) { + return new MalUrl( + $c->text(), + Constants::BASE_URL.$c->attr('href') + ); + } + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getManga(): array + { + $manga = $this->crawler + ->filterXPath('//td[3]/small/div/a'); + + if (!$manga->count()) { + return []; + } + + return $manga->each( + function (Crawler $c) { + return new MalUrl( + $c->text(), + Constants::BASE_URL.$c->attr('href') + ); + } + ); + } +} diff --git a/src/Parser/Search/CharacterSearchParser.php b/src/Parser/Search/CharacterSearchParser.php new file mode 100644 index 00000000..3b504c4b --- /dev/null +++ b/src/Parser/Search/CharacterSearchParser.php @@ -0,0 +1,73 @@ +crawler = $crawler; + } + + /** + * @return CharacterSearch + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): CharacterSearch + { + return CharacterSearch::fromParser($this); + } + + /** + * @return CharacterSearchListItem[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getResults(): array + { + return $this->crawler + ->filterXPath('//div[@id="content"]/table/tr[1]') + ->nextAll() + ->each( + function (Crawler $c) { + return (new CharacterSearchListItemParser($c))->getModel(); + } + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//div[@id="content"]/div[@class="borderClass"][1]/div/span/a'); + + if (!$pages->count()) { + return 1; + } + + return (int)$pages->last()->text(); + } +} diff --git a/src/Parser/Search/MangaSearchListItemParser.php b/src/Parser/Search/MangaSearchListItemParser.php new file mode 100644 index 00000000..4c393283 --- /dev/null +++ b/src/Parser/Search/MangaSearchListItemParser.php @@ -0,0 +1,197 @@ +crawler = $crawler; + } + + /** + * @return MangaSearchListItem + * @throws \Exception + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): MangaSearchListItem + { + return MangaSearchListItem::fromParser($this); + } + + /** + * @return \Jikan\Model\Common\MalUrl + * @throws \InvalidArgumentException + */ + public function getUrl(): MalUrl + { + return new MalUrl( + $this->getTitle(), + $this->crawler->filterXPath('//td[2]/a')->attr('href') + ); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getTitle(): string + { + return $this->crawler->filterXPath('//td[2]/a/strong')->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImageUrl(): string + { + return $this->crawler->filterXPath('//td[1]/div/a/img')->attr('data-src'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getSynopsis(): string + { + return JString::cleanse( + Parser::removeChildNodes( + $this->crawler->filterXPath('//td[2]/div[@class="pt4"]') + )->text() + ); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getType(): string + { + return JString::cleanse( + $this->crawler->filterXPath('//td[3]')->text() + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getVolumes(): int + { + return (int)$this->crawler->filterXPath('//td[4]')->text(); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getChapters(): int + { + return (int)$this->crawler->filterXPath('//td[5]')->text(); + } + + /** + * @return float + * @throws \InvalidArgumentException + */ + public function getScore(): float + { + return (float)$this->crawler->filterXPath('//td[6]')->text(); + } + + /** + * @return \DateTimeImmutable|null ?\DateTimeImmutable + * @throws \InvalidArgumentException + */ + public function getStartDate(): ?\DateTimeImmutable + { + $date = $this->getStartDateString(); + + if (null === $date) { + return null; + } + + return Parser::parseDateMDY($date); + } + + /** + * @return null|string ?string + * @throws \InvalidArgumentException + */ + public function getStartDateString(): ?string + { + $date = JString::cleanse($this->crawler->filterXPath('//td[7]')->text()); + + if ($date === '-') { + return null; + } + + return $date; + } + + /** + * @return \DateTimeImmutable|null ?\DateTimeImmutable + * @throws \InvalidArgumentException + */ + public function getEndDate(): ?\DateTimeImmutable + { + $date = $this->getEndDateString(); + + if (null === $date) { + return null; + } + + return Parser::parseDateMDY($date); + } + + /** + * @return null|string ?string + * @throws \InvalidArgumentException + */ + public function getEndDateString(): ?string + { + $date = JString::cleanse($this->crawler->filterXPath('//td[8]')->text()); + + if ($date === '-') { + return null; + } + + return $date; + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMembers(): int + { + return (int)str_replace( + ',', + '', + $this->crawler->filterXPath('//td[9]')->text() + ); + } +} diff --git a/src/Parser/Search/MangaSearchParser.php b/src/Parser/Search/MangaSearchParser.php new file mode 100644 index 00000000..c9fda7b5 --- /dev/null +++ b/src/Parser/Search/MangaSearchParser.php @@ -0,0 +1,75 @@ +crawler = $crawler; + } + + /** + * @return MangaSearch + * @throws \Exception + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): MangaSearch + { + return MangaSearch::fromParser($this); + } + + /** + * @return MangaSearchListItem[] + * @throws \Exception + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getResults(): array + { + return $this->crawler + ->filterXPath('//div[contains(@class, "js-categories-seasonal")]/table/tr[1]') + ->nextAll() + ->each( + function (Crawler $c) { + return (new MangaSearchListItemParser($c))->getModel(); + } + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//div[contains(@class, "normal_header")]/div/div/span/a'); + + if (!$pages->count()) { + return 1; + } + + return (int)$pages->last()->text(); + } +} diff --git a/src/Parser/Search/PersonSearchListItemParser.php b/src/Parser/Search/PersonSearchListItemParser.php new file mode 100644 index 00000000..dff2b289 --- /dev/null +++ b/src/Parser/Search/PersonSearchListItemParser.php @@ -0,0 +1,93 @@ +crawler = $crawler; + } + + /** + * @return PersonSearchListItem + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): PersonSearchListItem + { + return PersonSearchListItem::fromParser($this); + } + + /** + * @return MalUrl + * @throws \InvalidArgumentException + */ + public function getUrl(): MalUrl + { + return new MalUrl( + $this->getName(), + $this->crawler->filterXPath('//td[2]/a')->attr('href') + ); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getName(): string + { + return $this->crawler->filterXPath('//td[2]/a')->text(); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getAlternativeNames(): array + { + $names = $this->crawler->filterXPath('//td[2]/small'); + + if (!$names->count()) { + return []; + } + + $names = str_replace(['(', ')'], '', $names->text()); + $names = explode(',', $names); + + foreach ($names as &$name) { + $name = JString::cleanse($name); + } + + return $names; + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImageUrl(): string + { + return $this->crawler->filterXPath('//td[1]/div/a/img')->attr('src'); + } +} diff --git a/src/Parser/Search/PersonSearchParser.php b/src/Parser/Search/PersonSearchParser.php new file mode 100644 index 00000000..42b920b3 --- /dev/null +++ b/src/Parser/Search/PersonSearchParser.php @@ -0,0 +1,74 @@ +crawler = $crawler; + } + + /** + * @return PersonSearch + * @throws \RuntimeException + * @throws \InvalidArgumentException + * @throws \Exception + */ + public function getModel(): PersonSearch + { + return PersonSearch::fromParser($this); + } + + /** + * @return PersonSearchListItem[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getResults(): array + { + return $this->crawler + ->filterXPath('//div[@id="content"]/table/tr[1]') + ->nextAll() + ->each( + function (Crawler $c) { + return (new PersonSearchListItemParser($c))->getModel(); + } + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//div[@id="content"]/div[@class="borderClass"][1]/div/span/a'); + + if (!$pages->count()) { + return 1; + } + + return (int)$pages->last()->text(); + } +} diff --git a/src/Parser/SeasonList/SeasonListItemParser.php b/src/Parser/SeasonList/SeasonListItemParser.php new file mode 100644 index 00000000..10103dcc --- /dev/null +++ b/src/Parser/SeasonList/SeasonListItemParser.php @@ -0,0 +1,72 @@ +crawler = $crawler; + } + + /** + * @return SeasonListItem + * @throws \InvalidArgumentException + */ + public function getModel(): SeasonListItem + { + return SeasonListItem::fromParser($this); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getYear(): int + { + return (int)preg_replace( + '/\D/', + '', + $this->crawler + ->filterXPath('//td') + ->first() + ->text() + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getSeasons(): array + { + $seasons = $this->crawler->text(); + + return array_filter( + Constants::SEASONS, + function ($season) use ($seasons) { + return preg_match("/$season/", $seasons) !== false; + } + ); + } +} diff --git a/src/Parser/SeasonList/SeasonListParser.php b/src/Parser/SeasonList/SeasonListParser.php new file mode 100644 index 00000000..1c06ee17 --- /dev/null +++ b/src/Parser/SeasonList/SeasonListParser.php @@ -0,0 +1,46 @@ +crawler = $crawler; + } + + /** + * @return SeasonListItem[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): array + { + return $this->crawler + ->filterXPath('//table[contains(@class, "anime-seasonal-byseason")]//tr') + ->each( + function (Crawler $crawler) { + return (new SeasonListItemParser($crawler))->getModel(); + } + ); + } +} diff --git a/src/Parser/Seasonal/SeasonalParser.php b/src/Parser/Seasonal/SeasonalParser.php new file mode 100644 index 00000000..55248bba --- /dev/null +++ b/src/Parser/Seasonal/SeasonalParser.php @@ -0,0 +1,70 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Seasonal\Seasonal + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): Model\Seasonal\Seasonal + { + return Model\Seasonal\Seasonal::fromParser($this); + } + + /** + * @return array|\Jikan\Model\Seasonal\SeasonalAnime[] + * @throws \InvalidArgumentException + * @throws \RuntimeException + */ + public function getSeasonalAnime(): array + { + return $this->crawler + ->filter('div.seasonal-anime') + ->each( + function (Crawler $animeCrawler) { + return (new AnimeCardParser($animeCrawler))->getSeasonalModel(); + } + ); + } + + /** + * @return string + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getSeason(): string + { + $season = $this->crawler->filter('div.navi-seasonal a.on')->text(); + + return JString::cleanse($season); + } +} diff --git a/src/Parser/Top/TopAnimeParser.php b/src/Parser/Top/TopAnimeParser.php new file mode 100644 index 00000000..5464b605 --- /dev/null +++ b/src/Parser/Top/TopAnimeParser.php @@ -0,0 +1,46 @@ +crawler = $crawler; + } + + /** + * @return TopAnime[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getTopAnime(): array + { + return $this->crawler + ->filterXPath('//tr[@class="ranking-list"]') + ->each( + function (Crawler $crawler) { + return TopAnime::fromParser(new TopListItemParser($crawler)); + } + ); + } +} diff --git a/src/Parser/Top/TopCharactersParser.php b/src/Parser/Top/TopCharactersParser.php new file mode 100644 index 00000000..cef1a381 --- /dev/null +++ b/src/Parser/Top/TopCharactersParser.php @@ -0,0 +1,46 @@ +crawler = $crawler; + } + + /** + * @return TopCharacter[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getTopCharacters(): array + { + return $this->crawler + ->filterXPath('//tr[@class="ranking-list"]') + ->each( + function (Crawler $crawler) { + return TopCharacter::fromParser(new TopListItemParser($crawler)); + } + ); + } +} diff --git a/src/Parser/Top/TopListItemParser.php b/src/Parser/Top/TopListItemParser.php new file mode 100644 index 00000000..b405d681 --- /dev/null +++ b/src/Parser/Top/TopListItemParser.php @@ -0,0 +1,229 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\Common\MalUrl + * @throws \InvalidArgumentException + */ + public function getMalUrl(): MalUrl + { + return (new MalUrlParser($this->crawler->filterXPath('//a[contains(@class,"fs14 fw-b")][1]')))->getModel(); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getImage(): ?string + { + return $this->crawler->filterXPath('//img[1]')->attr('data-src'); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getRank(): int + { + return (int)$this->crawler->filterXPath('//td[1]/span')->text(); + } + + /** + * @return float + * @throws \InvalidArgumentException + */ + public function getRating(): float + { + return (float)$this->crawler->filterXPath('//td[3]/div/span')->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getType(): string + { + return preg_replace('/^(\w+).*$/', '$1', $this->getTextArray()[0]); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + private function getTextArray(): array + { + $parts = explode("\n", $this->getText()); + $parts = array_map('trim', $parts); + $parts = array_filter($parts); + + return array_values($parts); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + private function getText(): string + { + if ($this->animeText !== null) { + return $this->animeText; + } + + return JString::cleanse( + $this->animeText = $this->crawler + ->filterXPath('//div[contains(@class, "information")]') + ->text() + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getEpisodes(): int + { + return (int)preg_replace('/.*\((\d+) eps\).*/', '$1', $this->getTextArray()[0]); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getVolumes(): ?int + { + $count = 0; + $vols = preg_replace('/.*\((\d+) vols\).*/', '$1', $this->getTextArray()[0], -1, $count); + + return $count ? (int)$vols : null; + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getMembers(): int + { + return (int)preg_replace('/\D/', '', $this->getTextArray()[2]); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getStartDate(): string + { + return JString::cleanse(explode('-', $this->getTextArray()[1])[0]); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getEndDate(): string + { + return JString::cleanse(explode('-', $this->getTextArray()[1])[1] ?? '?'); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getKanjiName(): ?string + { + try { + return trim($this->crawler->filterXPath('//span[@class="fs12 fn-grey6"][1]')->text(), '()'); + } catch (\Exception $e) { + return null; + } + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + * @throws \InvalidArgumentException + */ + public function getAnimeography(): array + { + return $this->crawler->filterXPath('//td[3]/div/a') + ->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + /** + * @return \Jikan\Model\Common\MalUrl[] + * @throws \InvalidArgumentException + */ + public function getMangaography(): array + { + return $this->crawler->filterXPath('//td[4]/div/a') + ->each( + function (Crawler $crawler) { + return (new MalUrlParser($crawler))->getModel(); + } + ); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getFavorites(): int + { + return (int)preg_replace('/\D/', '', $this->crawler->filterXPath('//td[5]')->text()); + } + + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getPeopleFavorites(): int + { + return (int)preg_replace('/\D/', '', $this->crawler->filterXPath('//td[4]')->text()); + } + + /** + * @return \DateTimeImmutable|null + * @throws \InvalidArgumentException + */ + public function getBirthday(): ?\DateTimeImmutable + { + return Parser::parseDate($this->crawler->filterXPath('//td[3]')->text()); + } +} diff --git a/src/Parser/Top/TopMangaParser.php b/src/Parser/Top/TopMangaParser.php new file mode 100644 index 00000000..70e5b4c9 --- /dev/null +++ b/src/Parser/Top/TopMangaParser.php @@ -0,0 +1,46 @@ +crawler = $crawler; + } + + /** + * @return TopManga[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getTopManga(): array + { + return $this->crawler + ->filterXPath('//tr[@class="ranking-list"]') + ->each( + function (Crawler $crawler) { + return TopManga::fromParser(new TopListItemParser($crawler)); + } + ); + } +} diff --git a/src/Parser/Top/TopPeopleParser.php b/src/Parser/Top/TopPeopleParser.php new file mode 100644 index 00000000..824bdedd --- /dev/null +++ b/src/Parser/Top/TopPeopleParser.php @@ -0,0 +1,46 @@ +crawler = $crawler; + } + + /** + * @return TopPerson[] + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getTopPeople(): array + { + return $this->crawler + ->filterXPath('//tr[@class="ranking-list"]') + ->each( + function (Crawler $crawler) { + return TopPerson::fromParser(new TopListItemParser($crawler)); + } + ); + } +} diff --git a/src/Parser/User/Friends/FriendParser.php b/src/Parser/User/Friends/FriendParser.php new file mode 100644 index 00000000..7f8bc3ab --- /dev/null +++ b/src/Parser/User/Friends/FriendParser.php @@ -0,0 +1,97 @@ +crawler = $crawler; + } + + /** + * Return the model + * + * @throws \InvalidArgumentException + */ + public function getModel(): Friend + { + return Friend::fromParser($this); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getAvatar(): string + { + return $this->crawler->filterXPath('//div/a/img')->attr('src'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getName(): string + { + return $this->crawler->filterXPath('//div[3]/a/strong')->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getUrl(): string + { + return $this->crawler->filterXPath('//div[3]/a')->attr('href'); + } + + /** + * @return \DateTimeImmutable|null + * @throws \InvalidArgumentException + */ + public function getFriendsSince(): ?\DateTimeImmutable + { + $count = 0; + $text = $this->crawler->filterXPath('//div[last()]')->text(); + $text = preg_replace('/^Friends since (.*)$/', '$1', $text, -1, $count); + if (!$count) { + return null; + } + + return Parser::parseDate($text); + } + + /** + * @return \DateTimeImmutable + * @throws \InvalidArgumentException + */ + public function getLastOnline(): \DateTimeImmutable + { + return new \DateTimeImmutable( + JString::cleanse($this->crawler->filterXPath('//div[4]')->text()), + new \DateTimeZone('UTC') + ); + } +} diff --git a/src/Parser/User/Friends/FriendsParser.php b/src/Parser/User/Friends/FriendsParser.php new file mode 100644 index 00000000..74489afe --- /dev/null +++ b/src/Parser/User/Friends/FriendsParser.php @@ -0,0 +1,43 @@ +crawler = $crawler; + } + + /** + * @return Friend[] + * @throws \InvalidArgumentException + */ + public function getModel(): array + { + return $this->crawler->filterXPath('//div[contains(@class, "friendBlock")]')->each( + function (Crawler $c) { + return (new FriendParser($c))->getModel(); + } + ); + } +} diff --git a/src/Parser/User/History/HistoryItemParser.php b/src/Parser/User/History/HistoryItemParser.php new file mode 100644 index 00000000..3ceb364f --- /dev/null +++ b/src/Parser/User/History/HistoryItemParser.php @@ -0,0 +1,85 @@ +crawler = $crawler; + } + + /** + * Return the model + * + * @throws \Exception + * @throws \InvalidArgumentException + */ + public function getModel(): History + { + return History::fromParser($this); + } + + /** + * @return MalUrl + * @throws \InvalidArgumentException + */ + public function getUrl(): MalUrl + { + $url = $this->crawler->filterXPath('//td[1]/a')->attr('href'); + $name = $this->crawler->filterXPath('//td[1]/a')->text(); + + preg_match('~/(.\w+).php\?id=(.\d+)~', $url, $matches); + $url = Constants::BASE_URL.'/'.$matches[1].'/'.$matches[2]; + + return new MalUrl($name, $url); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getIncrement(): int + { + return (int)$this->crawler->filterXPath('//td[1]/strong')->text(); + } + + /** + * @return \DateTimeImmutable + * @throws \InvalidArgumentException + * @throws \Exception + */ + public function getDate(): \DateTimeImmutable + { + $date = JString::cleanse( + Parser::removeChildNodes( + $this->crawler->filterXPath('//td[2]') + )->text() + ); + + return new \DateTimeImmutable($date, new \DateTimeZone('UTC')); + } +} diff --git a/src/Parser/User/History/HistoryParser.php b/src/Parser/User/History/HistoryParser.php new file mode 100644 index 00000000..9cb12d92 --- /dev/null +++ b/src/Parser/User/History/HistoryParser.php @@ -0,0 +1,52 @@ +crawler = $crawler; + } + + /** + * @return History[] + * @throws \Exception + * @throws \InvalidArgumentException + */ + public function getModel(): array + { + $node = $this->crawler->filterXPath('//div[@id="content"]/div/table/tr'); + + return $node + ->reduce( + function (Crawler $c) { + return (bool)$c->filterXPath('//td[contains(@class, "borderClass")]')->count(); + } + ) + ->each( + function (Crawler $c) { + return (new HistoryItemParser($c))->getModel(); + } + ); + } +} diff --git a/src/Parser/User/Profile/AnimeStatsParser.php b/src/Parser/User/Profile/AnimeStatsParser.php new file mode 100644 index 00000000..0945cebf --- /dev/null +++ b/src/Parser/User/Profile/AnimeStatsParser.php @@ -0,0 +1,200 @@ +crawler = $crawler; + } + + /** + * @return \Jikan\Model\User\AnimeStats + * @throws \InvalidArgumentException + */ + public function getModel(): AnimeStats + { + return AnimeStats::fromParser($this); + } + + /** + * @return float|null + * @throws \InvalidArgumentException + */ + public function getDaysWatched(): ?float + { + $node = $this->crawler + ->filterXPath('//div[@class=\'di-tc al pl8 fs12 fw-b\'][1]'); + + if (!$node->count()) { + return null; + } + + return Parser::removeChildNodes($node)->text(); + } + + /** + * @return float|null + * @throws \InvalidArgumentException + */ + public function getMeanScore(): ?float + { + $node = $this->crawler + ->filterXPath('//div[@class=\'di-tc ar pr8 fs12 fw-b\'][1]'); + + if (!$node->count()) { + return null; + } + + return Parser::removeChildNodes($node)->text(); + } + + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getWatching(): ?int + { + $node = $this->crawler + ->filterXPath('//a[contains(@class, \'watching\')]/following-sibling::span'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getCompleted(): ?int + { + $node = $this->crawler + ->filterXPath('//a[contains(@class, \'completed\')]/following-sibling::span'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getOnHold(): ?int + { + $node = $this->crawler + ->filterXPath('//a[contains(@class, \'on_hold\')]/following-sibling::span'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getDropped(): ?int + { + $node = $this->crawler + ->filterXPath('//a[contains(@class, \'dropped\')]/following-sibling::span'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getPlanToWatch(): ?int + { + $node = $this->crawler + ->filterXPath('//a[contains(@class, \'plan_to_watch\')]/following-sibling::span'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getTotalEntries(): ?int + { + $node = $this->crawler + ->filterXPath('//ul[@class=\'stats-data fl-r\'][1]/li[1]/span[2]'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getRewatched(): ?int + { + $node = $this->crawler + ->filterXPath('//ul[@class=\'stats-data fl-r\'][1]/li[2]/span[2]'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getEpisodesWatched(): ?int + { + $node = $this->crawler + ->filterXPath('//ul[@class=\'stats-data fl-r\'][1]/li[3]/span[2]'); + + if (!$node->count()) { + return null; + } + + return str_replace(',', '', $node->text()); + } +} diff --git a/src/Parser/User/Profile/FavoritesParser.php b/src/Parser/User/Profile/FavoritesParser.php new file mode 100644 index 00000000..c3ca3ed9 --- /dev/null +++ b/src/Parser/User/Profile/FavoritesParser.php @@ -0,0 +1,143 @@ +crawler = $crawler; + } + + /** + * @return Favorites + * @throws \InvalidArgumentException + */ + public function getModel(): Favorites + { + return Favorites::fromParser($this); + } + + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getAnime(): array + { + return $this->crawler->filterXPath('//ul[@class=\'favorites-list anime\']/li') + ->each( + function (Crawler $crawler) { + preg_match( + '~background-image:url\(\'(.*)\'\)~', + $crawler->filterXPath('//div[position() = 1]/a') + ->attr('style'), + $matches + ); + + return new AnimeMeta( + $crawler->filterXPath('//div[position() = 2]/a')->text(), + $crawler->filterXPath('//div[position() = 2]/a')->attr('href'), + $matches[1] + ); + } + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getManga(): array + { + return $this->crawler->filterXPath('//ul[@class=\'favorites-list manga\']/li') + ->each( + function (Crawler $crawler) { + preg_match( + '~background-image:url\(\'(.*)\'\)~', + $crawler->filterXPath('//div[position() = 1]/a') + ->attr('style'), + $matches + ); + + return new MangaMeta( + $crawler->filterXPath('//div[position() = 2]/a')->text(), + $crawler->filterXPath('//div[position() = 2]/a')->attr('href'), + $matches[1] + ); + } + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getCharacters(): array + { + return $this->crawler->filterXPath('//ul[@class=\'favorites-list characters\']/li') + ->each( + function (Crawler $crawler) { + preg_match( + '~background-image:url\(\'(.*)\'\)~', + $crawler->filterXPath('//div[position() = 1]/a') + ->attr('style'), + $matches + ); + + return new CharacterMeta( + $crawler->filterXPath('//div[position() = 2]/a')->text(), + $crawler->filterXPath('//div[position() = 2]/a')->attr('href'), + $matches[1] + ); + } + ); + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getPeople(): array + { + return $this->crawler->filterXPath('//ul[@class=\'favorites-list people\']/li') + ->each( + function (Crawler $crawler) { + preg_match( + '~background-image:url\(\'(.*)\'\)~', + $crawler->filterXPath('//div[position() = 1]/a') + ->attr('style'), + $matches + ); + + return new PersonMeta( + $crawler->filterXPath('//div[position() = 2]/a')->text(), + $crawler->filterXPath('//div[position() = 2]/a')->attr('href'), + $matches[1] + ); + } + ); + } +} diff --git a/src/Parser/User/Profile/MangaStatsParser.php b/src/Parser/User/Profile/MangaStatsParser.php new file mode 100644 index 00000000..bce8e9ad --- /dev/null +++ b/src/Parser/User/Profile/MangaStatsParser.php @@ -0,0 +1,216 @@ +crawler = $crawler; + } + + /** + * @return MangaStats + * @throws \InvalidArgumentException + */ + public function getModel(): MangaStats + { + return MangaStats::fromParser($this); + } + + /** + * @return float|null + * @throws \InvalidArgumentException + */ + public function getDaysRead(): ?float + { + $node = $this->crawler + ->filterXPath('//div[@class=\'di-tc al pl8 fs12 fw-b\'][2]'); + + if (!$node->count()) { + return null; + } + + return Parser::removeChildNodes($node)->text(); + } + + /** + * @return float|null + * @throws \InvalidArgumentException + */ + public function getMeanScore(): ?float + { + $node = $this->crawler + ->filterXPath('//div[@class=\'di-tc ar pr8 fs12 fw-b\'][2]'); + + if (!$node->count()) { + return null; + } + + return Parser::removeChildNodes($node)->text(); + } + + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getReading(): ?int + { + $node = $this->crawler + ->filterXPath('//a[contains(@class, \'reading\')]/following-sibling::span'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getCompleted(): ?int + { + $node = $this->crawler + ->filterXPath('//a[contains(@class, \'completed\')][2]/following-sibling::span'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getOnHold(): ?int + { + $node = $this->crawler + ->filterXPath('//a[contains(@class, \'on_hold\')][2]/following-sibling::span'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getDropped(): ?int + { + $node = $this->crawler + ->filterXPath('//a[contains(@class, \'dropped\')][2]/following-sibling::span'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getPlanToRead(): ?int + { + $node = $this->crawler + ->filterXPath('//a[contains(@class, \'plan_to_read\')]/following-sibling::span'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getTotalEntries(): ?int + { + $node = $this->crawler + ->filterXPath('//ul[@class=\'stats-data fl-r\'][2]/li[1]/span[2]'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getReread(): ?int + { + $node = $this->crawler + ->filterXPath('//ul[@class=\'stats-data fl-r\'][2]/li[2]/span[2]'); + + if (!$node->count()) { + return null; + } + + return $node->text(); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getChaptersRead(): ?int + { + $node = $this->crawler + ->filterXPath('//ul[@class=\'stats-data fl-r\'][2]/li[3]/span[2]'); + + if (!$node->count()) { + return null; + } + + return str_replace(',', '', $node->text()); + } + + /** + * @return int|null + * @throws \InvalidArgumentException + */ + public function getVolumesRead(): ?int + { + $node = $this->crawler + ->filterXPath('//ul[@class=\'stats-data fl-r\'][2]/li[4]/span[2]'); + + if (!$node->count()) { + return null; + } + + return str_replace(',', '', $node->text()); + } +} diff --git a/src/Parser/User/Profile/UserProfileParser.php b/src/Parser/User/Profile/UserProfileParser.php new file mode 100644 index 00000000..29cdd87a --- /dev/null +++ b/src/Parser/User/Profile/UserProfileParser.php @@ -0,0 +1,198 @@ +crawler = $crawler; + } + + /** + * Return the model + * + * @throws \InvalidArgumentException + * @throws \Exception + * @throws \Exception + */ + public function getModel(): Model\User\Profile + { + return Model\User\Profile::fromParser($this); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getUsername(): string + { + return (string)preg_replace('#.*/(\w+)$#', '$1', $this->getProfileUrl()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getProfileUrl(): string + { + return $this->crawler->filterXPath('//meta[@property="og:url"]')->attr('content'); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getImageUrl(): ?string + { + try { + return $this->crawler->filterXPath('//div[contains(@class, "user-image")]/img')->attr('src'); + } catch (\Exception $e) { + return null; + } + } + + /** + * @return \DateTimeImmutable|null + * @throws \InvalidArgumentException + * @throws \Exception + */ + public function getJoinDate(): ?\DateTimeImmutable + { + return Parser::parseDateMDYReadable( + $this->crawler->filterXPath('//span[contains(text(), \'Joined\')]/following-sibling::span')->text() + ); + } + + /** + * @return \DateTimeImmutable + * @throws \InvalidArgumentException + */ + public function getLastOnline(): \DateTimeImmutable + { + return new \DateTimeImmutable( + $this->crawler->filterXPath('//span[contains(text(), \'Last Online\')]/following-sibling::span')->text(), + new \DateTimeZone('UTC') + ); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getGender(): ?string + { + $gender = $this->crawler->filterXPath('//span[contains(text(), \'Gender\')]/following-sibling::span'); + if (!$gender->count()) { + return null; + } + + return $gender->text(); + } + + /** + * @return \DateTimeImmutable|null + * @throws \InvalidArgumentException + * @throws \Exception + */ + public function getBirthday(): ?\DateTimeImmutable + { + $node = $this->crawler->filterXPath('//span[contains(text(), \'Birthday\')]/following-sibling::span'); + if (!$node->count()) { + return null; + } + + return Parser::parseDateMDYReadable( + $node->text() + ); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getLocation(): ?string + { + $gender = $this->crawler->filterXPath('//span[contains(text(), \'Location\')]/following-sibling::span'); + if (!$gender->count()) { + return null; + } + + return $gender->text(); + } + + /** + * @return \Jikan\Model\User\AnimeStats + * @throws \InvalidArgumentException + */ + public function getAnimeStats(): AnimeStats + { + $this->crawler + ->filterXPath('//div[@class=\'stats anime\']'); + + return (new AnimeStatsParser($this->crawler))->getModel(); + } + + /** + * @return \Jikan\Model\User\MangaStats + * @throws \InvalidArgumentException + */ + public function getMangaStats(): MangaStats + { + $this->crawler + ->filterXPath('//div[@class=\'stats anime\']'); + + return (new MangaStatsParser($this->crawler))->getModel(); + } + + /** + * @return string|null + * @throws \InvalidArgumentException + */ + public function getAbout(): ?string + { + $about = $this->crawler->filterXPath('//div[@class=\'profile-about-user js-truncate-inner\']/table/tr/td/div'); + + + if (!$about->count()) { + return null; + } + + return trim( + $about->html() + ); + } + + /** + * @return \Jikan\Model\User\Favorites + * @throws \InvalidArgumentException + */ + public function getFavorites(): Model\User\Favorites + { + // $node = $this->crawler->filterXPath('//ul[@class=\'favorites-list anime\']/li') + $node = $this->crawler->filterXPath('//div[contains(@class, \'user-favorites\')]'); + + return (new FavoritesParser($node))->getModel(); + } +} diff --git a/src/Request/Anime/AnimeCharactersAndStaffRequest.php b/src/Request/Anime/AnimeCharactersAndStaffRequest.php new file mode 100644 index 00000000..a9530f5a --- /dev/null +++ b/src/Request/Anime/AnimeCharactersAndStaffRequest.php @@ -0,0 +1,36 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/anime/%s/_/characters', $this->id); + } +} diff --git a/src/Request/Anime/AnimeEpisodesRequest.php b/src/Request/Anime/AnimeEpisodesRequest.php new file mode 100644 index 00000000..a69fbd09 --- /dev/null +++ b/src/Request/Anime/AnimeEpisodesRequest.php @@ -0,0 +1,44 @@ +id = $id; + $this->page = ($page - 1) * 100; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/anime/%s/_/episode?offset=%s', $this->id, $this->page); + } +} diff --git a/src/Request/Anime/AnimeForumRequest.php b/src/Request/Anime/AnimeForumRequest.php new file mode 100644 index 00000000..0341588e --- /dev/null +++ b/src/Request/Anime/AnimeForumRequest.php @@ -0,0 +1,53 @@ +id = $id; + $this->topic = $topic; + } + + /** + * @return string + */ + public function getPath(): string + { + $query = ''; + if ($this->topic !== null && \in_array($this->topic, self::$validTypes, true)) { + $query = '?'.http_build_query(['topic' => $this->topic]); + } + + return sprintf('https://myanimelist.net/anime/%s/_/forum%s', $this->id, $query); + } +} diff --git a/src/Request/Anime/AnimeMoreInfoRequest.php b/src/Request/Anime/AnimeMoreInfoRequest.php new file mode 100644 index 00000000..b72868a6 --- /dev/null +++ b/src/Request/Anime/AnimeMoreInfoRequest.php @@ -0,0 +1,36 @@ +id = $id; + } + + /** + * return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/anime/%d/_/moreinfo', $this->id); + } +} diff --git a/src/Request/Anime/AnimeNewsRequest.php b/src/Request/Anime/AnimeNewsRequest.php new file mode 100644 index 00000000..54f33da0 --- /dev/null +++ b/src/Request/Anime/AnimeNewsRequest.php @@ -0,0 +1,36 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/anime/%s/_/news', $this->id); + } +} diff --git a/src/Request/Anime/AnimePicturesRequest.php b/src/Request/Anime/AnimePicturesRequest.php new file mode 100644 index 00000000..91714552 --- /dev/null +++ b/src/Request/Anime/AnimePicturesRequest.php @@ -0,0 +1,37 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + // MyAnimeList wants after //... it happily accepts jikan as a valid parameter though + return sprintf('https://myanimelist.net/anime/%d/jikan/pics', $this->id); + } +} diff --git a/src/Request/Anime/AnimeRequest.php b/src/Request/Anime/AnimeRequest.php new file mode 100644 index 00000000..0a7c5e41 --- /dev/null +++ b/src/Request/Anime/AnimeRequest.php @@ -0,0 +1,36 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/anime/%s/', $this->id); + } +} diff --git a/src/Request/Anime/AnimeStatsRequest.php b/src/Request/Anime/AnimeStatsRequest.php new file mode 100644 index 00000000..b2f23134 --- /dev/null +++ b/src/Request/Anime/AnimeStatsRequest.php @@ -0,0 +1,37 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + // MyAnimeList wants after //... it happily accepts jikan as a valid parameter though + return sprintf('https://myanimelist.net/anime/%d/jikan/stats', $this->id); + } +} diff --git a/src/Request/Anime/AnimeVideosRequest.php b/src/Request/Anime/AnimeVideosRequest.php new file mode 100644 index 00000000..23787541 --- /dev/null +++ b/src/Request/Anime/AnimeVideosRequest.php @@ -0,0 +1,36 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/anime/%d/_/video', $this->id); + } +} diff --git a/src/Request/Character/CharacterPicturesRequest.php b/src/Request/Character/CharacterPicturesRequest.php new file mode 100644 index 00000000..0b707708 --- /dev/null +++ b/src/Request/Character/CharacterPicturesRequest.php @@ -0,0 +1,37 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + // MyAnimeList wants after //... it happily accepts jikan as a valid parameter though + return sprintf('https://myanimelist.net/character/%d/jikan/pictures', $this->id); + } +} diff --git a/src/Request/Character/CharacterRequest.php b/src/Request/Character/CharacterRequest.php new file mode 100644 index 00000000..bc853fd6 --- /dev/null +++ b/src/Request/Character/CharacterRequest.php @@ -0,0 +1,38 @@ +id = $id; + } + + /** + * Get the path to request + * + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/character/%s', $this->id); + } +} diff --git a/src/Request/Genre/AnimeGenreRequest.php b/src/Request/Genre/AnimeGenreRequest.php new file mode 100644 index 00000000..490abb7b --- /dev/null +++ b/src/Request/Genre/AnimeGenreRequest.php @@ -0,0 +1,44 @@ +id = $id; + $this->page = $page; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/anime/genre/%s?page=%s', $this->id, $this->page); + } +} diff --git a/src/Request/Genre/MangaGenreRequest.php b/src/Request/Genre/MangaGenreRequest.php new file mode 100644 index 00000000..4b99f459 --- /dev/null +++ b/src/Request/Genre/MangaGenreRequest.php @@ -0,0 +1,44 @@ +id = $id; + $this->page = $page; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/manga/genre/%s?page=%s', $this->id, $this->page); + } +} diff --git a/src/Request/Magazine/MagazineRequest.php b/src/Request/Magazine/MagazineRequest.php new file mode 100644 index 00000000..aa1905b3 --- /dev/null +++ b/src/Request/Magazine/MagazineRequest.php @@ -0,0 +1,44 @@ +id = $id; + $this->page = $page; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/manga/magazine/%s?page=%s', $this->id, $this->page); + } +} diff --git a/src/Request/Manga/MangaCharactersRequest.php b/src/Request/Manga/MangaCharactersRequest.php new file mode 100644 index 00000000..cbe80b62 --- /dev/null +++ b/src/Request/Manga/MangaCharactersRequest.php @@ -0,0 +1,36 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/manga/%s/_/characters', $this->id); + } +} diff --git a/src/Request/Manga/MangaForumRequest.php b/src/Request/Manga/MangaForumRequest.php new file mode 100644 index 00000000..5c2eeb38 --- /dev/null +++ b/src/Request/Manga/MangaForumRequest.php @@ -0,0 +1,53 @@ +id = $id; + $this->topic = $topic; + } + + /** + * @return string + */ + public function getPath(): string + { + $query = ''; + if ($this->topic !== null && \in_array($this->topic, self::$validTypes, true)) { + $query = '?'.http_build_query(['topic' => $this->topic]); + } + + return sprintf('https://myanimelist.net/manga/%s/_/forum%s', $this->id, $query); + } +} diff --git a/src/Request/Manga/MangaMoreInfoRequest.php b/src/Request/Manga/MangaMoreInfoRequest.php new file mode 100644 index 00000000..bdd00f64 --- /dev/null +++ b/src/Request/Manga/MangaMoreInfoRequest.php @@ -0,0 +1,36 @@ +id = $id; + } + + /** + * return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/manga/%d/_/moreinfo', $this->id); + } +} diff --git a/src/Request/Manga/MangaNewsRequest.php b/src/Request/Manga/MangaNewsRequest.php new file mode 100644 index 00000000..56948aaf --- /dev/null +++ b/src/Request/Manga/MangaNewsRequest.php @@ -0,0 +1,36 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/manga/%s/_/news', $this->id); + } +} diff --git a/src/Request/Manga/MangaPicturesRequest.php b/src/Request/Manga/MangaPicturesRequest.php new file mode 100644 index 00000000..3c5f954a --- /dev/null +++ b/src/Request/Manga/MangaPicturesRequest.php @@ -0,0 +1,37 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + // MyAnimeList wants after //... it happily accepts jikan as a valid parameter though + return sprintf('https://myanimelist.net/manga/%d/jikan/pics', $this->id); + } +} diff --git a/src/Request/Manga/MangaRequest.php b/src/Request/Manga/MangaRequest.php new file mode 100644 index 00000000..13976436 --- /dev/null +++ b/src/Request/Manga/MangaRequest.php @@ -0,0 +1,37 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/manga/%s/', $this->id); + } +} diff --git a/src/Request/Manga/MangaStatsRequest.php b/src/Request/Manga/MangaStatsRequest.php new file mode 100644 index 00000000..df2bc43b --- /dev/null +++ b/src/Request/Manga/MangaStatsRequest.php @@ -0,0 +1,37 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + // MyAnimeList wants after //... it happily accepts jikan as a valid parameter though + return sprintf('https://myanimelist.net/manga/%d/jikan/stats', $this->id); + } +} diff --git a/src/Request/Person/PersonPicturesRequest.php b/src/Request/Person/PersonPicturesRequest.php new file mode 100644 index 00000000..d61e8473 --- /dev/null +++ b/src/Request/Person/PersonPicturesRequest.php @@ -0,0 +1,37 @@ +id = $id; + } + + /** + * @return string + */ + public function getPath(): string + { + // MyAnimeList wants after //... it happily accepts jikan as a valid parameter though + return sprintf('https://myanimelist.net/people/%d/jikan/pictures', $this->id); + } +} diff --git a/src/Request/Person/PersonRequest.php b/src/Request/Person/PersonRequest.php new file mode 100644 index 00000000..e7921307 --- /dev/null +++ b/src/Request/Person/PersonRequest.php @@ -0,0 +1,38 @@ +id = $id; + } + + /** + * Get the path to request + * + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/people/%s', $this->id); + } +} diff --git a/src/Request/Producer/ProducerRequest.php b/src/Request/Producer/ProducerRequest.php new file mode 100644 index 00000000..88bf4c21 --- /dev/null +++ b/src/Request/Producer/ProducerRequest.php @@ -0,0 +1,44 @@ +id = $id; + $this->page = $page; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/anime/producer/%s?page=%s', $this->id, $this->page); + } +} diff --git a/src/Request/RequestInterface.php b/src/Request/RequestInterface.php new file mode 100644 index 00000000..c8030558 --- /dev/null +++ b/src/Request/RequestInterface.php @@ -0,0 +1,18 @@ +query = $query; + $this->page = $page; + + $this->query = $this->query ?? ""; + } + + /** + * Get the path to request + * + * @return string + */ + public function getPath(): string + { + + $query = http_build_query( + [ + 'q' => $this->query, + 'show' => ($this->page !== 1) ? 50 * ($this->page - 1) : null, + 'letter' => $this->char, + 'type' => $this->type, + 'score' => $this->score, + 'status' => $this->status, + 'p' => $this->producer, + 'r' => $this->rated, + 'sd' => $this->startDate[0], + 'sm' => $this->startDate[1], + 'sy' => $this->startDate[2], + 'ed' => $this->endDate[0], + 'em' => $this->endDate[1], + 'ey' => $this->endDate[2], + 'gx' => (int)$this->genreExclude, + ] + ); + + // Add genre[]= + if (!empty($this->genre)) { + foreach ($this->genre as $genre) { + $query .= '&genre[]='.$genre; + } + } + + return sprintf( + 'https://myanimelist.net/anime.php?%s&c[]=a&c[]=b&c[]=c&c[]=f&c[]=d&c[]=e&c[]=g', + $query + ); + } + + /** + * @param null|string $query + * + * @return $this + */ + public function setQuery(?string $query = null): self + { + $this->query = $query; + $this->query = $this->query ?? ""; + + return $this; + } + + /** + * @param int $page + * + * @return $this + */ + public function setPage(int $page): self + { + $this->page = $page; + + return $this; + } + + /** + * @param string $char + * + * @return $this + */ + public function setStartsWithChar(string $char): self + { + $this->char = $char; + + return $this; + } + + /** + * @param string $type + * + * @return $this + */ + public function setType(string $type): self + { + $this->type = $type; + + return $this; + } + + /** + * @param float $score + * + * @return $this + */ + public function setScore(float $score): self + { + $this->score = $score; + + return $this; + } + + /** + * @param int $status + * + * @return $this + */ + public function setStatus(int $status): self + { + $this->status = $status; + + return $this; + } + + /** + * @param int $producer + * + * @return $this + */ + public function setProducer(int $producer): self + { + $this->producer = $producer; + + return $this; + } + + /** + * @param int $rated + * + * @return $this + */ + public function setRated(int $rated): self + { + $this->rated = $rated; + + return $this; + } + + /** + * @param int $day , int $month, int $year + * @param int $month + * @param int $year + * + * @return $this + */ + public function setStartDate(int $day, int $month, int $year): self + { + $this->startDate = [$day, $month, $year]; + + return $this; + } + + /** + * @param int $day , int $month, int $year + * @param int $month + * @param int $year + * + * @return $this + */ + public function setEndDate(int $day, int $month, int $year): self + { + $this->endDate = [$day, $month, $year]; + + return $this; + } + + /** + * @param array|int ...$genre + * + * @return AnimeSearchRequest + */ + public function setGenre(...$genre): self + { + $this->genre = array_unique( + array_merge($genre, $this->genre) + ); + + + return $this; + } + + /** + * @param bool $genreExclude + * + * @return $this + */ + public function setGenreExclude(bool $genreExclude): self + { + $this->genreExclude = $genreExclude; + + return $this; + } +} diff --git a/src/Request/Search/CharacterSearchRequest.php b/src/Request/Search/CharacterSearchRequest.php new file mode 100644 index 00000000..849a3108 --- /dev/null +++ b/src/Request/Search/CharacterSearchRequest.php @@ -0,0 +1,107 @@ +query = $query; + $this->page = $page; + + $this->query = $this->query ?? ""; + } + + /** + * Get the path to request + * + * @return string + */ + public function getPath(): string + { + + $query = http_build_query( + [ + 'q' => $this->query, + 'show' => ($this->page !== 1) ? 50 * ($this->page - 1) : null, + 'letter' => $this->char, + ] + ); + + return sprintf( + 'https://myanimelist.net/character.php?%s', + $query + ); + } + + /** + * @param null|string $query + * + * @return $this + */ + public function setQuery(?string $query = null): self + { + $this->query = $query; + $this->query = $this->query ?? ""; + + return $this; + } + + /** + * @param int $page + * + * @return $this + */ + public function setPage(int $page): self + { + $this->page = $page; + + return $this; + } + + /** + * @param string $char + * + * @return $this + */ + public function setStartsWithChar(string $char): self + { + $this->char = $char; + + return $this; + } +} diff --git a/src/Request/Search/MangaSearchRequest.php b/src/Request/Search/MangaSearchRequest.php new file mode 100644 index 00000000..1947e1cc --- /dev/null +++ b/src/Request/Search/MangaSearchRequest.php @@ -0,0 +1,268 @@ +query = $query; + $this->page = $page; + + $this->query = $this->query ?? ""; + } + + /** + * Get the path to request + * + * @return string + */ + public function getPath(): string + { + + $query = http_build_query( + [ + 'q' => $this->query, + 'show' => ($this->page !== 1) ? 50 * ($this->page - 1) : null, + 'letter' => $this->char, + 'type' => $this->type, + 'score' => $this->score, + 'status' => $this->status, + 'mid' => $this->magazine, + 'sd' => $this->startDate[0], + 'sm' => $this->startDate[1], + 'sy' => $this->startDate[2], + 'ed' => $this->endDate[0], + 'em' => $this->endDate[1], + 'ey' => $this->endDate[2], + 'gx' => (int)$this->genreExclude, + ] + ); + + // Add genre[]= + if (!empty($this->genre)) { + foreach ($this->genre as $genre) { + $query .= '&genre[]='.$genre; + } + } + + return sprintf( + 'https://myanimelist.net/manga.php?%s&c[]=a&c[]=b&c[]=c&c[]=f&c[]=d&c[]=e&c[]=g', + $query + ); + } + + /** + * @param null|string $query + * + * @return $this + */ + public function setQuery(?string $query = null): self + { + $this->query = $query; + $this->query = $this->query ?? ""; + + return $this; + } + + /** + * @param int $page + * + * @return $this + */ + public function setPage(int $page): self + { + $this->page = $page; + + return $this; + } + + /** + * @param string $char + * + * @return $this + */ + public function setStartsWithChar(string $char): self + { + $this->char = $char; + + return $this; + } + + /** + * @param string $type + * + * @return $this + */ + public function setType(string $type): self + { + $this->type = $type; + + return $this; + } + + /** + * @param float $score + * + * @return $this + */ + public function setScore(float $score): self + { + $this->score = $score; + + return $this; + } + + /** + * @param int $status + * + * @return $this + */ + public function setStatus(int $status): self + { + $this->status = $status; + + return $this; + } + + /** + * @param int $magazine + * + * @return $this + */ + public function setMagazine(int $magazine): self + { + $this->magazine = $magazine; + + return $this; + } + + /** + * @param int $day , int $month, int $year + * @param int $month + * @param int $year + * + * @return $this + */ + public function setStartDate(int $day, int $month, int $year): self + { + $this->startDate = [$day, $month, $year]; + + return $this; + } + + /** + * @param int $day , int $month, int $year + * @param int $month + * @param int $year + * + * @return $this + */ + public function setEndDate(int $day, int $month, int $year): self + { + $this->endDate = [$day, $month, $year]; + + return $this; + } + + /** + * @param array|int ...$genre + * + * @return MangaSearchRequest + */ + public function setGenre(...$genre): self + { + $this->genre = array_unique( + array_merge($genre, $this->genre) + ); + + + return $this; + } + + /** + * @param bool $genreExclude + * + * @return $this + */ + public function setGenreExclude(bool $genreExclude): self + { + $this->genreExclude = $genreExclude; + + return $this; + } +} diff --git a/src/Request/Search/PersonSearchRequest.php b/src/Request/Search/PersonSearchRequest.php new file mode 100644 index 00000000..77a0e7db --- /dev/null +++ b/src/Request/Search/PersonSearchRequest.php @@ -0,0 +1,107 @@ +query = $query; + $this->page = $page; + + $this->query = $this->query ?? ""; + } + + /** + * Get the path to request + * + * @return string + */ + public function getPath(): string + { + + $query = http_build_query( + [ + 'q' => $this->query, + 'show' => ($this->page !== 1) ? 50 * ($this->page - 1) : null, + 'letter' => $this->char, + ] + ); + + return sprintf( + 'https://myanimelist.net/character.php?%s', + $query + ); + } + + /** + * @param null|string $query + * + * @return $this + */ + public function setQuery(?string $query = null): self + { + $this->query = $query; + $this->query = $this->query ?? ""; + + return $this; + } + + /** + * @param int $page + * + * @return $this + */ + public function setPage(int $page): self + { + $this->page = $page; + + return $this; + } + + /** + * @param string $char + * + * @return $this + */ + public function setStartsWithChar(string $char): self + { + $this->char = $char; + + return $this; + } +} diff --git a/src/Request/SeasonList/SeasonListRequest.php b/src/Request/SeasonList/SeasonListRequest.php new file mode 100644 index 00000000..dffda07c --- /dev/null +++ b/src/Request/SeasonList/SeasonListRequest.php @@ -0,0 +1,21 @@ +year = $year; + $this->season = $season; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/anime/season/%s/%s', $this->year, $this->season); + } +} diff --git a/src/Request/Top/TopAnimeRequest.php b/src/Request/Top/TopAnimeRequest.php new file mode 100644 index 00000000..c70cb18c --- /dev/null +++ b/src/Request/Top/TopAnimeRequest.php @@ -0,0 +1,73 @@ +page = $page; + + if (null !== $type) { + if (!\in_array( + $type, + [ + Constants::TOP_AIRING, + Constants::TOP_UPCOMING, + Constants::TOP_TV, + Constants::TOP_MOVIE, + Constants::TOP_OVA, + Constants::TOP_SPECIAL, + Constants::TOP_BY_POPULARITY, + Constants::TOP_BY_FAVORITES, + ], + true + )) { + throw new \InvalidArgumentException(sprintf('Type %s is not valid', $type)); + } + + $this->type = $type; + } + } + + /** + * Get the path to request + * + * @return string + */ + public function getPath(): string + { + return 'https://myanimelist.net/topanime.php?'.http_build_query( + [ + 'limit' => 50 * ($this->page - 1), + 'type' => $this->type, + ] + ); + } +} diff --git a/src/Request/Top/TopCharactersRequest.php b/src/Request/Top/TopCharactersRequest.php new file mode 100644 index 00000000..e8151c61 --- /dev/null +++ b/src/Request/Top/TopCharactersRequest.php @@ -0,0 +1,38 @@ +page = $page; + } + + /** + * Get the path to request + * + * @return string + */ + public function getPath(): string + { + return 'https://myanimelist.net/character.php?'.http_build_query(['limit' => 50 * $this->page]); + } +} diff --git a/src/Request/Top/TopMangaRequest.php b/src/Request/Top/TopMangaRequest.php new file mode 100644 index 00000000..13050cc4 --- /dev/null +++ b/src/Request/Top/TopMangaRequest.php @@ -0,0 +1,73 @@ +page = $page; + + if (null !== $type) { + if (!\in_array( + $type, + [ + Constants::TOP_MANGA, + Constants::TOP_NOVEL, + Constants::TOP_ONE_SHOT, + Constants::TOP_DOUJINSHI, + Constants::TOP_MANHWA, + Constants::TOP_MANHUA, + Constants::TOP_BY_POPULARITY, + Constants::TOP_BY_FAVORITES, + ], + true + )) { + throw new \InvalidArgumentException(sprintf('Type %s is not valid', $type)); + } + + $this->type = $type; + } + } + + /** + * Get the path to request + * + * @return string + */ + public function getPath(): string + { + return 'https://myanimelist.net/topmanga.php?'.http_build_query( + [ + 'limit' => 50 * ($this->page - 1), + 'type' => $this->type, + ] + ); + } +} diff --git a/src/Request/Top/TopPeopleRequest.php b/src/Request/Top/TopPeopleRequest.php new file mode 100644 index 00000000..fc67c033 --- /dev/null +++ b/src/Request/Top/TopPeopleRequest.php @@ -0,0 +1,38 @@ +page = $page; + } + + /** + * Get the path to request + * + * @return string + */ + public function getPath(): string + { + return 'https://myanimelist.net/people.php?'.http_build_query(['limit' => 50 * $this->page]); + } +} diff --git a/src/Request/User/UserFriendsRequest.php b/src/Request/User/UserFriendsRequest.php new file mode 100644 index 00000000..4aea488c --- /dev/null +++ b/src/Request/User/UserFriendsRequest.php @@ -0,0 +1,48 @@ +username = $username; + $this->page = $page; + } + + /** + * @return string + */ + public function getPath(): string + { + $query = ''; + if ($this->page) { + $query = '?'.http_build_query(['offset' => ($this->page - 1) * 100]); + } + + return sprintf('https://myanimelist.net/profile/%s/friends%s', $this->username, $query); + } +} diff --git a/src/Request/User/UserHistoryRequest.php b/src/Request/User/UserHistoryRequest.php new file mode 100644 index 00000000..a83d4e75 --- /dev/null +++ b/src/Request/User/UserHistoryRequest.php @@ -0,0 +1,54 @@ +username = $username; + + + if (null !== $type) { + if (!\in_array($type, ['anime', 'manga'])) { + throw new \InvalidArgumentException(sprintf('Type %s is not valid', $type)); + } + + $this->type = $type; + } + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/history/%s/%s', $this->username, $this->type); + } +} diff --git a/src/Request/User/UserProfileRequest.php b/src/Request/User/UserProfileRequest.php new file mode 100644 index 00000000..8b2a85be --- /dev/null +++ b/src/Request/User/UserProfileRequest.php @@ -0,0 +1,37 @@ +username = $username; + } + + /** + * @return string + */ + public function getPath(): string + { + return sprintf('https://myanimelist.net/profile/%s/', $this->username); + } +} diff --git a/src/config.php b/src/config.php deleted file mode 100755 index 86654c49..00000000 --- a/src/config.php +++ /dev/null @@ -1,163 +0,0 @@ -format('Y-m-d')); + + $date = Parser::parseDate('Dec 1, 2004'); + self::assertInstanceOf(\DateTimeImmutable::class, $date); + self::assertEquals('2004-12-01', $date->format('Y-m-d')); + + $date = Parser::parseDate('?'); + self::assertNull($date); + } +} diff --git a/test/JikanTest/JikanTest.php b/test/JikanTest/JikanTest.php new file mode 100644 index 00000000..152f80c7 --- /dev/null +++ b/test/JikanTest/JikanTest.php @@ -0,0 +1,400 @@ +jikan = new MalClient; + } + + /** + * @test + * @vcr JikanTest_it_gets_anime.yaml + */ + public function it_gets_anime() + { + $anime = $this->jikan->getAnime(new \Jikan\Request\Anime\AnimeRequest(21)); + self::assertInstanceOf(\Jikan\Model\Anime\Anime::class, $anime); + } + + /** + * @test + * @vcr JikanTest_it_gets_manga.yaml + */ + public function it_gets_manga() + { + $manga = $this->jikan->getManga(new \Jikan\Request\Manga\MangaRequest(11)); + self::assertInstanceOf(\Jikan\Model\Manga\Manga::class, $manga); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_characters() + { + $character = $this->jikan->getCharacter(new \Jikan\Request\Character\CharacterRequest(116281)); + self::assertInstanceOf(\Jikan\Model\Character\Character::class, $character); + self::assertCount(9, $character->getAnimeography()); + self::assertCount(2, $character->getMangaography()); + self::assertCount(4, $character->getVoiceActors()); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_person() + { + $person = $this->jikan->getPerson(new \Jikan\Request\Person\PersonRequest(1)); + self::assertInstanceOf(\Jikan\Model\Person\Person::class, $person); + self::assertCount(367, $person->getVoiceActingRoles()); + self::assertCount(15, $person->getAnimeStaffPositions()); + self::assertCount(0, $person->getPublishedManga()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_seasonal_anime() + { + $seasonal = $this->jikan->getSeasonal(new \Jikan\Request\Seasonal\SeasonalRequest(2018, 'spring')); + self::assertInstanceOf(\Jikan\Model\Seasonal\Seasonal::class, $seasonal); + self::assertCount(234, $seasonal->getAnime()); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Seasonal\SeasonalAnime::class, $seasonal->getAnime()); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_user_profile() + { + $user = $this->jikan->getUserProfile(new \Jikan\Request\User\UserProfileRequest('sandshark')); + self::assertInstanceOf(\Jikan\Model\User\Profile::class, $user); + self::assertInstanceOf(\Jikan\Model\User\AnimeStats::class, $user->getAnimeStats()); + self::assertInstanceOf(\Jikan\Model\User\MangaStats::class, $user->getMangaStats()); + } + + /** + * @test + * @vcr ScheduleParserTest.yaml + */ + public function it_gets_schedule() + { + $schedule = $this->jikan->getSchedule(new \Jikan\Request\Schedule\ScheduleRequest()); + self::assertInstanceOf(\Jikan\Model\Shedule\Schedule::class, $schedule); + } + + /** + * @test + * @vcr FriendsParserTest.yaml + */ + public function it_gets_friends() + { + $friends = $this->jikan->getUserFriends(new \Jikan\Request\User\UserFriendsRequest('morshuwarrior')); + self::assertContainsOnlyInstancesOf(Friend::class, $friends); + self::assertCount(100, $friends); + self::assertContains('sandshark', $friends); + self::assertContains('mangalicker94', $friends); + self::assertContains('Moune-Chan', $friends); + + // Second page + $friends = $this->jikan->getUserFriends(new \Jikan\Request\User\UserFriendsRequest('morshuwarrior', 1)); + self::assertContainsOnlyInstancesOf(Friend::class, $friends); + self::assertCount(100, $friends); + self::assertContains('Benku', $friends); + self::assertContains('Seiya', $friends); + + // Empty page + // Second page + $friends = $this->jikan->getUserFriends(new \Jikan\Request\User\UserFriendsRequest('morshuwarrior', 100)); + self::assertContainsOnlyInstancesOf(Friend::class, $friends); + self::assertCount(0, $friends); + } + + /** + * @test + * @vcr ProducerParserTest.yaml + */ + public function it_gets_producer() + { + $producer = $this->jikan->getProducer(new \Jikan\Request\Producer\ProducerRequest(1)); + self::assertInstanceOf(\Jikan\Model\Producer\Producer::class, $producer); + } + + /** + * @test + * @vcr CharactersAndStaffParserTest.yaml + */ + public function it_gets_characters_and_staff() + { + $charactersAndStaff = $this->jikan->getAnimeCharactersAndStaff( + new \Jikan\Request\Anime\AnimeCharactersAndStaffRequest(35073) + ); + $staff = $charactersAndStaff->getStaff(); + $characters = $charactersAndStaff->getCharacters(); + self::assertCount(53, $characters); + self::assertCount(13, $staff); + } + + /** + * @test + * @vcr AnimeVideosParserTest.yaml + */ + public function it_gets_anime_videos() + { + $videos = $this->jikan->getAnimeVideos(new \Jikan\Request\Anime\AnimeVideosRequest(1)); + $promos = $videos->getPromos(); + $episodes = $videos->getEpisodes(); + self::assertCount(3, $promos); + self::assertCount(26, $episodes); + } + + /** + * @test + * @vcr AnimePicturesParserTest.yaml + */ + public function it_gets_anime_pictures() + { + $pictures = $this->jikan->getAnimePictures(new \Jikan\Request\Anime\AnimePicturesRequest(1)); + self::assertCount(10, $pictures); + } + + /** + * @test + * @vcr MangaPicturesParserTest.yaml + */ + public function it_gets_manga_pictures() + { + $pictures = $this->jikan->getMangaPictures(new \Jikan\Request\Manga\MangaPicturesRequest(1)); + self::assertCount(8, $pictures); + } + + /** + * @test + * @vcr PersonPicturesParserTest.yaml + */ + public function it_gets_person_pictures() + { + $pictures = $this->jikan->getPersonPictures(new \Jikan\Request\Person\PersonPicturesRequest(1)); + self::assertCount(4, $pictures); + } + + /** + * @test + * @vcr CharacterPicturesParserTest.yaml + */ + public function it_gets_character_pictures() + { + $pictures = $this->jikan->getCharacterPictures(new \Jikan\Request\Character\CharacterPicturesRequest(1)); + self::assertCount(15, $pictures); + } + + /** + * @test + * @vcr MangaNewsParserTest.yaml + */ + public function it_gets_manga_news() + { + $items = $this->jikan->getNewsList(new MangaNewsRequest(2)); + self::assertCount(14, $items); + self::assertContainsOnlyInstancesOf(NewsListItem::class, $items); + } + + /** + * @test + * @vcr AnimeNewsParserTest.yaml + */ + public function it_gets_anime_news() + { + $items = $this->jikan->getNewsList(new AnimeNewsRequest(21)); + self::assertCount(30, $items); + self::assertContainsOnlyInstancesOf(NewsListItem::class, $items); + } + + /** + * @test + * @vcr AnimeSearchParserTest.yaml + */ + public function it_gets_anime_search() + { + $search = $this->jikan->getAnimeSearch(new \Jikan\Request\Search\AnimeSearchRequest('Fate')); + self::assertCount(50, $search->getResults()); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Search\AnimeSearchListItem::class, $search->getResults()); + self::assertEquals(17, $search->getLastPage()); + } + + /** + * @test + * @vcr MangaSearchParserTest.yaml + */ + public function it_gets_manga_search() + { + $search = $this->jikan->getMangaSearch(new \Jikan\Request\Search\MangaSearchRequest('Fate')); + self::assertCount(50, $search->getResults()); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Search\MangaSearchListItem::class, $search->getResults()); + self::assertEquals(20, $search->getLastPage()); + } + + /** + * @test + * @vcr CharacterSearchParserTest.yaml + */ + public function it_gets_character_search() + { + $search = $this->jikan->getCharacterSearch(new \Jikan\Request\Search\CharacterSearchRequest('Fate')); + self::assertCount(50, $search->getResults()); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Search\CharacterSearchListItem::class, $search->getResults()); + self::assertEquals(11, $search->getLastPage()); + } + + /** + * @test + * @vcr PersonSearchParserTest.yaml + */ + public function it_gets_person_search() + { + $search = $this->jikan->getPersonSearch(new \Jikan\Request\Search\PersonSearchRequest('Ara')); + self::assertCount(50, $search->getResults()); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Search\PersonSearchListItem::class, $search->getResults()); + self::assertEquals(20, $search->getLastPage()); + } + + /** + * @test + * @vcr MangaCharacterListParserTest.yaml + */ + public function it_gets_manga_characters() + { + $characters = $this->jikan->getMangaCharacters(new \Jikan\Request\Manga\MangaCharactersRequest(2)); + self::assertCount(70, $characters); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Manga\CharacterListItem::class, $characters); + } + + /** + * @test + * @vcr TopAnimeParserTest.yaml + */ + public function it_gets_top_anime() + { + $anime = $this->jikan->getTopAnime(new \Jikan\Request\Top\TopAnimeRequest()); + self::assertCount(50, $anime); + self::assertContainsOnlyInstancesOf(TopAnime::class, $anime); + self::assertContains('Fullmetal Alchemist: Brotherhood', $anime); + self::assertContains('Mushishi Zoku Shou: Suzu no Shizuku', $anime); + } + + /** + * @test + * @vcr TopMangaParserTest.yaml + */ + public function it_gets_top_manga() + { + $manga = $this->jikan->getTopManga(new \Jikan\Request\Top\TopMangaRequest()); + self::assertCount(50, $manga); + self::assertContainsOnlyInstancesOf(TopManga::class, $manga); + self::assertContains('Berserk', $manga); + self::assertContains('Shigatsu wa Kimi no Uso', $manga); + } + + /** + * @test + * @vcr TopCharacterParserTest.yaml + */ + public function it_gets_top_characters() + { + $characters = $this->jikan->getTopCharacters(new \Jikan\Request\Top\TopCharactersRequest()); + self::assertCount(50, $characters); + self::assertContainsOnlyInstancesOf(TopCharacter::class, $characters); + self::assertContains('Lamperouge, Lelouch', $characters); + self::assertContains('Usui, Takumi', $characters); + } + + /** + * @test + * @vcr TopPeopleParserTest.yaml + */ + public function it_gets_top_people() + { + $people = $this->jikan->getTopPeople(new \Jikan\Request\Top\TopPeopleRequest()); + self::assertCount(50, $people); + self::assertContainsOnlyInstancesOf(TopPerson::class, $people); + self::assertContains('Hanazawa, Kana', $people); + self::assertContains('Asano, Inio', $people); + } + + /** + * @test + * @vcr ForumTopicParserTest.yaml + */ + public function it_gets_anime_forum() + { + $topics = $this->jikan->getAnimeForum(new AnimeForumRequest(21)); + self::assertCount(15, $topics); + self::assertContainsOnlyInstancesOf(ForumTopic::class, $topics); + self::assertContains('One Piece Episode 461 Discussion', $topics); + self::assertContains('One Piece Episode 101 Discussion', $topics); + } + + /** + * @test + * @vcr MangaForumTopicParserTest.yaml + */ + public function it_gets_manga_forum() + { + $topics = $this->jikan->getMangaForum(new MangaForumRequest(21)); + self::assertCount(15, $topics); + self::assertContainsOnlyInstancesOf(ForumTopic::class, $topics); + self::assertContains('Death Note Chapter 60 Discussion', $topics); + self::assertContains('Death Note Chapter 21 Discussion', $topics); + } + + /** + * @test + * @vcr HistoryParserTest.yaml + */ + public function it_gets_user_history() + { + $history = $this->jikan->getUserHistory(new \Jikan\Request\User\UserHistoryRequest('nekomata1037')); + self::assertCount(17, $history); + self::assertContainsOnlyInstancesOf(\Jikan\Model\User\History::class, $history); + } + + /** + * @test + * @vcr AnimeEpisodesParserTest.yaml + */ + public function it_gets_anime_episodes() + { + $episodes = $this->jikan->getAnimeEpisodes(new \Jikan\Request\Anime\AnimeEpisodesRequest(21)); + self::assertCount(100, $episodes->getEpisodes()); + self::assertEquals(9, $episodes->getEpisodesLastPage()); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Anime\EpisodeListItem::class, $episodes->getEpisodes()); + } +} diff --git a/test/JikanTest/Model/AnimeTest.php b/test/JikanTest/Model/AnimeTest.php new file mode 100644 index 00000000..0195e209 --- /dev/null +++ b/test/JikanTest/Model/AnimeTest.php @@ -0,0 +1,45 @@ +anime = $jikan->getAnime($request); + } + + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_episodes_unknown(): void + { + self::assertEquals(true,$this->anime->isEpisodesUnknown()); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_airing(): void + { + self::assertEquals(true,$this->anime->isAiring()); + } +} diff --git a/test/JikanTest/Parser/Anime/AnimeEpisodesParserTest.php b/test/JikanTest/Parser/Anime/AnimeEpisodesParserTest.php new file mode 100644 index 00000000..657fc416 --- /dev/null +++ b/test/JikanTest/Parser/Anime/AnimeEpisodesParserTest.php @@ -0,0 +1,152 @@ +request('GET', $request->getPath()); + $this->parser = new \Jikan\Parser\Anime\EpisodesParser($crawler); + } + + /** + * @test + * @covers \Jikan\Parser\Anime\EpisodesParser + * @vcr AnimeEpisodesParserTest.yaml + */ + public function it_gets_episodes_last_page(): void + { + self::assertEquals( + 9, + $this->parser->getEpisodesLastPage() + ); + } + + /** + * @test + * @covers \Jikan\Parser\Anime\EpisodesParser + * @vcr AnimeEpisodesParserTest.yaml + */ + public function it_gets_episode_id(): void + { + self::assertEquals( + 1, + $this->parser->getEpisodes()[0]->getEpisodeId() + ); + } + + /** + * @test + * @covers \Jikan\Parser\Anime\EpisodesParser + * @vcr AnimeEpisodesParserTest.yaml + */ + public function it_gets_episode_title(): void + { + self::assertEquals( + "I'm Luffy! The Man Who's Gonna Be King of the Pirates!", + $this->parser->getEpisodes()[0]->getTitle() + ); + } + + /** + * @test + * @covers \Jikan\Parser\Anime\EpisodesParser + * @vcr AnimeEpisodesParserTest.yaml + */ + public function it_gets_episode_title_japanese(): void + { + self::assertEquals( + "俺はルフィ!海賊王になる男だ!", + $this->parser->getEpisodes()[0]->getTitleJapanese() + ); + } + + /** + * @test + * @covers \Jikan\Parser\Anime\EpisodesParser + * @vcr AnimeEpisodesParserTest.yaml + */ + public function it_gets_episode_title_romanji(): void + { + self::assertContains( + "Ore wa Luffy! Kaizoku Ou ni Naru Otoko Da!", + $this->parser->getEpisodes()[0]->getTitleRomanji() + ); + } + + /** + * @test + * @covers \Jikan\Parser\Anime\EpisodesParser + * @vcr AnimeEpisodesParserTest.yaml + */ + public function it_gets_episode_aired(): void + { + self::assertInstanceOf( + \Jikan\Model\Common\DateRange::class, + $this->parser->getEpisodes()[0]->getAired() + ); + } + + /** + * @test + * @covers \Jikan\Parser\Anime\EpisodesParser + * @vcr AnimeEpisodesParserTest.yaml + */ + public function it_gets_episode_filler(): void + { + self::assertEquals( + false, + $this->parser->getEpisodes()[0]->isFiller() + ); + } + + /** + * @test + * @covers \Jikan\Parser\Anime\EpisodesParser + * @vcr AnimeEpisodesParserTest.yaml + */ + public function it_gets_episode_recap(): void + { + self::assertEquals( + false, + $this->parser->getEpisodes()[0]->isRecap() + ); + } + + + /** + * @test + * @covers \Jikan\Parser\Anime\EpisodesParser + * @vcr AnimeEpisodesParserTest.yaml + */ + public function it_gets_episode_video_url(): void + { + self::assertEquals( + "https://myanimelist.net/anime/21/One_Piece/episode/1", + $this->parser->getEpisodes()[0]->getVideoUrl() + ); + } + + /** + * @test + * @covers \Jikan\Parser\Anime\EpisodesParser + * @vcr AnimeEpisodesParserTest.yaml + */ + public function it_gets_episode_forum_url(): void + { + self::assertEquals( + "https://myanimelist.net/forum/?topicid=43183", + $this->parser->getEpisodes()[0]->getForumUrl() + ); + } +} \ No newline at end of file diff --git a/test/JikanTest/Parser/Anime/AnimeMoreInfoParserTest.php b/test/JikanTest/Parser/Anime/AnimeMoreInfoParserTest.php new file mode 100644 index 00000000..e4e6d170 --- /dev/null +++ b/test/JikanTest/Parser/Anime/AnimeMoreInfoParserTest.php @@ -0,0 +1,34 @@ +request('GET', $request->getPath()); + $this->parser = new \Jikan\Parser\Anime\MoreInfoParser($crawler); + } + + /** + * @test + * @covers \Jikan\Parser\Anime\MoreInfoParser + * @vcr AnimeMoreInfoParserTest.yaml + */ + public function it_gets_more_info(): void + { + self::assertContains( + 'Episode 492 is the second part of a two part special called Toriko x One Piece Collabo Special', + $this->parser->getMoreInfo() + ); + } +} \ No newline at end of file diff --git a/test/JikanTest/Parser/Anime/AnimeParserTest.php b/test/JikanTest/Parser/Anime/AnimeParserTest.php new file mode 100644 index 00000000..1a3a9cc7 --- /dev/null +++ b/test/JikanTest/Parser/Anime/AnimeParserTest.php @@ -0,0 +1,408 @@ +request('GET', $request->getPath()); + $this->parser = new \Jikan\Parser\Anime\AnimeParser($crawler); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_mal_id(): void + { + self::assertEquals(21, $this->parser->getId()); + } + + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_url(): void + { + self::assertEquals('https://myanimelist.net/anime/21/One_Piece', $this->parser->getURL()); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_title(): void + { + self::assertEquals('One Piece', $this->parser->getTitle()); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_title_english(): void + { + self::assertEquals('One Piece', $this->parser->getTitleEnglish()); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_title_synonyms(): void + { + self::assertContains('OP', $this->parser->getTitleSynonyms()); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_title_japanese(): void + { + self::assertEquals('ONE PIECE', $this->parser->getTitleJapanese()); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_image_url(): void + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/images/anime/6/73245.jpg', + $this->parser->getImageURL() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_synopsis(): void + { + self::assertEquals( + 'Gol D. Roger was known as the "Pirate King," the strongest and most infamous being to have sailed the Grand Line. The capture and execution of Roger by the World Government brought a change throughout the world. His last words before his death revealed the existence of the greatest treasure in the world, One Piece. It was this revelation that brought about the Grand Age of Pirates, men who dreamed of finding One Piece—which promises an unlimited amount of riches and fame—and quite possibly the pinnacle of glory and the title of the Pirate King. Enter Monkey D. Luffy, a 17-year-old boy who defies your standard definition of a pirate. Rather than the popular persona of a wicked, hardened, toothless pirate ransacking villages for fun, Luffy’s reason for being a pirate is one of pure wonder: the thought of an exciting adventure that leads him to intriguing people and ultimately, the promised treasure. Following in the footsteps of his childhood hero, Luffy and his crew travel across the Grand Line, experiencing crazy adventures, unveiling dark mysteries and battling strong enemies, all in order to reach the most coveted of all fortunes—One Piece. [Written by MAL Rewrite]', + $this->parser->getSynopsis() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_type(): void + { + self::assertEquals( + 'TV', + $this->parser->getType() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_episodes(): void + { + self::assertEquals( + 0, + $this->parser->getEpisodes() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_status(): void + { + self::assertEquals( + 'Currently Airing', + $this->parser->getStatus() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_aired_string(): void + { + self::assertEquals( + 'Oct 20, 1999 to ?', + $this->parser->getAnimeAiredString() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_aired(): void + { + $aired = $this->parser->getAired(); + self::assertInstanceOf(\DateTimeImmutable::class, $aired->getFrom()); + self::assertEquals('1999-10-20', $aired->getFrom()->format('Y-m-d')); + self::assertNull($aired->getUntil()); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_premiered(): void + { + self::assertEquals('Fall 1999', $this->parser->getPremiered()); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_broadcast(): void + { + self::assertEquals('Sundays at 09:30 (JST)', $this->parser->getBroadcast()); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_producer(): void + { + $producers = $this->parser->getProducers(); + self::assertCount(3, $producers); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\MalUrl::class, $producers); + self::assertContains('Fuji TV', $producers); + self::assertContains('TAP', $producers); + self::assertContains('Shueisha', $producers); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_licensor(): void + { + $licensors = $this->parser->getLicensors(); + self::assertCount(2, $licensors); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\MalUrl::class, $licensors); + self::assertContains('Funimation', $licensors); + self::assertContains('4Kids Entertainment', $licensors); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_studio(): void + { + $studios = $this->parser->getStudios(); + self::assertCount(1, $studios); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\MalUrl::class, $studios); + self::assertContains('Toei Animation', $studios); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_source(): void + { + self::assertEquals('Manga', $this->parser->getSource()); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_genre(): void + { + $genres = $this->parser->getGenres(); + self::assertCount(7, $genres); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\MalUrl::class, $genres); + self::assertContains('Action', $genres); + self::assertContains('Adventure', $genres); + self::assertContains('Comedy', $genres); + self::assertContains('Super Power', $genres); + self::assertContains('Drama', $genres); + self::assertContains('Fantasy', $genres); + self::assertContains('Shounen', $genres); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_duration(): void + { + self::assertEquals( + '24 min', + $this->parser->getDuration() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_rating(): void + { + self::assertEquals( + 'PG-13 - Teens 13 or older', + $this->parser->getRating() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_score(): void + { + self::assertEquals( + 8.54, + $this->parser->getScore() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_scored_by(): void + { + self::assertEquals( + 428921, + $this->parser->getScoredBy() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_rank(): void + { + self::assertEquals( + 89, + $this->parser->getRank() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_popularity(): void + { + self::assertEquals( + 37, + $this->parser->getPopularity() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_members(): void + { + self::assertEquals( + 730240, + $this->parser->getMembers() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_favorites(): void + { + self::assertEquals( + 70500, + $this->parser->getFavorites() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_related(): void + { + $related = $this->parser->getRelated(); + self::assertCount(6, $related); + self::assertContainsOnlyInstancesOf(MalUrl::class, $related['Adaptation']); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_background(): void + { + self::assertEquals( + 'Several anime-original arcs have been adapted into light novels, and the series has inspired 40 video games as of 2016.', + $this->parser->getBackground() + ); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_opening(): void + { + $ops = $this->parser->getOpeningThemes(); + self::assertCount(19, $ops); + self::assertContains('"We Are! (ウィーアー!)" by Hiroshi Kitadani (eps 1-47)', $ops); + self::assertContains('"We Are (ウィーアー! 〜10周年Ver.〜)" by TVXQ (eps 373-394)', $ops); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_anime_ending(): void + { + $eds = $this->parser->getEndingThemes(); + self::assertCount(21, $eds); + self::assertContains('"memories" by Maki Otsuki (eps 1-30)', $eds); + self::assertContains('"We go! (ウィーゴー!)" by Hiroshi Kitadani (eps 542, 590)', $eds); + } + + /** + * @test + * @vcr AnimeParserTest.yaml + */ + public function it_gets_the_preview_video() + { + $preview = $this->parser->getPreview(); + self::assertEquals('https://www.youtube.com/embed/um-tFlVamOI?enablejsapi=1&wmode=opaque&autoplay=1', $preview); + } +} diff --git a/test/JikanTest/Parser/Anime/AnimeStatsParserTest.php b/test/JikanTest/Parser/Anime/AnimeStatsParserTest.php new file mode 100644 index 00000000..f8f8123e --- /dev/null +++ b/test/JikanTest/Parser/Anime/AnimeStatsParserTest.php @@ -0,0 +1,57 @@ +request('GET', $request->getPath()); + $this->animeStatsParser = new \Jikan\Parser\Anime\AnimeStatsParser($crawler); + } + + /** + * @test + * @vcr AnimeStats.yaml + */ + public function it_gets_numeric_statistics() + { + self::assertGreaterThan(0, $this->animeStatsParser->getWatching()); + self::assertGreaterThan(0, $this->animeStatsParser->getCompleted()); + self::assertGreaterThan(0, $this->animeStatsParser->getOnHold()); + self::assertGreaterThan(0, $this->animeStatsParser->getDropped()); + self::assertGreaterThan(0, $this->animeStatsParser->getTotal()); + self::assertGreaterThan(0, $this->animeStatsParser->getPlanToWatch()); + } + + /** + * @test + * @vcr AnimeStats.yaml + */ + public function it_gets_score_statistics() + { + self::assertEquals(2, count($this->animeStatsParser->getScores()[10])); + self::assertEquals(2, count($this->animeStatsParser->getScores()[9])); + self::assertEquals(2, count($this->animeStatsParser->getScores()[8])); + self::assertEquals(2, count($this->animeStatsParser->getScores()[7])); + self::assertEquals(2, count($this->animeStatsParser->getScores()[6])); + self::assertEquals(2, count($this->animeStatsParser->getScores()[5])); + self::assertEquals(2, count($this->animeStatsParser->getScores()[4])); + self::assertEquals(2, count($this->animeStatsParser->getScores()[3])); + self::assertEquals(2, count($this->animeStatsParser->getScores()[2])); + self::assertEquals(2, count($this->animeStatsParser->getScores()[1])); + } +} diff --git a/test/JikanTest/Parser/Character/AnimeographyParserTest.php b/test/JikanTest/Parser/Character/AnimeographyParserTest.php new file mode 100644 index 00000000..d9d1e5c9 --- /dev/null +++ b/test/JikanTest/Parser/Character/AnimeographyParserTest.php @@ -0,0 +1,72 @@ +request('GET', 'https://myanimelist.net/character/116281'); + $crawler = $crawler->filterXPath('//div[contains(text(), \'Animeography\')]/../table/tr')->first(); + $this->parser = new \Jikan\Parser\Character\AnimeographyParser($crawler); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_anime_mal_id() + { + self::assertEquals(29803, $this->parser->getMalId()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_anime_url() + { + self::assertEquals('https://myanimelist.net/anime/29803/Overlord', $this->parser->getUrl()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_anime_name() + { + self::assertEquals('Overlord', $this->parser->getName()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_anime_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/r/23x32/images/anime/7/88019.jpg?s=ff141fea6f6c523c7205ff1957340003', + $this->parser->getImage() + ); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_role() + { + self::assertEquals('Main',$this->parser->getRole()); + } +} diff --git a/test/JikanTest/Parser/Character/CharacterListItemParserTest.php b/test/JikanTest/Parser/Character/CharacterListItemParserTest.php new file mode 100644 index 00000000..b3dfc684 --- /dev/null +++ b/test/JikanTest/Parser/Character/CharacterListItemParserTest.php @@ -0,0 +1,95 @@ +request('GET', 'https://myanimelist.net/anime/35073/Overlord_II/characters'); + + $this->parser = new CharacterListItemParser( + $crawler->filterXPath('//h2[text()="Characters & Voice Actors"]/following-sibling::table') + ->reduce( + function (Crawler $crawler) { + return (bool)$crawler->filterXPath( + '//a[contains(@href, "https://myanimelist.net/character")]' + )->count(); + } + )->first() + ); + } + + /** + * @test + * @vcr CharactersParserTest.yaml + */ + public function it_gets_the_mal_id() + { + self::assertEquals(116275, $this->parser->getMalId()); + } + + /** + * @test + * @vcr CharactersParserTest.yaml + */ + public function it_gets_the_name() + { + self::assertEquals('Albedo', $this->parser->getName()); + } + + /** + * @test + * @vcr CharactersParserTest.yaml + */ + public function it_gets_the_url() + { + self::assertEquals('https://myanimelist.net/character/116275/Albedo', $this->parser->getCharacterUrl()); + } + + /** + * @test + * @vcr CharactersParserTest.yaml + */ + public function it_gets_the_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/r/23x32/images/characters/5/288167.jpg?s=4eb5561fa112e46f87456377a9a997ce', + $this->parser->getImage() + ); + } + + /** + * @test + * @vcr CharactersParserTest.yaml + */ + public function it_gets_the_voice_actors() + { + $voiceActors = $this->parser->getVoiceActors(); + self::assertContainsOnly(VoiceActor::class, $voiceActors); + self::assertCount(2, $voiceActors); + self::assertContains('Hara, Yumi', $voiceActors); + self::assertEquals('Japanese', $voiceActors[0]->getLanguage()); + self::assertEquals('English', $voiceActors[1]->getLanguage()); + self::assertEquals( + 'https://myanimelist.cdn-dena.com/r/23x32/images/voiceactors/3/49242.jpg?s=8fafa056dafe96209a6757ff802b7f8f', + $voiceActors[1]->getImageUrl() + ); + self::assertContains('Maxwell, Elizabeth', $voiceActors); + } +} diff --git a/test/JikanTest/Parser/Character/CharacterParserTest.php b/test/JikanTest/Parser/Character/CharacterParserTest.php new file mode 100644 index 00000000..48dcf25c --- /dev/null +++ b/test/JikanTest/Parser/Character/CharacterParserTest.php @@ -0,0 +1,140 @@ +request('GET', $request->getPath()); + $this->parser = new \Jikan\Parser\Character\CharacterParser($crawler); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_mal_id() + { + self::assertEquals(116281, $this->parser->getMalId()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_character_url() + { + self::assertEquals('https://myanimelist.net/character/116281/Momonga', $this->parser->getCharacterUrl()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_name() + { + self::assertEquals('Momonga', $this->parser->getName()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_name_in_kanji() + { + self::assertEquals('モモンガ', $this->parser->getNameKanji()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_nicknames() + { + $aliases = $this->parser->getNameNicknames(); + self::assertCount(2, $aliases); + self::assertContains('Momon', $aliases); + self::assertContains('Ainz Ooal Gown', $aliases); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_about() + { + self::assertContains('He is the guild master of Ainz Ooal Gown and regarded', $this->parser->getAbout()); + self::assertContains('(Source: Overlord Wikia)', $this->parser->getAbout()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_member_favorites() + { + self::assertEquals(3755, $this->parser->getMemberFavorites()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/images/characters/3/288006.jpg', + $this->parser->getImage() + ); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_animeography() + { + $animeography = $this->parser->getAnimeography(); + self::assertCount(9, $animeography); + self::assertContainsOnly(\Jikan\Model\Character\Animeography::class, $animeography); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_mangaography() + { + $manaography = $this->parser->getMangaography(); + self::assertCount(2, $manaography); + self::assertContainsOnly(\Jikan\Model\Character\Mangaography::class, $manaography); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_voice_actors() + { + $voiceActors = $this->parser->getVoiceActors(); + self::assertCount(4, $voiceActors); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Character\VoiceActor::class, $voiceActors); + self::assertContains('Hino, Satoshi', $voiceActors); + self::assertContains('Mendiant, Charles', $voiceActors); + self::assertContains('Kaminski, Stefan', $voiceActors); + self::assertContains('Guerrero, Chris', $voiceActors); + } +} diff --git a/test/JikanTest/Parser/Character/StaffListItemParserTest.php b/test/JikanTest/Parser/Character/StaffListItemParserTest.php new file mode 100644 index 00000000..b46f87f4 --- /dev/null +++ b/test/JikanTest/Parser/Character/StaffListItemParserTest.php @@ -0,0 +1,79 @@ +request('GET', 'https://myanimelist.net/anime/35073/_/characters'); + + $this->parser = new \Jikan\Parser\Anime\StaffListItemParser( + $crawler->filterXPath('//h2/div/../following-sibling::table') + ->eq(4) + ); + } + + /** + * @test + * @vcr CharactersParserTest.yaml + */ + public function it_gets_the_mal_id() + { + self::assertEquals(12596, $this->parser->getMalId()); + } + + /** + * @test + * @vcr CharactersParserTest.yaml + */ + public function it_gets_the_name() + { + self::assertEquals('Tom-H@ck', $this->parser->getName()); + } + + /** + * @test + * @vcr CharactersParserTest.yaml + */ + public function it_gets_the_url() + { + self::assertEquals('https://myanimelist.net/people/12596/Tom-Hck', $this->parser->getUrl()); + } + + /** + * @test + * @vcr CharactersParserTest.yaml + */ + public function it_gets_the_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/r/23x32/images/voiceactors/3/33089.jpg?s=81a13198b1b0772a7565e8786b94cfe8', + $this->parser->getImage() + ); + } + + /** + * @test + * @vcr CharactersParserTest.yaml + */ + public function it_gets_the_positions() + { + $positions = $this->parser->getPositions(); + self::assertCount(2, $positions); + self::assertContains('Theme Song Composition', $positions); + self::assertContains('Theme Song Arrangement', $positions); + } +} diff --git a/test/JikanTest/Parser/Character/VoiceActorParserTest.php b/test/JikanTest/Parser/Character/VoiceActorParserTest.php new file mode 100644 index 00000000..4f06afd9 --- /dev/null +++ b/test/JikanTest/Parser/Character/VoiceActorParserTest.php @@ -0,0 +1,75 @@ +request('GET', 'https://myanimelist.net/character/116281'); + $crawler = $crawler->filterXPath('//div[contains(text(), \'Voice Actors\')]/../table/tr')->first(); + $this->parser = new \Jikan\Parser\Character\VoiceActorParser($crawler); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_mal_id() + { + self::assertEquals(245, $this->parser->getMalId()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_url() + { + self::assertEquals('https://myanimelist.net/people/245/Satoshi_Hino', $this->parser->getUrl()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_person() + { + $person = $this->parser->getPerson(); + self::assertInstanceOf(\Jikan\Model\Common\MalUrl::class, $person); + self::assertEquals('Hino, Satoshi', $person); + self::assertEquals('https://myanimelist.net/people/245/Satoshi_Hino', $person->getUrl()); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/images/voiceactors/3/18359v.jpg', + $this->parser->getImage() + ); + } + + /** + * @test + * @vcr CharacterParserTest.yaml + */ + public function it_gets_the_language() + { + self::assertEquals('Japanese', $this->parser->getLanguage()); + } +} diff --git a/test/JikanTest/Parser/Forum/ForumTopicParserTest.php b/test/JikanTest/Parser/Forum/ForumTopicParserTest.php new file mode 100644 index 00000000..b2a0e717 --- /dev/null +++ b/test/JikanTest/Parser/Forum/ForumTopicParserTest.php @@ -0,0 +1,104 @@ +request('GET', 'https://myanimelist.net/anime/21/_/forum'); + $this->parser = new ForumTopicParser($crawler->filterXPath('//tr[contains(@id, "topicRow")]')->eq(2)); + } + + /** + * @test + * @vcr ForumTopicParserTest.yaml + */ + public function it_gets_the_post_id(): void + { + self::assertEquals(251121, $this->parser->getTopicId()); + } + + /** + * @test + * @vcr ForumTopicParserTest.yaml + */ + public function it_gets_the_post_url(): void + { + self::assertEquals('https://myanimelist.net/forum/?topicid=251121', $this->parser->getUrl()); + } + + /** + * @test + * @vcr ForumTopicParserTest.yaml + */ + public function it_gets_the_post_title(): void + { + self::assertEquals('One Piece Episode 460 Discussion', $this->parser->getTitle()); + } + + /** + * @test + * @vcr ForumTopicParserTest.yaml + */ + public function it_gets_the_post_date(): void + { + self::assertEquals('2010-07-31', $this->parser->getPostDate()->format('Y-m-d')); + } + + /** + * @test + * @vcr ForumTopicParserTest.yaml + */ + public function it_gets_the_author_name(): void + { + self::assertEquals('JusticeGundam', $this->parser->getAuthorName()); + } + + /** + * @test + * @vcr ForumTopicParserTest.yaml + */ + public function it_gets_the_author_url(): void + { + self::assertEquals('https://myanimelist.net/profile/JusticeGundam', $this->parser->getAuthorUrl()); + } + + /** + * @test + * @vcr ForumTopicParserTest.yaml + */ + public function it_gets_the_replies(): void + { + self::assertEquals(83, $this->parser->getReplies()); + } + + /** + * @test + * @vcr ForumTopicParserTest.yaml + */ + public function it_gets_the_last_post(): void + { + $lastPost = $this->parser->getLastPost(); + self::assertInstanceOf(ForumPost::class, $lastPost); + self::assertEquals('Serhiyko', $lastPost->getAuthorName()); + self::assertEquals('https://myanimelist.net/profile/Serhiyko', $lastPost->getAuthorUrl()); + self::assertEquals('https://myanimelist.net/forum/?topicid=251121&goto=lastpost', $lastPost->getUrl()); + self::assertEquals('2018-05-27', $lastPost->getRelativeDate()->format('Y-m-d')); + } +} diff --git a/test/JikanTest/Parser/Genre/AnimeGenreParserTest.php b/test/JikanTest/Parser/Genre/AnimeGenreParserTest.php new file mode 100644 index 00000000..067c8db2 --- /dev/null +++ b/test/JikanTest/Parser/Genre/AnimeGenreParserTest.php @@ -0,0 +1,55 @@ +request('GET', 'https://myanimelist.net/anime/genre/1'); + $this->parser = new AnimeGenreParser($crawler); + } + + /** + * @test + * @vcr AnimeGenreParserTest.yaml + */ + public function it_gets_url() + { + $url = $this->parser->getUrl(); + self::assertEquals("https://myanimelist.net/anime/genre/1/Action", $url); + } + + /** + * @test + * @vcr AnimeGenreParserTest.yaml + */ + public function it_gets_anime() + { + $anime = $this->parser->getGenreAnime(); + self::assertContainsOnlyInstancesOf(AnimeCard::class, $anime); + } + + /** + * @test + * @vcr AnimeGenreParserTest.yaml + */ + public function it_gets_the_count() + { + self::assertEquals(3263, $this->parser->getCount()); + } +} diff --git a/test/JikanTest/Parser/Genre/MangaGenreParserTest.php b/test/JikanTest/Parser/Genre/MangaGenreParserTest.php new file mode 100644 index 00000000..4bbb0e2c --- /dev/null +++ b/test/JikanTest/Parser/Genre/MangaGenreParserTest.php @@ -0,0 +1,56 @@ +request('GET', 'https://myanimelist.net/manga/genre/1'); + $this->parser = new MangaGenreParser($crawler); + } + + /** + * @test + * @vcr MangaGenreParserTest.yaml + */ + public function it_gets_url() + { + $url = $this->parser->getUrl(); + self::assertEquals("https://myanimelist.net/manga/genre/1/Action", $url); + } + + /** + * @test + * @vcr MangaGenreParserTest.yaml + */ + public function it_gets_manga() + { + $manga = $this->parser->getGenreManga(); + self::assertContainsOnlyInstancesOf(MangaCard::class, $manga); + } + + /** + * @test + * @vcr MangaGenreParserTest.yaml + */ + public function it_gets_the_count() + { + self::assertEquals(6187, $this->parser->getCount()); + } +} diff --git a/test/JikanTest/Parser/Magazine/MagazineParserTest.php b/test/JikanTest/Parser/Magazine/MagazineParserTest.php new file mode 100644 index 00000000..7bf1fcf2 --- /dev/null +++ b/test/JikanTest/Parser/Magazine/MagazineParserTest.php @@ -0,0 +1,46 @@ +request('GET', 'https://myanimelist.net/manga/magazine/1'); + $this->parser = new MagazineParser($crawler); + } + + /** + * @test + * @vcr MagazineParserTest.yaml + */ + public function it_gets_url() + { + $url = $this->parser->getUrl(); + self::assertInstanceOf(\Jikan\Model\Common\MalUrl::class, $url); + } + + /** + * @test + * @vcr MagazineParserTest.yaml + */ + public function it_gets_manga() + { + $manga = $this->parser->getMagazineManga(); + self::assertCount(56, $manga); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\MangaCard::class, $manga); + } +} diff --git a/test/JikanTest/Parser/Manga/CharactersParserTest.php b/test/JikanTest/Parser/Manga/CharactersParserTest.php new file mode 100644 index 00000000..f62ab505 --- /dev/null +++ b/test/JikanTest/Parser/Manga/CharactersParserTest.php @@ -0,0 +1,37 @@ +request('GET', 'https://myanimelist.net/manga/2/Berserk/characters'); + $this->parser = new CharactersParser($crawler); + } + + /** + * @test + * @vcr MangaCharacterListParserTest.yaml + */ + public function it_gets_the_manga_characters() + { + $characters = $this->parser->getCharacters(); + self::assertCount(70, $characters); + self::assertContains('Wyald', $characters); + self::assertContains('Casca', $characters); + self::assertEquals('Main', $characters[0]->getRole()); + } +} diff --git a/test/JikanTest/Parser/Manga/MangaParserTest.php b/test/JikanTest/Parser/Manga/MangaParserTest.php new file mode 100644 index 00000000..f866eb3e --- /dev/null +++ b/test/JikanTest/Parser/Manga/MangaParserTest.php @@ -0,0 +1,356 @@ +request('GET', $request->getPath()); + $this->parser = new \Jikan\Parser\Manga\MangaParser($crawler); + + $jikan = new MalClient; + $this->manga = $jikan->getManga( + $request + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_mal_id() + { + self::assertEquals(11, $this->parser->getMangaID()); + } + + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_url() + { + self::assertEquals('https://myanimelist.net/manga/11/Naruto', $this->parser->getMangaURL()); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_title() + { + self::assertEquals('Naruto', $this->parser->getMangaTitle()); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_title_english() + { + self::assertEquals('Naruto', $this->parser->getMangaTitleEnglish()); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_title_synonyms() + { + self::assertEquals([], $this->parser->getMangaTitleSynonyms()); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_title_japanese() + { + self::assertEquals('NARUTO―ナルト―', $this->parser->getMangaTitleJapanese()); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_image_url() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/images/manga/3/117681.jpg', + $this->parser->getMangaImageURL() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_synopsis() + { + self::assertEquals( + "Whenever Naruto Uzumaki proclaims that he will someday become the Hokage—a title bestowed upon the best ninja in the Village Hidden in the Leaves—no one takes him seriously. Since birth, Naruto has been shunned and ridiculed by his fellow villagers. But their contempt isn't because Naruto is loud-mouthed, mischievous, or because of his ineptitude in the ninja arts, but because there is a demon inside him. Prior to Naruto's birth, the powerful and deadly Nine-Tailed Fox attacked the village. In order to stop the rampage, the Fourth Hokage sacrificed his life to seal the demon inside the body of the newborn Naruto. And so when he is assigned to Team 7—along with his new teammates Sasuke Uchiha and Sakura Haruno, under the mentorship of veteran ninja Kakashi Hatake—Naruto is forced to work together with other people for the first time in his life. Through undergoing vigorous training and taking on challenging missions, Naruto must learn what it means to work in a team and carve his own route toward becoming a full-fledged ninja recognized by his village. [Written by MAL Rewrite]", + $this->parser->getMangaSynopsis() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_type() + { + self::assertEquals( + 'Manga', + $this->parser->getMangaType() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_chapters() + { + self::assertEquals( + 700, + $this->parser->getMangaChapters() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_volumes() + { + self::assertEquals( + 72, + $this->parser->getMangaVolumes() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_chapters_unknown() + { + self::assertEquals( + false, + $this->manga->isChaptersUnknown() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_volumes_unknown() + { + self::assertEquals( + false, + $this->manga->isVolumesUnknown() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_status() + { + self::assertEquals( + 'Finished', + $this->parser->getMangaStatus() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_publishing() + { + self::assertEquals( + false, + $this->manga->isPublishing() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_published() + { + $range = $this->manga->getPublished(); + self::assertInstanceOf(DateRange::class, $range); + self::assertInstanceOf(\DateTimeImmutable::class, $range->getFrom()); + self::assertInstanceOf(\DateTimeImmutable::class, $range->getUntil()); + self::assertEquals('1999-09-21', $range->getFrom()->format('Y-m-d')); + self::assertEquals('2014-11-10', $range->getUntil()->format('Y-m-d')); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_authors() + { + $authors = $this->manga->getAuthors(); + self::assertCount(1, $authors); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\MalUrl::class, $authors); + self::assertContains('Kishimoto, Masashi', $authors); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_serialization() + { + $serializations = $this->manga->getSerializations(); + self::assertCount(1, $serializations); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\MalUrl::class, $serializations); + self::assertContains('Shounen Jump (Weekly)', $serializations); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_genre() + { + $genres = $this->manga->getGenres(); + self::assertCount(5, $genres); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\MalUrl::class, $genres); + self::assertContains('Action', $genres); + self::assertContains('Adventure', $genres); + self::assertContains('Martial Arts', $genres); + self::assertContains('Shounen', $genres); + self::assertContains('Super Power', $genres); + } + + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_score() + { + self::assertEquals( + 8.11, + $this->manga->getScore() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_scored_by() + { + self::assertEquals( + 177655, + $this->manga->getScoredBy() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_rank() + { + self::assertEquals( + 706, + $this->manga->getRank() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_popularity() + { + self::assertEquals( + 1, + $this->manga->getPopularity() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_members() + { + self::assertEquals( + 258896, + $this->manga->getMembers() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_favorites() + { + self::assertEquals( + 39966, + $this->manga->getFavorites() + ); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_related() + { + $related = $this->parser->getMangaRelated(); + self::assertCount(5, $related); + self::assertContainsOnlyInstancesOf(MalUrl::class, $related['Alternative version']); + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_manga_background() + { + $background = $this->manga->getBackground(); + self::assertContains( + 'Naruto has sold over 220 million copies worldwide as of 2015, making it the 4th highest grossing', + $background + ); + self::assertContains( + ' Comics/Planet Manga from May 2007 to June 2015, and again as Naruto Gold edition since July 2015.', + $background + ); + } + +} diff --git a/test/JikanTest/Parser/Manga/MangaStatsParserTest.php b/test/JikanTest/Parser/Manga/MangaStatsParserTest.php new file mode 100644 index 00000000..6306f5e8 --- /dev/null +++ b/test/JikanTest/Parser/Manga/MangaStatsParserTest.php @@ -0,0 +1,57 @@ +request('GET', $request->getPath()); + $this->mangaStatsParser = new MangaStatsParser($crawler); + } + + /** + * @test + * @vcr MangaStats.yaml + */ + public function it_gets_numeric_statistics() + { + self::assertGreaterThan(0, $this->mangaStatsParser->getReading()); + self::assertGreaterThan(0, $this->mangaStatsParser->getCompleted()); + self::assertGreaterThan(0, $this->mangaStatsParser->getOnHold()); + self::assertGreaterThan(0, $this->mangaStatsParser->getDropped()); + self::assertGreaterThan(0, $this->mangaStatsParser->getTotal()); + self::assertGreaterThan(0, $this->mangaStatsParser->getPlanToRead()); + } + + /** + * @test + * @vcr MangaStats.yaml + */ + public function it_gets_score_statistics() + { + self::assertEquals(2, count($this->mangaStatsParser->getScores()[10])); + self::assertEquals(2, count($this->mangaStatsParser->getScores()[9])); + self::assertEquals(2, count($this->mangaStatsParser->getScores()[8])); + self::assertEquals(2, count($this->mangaStatsParser->getScores()[7])); + self::assertEquals(2, count($this->mangaStatsParser->getScores()[6])); + self::assertEquals(2, count($this->mangaStatsParser->getScores()[5])); + self::assertEquals(2, count($this->mangaStatsParser->getScores()[4])); + self::assertEquals(2, count($this->mangaStatsParser->getScores()[3])); + self::assertEquals(2, count($this->mangaStatsParser->getScores()[2])); + self::assertEquals(2, count($this->mangaStatsParser->getScores()[1])); + } +} diff --git a/test/JikanTest/Parser/News/NewsListItemParserTest.php b/test/JikanTest/Parser/News/NewsListItemParserTest.php new file mode 100644 index 00000000..e4e1f8f0 --- /dev/null +++ b/test/JikanTest/Parser/News/NewsListItemParserTest.php @@ -0,0 +1,95 @@ +request('GET', 'https://myanimelist.net/manga/2/Berserk/news'); + $this->parser = new NewsListItemParser( + $crawler->filterXPath('//div[@class="js-scrollfix-bottom-rel"]/div[@class="clearfix"]')->first() + ); + } + + /** + * @test + * @vcr NewsParserTest.yaml + */ + public function it_gets_the_title(): void + { + self::assertEquals('Manga \'Berserk\' Resumes Serialization', $this->parser->getTitle()); + } + + /** + * @test + * @vcr NewsParserTest.yaml + */ + public function it_gets_the_url(): void + { + self::assertEquals('https://myanimelist.net/news/53304997', $this->parser->getUrl()); + } + + /** + * @test + * @vcr NewsParserTest.yaml + */ + public function it_gets_the_image(): void + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/r/50x78/s/common/uploaded_files/1512787795-f1674d6456f90126448afb689c3224be.jpeg?s=66f1c0637fa3b5b7e90dc0f40f608738', + $this->parser->getImage() + ); + } + + /** + * @test + * @vcr NewsParserTest.yaml + */ + public function it_gets_the_date(): void + { + self::assertEquals('2017-12-08 18:53', $this->parser->getDate()->format('Y-m-d H:i')); + } + + /** + * @test + * @vcr NewsParserTest.yaml + */ + public function it_gets_the_author(): void + { + self::assertEquals('Vindstot', (string)$this->parser->getAuthor()); + } + + /** + * @test + * @vcr NewsParserTest.yaml + */ + public function it_gets_the_discussion_link(): void + { + self::assertEquals('https://myanimelist.net/forum/?topicid=1690998', $this->parser->getDiscussionLink()); + } + + /** + * @test + * @vcr NewsParserTest.yaml + */ + public function it_gets_the_introduction(): void + { + self::assertEquals( + 'The 24th issue of this year\'s Young Animal magazine has announced on Friday that Kentarou Miura\'s adventure fantasy manga Berserk will resume its serializa...', + $this->parser->getIntro() + ); + } +} diff --git a/test/JikanTest/Parser/Person/PersonParserTest.php b/test/JikanTest/Parser/Person/PersonParserTest.php new file mode 100644 index 00000000..579fc25d --- /dev/null +++ b/test/JikanTest/Parser/Person/PersonParserTest.php @@ -0,0 +1,132 @@ +request('GET', $request->getPath()); + $this->parser = new \Jikan\Parser\Person\PersonParser($crawler); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_the_mal_id() + { + self::assertEquals(99, $this->parser->getPersonId()); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_the_Person_url() + { + self::assertEquals('https://myanimelist.net/people/99/Miyuki_Sawashiro', $this->parser->getPersonUrl()); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_the_name() + { + self::assertEquals('Miyuki Sawashiro', $this->parser->getPersonName()); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_the_given_name() + { + self::assertEquals('みゆき', $this->parser->getPersonGivenName()); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_the_family_name() + { + self::assertEquals('沢城', $this->parser->getPersonFamilyName()); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_the_about() + { + self::assertContains('She began her voice-acting career in 1999 and has continued her work as a seiyuu for more than a decade.\n', $this->parser->getPersonAbout()); + self::assertContains('Married on June 2, 2014, her 29th birthday.\n', $this->parser->getPersonAbout()); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_the_member_favorites() + { + self::assertEquals(26537, $this->parser->getPersonFavorites()); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_the_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/images/voiceactors/1/41394.jpg', + $this->parser->getPersonImageUrl() + ); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_the_voice_acting_roles() + { + $voiceActingRoles = $this->parser->getPersonVoiceActingRoles(); + self::assertCount(439, $voiceActingRoles); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Person\VoiceActingRole::class, $voiceActingRoles); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_the_anime_staff_positions() + { + $animeStaffPositions = $this->parser->getPersonAnimeStaffPositions(); + self::assertCount(42, $animeStaffPositions); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Person\AnimeStaffPosition::class, $animeStaffPositions); + } + + /** + * @test + * @vcr PersonParserTest.yaml + */ + public function it_gets_the_published_manga() + { + $publishedManga = $this->parser->getPersonPublishedManga(); + self::assertCount(0, $publishedManga); + } +} diff --git a/test/JikanTest/Parser/Pictures/PicturesPageParserTest.php b/test/JikanTest/Parser/Pictures/PicturesPageParserTest.php new file mode 100644 index 00000000..685bc0ce --- /dev/null +++ b/test/JikanTest/Parser/Pictures/PicturesPageParserTest.php @@ -0,0 +1,102 @@ +request('GET', 'https://myanimelist.net/manga/50145/jikan/pics'); + $this->mangaParser = new PicturesPageParser($crawler); + $pictures = $this->mangaParser->getModel(); + + self::assertGreaterThan(0, count($pictures)); + self::assertInstanceOf(Picture::class, $pictures[0]); + self::assertContains('https://myanimelist.cdn-dena.com/images/manga/', $pictures[0]->getSmall()); + self::assertContains('https://myanimelist.cdn-dena.com/images/manga/', $pictures[0]->getLarge()); + } + + /** + * @test + * @vcr AnimePictures.yaml + */ + public function it_gets_anime_pictures() + { + $client = new Client(); + $crawler = $client->request('GET', 'https://myanimelist.net/anime/22147/jikan/pics'); + $this->animeParser = new PicturesPageParser($crawler); + $pictures = $this->animeParser->getModel(); + + self::assertGreaterThan(0, count($pictures)); + self::assertInstanceOf(Picture::class, $pictures[0]); + self::assertContains('https://myanimelist.cdn-dena.com/images/anime/', $pictures[0]->getSmall()); + self::assertContains('https://myanimelist.cdn-dena.com/images/anime/', $pictures[0]->getLarge()); + } + + /** + * @test + * @vcr Peopleictures.yaml + */ + public function it_gets_person_pictures() + { + $client = new Client(); + $crawler = $client->request('GET', 'https://myanimelist.net/people/11162/jikan/pictures'); + $this->personParser = new PicturesPageParser($crawler); + $pictures = $this->personParser->getModel(); + + self::assertGreaterThan(0, count($pictures)); + self::assertInstanceOf(Picture::class, $pictures[0]); + self::assertContains('https://myanimelist.cdn-dena.com/images/voiceactors/', $pictures[0]->getSmall()); + self::assertContains('https://myanimelist.cdn-dena.com/images/voiceactors/', $pictures[0]->getLarge()); + } + + /** + * @test + * @vcr CharacterPictures.yaml + */ + public function it_gets_character_pictures() + { + $client = new Client(); + $crawler = $client->request('GET', 'https://myanimelist.net/character/105591/jikan/pictures'); + $this->characterParser = new PicturesPageParser($crawler); + $pictures = $this->characterParser->getModel(); + + self::assertGreaterThan(0, count($pictures)); + self::assertInstanceOf(Picture::class, $pictures[0]); + self::assertContains('https://myanimelist.cdn-dena.com/images/characters/', $pictures[0]->getSmall()); + self::assertContains('https://myanimelist.cdn-dena.com/images/characters/', $pictures[0]->getLarge()); + } +} diff --git a/test/JikanTest/Parser/Producer/ProducerParserTest.php b/test/JikanTest/Parser/Producer/ProducerParserTest.php new file mode 100644 index 00000000..d41194e7 --- /dev/null +++ b/test/JikanTest/Parser/Producer/ProducerParserTest.php @@ -0,0 +1,46 @@ +request('GET', 'https://myanimelist.net/anime/producer/1'); + $this->parser = new ProducerParser($crawler); + } + + /** + * @test + * @vcr ProducerParserTest.yaml + */ + public function it_gets_url() + { + $url = $this->parser->getUrl(); + self::assertInstanceOf(\Jikan\Model\Common\MalUrl::class, $url); + } + + /** + * @test + * @vcr ProducerParserTest.yaml + */ + public function it_gets_anime() + { + $anime = $this->parser->getProducerAnime(); + self::assertCount(100, $anime); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\AnimeCard::class, $anime); + } +} diff --git a/test/JikanTest/Parser/Schedule/ScheduleParserTest.php b/test/JikanTest/Parser/Schedule/ScheduleParserTest.php new file mode 100644 index 00000000..57572ff3 --- /dev/null +++ b/test/JikanTest/Parser/Schedule/ScheduleParserTest.php @@ -0,0 +1,136 @@ +request('GET', 'https://myanimelist.net/anime/season/schedule'); + $this->parser = new ScheduleParser($crawler); + } + + /** + * @test + * @vcr ScheduleParserTest.yaml + */ + public function it_gets_mondays() + { + $monday = $this->parser->getShedule('monday'); + self::assertContainsOnlyInstancesOf(AnimeCard::class, $monday); + self::assertCount(12, $monday); + } + + /** + * @test + * @vcr ScheduleParserTest.yaml + */ + public function it_gets_tuesdays() + { + $tuesday = $this->parser->getShedule('tuesday'); + self::assertContainsOnlyInstancesOf(AnimeCard::class, $tuesday); + self::assertCount(11, $tuesday); + } + + /** + * @test + * @vcr ScheduleParserTest.yaml + */ + public function it_gets_wednesdays() + { + $wednesday = $this->parser->getShedule('wednesday'); + self::assertContainsOnlyInstancesOf(AnimeCard::class, $wednesday); + self::assertCount(5, $wednesday); + } + + /** + * @test + * @vcr ScheduleParserTest.yaml + */ + public function it_gets_thursdays() + { + $thursday = $this->parser->getShedule('thursday'); + self::assertContainsOnlyInstancesOf(AnimeCard::class, $thursday); + self::assertCount(11, $thursday); + } + + /** + * @test + * @vcr ScheduleParserTest.yaml + */ + public function it_gets_fridays() + { + $friday = $this->parser->getShedule('friday'); + self::assertContainsOnlyInstancesOf(AnimeCard::class, $friday); + self::assertCount(15, $friday); + } + + /** + * @test + * @vcr ScheduleParserTest.yaml + */ + public function it_gets_saturdays() + { + $saturday = $this->parser->getShedule('saturday'); + self::assertContainsOnlyInstancesOf(AnimeCard::class, $saturday); + self::assertCount(14, $saturday); + } + + /** + * @test + * @vcr ScheduleParserTest.yaml + */ + public function it_gets_sundays() + { + $sunday = $this->parser->getShedule('sunday'); + self::assertContainsOnlyInstancesOf(AnimeCard::class, $sunday); + self::assertCount(18, $sunday); + } + + /** + * @test + * @vcr ScheduleParserTest.yaml + */ + public function it_gets_all() + { + $all = $this->parser->getShedule('all'); + self::assertContainsOnlyInstancesOf(AnimeCard::class, $all); + self::assertCount(148, $all); + } + + /** + * @test + * @vcr ScheduleParserTest.yaml + */ + public function it_gets_other() + { + $other = $this->parser->getShedule('other'); + self::assertContainsOnlyInstancesOf(AnimeCard::class, $other); + self::assertCount(17, $other); + } + + /** + * @test + * @vcr ScheduleParserTest.yaml + */ + public function it_gets_unknown() + { + $unknown = $this->parser->getShedule('unknown'); + self::assertContainsOnlyInstancesOf(AnimeCard::class, $unknown); + self::assertCount(36, $unknown); + } +} diff --git a/test/JikanTest/Parser/Search/AnimeSearchTest.php b/test/JikanTest/Parser/Search/AnimeSearchTest.php new file mode 100644 index 00000000..619649a4 --- /dev/null +++ b/test/JikanTest/Parser/Search/AnimeSearchTest.php @@ -0,0 +1,124 @@ +search = $jikan->getAnimeSearch( + new \Jikan\Request\Search\AnimeSearchRequest('Fate') + ); + $this->anime = $this->search->getResults()[0]; + } + + /** + * @test + * @vcr AnimeSearchTest.yaml + */ + public function it_gets_the_title() + { + self::assertEquals("Fate/Zero", $this->anime->getTitle()); + } + + /** + * @test + * @vcr AnimeSearchTest.yaml + */ + public function it_gets_the_image_url() + { + self::assertEquals("https://myanimelist.cdn-dena.com/r/50x70/images/anime/2/73249.jpg?s=0ddd3d84549e11eda144df33626f97ae", $this->anime->getImageUrl()); + } + + /** + * @test + * @vcr AnimeSearchTest.yaml + */ + public function it_gets_the_airing() + { + self::assertEquals($this->anime->isAiring(), false); + } + + /** + * @test + * @vcr AnimeSearchTest.yaml + */ + public function it_gets_the_synopsis() + { + self::assertContains("With the promise of granting any wish, the omnipotent Holy Grail triggered three wars in the past, each too cruel and fierce to leave a victor.", $this->anime->getSynopsis()); + } + + /** + * @test + * @vcr AnimeSearchTest.yaml + */ + public function it_gets_the_type() + { + self::assertEquals($this->anime->getType(), "TV"); + } + + /** + * @test + * @vcr AnimeSearchTest.yaml + */ + public function it_gets_the_episodes() + { + self::assertEquals($this->anime->getEpisodes(), 13); + } + + /** + * @test + * @vcr AnimeSearchTest.yaml + */ + public function it_gets_the_start_date() + { + self::assertInstanceOf(\DateTimeImmutable::class, $this->anime->getStartDate()); + } + + /** + * @test + * @vcr AnimeSearchTest.yaml + */ + public function it_gets_the_end_date() + { + self::assertInstanceOf(\DateTimeImmutable::class, $this->anime->getEndDate()); + } + + /** + * @test + * @vcr AnimeSearchTest.yaml + */ + public function it_gets_the_members() + { + self::assertEquals($this->anime->getMembers(), 677392); + } + + /** + * @test + * @vcr AnimeSearchTest.yaml + */ + public function it_gets_the_rated() + { + self::assertEquals($this->anime->getRated(), 'R'); + } + + /** + * @test + * @vcr AnimeSearchTest.yaml + */ + public function it_gets_the_score() + { + self::assertEquals($this->anime->getScore(), 8.44); + } +} diff --git a/test/JikanTest/Parser/Search/CharacterSearchTest.php b/test/JikanTest/Parser/Search/CharacterSearchTest.php new file mode 100644 index 00000000..8f1c47b5 --- /dev/null +++ b/test/JikanTest/Parser/Search/CharacterSearchTest.php @@ -0,0 +1,82 @@ +search = $jikan->getCharacterSearch( + new \Jikan\Request\Search\CharacterSearchRequest('Fate') + ); + $this->anime = $this->search->getResults()[0]; + } + + /** + * @test + * @vcr CharacterSearchTest.yaml + */ + public function it_gets_the_name() + { + self::assertEquals("Testarossa, Fate", $this->anime->getName()); + } + + /** + * @test + * @vcr CharacterSearchTest.yaml + */ + public function it_gets_the_image_url() + { + self::assertEquals("https://myanimelist.cdn-dena.com/r/23x32/images/characters/4/226585.jpg?s=d234ff14c48241f52809684930d5a968", $this->anime->getImageUrl()); + } + + /** + * @test + * @vcr CharacterSearchTest.yaml + */ + public function it_gets_the_url() + { + self::assertInstanceOf(\Jikan\Model\Common\MalUrl::class, $this->anime->getMalUrl()); + } + + /** + * @test + * @vcr CharacterSearchTest.yaml + */ + public function it_gets_the_alternative_names() + { + self::assertContains('Fate T. Harlaown', $this->anime->getAlternativeNames()); + self::assertContains('Har', $this->anime->getAlternativeNames()); + } + + /** + * @test + * @vcr CharacterSearchTest.yaml + */ + public function it_gets_the_anime() + { + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\MalUrl::class, $this->anime->getAnime()); + self::assertEquals("Mahou Shoujo Lyrical Nanoha: The Movie 1st", $this->anime->getAnime()[0]->getName()); + self::assertEquals("https://myanimelist.net/anime/4985/Mahou_Shoujo_Lyrical_Nanoha__The_Movie_1st", $this->anime->getAnime()[0]->getUrl()); + } + + /** + * @test + * @vcr CharacterSearchTest.yaml + */ + public function it_gets_the_manga() + { + self::assertEquals([], $this->anime->getManga()); + } +} diff --git a/test/JikanTest/Parser/Search/MangaSearchTest.php b/test/JikanTest/Parser/Search/MangaSearchTest.php new file mode 100644 index 00000000..7f5f4bef --- /dev/null +++ b/test/JikanTest/Parser/Search/MangaSearchTest.php @@ -0,0 +1,124 @@ +search = $jikan->getMangaSearch( + new \Jikan\Request\Search\MangaSearchRequest('Fate') + ); + $this->manga = $this->search->getResults()[0]; + } + + /** + * @test + * @vcr MangaSearchTest.yaml + */ + public function it_gets_the_title() + { + self::assertEquals("Fate/Zero", $this->manga->getTitle()); + } + + /** + * @test + * @vcr MangaSearchTest.yaml + */ + public function it_gets_the_image_url() + { + self::assertEquals("https://myanimelist.cdn-dena.com/r/50x70/images/manga/3/196931.jpg?s=7da8d65371bc975c9ecda0d30a832984", $this->manga->getImageUrl()); + } + + /** + * @test + * @vcr MangaSearchTest.yaml + */ + public function it_gets_the_publishing() + { + self::assertEquals($this->manga->isPublishing(), false); + } + + /** + * @test + * @vcr MangaSearchTest.yaml + */ + public function it_gets_the_synopsis() + { + self::assertContains("War of the Holy Grail—Pursuing the power of the \"Holy Grail\" which grants a miracle, this is a contest in which seven magi summon seven Heroic Spirits to compete for it.", $this->manga->getSynopsis()); + } + + /** + * @test + * @vcr MangaSearchTest.yaml + */ + public function it_gets_the_type() + { + self::assertEquals($this->manga->getType(), "Manga"); + } + + /** + * @test + * @vcr MangaSearchTest.yaml + */ + public function it_gets_the_chapters() + { + self::assertEquals($this->manga->getChapters(), 79); + } + + /** + * @test + * @vcr MangaSearchTest.yaml + */ + public function it_gets_the_volumes() + { + self::assertEquals($this->manga->getVolumes(), 14); + } + + /** + * @test + * @vcr MangaSearchTest.yaml + */ + public function it_gets_the_start_date() + { + self::assertInstanceOf(\DateTimeImmutable::class, $this->manga->getStartDate()); + } + + /** + * @test + * @vcr MangaSearchTest.yaml + */ + public function it_gets_the_end_date() + { + self::assertInstanceOf(\DateTimeImmutable::class, $this->manga->getEndDate()); + } + + /** + * @test + * @vcr MangaSearchTest.yaml + */ + public function it_gets_the_members() + { + self::assertEquals($this->manga->getMembers(), 3659); + } + + /** + * @test + * @vcr MangaSearchTest.yaml + */ + public function it_gets_the_score() + { + self::assertEquals($this->manga->getScore(), 7.81); + } +} diff --git a/test/JikanTest/Parser/Search/PersonSearchTest.php b/test/JikanTest/Parser/Search/PersonSearchTest.php new file mode 100644 index 00000000..52c07e3f --- /dev/null +++ b/test/JikanTest/Parser/Search/PersonSearchTest.php @@ -0,0 +1,61 @@ +search = $jikan->getPersonSearch( + new \Jikan\Request\Search\PersonSearchRequest('Ara') + ); + $this->person = $this->search->getResults()[0]; + } + + /** + * @test + * @vcr PersonSearchTest.yaml + */ + public function it_gets_the_name() + { + self::assertEquals("Ara-chan", $this->person->getName()); + } + + /** + * @test + * @vcr PersonSearchTest.yaml + */ + public function it_gets_the_image_url() + { + self::assertEquals("https://myanimelist.cdn-dena.com/r/23x32/images/characters/14/56841.jpg?s=10d5e5f7c810ad4f8e346c243478afba", $this->person->getImageUrl()); + } + + /** + * @test + * @vcr PersonSearchTest.yaml + */ + public function it_gets_the_url() + { + self::assertInstanceOf(\Jikan\Model\Common\MalUrl::class, $this->person->getMalUrl()); + } + + /** + * @test + * @vcr PersonSearchTest.yaml + */ + public function it_gets_the_alternative_names() + { + self::assertContains('Hokuto-kun', $this->person->getAlternativeNames()); + } +} diff --git a/test/JikanTest/Parser/SeasonList/SeasonListItemParserTest.php b/test/JikanTest/Parser/SeasonList/SeasonListItemParserTest.php new file mode 100644 index 00000000..b3b12d03 --- /dev/null +++ b/test/JikanTest/Parser/SeasonList/SeasonListItemParserTest.php @@ -0,0 +1,42 @@ +request('GET', 'https://myanimelist.net/anime/season/archive'); + $this->parser = new SeasonListItemParser( + $crawler->filterXPath('//table[contains(@class, "anime-seasonal-byseason")]/tr')->eq(1) + ); + } + + /** + * @test + * @covers \Jikan\Parser\SeasonList\SeasonListItemParser::getYear + * @vcr SeasonList.yaml + */ + public function it_gets_the_year(): void + { + self::assertEquals(2018, $this->parser->getYear()); + } + + /** + * @test + * @covers \Jikan\Parser\SeasonList\SeasonListItemParser::getSeasons + * @vcr SeasonList.yaml + */ + public function it_gets_the_seasons(): void + { + self::assertContains('Winter', $this->parser->getSeasons()); + } +} diff --git a/test/JikanTest/Parser/SeasonList/SeasonListParserTest.php b/test/JikanTest/Parser/SeasonList/SeasonListParserTest.php new file mode 100644 index 00000000..451e4e18 --- /dev/null +++ b/test/JikanTest/Parser/SeasonList/SeasonListParserTest.php @@ -0,0 +1,40 @@ +request('GET', $request->getPath()); + $this->parser = new SeasonListParser($crawler); + } + + /** + * @test + * @covers \Jikan\Parser\SeasonList\SeasonListParser::getModel + * @vcr SeasonList.yaml + */ + public function it_contains_season_items(): void + { + self::assertContainsOnlyInstancesOf( + SeasonListItem::class, + $this->parser->getModel() + ); + } +} diff --git a/test/JikanTest/Parser/Seasonal/SeasonalAnimeParserTest.php b/test/JikanTest/Parser/Seasonal/SeasonalAnimeParserTest.php new file mode 100644 index 00000000..41cb7a15 --- /dev/null +++ b/test/JikanTest/Parser/Seasonal/SeasonalAnimeParserTest.php @@ -0,0 +1,247 @@ +crawler = $crawler = $client->request('GET', $request->getPath()); + $this->parser = new AnimeCardParser($crawler->filter('div.seasonal-anime')->first()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_producer() + { + $this->parser2 = new AnimeCardParser($this->crawler->filter('div.seasonal-anime')->eq(2)); + $producer = $this->parser->getProducer(); + self::assertCount(1, $producer); + self::assertContainsOnly(\Jikan\Model\Common\MalUrl::class, $producer); + $producer = $producer[0]; + self::assertEquals('Bones', $producer); + self::assertEquals('https://myanimelist.net/anime/producer/4/Bones', $producer->getUrl()); + + $producer = $this->parser2->getProducer(); + self::assertCount(2, $producer); + self::assertContainsOnly(\Jikan\Model\Common\MalUrl::class, $producer); + self::assertContains('Pierrot Plus', $producer); + self::assertContains('Studio Pierrot', $producer); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_episodes() + { + $this->parser2 = new AnimeCardParser($this->crawler->filter('div.seasonal-anime')->eq(2)); + self::assertEquals(25, $this->parser->getEpisodes()); + self::assertEquals(12, $this->parser2->getEpisodes()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_source() + { + $this->parser2 = new AnimeCardParser($this->crawler->filter('div.seasonal-anime')->eq(2)); + self::assertEquals('Manga', $this->parser->getSource()); + self::assertEquals('Manga', $this->parser2->getSource()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_genres() + { + $genres = $this->parser->getGenres(); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\MalUrl::class, $genres); + self::assertContains('Action', $genres); + self::assertContains('Comedy', $genres); + self::assertContains('School', $genres); + self::assertContains('Shounen', $genres); + self::assertContains('Super Power', $genres); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_title() + { + self::assertEquals('Boku no Hero Academia 3rd Season', $this->parser->getTitle()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_description() + { + self::assertEquals('Third season of Boku no Hero Academia.', $this->parser->getDescription()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_type() + { + self::assertEquals('TV', $this->parser->getType()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_air_dates() + { + self::assertInstanceOf(\DateTimeImmutable::class, $this->parser->getAirDates()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_air_members() + { + self::assertEquals(329324, $this->parser->getMembers()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_anime_id() + { + self::assertEquals(36456, $this->parser->getMalId()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_anime_url() + { + self::assertEquals( + 'https://myanimelist.net/anime/36456/Boku_no_Hero_Academia_3rd_Season', + $this->parser->getAnimeUrl() + ); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_anime_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/r/167x242/images/anime/1319/92084.jpg?s=174e33772872a964b6c8b7668b46c2c5', + $this->parser->getAnimeImage() + ); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_anime_score() + { + $this->parser2 = new AnimeCardParser($this->crawler->filter('div.seasonal-anime')->eq(2)); + self::assertEquals( + 7.57, + $this->parser2->getAnimeScore() + ); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_anime_licensor() + { + self::assertCount(1, $this->parser->getLicensors()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_r18_rating() + { + self::assertFalse($this->parser->isR18()); + $this->parserR18 = new AnimeCardParser($this->crawler->filter('div.seasonal-anime.r18')->first()); + self::assertTrue($this->parserR18->isR18()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_kids_rating() + { + self::assertFalse($this->parser->isKids()); + $this->parserKids = new AnimeCardParser($this->crawler->filter('div.seasonal-anime.kids')->first()); + self::assertTrue($this->parserKids->isKids()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_continuing() + { + $this->springParser = new AnimeCardParser( + $this->crawler->filter( + '#content > div.js-categories-seasonal > div:nth-child(2) > div:nth-child(2)' + )->first() + ); + self::assertEquals('One Piece', $this->springParser->getTitle()); + self::assertTrue($this->springParser->isContinuing()); + self::assertEquals('Boku no Hero Academia 3rd Season', $this->parser->getTitle()); + self::assertFalse($this->parser->isContinuing()); + } +} diff --git a/test/JikanTest/Parser/Seasonal/SeasonalParserTest.php b/test/JikanTest/Parser/Seasonal/SeasonalParserTest.php new file mode 100644 index 00000000..4cb6cfe0 --- /dev/null +++ b/test/JikanTest/Parser/Seasonal/SeasonalParserTest.php @@ -0,0 +1,44 @@ +request('GET', $request->getPath()); + $this->springParser = new \Jikan\Parser\Seasonal\SeasonalParser($crawler); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_season() + { + self::assertEquals('Spring 2018', $this->springParser->getSeason()); + } + + /** + * @test + * @vcr SeasonalParserTest.yaml + */ + public function it_gets_the_anime() + { + $anime = $this->springParser->getSeasonalAnime(); + self::assertCount(234, $anime); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Seasonal\SeasonalAnime::class, $anime); + } +} diff --git a/test/JikanTest/Parser/Top/TopAnimeParserTest.php b/test/JikanTest/Parser/Top/TopAnimeParserTest.php new file mode 100644 index 00000000..92e52cdf --- /dev/null +++ b/test/JikanTest/Parser/Top/TopAnimeParserTest.php @@ -0,0 +1,114 @@ +request('GET', 'https://myanimelist.net/topanime.php'); + + $this->parser = new TopListItemParser( + $crawler->filterXPath('//tr[@class="ranking-list"]')->eq(10) + ); + } + + /** + * @test + * @vcr TopAnimeParserTest.yaml + */ + public function it_gets_the_mal_url() + { + $url = $this->parser->getMalUrl(); + self::assertEquals('Koe no Katachi', $url); + self::assertEquals('https://myanimelist.net/anime/28851/Koe_no_Katachi', $url->getUrl()); + } + + /** + * @test + * @vcr TopAnimeParserTest.yaml + */ + public function it_gets_the_rank() + { + self::assertEquals(11, $this->parser->getRank()); + } + + /** + * @test + * @vcr TopAnimeParserTest.yaml + */ + public function it_gets_the_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/r/50x70/images/anime/3/80136.jpg?s=a3b3a8039e99287c719995e564e3d084', + $this->parser->getImage() + ); + } + + /** + * @test + * @vcr TopAnimeParserTest.yaml + */ + public function it_gets_the_anime_rating() + { + self::assertEquals(9.04, $this->parser->getRating()); + } + + /** + * @test + * @vcr TopAnimeParserTest.yaml + */ + public function it_gets_the_anime_type() + { + self::assertEquals('Movie', $this->parser->getType()); + } + + /** + * @test + * @vcr TopAnimeParserTest.yaml + */ + public function it_gets_the_anime_episodes() + { + self::assertEquals(1, $this->parser->getEpisodes()); + } + + /** + * @test + * @vcr TopAnimeParserTest.yaml + */ + public function it_gets_the_anime_members() + { + self::assertEquals(533061, $this->parser->getMembers()); + } + + /** + * @test + * @vcr TopAnimeParserTest.yaml + */ + public function it_gets_the_anime_start_date() + { + self::assertEquals('Sep 2016', $this->parser->getStartDate()); + } + + /** + * @test + * @vcr TopAnimeParserTest.yaml + */ + public function it_gets_the_anime_end_date() + { + self::assertEquals('Sep 2016', $this->parser->getEndDate()); + } +} diff --git a/test/JikanTest/Parser/Top/TopCharacterParserTest.php b/test/JikanTest/Parser/Top/TopCharacterParserTest.php new file mode 100644 index 00000000..6ea50836 --- /dev/null +++ b/test/JikanTest/Parser/Top/TopCharacterParserTest.php @@ -0,0 +1,99 @@ +request('GET', 'https://myanimelist.net/character.php'); + + $this->parser = new TopListItemParser( + $crawler->filterXPath('//tr[@class="ranking-list"]')->eq(2) + ); + } + + /** + * @test + * @vcr TopCharacterParserTest.yaml + */ + public function it_gets_the_mal_url() + { + $url = $this->parser->getMalUrl(); + self::assertEquals('Monkey D., Luffy', $url); + self::assertEquals('https://myanimelist.net/character/40/Luffy_Monkey_D', $url->getUrl()); + } + + /** + * @test + * @vcr TopCharacterParserTest.yaml + */ + public function it_gets_the_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/r/50x78/images/characters/9/310307.jpg?s=1422edf1e44c7b6262386330461eecfd', + $this->parser->getImage() + ); + } + + /** + * @test + * @vcr TopCharacterParserTest.yaml + */ + public function it_gets_the_rank() + { + self::assertEquals(3, $this->parser->getRank()); + } + + /** + * @test + * @vcr TopCharacterParserTest.yaml + */ + public function it_gets_the_character_kanji() + { + self::assertEquals('モンキー・D・ルフィ', $this->parser->getKanjiName()); + } + + /** + * @test + * @vcr TopCharacterParserTest.yaml + */ + public function it_gets_the_animeography() + { + self::assertCount(3, $this->parser->getAnimeography()); + self::assertContainsOnlyInstancesOf(MalUrl::class, $this->parser->getAnimeography()); + } + + /** + * @test + * @vcr TopCharacterParserTest.yaml + */ + public function it_gets_the_mangaography() + { + self::assertCount(3, $this->parser->getMangaography()); + self::assertContainsOnlyInstancesOf(MalUrl::class, $this->parser->getMangaography()); + } + + /** + * @test + * @vcr TopCharacterParserTest.yaml + */ + public function it_gets_the_favorites() + { + self::assertEquals(49856, $this->parser->getFavorites()); + } +} diff --git a/test/JikanTest/Parser/Top/TopMangaParserTest.php b/test/JikanTest/Parser/Top/TopMangaParserTest.php new file mode 100644 index 00000000..2bb7c4f4 --- /dev/null +++ b/test/JikanTest/Parser/Top/TopMangaParserTest.php @@ -0,0 +1,124 @@ +crawler = $crawler = $client->request('GET', 'https://myanimelist.net/topmanga.php'); + + $this->parser = new TopListItemParser( + $crawler->filterXPath('//tr[@class="ranking-list"]')->eq(5) + ); + } + + /** + * @test + * @vcr TopMangaParserTest.yaml + */ + public function it_gets_the_mal_url() + { + $url = $this->parser->getMalUrl(); + self::assertEquals('One Piece', $url); + self::assertEquals('https://myanimelist.net/manga/13/One_Piece', $url->getUrl()); + } + + /** + * @test + * @vcr TopMangaParserTest.yaml + */ + public function it_gets_the_rank() + { + self::assertEquals(6, $this->parser->getRank()); + } + + /** + * @test + * @vcr TopMangaParserTest.yaml + */ + public function it_gets_the_manga_rating() + { + self::assertEquals(9.03, $this->parser->getRating()); + } + + /** + * @test + * @vcr TopMangaParserTest.yaml + */ + public function it_gets_the_manga_type() + { + self::assertEquals('Manga', $this->parser->getType()); + } + + /** + * @test + * @vcr TopMangaParserTest.yaml + */ + public function it_gets_the_manga_volumes() + { + $parser2 = new TopListItemParser( + $this->crawler->filterXPath('//tr[@class="ranking-list"]')->eq(1) + ); + self::assertNull($this->parser->getVolumes()); + self::assertEquals(24, $parser2->getVolumes()); + } + + /** + * @test + * @vcr TopMangaParserTest.yaml + */ + public function it_gets_the_manga_members() + { + self::assertEquals(212645, $this->parser->getMembers()); + } + + /** + * @test + * @vcr TopMangaParserTest.yaml + */ + public function it_gets_the_manga_start_date() + { + self::assertEquals('Jul 1997', $this->parser->getStartDate()); + } + + /** + * @test + * @vcr TopMangaParserTest.yaml + */ + public function it_gets_the_manga_end_date() + { + self::assertEquals('', $this->parser->getEndDate()); + } + + /** + * @test + * @vcr TopMangaParserTest.yaml + */ + public function it_gets_the_manga_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/r/50x70/images/manga/3/55539.jpg?s=b4d9e935b7152f0c9e69b34a7797fe02', + $this->parser->getImage() + ); + } +} diff --git a/test/JikanTest/Parser/Top/TopPeopleParserTest.php b/test/JikanTest/Parser/Top/TopPeopleParserTest.php new file mode 100644 index 00000000..f2e2b299 --- /dev/null +++ b/test/JikanTest/Parser/Top/TopPeopleParserTest.php @@ -0,0 +1,93 @@ +request('GET', 'https://myanimelist.net/people.php'); + + $this->parser = new TopListItemParser( + $crawler->filterXPath('//tr[@class="ranking-list"]')->eq(7) + ); + } + + /** + * @test + * @vcr TopPeopleParserTest.yaml + */ + public function it_gets_the_mal_url() + { + $url = $this->parser->getMalUrl(); + self::assertEquals('Sugita, Tomokazu', $url); + self::assertEquals('https://myanimelist.net/people/2/Tomokazu_Sugita', $url->getUrl()); + } + + /** + * @test + * @vcr TopPeopleParserTest.yaml + */ + public function it_gets_the_rank() + { + self::assertEquals(8, $this->parser->getRank()); + } + + /** + * @test + * @vcr TopPeopleParserTest.yaml + */ + public function it_gets_the_favorites() + { + self::assertEquals(24588, $this->parser->getPeopleFavorites()); + } + + /** + * @test + * @vcr TopPeopleParserTest.yaml + */ + public function it_gets_the_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/r/50x78/images/voiceactors/3/42163.jpg?s=e7aa2685616307adf04f3d1255e4dba3', + $this->parser->getImage() + ); + } + + /** + * @test + * @vcr TopPeopleParserTest.yaml + */ + public function it_gets_the_kanji_name() + { + self::assertEquals( + '杉田 智和', + $this->parser->getKanjiName() + ); + } + + /** + * @test + * @vcr TopPeopleParserTest.yaml + */ + public function it_gets_the_birthday() + { + self::assertEquals( + '1980-10-11', + $this->parser->getBirthday()->format('Y-m-d') + ); + } +} diff --git a/test/JikanTest/Parser/UserFriend/FriendParserTest.php b/test/JikanTest/Parser/UserFriend/FriendParserTest.php new file mode 100644 index 00000000..e4fda091 --- /dev/null +++ b/test/JikanTest/Parser/UserFriend/FriendParserTest.php @@ -0,0 +1,74 @@ +request('GET', 'https://myanimelist.net/profile/morshuwarrior/friends'); + $this->parser = new \Jikan\Parser\User\Friends\FriendParser( + $crawler->filterXPath( + '//div[contains(@class, "friendBlock")][3]' + ) + ); + } + + /** + * @test + * @vcr FriendsParserTest.yaml + */ + public function it_gets_the_name() + { + self::assertEquals('Dinoe', $this->parser->getName()); + } + + /** + * @test + * @vcr FriendsParserTest.yaml + */ + public function it_gets_the_url() + { + self::assertEquals('https://myanimelist.net/profile/Dinoe', $this->parser->getUrl()); + } + + /** + * @test + * @vcr FriendsParserTest.yaml + */ + public function it_gets_the_avatar() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/images/userimages/thumbs/5082596_thumb.jpg', + $this->parser->getAvatar() + ); + } + + /** + * @test + * @vcr FriendsParserTest.yaml + */ + public function it_gets_friends_since() + { + self::assertEquals( + '2016-05-11 04:37', + $this->parser->getFriendsSince()->format('Y-m-d H:i') + ); + } + /** + * @test + * @vcr FriendsParserTest.yaml + */ + public function it_gets_last_online() + { + self::assertInstanceOf(\DateTimeImmutable::class, $this->parser->getLastOnline()); + } +} \ No newline at end of file diff --git a/test/JikanTest/Parser/UserHistory/UserHistoryParser.php b/test/JikanTest/Parser/UserHistory/UserHistoryParser.php new file mode 100644 index 00000000..932b1c9e --- /dev/null +++ b/test/JikanTest/Parser/UserHistory/UserHistoryParser.php @@ -0,0 +1,52 @@ +request('GET', 'https://myanimelist.net/history/nekomata1037'); + $this->parser = (new \Jikan\Parser\User\History\HistoryParser($crawler))->getModel(); + } + + /** + * @test + * @vcr HistoryParserTest.yaml + */ + public function it_gets_the_url() + { + self::assertInstanceOf(\Jikan\Model\Common\MalUrl::class, $this->parser[0]->getUrl()); + self::assertEquals('Imouto sae Ireba Ii.', $this->parser[0]->getUrl()->getTitle()); + } + + /** + * @test + * @vcr HistoryParserTest.yaml + */ + public function it_gets_the_increment() + { + self::assertEquals(12, $this->parser[0]->getIncrement()); + } + + /** + * @test + * @vcr HistoryParserTest.yaml + */ + public function it_gets_the_date() + { + self::assertInstanceOf(\DateTimeImmutable::class, $this->parser[0]->getDate()); + } + +} \ No newline at end of file diff --git a/test/JikanTest/Parser/UserProfile/UserProfileParserTest.php b/test/JikanTest/Parser/UserProfile/UserProfileParserTest.php new file mode 100644 index 00000000..e088967b --- /dev/null +++ b/test/JikanTest/Parser/UserProfile/UserProfileParserTest.php @@ -0,0 +1,142 @@ +request('GET', 'https://myanimelist.net/profile/sandshark'); + $this->parser = new \Jikan\Parser\User\Profile\UserProfileParser($crawler); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_the_username() + { + self::assertEquals('sandshark', $this->parser->getUsername()); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_the_url() + { + self::assertEquals('https://myanimelist.net/profile/sandshark', $this->parser->getProfileUrl()); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_the_image() + { + self::assertEquals( + 'https://myanimelist.cdn-dena.com/images/userimages/3600201.jpg', + $this->parser->getImageUrl() + ); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_the_join_date() + { + self::assertInstanceOf(\DateTimeImmutable::class, $this->parser->getJoinDate()); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_the_last_online() + { + self::assertInstanceOf(\DateTimeImmutable::class, $this->parser->getLastOnline()); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_the_gender() + { + self::assertEquals('Male', $this->parser->getGender()); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_the_birthday() + { + self::assertEquals(null, $this->parser->getBirthday()); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_the_location() + { + self::assertEquals('101', $this->parser->getLocation()); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_the_anime_stats() + { + self::assertInstanceOf(\Jikan\Model\User\AnimeStats::class, $this->parser->getAnimeStats()); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_the_manga_stats() + { + self::assertInstanceOf(\Jikan\Model\User\MangaStats::class, $this->parser->getMangaStats()); + } + + /** + * @test + * @vcr ProfileParserTest.yaml + */ + public function it_gets_the_favorites() + { + self::assertInstanceOf(\Jikan\Model\User\Favorites::class, $this->parser->getFavorites()); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\AnimeMeta::class, $this->parser->getFavorites()->getAnime()); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\MangaMeta::class, $this->parser->getFavorites()->getManga()); + self::assertContainsOnlyInstancesOf( + \Jikan\Model\Common\CharacterMeta::class, + $this->parser->getFavorites()->getCharacters() + ); + self::assertContainsOnlyInstancesOf(\Jikan\Model\Common\PersonMeta::class, $this->parser->getFavorites()->getPeople()); + + } + + /** + * @test + * @vcr MangaParserTest.yaml + */ + public function it_gets_the_about() + { + self::assertEquals(null, $this->parser->getAbout()); + } +} diff --git a/test/JikanTest/Parser/Video/AnimeVideoParserTest.php b/test/JikanTest/Parser/Video/AnimeVideoParserTest.php new file mode 100644 index 00000000..f9b4981e --- /dev/null +++ b/test/JikanTest/Parser/Video/AnimeVideoParserTest.php @@ -0,0 +1,48 @@ +request('GET', 'https://myanimelist.net/anime/1/_/video'); + $this->parser = new VideosParser($crawler); + } + + + /** + * @test + * @vcr AnimeVideoParserTest.yaml + */ + public function it_gets_promos() + { + $videos = $this->parser->getPromos(); + self::assertContainsOnlyInstancesOf(PromoListItem::class, $videos); + } + + /** + * @test + * @vcr AnimeVideoParserTest.yaml + */ + public function it_gets_episodes() + { + $videos = $this->parser->getEpisodes(); + self::assertContainsOnlyInstancesOf(StreamEpisodeListItem::class, $videos); + } +} diff --git a/test/bootstrap.php b/test/bootstrap.php new file mode 100644 index 00000000..9f324b91 --- /dev/null +++ b/test/bootstrap.php @@ -0,0 +1,9 @@ +setCassettePath(__DIR__ . "/../vendor/jikan-me/jikan-fixtures/fixtures") + ->enableLibraryHooks(['curl']) + ->enableRequestMatchers(['url', 'method', 'query_string']) +; +\VCR\VCR::turnOn(); diff --git a/travis.php b/travis.php deleted file mode 100755 index 8931532e..00000000 --- a/travis.php +++ /dev/null @@ -1,27 +0,0 @@ -Anime(21); -sleep(5); -$jikan->Anime(21, [EPISODES]); -sleep(5); -$jikan->Anime(21, [CHARACTERS_STAFF]); -sleep(5); -$jikan->Anime(21, [NEWS]); -sleep(5); -$jikan->Manga(1); -sleep(5); -$jikan->Manga(1, [CHARACTERS]); -sleep(5); -$jikan->Manga(1, [NEWS]); -sleep(5); -$jikan->Person(1); -sleep(5); -$jikan->Character(1);