Anime V4 endpoints complete

This commit is contained in:
Irfan 2020-07-05 11:29:11 +05:00
parent dcdf2e8f66
commit 079ed17e9f
25 changed files with 1485 additions and 72 deletions

View File

@ -2,11 +2,13 @@
namespace App;
use App\Http\HttpHelper;
use Jenssegers\Mongodb\Eloquent\Model;
use Jikan\Helper\Media;
use Jikan\Helper\Parser;
use Jikan\Jikan;
use Jikan\Model\Common\YoutubeMeta;
use Jikan\Request\Anime\AnimeRequest;
class Anime extends Model
{
@ -53,7 +55,7 @@ class Anime extends Model
* @var array
*/
protected $hidden = [
'_id', 'expiresAt', 'request_hash', 'trailer_url', 'premiered', 'opening_themes', 'ending_themes', 'images'
'_id', 'trailer_url', 'premiered', 'opening_themes', 'ending_themes', 'images'
];
public function setRelatedAttribute($value)
@ -61,6 +63,8 @@ class Anime extends Model
$this->attributes['related'] = $this->getRelatedAttribute();
}
/*
// For V3 or below
public function getRelatedAttribute()
{
// Fix JSON response for empty related object
@ -85,7 +89,7 @@ class Anime extends Model
public function setTrailerAttribute($value)
{
$this->attributes['trailer'] = $this->getTrailerAttribute();
}
}*/
public function getTrailerAttribute()
{
@ -205,4 +209,17 @@ class Anime extends Model
]
];
}
public static function scrape(int $id)
{
$data = app('JikanParser')->getAnime(new AnimeRequest($id));
return HttpHelper::serializeEmptyObjectsControllerLevel(
json_decode(
app('SerializerV4')
->serialize($data, 'json'),
true
)
);
}
}

47
app/Episode.php Normal file
View File

@ -0,0 +1,47 @@
<?php
namespace App;
use App\Http\HttpHelper;
use Jenssegers\Mongodb\Eloquent\Model;
use Jikan\Helper\Media;
use Jikan\Helper\Parser;
use Jikan\Jikan;
use Jikan\Model\Common\YoutubeMeta;
use Jikan\Request\Anime\AnimeRequest;
class Episode extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'mal_id', 'title', 'title_japanese', 'title_romanji', 'aired', 'filler', 'recap', 'video_url', 'forum_url', 'synopsis'
];
/**
* The accessors to append to the model's array form.
*
* @var array
*/
protected $appends = [];
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'anime_episodes';
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = [
];
}

View File

@ -3,8 +3,24 @@
namespace App\Http\Controllers\V4DB;
use App\Anime;
use App\DatabaseHandler;
use App\Http\HttpHelper;
use App\Http\HttpResponse;
use App\Http\Resources\V4\AnimeCharactersResource;
use App\Http\Resources\V4\AnimeCollection;
use App\Http\Resources\V4\AnimeEpisodeResource;
use App\Http\Resources\V4\AnimeEpisodesResource;
use App\Http\Resources\V4\AnimeForumResource;
use App\Http\Resources\V4\AnimeMoreInfoResource;
use App\Http\Resources\V4\AnimeNewsResource;
use App\Http\Resources\V4\AnimePicturesResource;
use App\Http\Resources\V4\AnimeRecommendationsResource;
use App\Http\Resources\V4\AnimeReviewsResource;
use App\Http\Resources\V4\AnimeStaffResource;
use App\Http\Resources\V4\AnimeStatisticsResource;
use App\Http\Resources\V4\AnimeUserUpdatesResource;
use App\Http\Resources\V4\AnimeVideosResource;
use App\Http\Resources\V4\CommonResource;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Jikan\Request\Anime\AnimeCharactersAndStaffRequest;
@ -20,95 +36,793 @@ use Jikan\Request\Anime\AnimeRequest;
use Jikan\Request\Anime\AnimeReviewsRequest;
use Jikan\Request\Anime\AnimeStatsRequest;
use Jikan\Request\Anime\AnimeVideosRequest;
use Laravel\Lumen\Http\ResponseFactory;
use MongoDB\BSON\UTCDateTime;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class AnimeController extends Controller
{
public function main(Request $request, int $id)
{
$results = Anime::query()
->where('mal_id', $id)
->get();
if (empty($results->all())) {
if ($results->isEmpty()) {
$response = Anime::scrape($id);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
$response = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime()
] + $response;
Anime::query()
->insert($response);
$results = Anime::query()
->where('mal_id', $id)
->get();
}
if ($this->isExpired($request, $results)) {
$response = Anime::scrape($id);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
$response = [
'modifiedAt' => new UTCDateTime()
] + $response;
Anime::query()
->where('request_hash', $this->fingerprint)
->update($response);
// requery
$results = Anime::query()
->where('mal_id', $id)
->get();
}
if ($results->isEmpty()) {
return HttpResponse::notFound($request);
}
return new \App\Http\Resources\V4\AnimeResource(
$response = (new \App\Http\Resources\V4\AnimeResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function characters_staff(int $id)
public function characters(Request $request, int $id)
{
$anime = $this->jikan->getAnimeCharactersAndStaff(new AnimeCharactersAndStaffRequest($id));
return response($this->serializer->serialize($anime, 'json'));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1;
$anime = $this->jikan->getAnimeCharactersAndStaff(new AnimeCharactersAndStaffRequest($id));
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeCharactersResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function episode(int $id, int $episodeId)
public function staff(Request $request, int $id)
{
$anime = $this->jikan->getAnimeEpisode(new AnimeEpisodeRequest($id, $episodeId));
return response($this->serializer->serialize($anime, 'json'));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1;
$anime = $this->jikan->getAnimeCharactersAndStaff(new AnimeCharactersAndStaffRequest($id));
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeStaffResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function episodes(int $id)
public function episode(Request $request, int $id, int $episodeId)
{
$page = $_GET['page'] ?? 1;
$anime = $this->jikan->getAnimeEpisodes(new AnimeEpisodesRequest($id, $page));
return response($this->serializer->serialize($anime, 'json'));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1;
$anime = $this->jikan->getAnimeEpisode(new AnimeEpisodeRequest($id, $episodeId));
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeEpisodeResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function news(int $id)
public function episodes(Request $request, int $id)
{
$anime = ['articles' => $this->jikan->getNewsList(new AnimeNewsRequest($id))];
return response($this->serializer->serialize($anime, 'json'));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1;
$anime = $this->jikan->getAnimeEpisodes(new AnimeEpisodesRequest($id, $page));
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeEpisodesResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function forum(int $id)
public function news(Request $request, int $id)
{
$anime = ['topics' => $this->jikan->getAnimeForum(new AnimeForumRequest($id))];
return response($this->serializer->serialize($anime, 'json'));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1; // todo add page support to parser
$anime = ['articles' => $this->jikan->getNewsList(new AnimeNewsRequest($id))];
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeNewsResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function videos(int $id)
public function forum(Request $request, int $id)
{
$anime = $this->jikan->getAnimeVideos(new AnimeVideosRequest($id));
return response($this->serializer->serialize($anime, 'json'));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$topic = $request->get('topic');
$anime = ['topics' => $this->jikan->getAnimeForum(new AnimeForumRequest($id, $topic))];
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeForumResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function pictures(int $id)
public function videos(Request $request, int $id)
{
$anime = ['pictures' => $this->jikan->getAnimePictures(new AnimePicturesRequest($id))];
return response($this->serializer->serialize($anime, 'json'));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$anime = $this->jikan->getAnimeVideos(new AnimeVideosRequest($id));
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeVideosResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function stats(int $id)
public function pictures(Request $request, int $id)
{
$anime = $this->jikan->getAnimeStats(new AnimeStatsRequest($id));
return response($this->serializer->serialize($anime, 'json'));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$anime = ['pictures' => $this->jikan->getAnimePictures(new AnimePicturesRequest($id))];
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimePicturesResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function moreInfo(int $id)
public function stats(Request $request, int $id)
{
$anime = ['moreinfo' => $this->jikan->getAnimeMoreInfo(new AnimeMoreInfoRequest($id))];
return response(json_encode($anime));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$anime = $this->jikan->getAnimeStats(new AnimeStatsRequest($id));
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeStatisticsResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function recommendations(int $id)
public function moreInfo(Request $request, int $id)
{
$anime = ['recommendations' => $this->jikan->getAnimeRecommendations(new AnimeRecommendationsRequest($id))];
return response($this->serializer->serialize($anime, 'json'));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$anime = ['moreinfo' => $this->jikan->getAnimeMoreInfo(new AnimeMoreInfoRequest($id))];
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeMoreInfoResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function userupdates(int $id, int $page = 1)
public function recommendations(Request $request, int $id)
{
$anime = ['users' => $this->jikan->getAnimeRecentlyUpdatedByUsers(new AnimeRecentlyUpdatedByUsersRequest($id, $page))];
return response($this->serializer->serialize($anime, 'json'));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$anime = ['recommendations' => $this->jikan->getAnimeRecommendations(new AnimeRecommendationsRequest($id))];
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeRecommendationsResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function reviews(int $id, int $page = 1)
public function userupdates(Request $request, int $id)
{
$anime = ['reviews' => $this->jikan->getAnimeReviews(new AnimeReviewsRequest($id, $page))];
return response($this->serializer->serialize($anime, 'json'));
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1;
$anime = ['users' => $this->jikan->getAnimeRecentlyUpdatedByUsers(new AnimeRecentlyUpdatedByUsersRequest($id, $page))];
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeUserUpdatesResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
public function reviews(Request $request, int $id)
{
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
if (
$results->isEmpty()
|| $this->isExpired($request, $results)
) {
$page = $request->get('page') ?? 1;
$anime = ['reviews' => $this->jikan->getAnimeReviews(new AnimeReviewsRequest($id, $page))];
$response = \json_decode($this->serializer->serialize($anime, 'json'), true);
if (HttpHelper::hasError($response)) {
return HttpResponse::notFound($request);
}
if ($results->isEmpty()) {
$meta = [
'createdAt' => new UTCDateTime(),
'modifiedAt' => new UTCDateTime(),
'request_hash' => $this->fingerprint
];
}
$meta['modifiedAt'] = new UTCDateTime();
$response = $meta + $response;
if ($results->isEmpty()) {
DB::table($this->getRouteTable($request))
->insert($response);
}
if ($this->isExpired($request, $results)) {
DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->update($response);
}
$results = DB::table($this->getRouteTable($request))
->where('request_hash', $this->fingerprint)
->get();
}
$response = (new AnimeReviewsResource(
$results->first()
))->response();
return $this->prepareResponse(
$response,
$results,
$request
);
}
}

View File

@ -6,12 +6,16 @@ use App\Http\HttpHelper;
use App\Providers\SerializerFactory;
use App\Providers\SerializerServiceProdivder;
use App\Providers\SerializerServiceProviderV3;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Jikan\Jikan;
use Jikan\MyAnimeList\MalClient;
use JMS\Serializer\Context;
use JMS\Serializer\Serializer;
use Laravel\Lumen\Routing\Controller as BaseController;
use mysql_xdevapi\Exception;
use r\Queries\Control\Http;
use Symfony\Component\HttpFoundation\Response;
/**
* Class Controller
@ -39,34 +43,121 @@ class Controller extends BaseController
*/
private $response;
protected $expired = false;
protected $fingerprint;
/**
* AnimeController constructor.
*
* @param Serializer $serializer
* @param MalClient $jikan
*/
public function __construct(MalClient $jikan)
public function __construct(Request $request, MalClient $jikan)
{
$this->serializer = SerializerFactory::createV4();
$this->jikan = $jikan;
$this->fingerprint = HttpHelper::resolveRequestFingerprint($request);
}
protected function isExpired($request, $results) : bool
{
try {
if ($results->first()->modifiedAt === null) {
return true;
}
$modifiedAt = (int) $results->first()->modifiedAt->toDateTime()->format('U');
$routeName = HttpHelper::getRouteName($request);
$expiry = (int) config("controller.{$routeName}.ttl") + $modifiedAt;
if (time() > $expiry) {
return true;
}
} catch (\Exception $e) {
return false;
}
return false;
}
protected function getExpiry($results, $request)
{
$modifiedAt = $this->getLastModified($results);
$routeName = HttpHelper::getRouteName($request);
return (int) config("controller.{$routeName}.ttl") + $modifiedAt;
}
protected function getTtl($results, $request)
{
$routeName = HttpHelper::getRouteName($request);
return (int) config("controller.{$routeName}.ttl");
}
protected function getLastModified($results) : int
{
if (is_array($results->first())) {
return (int) $results->first()['modifiedAt']->toDateTime()->format('U');
}
if (is_object($results->first())) {
return (int) $results->first()->modifiedAt->toDateTime()->format('U');
}
throw new \Exception('Failed to get Last Modified');
}
protected function serialize($data) : array
{
return \json_decode(
$this->serializer->serialize($data, 'json')
);
}
protected function getRouteName($request) : string
{
return HttpHelper::getRouteName($request);
}
protected function getRouteTable($request) : string
{
return config("controller.{$this->getRouteName($request)}.table_name");
}
protected function prepareResponse($response, $results, $request)
{
return $response
->header('X-Request-Fingerprint', $this->fingerprint)
->setTtl($this->getTtl($results, $request))
->setExpires(
(new \DateTimeImmutable())->setTimestamp(
$this->getExpiry($results, $request)
)
)
->setLastModified(
(new \DateTimeImmutable())->setTimestamp(
$this->getLastModified($results)
)
);
}
/**
* @param array $response
* @return array
*/
protected function prepareResponse(Request $request, array $response) : array
{
$this->request = $request;
$this->response = $response;
unset($this->response['_id']);
$this->mutation();
$this->response = ['data' => $this->response];
return $this->response;
}
// protected function prepareResponse(Request $request, array $response) : array
// {
// $this->request = $request;
// $this->response = $response;
//
// unset($this->response['_id']);
//
// $this->mutation();
//
// $this->response = ['data' => $this->response];
// return $this->response;
// }
/**
* @param Request $request
@ -96,4 +187,5 @@ class Controller extends BaseController
}
}
}
}

View File

@ -2,15 +2,18 @@
namespace App\Http\Controllers\V4DB;
use Illuminate\Http\Request;
use Jikan\Request\Person\PersonRequest;
use Jikan\Request\Person\PersonPicturesRequest;
class PersonController extends Controller
{
public function main(int $id)
public function main(Request $request, int $id)
{
$person = $this->jikan->getPerson(new PersonRequest($id));
return response($this->serializer->serialize($person, 'json'));
if ($request->header('auth') === env('APP_KEY')) {
$person = $this->jikan->getPerson(new PersonRequest($id));
return response($this->serializer->serialize($person, 'json'));
}
}
public function pictures(int $id)

View File

@ -83,12 +83,11 @@ class HttpHelper
return $data;
}
public static function requestControllerName(Request $request) : string
public static function getRouteName(Request $request) : string
{
$route = explode('\\', $request->route()[1]['uses']);
$route = end($route);
return explode('@', $route)[0];
return end($route);
}
public static function getRequestUriHash(Request $request) : string
@ -96,4 +95,9 @@ class HttpHelper
return sha1($request->getRequestUri());
}
public static function getRouteTable($request) : string
{
$routeName = HttpHelper::getRouteName($request);
return config("controller.{$routeName}.table_name");
}
}

View File

@ -0,0 +1,105 @@
<?php
namespace App\Http\Middleware;
use App\Anime;
use App\DatabaseHandler;
use App\Http\Controllers\V4\AnimeController;
use App\Http\Controllers\V4\Controller;
use App\Http\HttpHelper;
use App\Jobs\UpdateDatabaseJob;
use Closure;
use FastRoute\Route;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
use MongoDB\BSON\UTCDateTime;
class SourceDataManager
{
public function handle(Request $request, Closure $next)
{
if (
$request->header('auth') === env('APP_KEY')
|| empty($request->segments())
|| !isset($request->segments()[1])
|| \in_array('meta', $request->segments())
) {
return $next($request);
}
// todo check if mongo enabled
$routeExpanded = explode(
'\\',
$request->route()[1]['uses']
);
$route = end($routeExpanded);
// if (!\in_array($route, self::STORABLE_DATA)) {
// return $next($request);
// }
$fingerprint = HttpHelper::resolveRequestFingerprint($request);
$table = DatabaseHandler::getMappedTableName($route);
$document = DB::table($table)->where('request_hash', $fingerprint);
$documentExists = $document->exists();
// Data exists
if ($documentExists) {
// check expiry and dispatch job request if needed
$expiry = $document->get('expiresAt');
dd('document exists!');
return;
}
// If cache does not exist
if (!$documentExists) {
$response = $next($request);
$freshRequest = Request::create(
env('APP_URL') . $request->getRequestUri(), 'GET', [
'auth' => env('APP_KEY')
]
);
$freshResponse = app()->handle($freshRequest);
dd($freshResponse);
// skip DB, start scraping
// $response = app('GuzzleClient')
// ->request(
// 'GET',
// env('APP_URL') . $request->getRequestUri(),
// [
// 'headers' => [
// 'auth' => env('APP_KEY')
// ]
// ]
// );
//
// dd($response);
if (HttpHelper::hasError($response)) {
return $response;
}
// $results = DB::table($table)->insert(
// [
// 'created_at' => new UTCDateTime(),
// 'modified_at' => new UTCDateTime(),
// 'request_hash' => $fingerprint
// ] + $response
// );
//
// dd($results);
}
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeCharactersResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return $this['characters'];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeEpisodeResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'mal_id' => $this['mal_id'],
'url' => $this['url'],
'title' => $this['title'],
'title_japanese' => $this['title_japanese'],
'title_romanji' => $this['title_romanji'],
'duration' => $this['duration'],
'aired' => $this['aired'],
'filler' => $this['filler'],
'recap' => $this['recap'],
'synopsis' => $this['synopsis']
];
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeEpisodesResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'last_visible_page' => $this['episodes_last_page'],
'has_next_page' => $this['has_next_page'] ?? false,
'episodes' => $this['episodes']
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeForumResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return $this['topics'];
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeMoreInfoResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'moreinfo' => $this['moreinfo']
];
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeNewsResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'last_visible_page' => $this['last_visible_page'] ?? null,
'has_next_page' => $this['has_next_page'] ?? false,
'articles' => $this['articles']
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimePicturesResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return $this['pictures'];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeRecommendationsResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return $this['recommendations'];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeReviewsResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return $this['reviews'];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeStaffResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return $this['staff'];
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeStatisticsResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'watching' => $this['watching'],
'completed' => $this['completed'],
'on_hold' => $this['on_hold'],
'dropped' => $this['dropped'],
'plan_to_watch' => $this['plan_to_watch'],
'total' => $this['total'],
'scores' => $this['scores']
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeUserUpdatesResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return $this['users'];
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class AnimeVideosResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'promo' => $this['promo'],
'episodes' => $this['episodes']
];
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace App\Http\Resources\V4;
use Illuminate\Http\Resources\Json\JsonResource;
class CommonResource extends JsonResource
{
}

View File

@ -48,7 +48,6 @@ class UpdateCacheJob extends Job
$this->requestCached = (bool) Cache::has($this->fingerprint);
}
/**
* @throws \GuzzleHttp\Exception\GuzzleException
*/
@ -57,9 +56,7 @@ class UpdateCacheJob extends Job
$queueFingerprint = "queue_update:{$this->fingerprint}";
$client = new Client();
$response = $client
$response = app('GuzzleClient')
->request(
'GET',
env('APP_URL') . $this->requestUri,

View File

@ -1,5 +1,6 @@
<?php
use App\Providers\SerializerFactory;
use PackageVersions\Versions;
require_once __DIR__.'/../vendor/autoload.php';
@ -77,7 +78,8 @@ $app->routeMiddleware([
// 'throttle' => App\Http\Middleware\Throttle::class,
// 'etag' => \App\Http\Middleware\EtagMiddleware::class,
// 'microcaching' => \App\Http\Middleware\MicroCaching::class,
'database-resolver' => \App\Http\Middleware\DatabaseResolver::class,
// 'database-resolver' => \App\Http\Middleware\DatabaseResolver::class,
'source-data-manager' => \App\Http\Middleware\SourceDataManager::class,
// 'source-health-monitor' => \App\Http\Middleware\SourceHealthMonitor::class
]);
@ -95,6 +97,7 @@ $app->routeMiddleware([
$app->configure('database');
$app->configure('queue');
$app->configure('controller-to-table-mapping');
$app->configure('controller');
if (env('CACHING')) {
$app->configure('cache');
@ -109,6 +112,8 @@ $app->instance('GuzzleClient', $guzzleClient);
$jikan = new \Jikan\MyAnimeList\MalClient(app('GuzzleClient'));
$app->instance('JikanParser', $jikan);
$app->instance('SerializerV4', SerializerFactory::createV4());
if (env('SOURCE_BAD_HEALTH_FAILOVER') && env('DB_CACHING')) {
$app->register(\App\Providers\SourceHealthServiceProvider::class);
}
@ -135,11 +140,12 @@ $commonMiddleware = [
// 'slave-auth',
// 'meta',
// 'etag',
'database-resolver',
// 'database-resolver',
// 'microcaching',
// 'cache-resolver',
// 'throttle'
// 'source-health-monitor'
// 'source-data-manager'
];
$app->router->group(
@ -168,15 +174,13 @@ $app->router->group(
$app->router->group(
[
'prefix' => '/',
'namespace' => 'App\Http\Controllers\V3',
'middleware' => $commonMiddleware
],
function ($router) {
$router->get('/', function () {
return response()->json([
'author_url' => 'http://irfan.dahir.co',
'discord_url' => 'https://discord.gg/4tvCr36',
'version' => '3.4',
'discord_url' => 'http://discord.jikan.moe',
'version' => '4.0',
'parser_version' => JIKAN_PARSER_VERSION,
'website_url' => 'https://jikan.moe',
'documentation_url' => 'https://jikan.docs.apiary.io',

137
config/controller.php Normal file
View File

@ -0,0 +1,137 @@
<?php
return [
'AnimeController@main' => [
'table_name' => 'anime',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@characters_staff' => [
'table_name' => 'anime_characters_staff',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@characters' => [
'table_name' => 'anime_characters_staff',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@staff' => [
'table_name' => 'anime_characters_staff',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@episodes' => [
'table_name' => 'anime_episodes',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@episode' => [
'table_name' => 'anime_episode',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@news' => [
'table_name' => 'anime_news',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@forum' => [
'table_name' => 'anime_forum',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@videos' => [
'table_name' => 'anime_videos',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@pictures' => [
'table_name' => 'anime_pictures',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@stats' => [
'table_name' => 'anime_stats',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@moreInfo' => [
'table_name' => 'anime_moreinfo',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@recommendations' => [
'table_name' => 'anime_recommendations',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@userupdates' => [
'table_name' => 'anime_userupdates',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'AnimeController@reviews' => [
'table_name' => 'anime_reviews',
'ttl' => env('CACHE_DEFAULT_EXPIRE')
],
'MangaController@main' => 'manga',
'MangaController@characters' => 'manga_characters',
'MangaController@news' => 'manga_news',
'MangaController@forum' => 'manga_forum',
'MangaController@pictures' => 'manga_pictures',
'MangaController@stats' => 'manga_stats',
'MangaController@moreInfo' => 'manga_moreinfo',
'MangaController@recommendations' => 'manga_recommendations',
'MangaController@userupdates' => 'manga_userupdates',
'MangaController@reviews' => 'manga_reviews',
'CharacterController@main' => 'characters',
'CharacterController@pictures' => 'characters_pictures',
'PersonController@main' => 'people',
'PersonController@pictures' => 'people_pictures',
'SeasonController@archive' => 'season_archive',
'SeasonController@later' => 'season_later',
'SeasonController@main' => 'season',
'ScheduleController@main' => 'schedule',
'ProducerController@main' => 'producers',
'ProducerController@resource' => 'producers_anime',
'MagazineController@main' => 'magazines',
'MagazineController@resource' => 'magazines_manga',
'UserController@recentlyOnline' => 'users_recently_online',
'UserController@profile' => 'users',
'UserController@history' => 'users_history',
'UserController@friends' => 'users_friends',
'UserController@animelist' => 'users_animelist',
'UserController@mangalist' => 'users_mangalist',
'UserController@recommendations' => 'users_recommendations',
'UserController@reviews' => 'users_reviews',
'UserController@clubs' => 'users_clubs',
'GenreController@animeListing' => 'genres',
'GenreController@mangaListing' => 'genres',
'GenreController@anime' => 'genres_anime',
'GenreController@manga' => 'genres_manga',
'TopController@anime' => 'top_anime',
'TopController@manga' => 'top_manga',
'TopController@characters' => 'top_characters',
'TopController@people' => 'top_people',
'ReviewsController@bestVoted' => 'top_reviews',
'SearchController@anime' => 'search_anime',
'SearchController@manga' => 'search_manga',
'SearchController@character' => 'search_characters',
'SearchController@people' => 'search_people',
'SearchController@users' => 'search_users',
'SearchController@userById' => 'search_users_by_id',
'ClubController@main' => 'clubs',
'ClubController@members' => 'clubs_members',
'ReviewsController@anime' => 'reviews',
'ReviewsController@manga' => 'reviews',
'RecommendationsController@anime' => 'recommendations',
'RecommendationsController@manga' => 'recommendations',
'WatchController@recentEpisodes' => 'watch',
'WatchController@popularEpisodes' => 'watch',
'WatchController@recentPromos' => 'watch',
'WatchController@popularPromos' => 'watch',
];

View File

@ -75,8 +75,12 @@ $router->group(
'uses' => 'AnimeController@forum'
]);
$router->get('/media', [
'uses' => 'AnimeController@media'
$router->get('/videos', [
'uses' => 'AnimeController@videos'
]);
$router->get('/pictures', [
'uses' => 'AnimeController@pictures'
]);
$router->get('/statistics', [