mirror of
https://github.com/jikan-me/jikan-rest.git
synced 2025-02-20 11:23:35 +08:00
commit
454442ae9d
16
.env.example
Normal file
16
.env.example
Normal file
@ -0,0 +1,16 @@
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_KEY=
|
||||
APP_TIMEZONE=UTC
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=homestead
|
||||
DB_USERNAME=homestead
|
||||
DB_PASSWORD=secret
|
||||
|
||||
CACHE_DRIVER=redis
|
||||
QUEUE_DRIVER=sync
|
||||
|
||||
BUGSNAG_API_KEY=
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/vendor
|
||||
/.idea
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
.env
|
18
README.MD
Normal file
18
README.MD
Normal file
@ -0,0 +1,18 @@
|
||||
# Jikan REST API Source
|
||||
|
||||
This REST API is built on Lumen and is in development, therefore neither will I produce or help in any form for any kind of in-depth installation/set up or guides for the time being
|
||||
|
||||
|
||||
## What this requires
|
||||
- Composer
|
||||
- Lumen
|
||||
- BugSnag (API Key)
|
||||
- JikanPHP Library (just composer update)
|
||||
- Redis
|
||||
|
||||
## Quick set up
|
||||
1. Git Clone the repo
|
||||
2. Rename `.env.example` to `.env`
|
||||
3. `composer update`
|
||||
4. Make a BugSnag Account & set the API Key in `.env`
|
||||
5. Install Redis
|
0
app/Console/Commands/.gitkeep
Executable file
0
app/Console/Commands/.gitkeep
Executable file
29
app/Console/Kernel.php
Executable file
29
app/Console/Kernel.php
Executable file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Laravel\Lumen\Console\Kernel as ConsoleKernel;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
/**
|
||||
* The Artisan commands provided by your application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
//
|
||||
];
|
||||
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
* @return void
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
10
app/Events/Event.php
Executable file
10
app/Events/Event.php
Executable file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
abstract class Event
|
||||
{
|
||||
use SerializesModels;
|
||||
}
|
16
app/Events/ExampleEvent.php
Executable file
16
app/Events/ExampleEvent.php
Executable file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
class ExampleEvent extends Event
|
||||
{
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
99
app/Exceptions/Handler.php
Executable file
99
app/Exceptions/Handler.php
Executable file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
use Illuminate\Http\Response;
|
||||
use Symfony\Component\Debug\Exception\FlattenException;
|
||||
use Symfony\Component\Console\Application as ConsoleApplication;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Debug\ExceptionHandler as SymfonyExceptionHandler;
|
||||
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
/**
|
||||
* A list of the exception types that should not be reported.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dontReport = [
|
||||
AuthorizationException::class,
|
||||
HttpException::class,
|
||||
ModelNotFoundException::class,
|
||||
ValidationException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Report or log an exception.
|
||||
*
|
||||
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
|
||||
*
|
||||
* @param \Exception $e
|
||||
* @return void
|
||||
*/
|
||||
public function report(Exception $e)
|
||||
{
|
||||
parent::report($e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Exception $e
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function render($request, Exception $e)
|
||||
{
|
||||
|
||||
Bugsnag::notifyException($e);
|
||||
if ($e instanceof HttpResponseException) {
|
||||
} elseif ($e instanceof ModelNotFoundException) {
|
||||
$e = new NotFoundHttpException($e->getMessage(), $e);
|
||||
} elseif ($e instanceof AuthorizationException) {
|
||||
$e = new HttpException(403, $e->getMessage());
|
||||
} elseif ($e instanceof ValidationException && $e->getResponse()) {
|
||||
}
|
||||
|
||||
$fe = FlattenException::create($e);
|
||||
|
||||
//$decorated = $this->decorate($handler->getContent($fe), $handler->getStylesheet($fe));
|
||||
return response()->json(['error' => $this->getContent($fe->getStatusCode())], $fe->getStatusCode());
|
||||
|
||||
//return response()->json($this->getContent($fe), $fe->getStatusCode());
|
||||
|
||||
//$response->exception = $e;
|
||||
|
||||
|
||||
//return $response;
|
||||
|
||||
//if ($e instanceof CustomException) {
|
||||
// return response('Custom Message');
|
||||
//}
|
||||
|
||||
|
||||
//return response(['error' => $e->getMessage()], 400);
|
||||
//var_dump(parent::render($request, $e));
|
||||
//return parent::render($request, $e);
|
||||
}
|
||||
|
||||
public function getContent($statusCode) {
|
||||
switch ($statusCode) {
|
||||
case 404:
|
||||
return 'Invalid or incomplete endpoint';
|
||||
case 400:
|
||||
return 'Bad Request';
|
||||
case 500:
|
||||
return 'Server Error';
|
||||
default:
|
||||
return 'Unknown error';
|
||||
}
|
||||
}
|
||||
}
|
194
app/Http/Controllers/AnimeController.php
Executable file
194
app/Http/Controllers/AnimeController.php
Executable file
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Exceptions\Handler as Handler;
|
||||
use Jikan\Jikan;
|
||||
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
|
||||
use Lazer\Classes\Database as Lazer;
|
||||
|
||||
class AnimeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public $id;
|
||||
public $extend;
|
||||
public $extendArgs;
|
||||
|
||||
private $validExtends = ['episodes', 'characters_staff', 'news', 'videos', 'pictures', 'stats', 'forum', 'moreinfo'];
|
||||
|
||||
public function request($id, $extend = null, $extendArgs = null) {
|
||||
|
||||
$this->id = $id;
|
||||
$this->extend = $extend;
|
||||
$this->extendArgs = is_array($extendArgs) ? $extendArgs[0] : $extendArgs;
|
||||
|
||||
$this->hash = sha1('anime' . $this->id . $this->extend . $this->extendArgs);
|
||||
$this->response['request_hash'] = $this->hash;
|
||||
$this->response['request_cached'] = false;
|
||||
|
||||
if (app('redis')->exists($this->hash)) {
|
||||
$this->response['request_cached'] = true;
|
||||
return response()->json(
|
||||
$this->response + json_decode(app('redis')->get($this->hash), true)
|
||||
);
|
||||
}
|
||||
|
||||
$jikan = new Jikan;
|
||||
|
||||
if (isset($this->extend)) {
|
||||
if (!in_array($this->extend, $this->validExtends)) {
|
||||
return response()->json(
|
||||
['error' => 'Invalid extended request: "' . $this->extend . '"'], 400
|
||||
);
|
||||
}
|
||||
|
||||
switch ($this->extend) {
|
||||
case 'episodes':
|
||||
try {
|
||||
|
||||
if (!isset($this->extendArgs) || empty($this->extendArgs)) {
|
||||
$this->extendArgs = 1;
|
||||
} else {
|
||||
intval($this->extendArgs);
|
||||
}
|
||||
|
||||
$this->extendArgs = $this->extendArgs <= 0 ? 1 : $this->extendArgs;
|
||||
|
||||
$jikan->Anime($this->id, [EPISODES => $this->extendArgs]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'characters_staff':
|
||||
try {
|
||||
|
||||
$jikan->Anime($this->id, [CHARACTERS_STAFF]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'news':
|
||||
try {
|
||||
|
||||
$jikan->Anime($this->id, [NEWS]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'videos':
|
||||
try {
|
||||
|
||||
$jikan->Anime($this->id, [VIDEOS]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'pictures':
|
||||
try {
|
||||
|
||||
$jikan->Anime($this->id, [PICTURES]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'stats':
|
||||
try {
|
||||
|
||||
$jikan->Anime($this->id, [STATS]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'moreinfo':
|
||||
try {
|
||||
|
||||
$jikan->Anime($this->id, [MORE_INFO]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'forum':
|
||||
try {
|
||||
|
||||
$jikan->Anime($this->id, [FORUM]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
try {
|
||||
|
||||
$jikan->Anime($this->id);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($jikan->response) || $jikan->response === false) {
|
||||
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
|
||||
}
|
||||
|
||||
$this->cache = json_encode($jikan->response);
|
||||
if ($this->cache !== false) {
|
||||
if (app('redis')->set($this->hash, $this->cache)) {
|
||||
app('redis')->expire($this->hash, CACHE_EXPIRE);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(
|
||||
$this->response + $jikan->response
|
||||
);
|
||||
}
|
||||
|
||||
}
|
97
app/Http/Controllers/CharacterController.php
Executable file
97
app/Http/Controllers/CharacterController.php
Executable file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Exceptions\Handler as Handler;
|
||||
use Jikan\Jikan;
|
||||
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
|
||||
|
||||
class CharacterController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public $id;
|
||||
public $extend;
|
||||
public $extendArgs;
|
||||
|
||||
private $validExtends = ['pictures'];
|
||||
|
||||
public function request($id, $extend = null, $extendArgs = null) {
|
||||
|
||||
$this->id = $id;
|
||||
$this->extend = $extend;
|
||||
$this->extendArgs = $extendArgs;
|
||||
|
||||
$this->hash = sha1('character' . $this->id . $this->extend . $this->extendArgs);
|
||||
$this->response['request_hash'] = $this->hash;
|
||||
$this->response['request_cached'] = false;
|
||||
|
||||
if (app('redis')->exists($this->hash)) {
|
||||
$this->response['request_cached'] = true;
|
||||
return response()->json(
|
||||
$this->response + json_decode(app('redis')->get($this->hash), true)
|
||||
);
|
||||
}
|
||||
|
||||
$jikan = new Jikan;
|
||||
|
||||
if (isset($this->extend)) {
|
||||
if (!in_array($this->extend, $this->validExtends)) {
|
||||
return response()->json(
|
||||
['error' => 'Invalid extended request: "' . $this->extend . '"'], 400
|
||||
);
|
||||
}
|
||||
|
||||
switch ($this->extend) {
|
||||
case 'pictures':
|
||||
|
||||
try {
|
||||
|
||||
$jikan->Character($this->id, [PICTURES]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
try {
|
||||
|
||||
$jikan->Character($this->id);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($jikan->response) || $jikan->response === false) {
|
||||
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
|
||||
}
|
||||
|
||||
$this->cache = json_encode($jikan->response);
|
||||
if ($this->cache !== false) {
|
||||
if (app('redis')->set($this->hash, $this->cache)) {
|
||||
app('redis')->expire($this->hash, CACHE_EXPIRE);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(
|
||||
$this->response + $jikan->response
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
12
app/Http/Controllers/Controller.php
Executable file
12
app/Http/Controllers/Controller.php
Executable file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Laravel\Lumen\Routing\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
private $hash;
|
||||
private $cache;
|
||||
private $response = [];
|
||||
}
|
18
app/Http/Controllers/ExampleController.php
Executable file
18
app/Http/Controllers/ExampleController.php
Executable file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
class ExampleController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
//
|
||||
}
|
157
app/Http/Controllers/MangaController.php
Executable file
157
app/Http/Controllers/MangaController.php
Executable file
@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Exceptions\Handler as Handler;
|
||||
use Jikan\Jikan;
|
||||
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
|
||||
|
||||
class MangaController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public $id;
|
||||
public $extend;
|
||||
public $extendArgs;
|
||||
|
||||
private $validExtends = ['characters', 'news', 'pictures', 'stats', 'forum', 'moreinfo'];
|
||||
|
||||
public function request($id, $extend = null, $extendArgs = null) {
|
||||
|
||||
$this->id = $id;
|
||||
$this->extend = $extend;
|
||||
$this->extendArgs = $extendArgs;
|
||||
|
||||
$this->hash = sha1('manga' . $this->id . $this->extend . $this->extendArgs);
|
||||
$this->response['request_hash'] = $this->hash;
|
||||
$this->response['request_cached'] = false;
|
||||
|
||||
if (app('redis')->exists($this->hash)) {
|
||||
$this->response['request_cached'] = true;
|
||||
return response()->json(
|
||||
$this->response + json_decode(app('redis')->get($this->hash), true)
|
||||
);
|
||||
}
|
||||
|
||||
$jikan = new Jikan;
|
||||
|
||||
if (isset($this->extend)) {
|
||||
if (!in_array($this->extend, $this->validExtends)) {
|
||||
return response()->json(
|
||||
['error' => 'Invalid extended request: "' . $this->extend . '"'], 400
|
||||
);
|
||||
}
|
||||
|
||||
switch ($this->extend) {
|
||||
case 'characters':
|
||||
try {
|
||||
|
||||
$jikan->Manga($this->id, [CHARACTERS]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'news':
|
||||
try {
|
||||
|
||||
$jikan->Manga($this->id, [NEWS]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'pictures':
|
||||
try {
|
||||
|
||||
$jikan->Manga($this->id, [PICTURES]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'stats':
|
||||
try {
|
||||
|
||||
$jikan->Manga($this->id, [STATS]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'moreinfo':
|
||||
try {
|
||||
|
||||
$jikan->Manga($this->id, [MORE_INFO]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'forum':
|
||||
try {
|
||||
|
||||
$jikan->Manga($this->id, [FORUM]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
try {
|
||||
|
||||
$jikan->Manga($this->id);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($jikan->response) || $jikan->response === false) {
|
||||
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
|
||||
}
|
||||
|
||||
$this->cache = json_encode($jikan->response);
|
||||
if ($this->cache !== false) {
|
||||
if (app('redis')->set($this->hash, $this->cache)) {
|
||||
app('redis')->expire($this->hash, CACHE_EXPIRE);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(
|
||||
$this->response + $jikan->response
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
146
app/Http/Controllers/MetaController.php
Normal file
146
app/Http/Controllers/MetaController.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
class MetaController extends Controller
|
||||
{
|
||||
|
||||
private const VALID_REQUESTS = ['status', 'requests'];
|
||||
private const VALID_TYPE = ['anime', 'manga', 'character', 'people', 'person', 'search', 'top', 'season'];
|
||||
private const VALID_PERIOD = ['today', 'weekly', 'monthly'];
|
||||
private const LIMIT = 5;
|
||||
|
||||
private $request;
|
||||
private $type;
|
||||
private $period;
|
||||
private $page;
|
||||
|
||||
public function request($request, $type = null, $period = null, $page = 0) {
|
||||
|
||||
if (!is_null($request)) {
|
||||
if (!in_array($request, self::VALID_REQUESTS)) {
|
||||
return response()->json([
|
||||
'error' => 'Invalid or incomplete endpoint'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
if (!is_null($type)) {
|
||||
if (!in_array($type, self::VALID_TYPE)) {
|
||||
return response()->json([
|
||||
'error' => 'Invalid type request'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
if (!is_null($period)) {
|
||||
if (!in_array($period, self::VALID_PERIOD)) {
|
||||
return response()->json([
|
||||
'error' => 'Invalid period request'
|
||||
]);
|
||||
}
|
||||
|
||||
$this->period = $period;
|
||||
}
|
||||
|
||||
if (!is_null($page)) {
|
||||
$this->page = $page - 1;
|
||||
|
||||
if ($this->page < 0) {
|
||||
$this->page = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($request, self::VALID_REQUESTS)) {
|
||||
return response()->json($this->{$request}());
|
||||
}
|
||||
|
||||
|
||||
/* $key = "meta:requests:".date("m-o");
|
||||
|
||||
if (!app('redis')->exists($key)) {
|
||||
return response()->json([
|
||||
'error' => 'Requests for this period do not exist'
|
||||
], 404);
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
public function status() {
|
||||
$key = "meta:requests:".date("m-o");
|
||||
$requests_this_month = 0;
|
||||
$requests_this_week = 0;
|
||||
$requests_today = 0;
|
||||
|
||||
$requests = [];
|
||||
if (app('redis')->exists($key)) {
|
||||
$requests = app('redis')->hGetAll($key);
|
||||
}
|
||||
|
||||
$today = strtotime('today UTC');
|
||||
$last_week = strtotime("-1 week");
|
||||
$now = time();
|
||||
|
||||
foreach ($requests as $time => $data) {
|
||||
|
||||
$data = json_decode($data, true);
|
||||
$count = count($data);
|
||||
|
||||
$requests_this_month += $count;
|
||||
|
||||
if ($time >= $last_week && $time <= $now) {
|
||||
$requests_this_week += $count;
|
||||
}
|
||||
|
||||
if ($time >= $today && $time <= $now) {
|
||||
$requests_today += $count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$info = app('redis')->info();
|
||||
|
||||
|
||||
return response()->json([
|
||||
'cached_requests' => app('redis')->dbsize(),
|
||||
'requests_today' => $requests_today,
|
||||
'requests_this_week' => $requests_this_week,
|
||||
'requests_this_month' => $requests_this_month,
|
||||
'connected_clients' => $info['Clients']['connected_clients'],
|
||||
'total_connections_received' => $info['Stats']['total_connections_received'],
|
||||
'db_keys' => $info['Keyspace']['db0']['keys'],
|
||||
'db_expires' => $info['Keyspace']['db0']['expires'],
|
||||
'db_avg_ttl' => $info['Keyspace']['db0']['avg_ttl'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function requests() {
|
||||
|
||||
$requests = [];
|
||||
$requestsHashKey = app('redis')->sort('requests', [
|
||||
'by' => 'requests:*->time',
|
||||
'sort' => 'desc'
|
||||
]);
|
||||
|
||||
foreach ($requestsHashKey as $value) {
|
||||
$data = app('redis')->hMGet($value, ['time', 'request', 'request_type']);
|
||||
|
||||
if ($data[2] != $this->type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($request[$data[1]])) {
|
||||
$request[$data[1]] = [];
|
||||
}
|
||||
|
||||
$request[$data[1]][] = (int) $data[0];
|
||||
}
|
||||
|
||||
return array_slice($request, 0, self::LIMIT);
|
||||
|
||||
}
|
||||
}
|
88
app/Http/Controllers/MetaLiteController.php
Normal file
88
app/Http/Controllers/MetaLiteController.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
class MetaLiteController extends Controller
|
||||
{
|
||||
|
||||
private const VALID_REQUESTS = ['status', 'requests'];
|
||||
private const VALID_TYPE = ['anime', 'manga', 'character', 'people', 'person', 'search', 'top', 'season'];
|
||||
private const VALID_PERIOD = ['today', 'weekly', 'monthly'];
|
||||
private const LIMIT = 1000;
|
||||
|
||||
private $request;
|
||||
private $type;
|
||||
private $period;
|
||||
|
||||
public function request($request, $type = null, $period = null) {
|
||||
|
||||
if (!in_array($request, self::VALID_REQUESTS)) {
|
||||
return response()->json([
|
||||
'error' => 'Invalid or incomplete endpoint'
|
||||
], 400);
|
||||
}
|
||||
$this->request = $request;
|
||||
|
||||
if (!is_null($type)) {
|
||||
if (!in_array($type, self::VALID_TYPE)) {
|
||||
return response()->json([
|
||||
'error' => 'Invalid type request'
|
||||
], 400);
|
||||
}
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
if (!is_null($period)) {
|
||||
if (!in_array($period, self::VALID_PERIOD)) {
|
||||
return response()->json([
|
||||
'error' => 'Invalid period request'
|
||||
], 400);
|
||||
}
|
||||
$this->period = $period;
|
||||
}
|
||||
|
||||
return response()->json(
|
||||
$this->{$this->request}()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private function status() {
|
||||
$info = app('redis')->info();
|
||||
|
||||
return [
|
||||
'cached_requests' => app('redis')->dbsize(),
|
||||
'requests_today' => count(app('redis')->keys('requests:today:*')),
|
||||
'requests_this_week' => count(app('redis')->keys('requests:weekly:*')),
|
||||
'requests_this_month' => count(app('redis')->keys('requests:monthly:*')),
|
||||
'connected_clients' => $info['Clients']['connected_clients'],
|
||||
'total_connections_received' => $info['Stats']['total_connections_received'],
|
||||
//'db_keys' => $info['Keyspace']['db0']['keys'],
|
||||
//'db_expires' => $info['Keyspace']['db0']['expires'],
|
||||
//'db_avg_ttl' => $info['Keyspace']['db0']['avg_ttl'],
|
||||
];
|
||||
}
|
||||
|
||||
private function requests() {
|
||||
|
||||
if (is_null($this->type)) {
|
||||
return ['error' => 'Missing type'];
|
||||
}
|
||||
|
||||
if (is_null($this->period)) {
|
||||
return ['error' => 'Missing period'];
|
||||
}
|
||||
|
||||
$requests = [];
|
||||
$data = app('redis')->keys('requests:'.$this->period.':*'.$this->type.'*');
|
||||
|
||||
foreach ($data as $hashKey) {
|
||||
$requests[explode(":", $hashKey)[2]] = (int) app('redis')->get($hashKey);
|
||||
}
|
||||
|
||||
arsort($requests);
|
||||
|
||||
return array_slice($requests, 0, self::LIMIT);
|
||||
}
|
||||
|
||||
}
|
97
app/Http/Controllers/PersonController.php
Executable file
97
app/Http/Controllers/PersonController.php
Executable file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Exceptions\Handler as Handler;
|
||||
use Jikan\Jikan;
|
||||
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
|
||||
|
||||
class PersonController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public $id;
|
||||
public $extend;
|
||||
public $extendArgs;
|
||||
|
||||
private $validExtends = ['pictures'];
|
||||
|
||||
public function request($id, $extend = null, $extendArgs = null) {
|
||||
|
||||
$this->id = $id;
|
||||
$this->extend = $extend;
|
||||
$this->extendArgs = $extendArgs;
|
||||
|
||||
$this->hash = sha1('person' . $this->id . $this->extend . $this->extendArgs);
|
||||
$this->response['request_hash'] = $this->hash;
|
||||
$this->response['request_cached'] = false;
|
||||
|
||||
if (app('redis')->exists($this->hash)) {
|
||||
$this->response['request_cached'] = true;
|
||||
return response()->json(
|
||||
$this->response + json_decode(app('redis')->get($this->hash), true)
|
||||
);
|
||||
}
|
||||
|
||||
$jikan = new Jikan;
|
||||
|
||||
if (isset($this->extend)) {
|
||||
if (!in_array($this->extend, $this->validExtends)) {
|
||||
return response()->json(
|
||||
['error' => 'Invalid extended request: "' . $this->extend . '"'], 400
|
||||
);
|
||||
}
|
||||
|
||||
switch ($this->extend) {
|
||||
case 'pictures':
|
||||
|
||||
try {
|
||||
|
||||
$jikan->Person($this->id, [PICTURES]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
try {
|
||||
|
||||
$jikan->Person($this->id);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($jikan->response) || $jikan->response === false) {
|
||||
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
|
||||
}
|
||||
|
||||
$this->cache = json_encode($jikan->response);
|
||||
if ($this->cache !== false) {
|
||||
if (app('redis')->set($this->hash, $this->cache)) {
|
||||
app('redis')->expire($this->hash, CACHE_EXPIRE);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(
|
||||
$this->response + $jikan->response
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
82
app/Http/Controllers/ScheduleController.php
Normal file
82
app/Http/Controllers/ScheduleController.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Exceptions\Handler as Handler;
|
||||
use Jikan\Jikan;
|
||||
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
|
||||
use Lazer\Classes\Database as Lazer;
|
||||
|
||||
class ScheduleController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public $day;
|
||||
|
||||
private $validDays = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
|
||||
|
||||
public function request($day = null) {
|
||||
|
||||
$antiXss = new \voku\helper\AntiXSS();
|
||||
|
||||
if (!is_null($day)) {
|
||||
$this->day = $antiXss->xss_clean($day);
|
||||
if (!in_array($this->day, $this->validDays)) {
|
||||
return response()->json(
|
||||
['error' => 'Invalid day request: "' . $this->day . '"'], 400
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->hash = sha1('schedule' . $this->day);
|
||||
$this->response['request_hash'] = $this->hash;
|
||||
$this->response['request_cached'] = false;
|
||||
|
||||
if (app('redis')->exists($this->hash)) {
|
||||
$this->response['request_cached'] = true;
|
||||
return response()->json(
|
||||
$this->response + json_decode(app('redis')->get($this->hash), true)
|
||||
);
|
||||
}
|
||||
|
||||
$jikan = new Jikan;
|
||||
|
||||
try {
|
||||
|
||||
$jikan->Schedule();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($jikan->response) || $jikan->response === false) {
|
||||
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
|
||||
}
|
||||
|
||||
if (!is_null($this->day)) {
|
||||
$day = $jikan->response[$this->day];
|
||||
$jikan->response = [];
|
||||
$jikan->response[$this->day] = $day;
|
||||
}
|
||||
|
||||
$this->cache = json_encode($jikan->response);
|
||||
if ($this->cache !== false) {
|
||||
if (app('redis')->set($this->hash, $this->cache)) {
|
||||
app('redis')->expire($this->hash, CACHE_EXPIRE);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(
|
||||
$this->response + $jikan->response
|
||||
);
|
||||
}
|
||||
|
||||
}
|
258
app/Http/Controllers/SearchController.php
Executable file
258
app/Http/Controllers/SearchController.php
Executable file
@ -0,0 +1,258 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Exceptions\Handler as Handler;
|
||||
use Jikan;
|
||||
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
|
||||
use Lazer\Classes\Database as Lazer;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*build
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public $type;
|
||||
public $query;
|
||||
public $page;
|
||||
public $config = [];
|
||||
public $configObj;
|
||||
|
||||
private $validTypes = ['anime', 'manga', 'character', 'person', 'people'];
|
||||
private $validSubTypes = [
|
||||
'tv' => 1,
|
||||
'ova' => 2,
|
||||
'movie' => 3,
|
||||
'special' => 4,
|
||||
'ona' => 5,
|
||||
'music' => 6,
|
||||
'manga' => 1,
|
||||
'novel' => 2,
|
||||
'oneshot' => 3,
|
||||
'doujin' => 4,
|
||||
'manhwa' => 5,
|
||||
'manhua' => 6
|
||||
];
|
||||
private $validStatus = [
|
||||
'airing' => 1,
|
||||
'completed' => 2,
|
||||
'complete' => 2,
|
||||
'tba' => 3,
|
||||
'upcoming' => 3
|
||||
];
|
||||
private $validRating = [
|
||||
'g' => 1,
|
||||
'pg' => 2,
|
||||
'pg13' => 3,
|
||||
'r17' => 4,
|
||||
'r' => 5,
|
||||
'rx' => 6
|
||||
];
|
||||
private $validGenre = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43];
|
||||
|
||||
public function request($type = null, $query = null, $page = 1) {
|
||||
|
||||
$antiXss = new \voku\helper\AntiXSS();
|
||||
|
||||
$this->type = $type;
|
||||
$this->query = urlencode($antiXss->xss_clean($query));
|
||||
$this->page = $page;
|
||||
|
||||
$jikan = new \Jikan\Jikan;
|
||||
|
||||
if ($type == 'anime' || $type == 'manga') {
|
||||
$this->buildConfig();
|
||||
|
||||
if (!empty($this->config)) {
|
||||
$this->configObj = new \Jikan\Helper\SearchConfig($type);
|
||||
|
||||
foreach ($this->config as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$this->configObj->{"set".$key}(...$value);
|
||||
} else {
|
||||
$this->configObj->{"set".$key}($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->hash = sha1('search' . $this->type . $this->query . $this->page . $this->configToString());
|
||||
$this->response['request_hash'] = $this->hash;
|
||||
$this->response['request_cached'] = false;
|
||||
|
||||
if (app('redis')->exists($this->hash)) {
|
||||
$this->response['request_cached'] = true;
|
||||
return response()->json(
|
||||
$this->response + json_decode(app('redis')->get($this->hash), true)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (!in_array($this->type, $this->validTypes)) {
|
||||
return response()->json(
|
||||
['error' => 'Invalid type request: "' . $this->type . '"'], 400
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
switch ($this->type) {
|
||||
case 'anime':
|
||||
try {
|
||||
|
||||
if (!empty($this->config)) {
|
||||
$jikan->Search($this->query, ANIME, $this->page, $this->configObj);
|
||||
} else {
|
||||
$jikan->Search($this->query, ANIME, $this->page);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'manga':
|
||||
try {
|
||||
|
||||
if (!empty($this->config)) {
|
||||
$jikan->Search($this->query, MANGA, $this->page, $this->configObj);
|
||||
} else {
|
||||
$jikan->Search($this->query, MANGA, $this->page);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'person':
|
||||
case 'people':
|
||||
try {
|
||||
|
||||
$jikan->Search($this->query, PERSON, $this->page);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'character':
|
||||
try {
|
||||
|
||||
$jikan->Search($this->query, CHARACTER, $this->page);
|
||||
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (empty($jikan->response) || $jikan->response === false) {
|
||||
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
|
||||
}
|
||||
|
||||
$this->cache = json_encode($jikan->response);
|
||||
if ($this->cache !== false) {
|
||||
if (app('redis')->set($this->hash, $this->cache)) {
|
||||
app('redis')->expire($this->hash, CACHE_EXPIRE_SEARCH);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(
|
||||
$this->response + $jikan->response
|
||||
);
|
||||
}
|
||||
|
||||
private function buildConfig() {
|
||||
$antiXss = new \voku\helper\AntiXSS();
|
||||
|
||||
if (!isset($_GET)) {return;}
|
||||
|
||||
if (isset($_GET['type'])) {
|
||||
$subtype = strtolower($antiXss->xss_clean($_GET['type']));
|
||||
if (array_key_exists($subtype, $this->validSubTypes)) {
|
||||
$this->config['Type'] = $this->validSubTypes[$subtype];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['score'])) {
|
||||
$this->config['Score'] = (float) $_GET['score'];
|
||||
}
|
||||
|
||||
if (isset($_GET['status'])) {
|
||||
$status = strtolower($antiXss->xss_clean($_GET['status']));
|
||||
if (array_key_exists($status, $this->validStatus)) {
|
||||
$this->config['Status'] = $this->validStatus[$status];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['rated'])) {
|
||||
$rated = strtolower($antiXss->xss_clean($_GET['rated']));
|
||||
if (array_key_exists($rated, $this->validRating)) {
|
||||
$this->config['Rated'] = $this->validRating[$rated];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['start_date'])) {
|
||||
$startDate = $antiXss->xss_clean($_GET['start_date']);
|
||||
if (preg_match("~[0-9]{4}-[0-9]{2}-[0-9]{2}~", $startDate)) {
|
||||
$this->config['StartDate'] = explode("-", $startDate);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['end_date'])) {
|
||||
$endDate = $antiXss->xss_clean($_GET['end_date']);
|
||||
if (preg_match("~[0-9]{4}-[0-9]{2}-[0-9]{2}~", $endDate)) {
|
||||
$this->config['EndDate'] = explode("-", $endDate);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['genre'])) {
|
||||
if (!is_array($_GET['genre'])) {
|
||||
return response()->json(
|
||||
['error' => 'Bad genre parse: "' . $this->type . '"'], 400
|
||||
);
|
||||
}
|
||||
|
||||
$this->config['genre'] = [];
|
||||
foreach ($_GET['genre'] as $genre) {
|
||||
$genre = (int) $genre;
|
||||
|
||||
if (in_array($genre, $this->validGenre)) {
|
||||
$this->config['genre'][] = $genre;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['genre_exclude'])) {
|
||||
$this->config['GenreInclude'] = ((int) $_GET['genre_exclude'] == 1) ? false : true;
|
||||
}
|
||||
}
|
||||
|
||||
private function configToString() {
|
||||
$url = "?";
|
||||
foreach ($this->config as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$value = implode(",", $value);
|
||||
}
|
||||
|
||||
$url .= $key . "=" . $value . "&";
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
}
|
83
app/Http/Controllers/SeasonController.php
Normal file
83
app/Http/Controllers/SeasonController.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Exceptions\Handler as Handler;
|
||||
use Jikan\Jikan;
|
||||
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
|
||||
use Lazer\Classes\Database as Lazer;
|
||||
|
||||
class SeasonController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public $year;
|
||||
public $season;
|
||||
|
||||
private $validSeasons = ['summer', 'spring', 'fall', 'winter'];
|
||||
|
||||
public function request($year = null, $season = null) {
|
||||
|
||||
$antiXss = new \voku\helper\AntiXSS();
|
||||
|
||||
if (!is_null($year) && !is_null($season)) {
|
||||
$this->year = (int) $year;
|
||||
|
||||
$this->season = $antiXss->xss_clean($season);
|
||||
if (!in_array($this->season, $this->validSeasons)) {
|
||||
return response()->json(
|
||||
['error' => 'Invalid season request: "' . $this->year . '/' . $this->season . '"'], 400
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->hash = sha1('season' . $this->year . $this->season);
|
||||
$this->response['request_hash'] = $this->hash;
|
||||
$this->response['request_cached'] = false;
|
||||
|
||||
if (app('redis')->exists($this->hash)) {
|
||||
$this->response['request_cached'] = true;
|
||||
return response()->json(
|
||||
$this->response + json_decode(app('redis')->get($this->hash), true)
|
||||
);
|
||||
}
|
||||
|
||||
$jikan = new Jikan;
|
||||
|
||||
try {
|
||||
|
||||
if (!is_null($this->year) && !is_null($this->season)) {
|
||||
$jikan->Seasonal($this->season, $this->year);
|
||||
} else {
|
||||
$jikan->Seasonal();
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($jikan->response) || $jikan->response === false) {
|
||||
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
|
||||
}
|
||||
|
||||
$this->cache = json_encode($jikan->response);
|
||||
if ($this->cache !== false) {
|
||||
if (app('redis')->set($this->hash, $this->cache)) {
|
||||
app('redis')->expire($this->hash, CACHE_EXPIRE);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(
|
||||
$this->response + $jikan->response
|
||||
);
|
||||
}
|
||||
|
||||
}
|
88
app/Http/Controllers/TopController.php
Normal file
88
app/Http/Controllers/TopController.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Exceptions\Handler as Handler;
|
||||
use Jikan\Jikan;
|
||||
use Bugsnag\BugsnagLaravel\Facades\Bugsnag;
|
||||
use Lazer\Classes\Database as Lazer;
|
||||
|
||||
class TopController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public $type;
|
||||
public $subtype;
|
||||
public $page;
|
||||
|
||||
private $validTypes = ['anime', 'manga'];
|
||||
private $validSubTypes = ['airing', 'upcoming', 'tv', 'movie', 'ova', 'special', 'manga', 'novels', 'oneshots', 'doujin', 'manhwa', 'manhua', 'bypopularity', 'favorite'];
|
||||
|
||||
public function request($type = null, $page = 1, $subtype = null) {
|
||||
|
||||
$antiXss = new \voku\helper\AntiXSS();
|
||||
|
||||
$this->type = $antiXss->xss_clean($type);
|
||||
$this->page = (int) $page;
|
||||
|
||||
if (!in_array($this->type, $this->validTypes)) {
|
||||
return response()->json(
|
||||
['error' => 'Invalid type request: "' . $this->type . '/' . $this->page . '/' . $this->subtype . '"'], 400
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_null($subtype)) {
|
||||
$this->subtype = $antiXss->xss_clean($subtype);
|
||||
if (!in_array($this->subtype, $this->validSubTypes)) {
|
||||
return response()->json(
|
||||
['error' => 'Invalid sub type request: "' . $this->type . '/' . $this->page . '/' . $this->subtype . '"'], 400
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->hash = sha1('top' . $this->type . $this->page . $this->subtype);
|
||||
$this->response['request_hash'] = $this->hash;
|
||||
$this->response['request_cached'] = false;
|
||||
|
||||
if (app('redis')->exists($this->hash)) {
|
||||
$this->response['request_cached'] = true;
|
||||
return response()->json(
|
||||
$this->response + json_decode(app('redis')->get($this->hash), true)
|
||||
);
|
||||
}
|
||||
|
||||
$jikan = new Jikan;
|
||||
|
||||
try {
|
||||
|
||||
$jikan->Top($this->type, $this->page, $this->subtype);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Bugsnag::notifyException($e);
|
||||
return response()->json(
|
||||
['error' => $e->getMessage()], 404
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($jikan->response) || $jikan->response === false) {
|
||||
return response()->json(['error' => 'MyAnimeList Rate Limiting reached. Slow down!'], 429);
|
||||
}
|
||||
|
||||
$this->cache = json_encode($jikan->response);
|
||||
if ($this->cache !== false) {
|
||||
if (app('redis')->set($this->hash, $this->cache)) {
|
||||
app('redis')->expire($this->hash, CACHE_EXPIRE_SEARCH);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(
|
||||
$this->response + $jikan->response
|
||||
);
|
||||
}
|
||||
|
||||
}
|
44
app/Http/Middleware/Authenticate.php
Executable file
44
app/Http/Middleware/Authenticate.php
Executable file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Auth\Factory as Auth;
|
||||
|
||||
class Authenticate
|
||||
{
|
||||
/**
|
||||
* The authentication guard factory instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\Factory
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* Create a new middleware instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Factory $auth
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Auth $auth)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next, $guard = null)
|
||||
{
|
||||
if ($this->auth->guard($guard)->guest()) {
|
||||
return response('Unauthorized.', 401);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
26
app/Http/Middleware/Cache.php
Executable file
26
app/Http/Middleware/Cache.php
Executable file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class Cache
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$response = $next($request);
|
||||
$data = $response->original;
|
||||
|
||||
if (!array_key_exists('error', $data)) {
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
20
app/Http/Middleware/ExampleMiddleware.php
Executable file
20
app/Http/Middleware/ExampleMiddleware.php
Executable file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class ExampleMiddleware
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
return $next($request);
|
||||
}
|
||||
}
|
45
app/Http/Middleware/Meta.php
Normal file
45
app/Http/Middleware/Meta.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class Meta
|
||||
{
|
||||
|
||||
private $request;
|
||||
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$req = $_SERVER['REQUEST_URI'];
|
||||
$req_type = explode('/', $req)[1];
|
||||
|
||||
$response = $next($request);
|
||||
|
||||
if (isset($response->original['error'])) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$date = date("m-o");
|
||||
$time = round(microtime(true) * 1000);
|
||||
$key = "requests:".$date.":".$time;
|
||||
|
||||
|
||||
$this->updateMeta("requests:today", $req, 86400);
|
||||
$this->updateMeta("requests:weekly", $req, 604800);
|
||||
$this->updateMeta("requests:monthly", $req, 2629746);
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function updateMeta($key, $req, $expire) {
|
||||
$hashKey = $key . ":" . $req;
|
||||
if (!app('redis')->exists($hashKey)) {
|
||||
app('redis')->set($hashKey, 0);
|
||||
app('redis')->expire($hashKey, $expire);
|
||||
}
|
||||
app('redis')->incrBy($hashKey, 1);
|
||||
}
|
||||
|
||||
}
|
78
app/Http/Middleware/Throttle.php
Executable file
78
app/Http/Middleware/Throttle.php
Executable file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class Throttle
|
||||
{
|
||||
|
||||
private $ip;
|
||||
private $hit;
|
||||
|
||||
private $sessions = [];
|
||||
private $rateLimited = false;
|
||||
|
||||
private $request_hash;
|
||||
private $request_cached;
|
||||
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
|
||||
$response = $next($request);
|
||||
|
||||
$this->loadSessions(); // load the session
|
||||
|
||||
if (!isset($response->original['error'])) { // don't throttle errors
|
||||
|
||||
$this->request_hash = $response->original['request_hash'];
|
||||
$this->request_cached = $response->original['request_cached'];
|
||||
|
||||
if (!$this->request_cached) { // don't throttle cached requests
|
||||
$this->hit(); // increase API Call Count
|
||||
}
|
||||
}
|
||||
|
||||
$this->rateLimit(); // check if it's over the limit
|
||||
|
||||
$this->save(); // save the updated session
|
||||
|
||||
if ($this->rateLimited) {
|
||||
return response()->json(['error' => 'You have reached your limit of ' . RATE_LIMIT . ' API calls per day, please try again later'], 429);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function hit() {
|
||||
$this->ip = $_SERVER['REMOTE_ADDR'];
|
||||
$date = date("d-m-Y");
|
||||
|
||||
|
||||
if (!isset($this->sessions[$this->ip])) { // register the session
|
||||
$this->sessions[$this->ip] = [
|
||||
$date => 0
|
||||
];
|
||||
}
|
||||
|
||||
if (!isset($this->sessions[$this->ip][$date])) { // register today's session
|
||||
$this->sessions[$this->ip][$date] = 0;
|
||||
}
|
||||
|
||||
$this->sessions[$this->ip][$date]++; // increase API Call count
|
||||
|
||||
$this->hit = $this->sessions[$this->ip][$date];
|
||||
}
|
||||
|
||||
public function rateLimit() {
|
||||
$this->rateLimited = ($this->hit > RATE_LIMIT) ? true : false;
|
||||
}
|
||||
|
||||
public function loadSessions() {
|
||||
$this->sessions = file_exists(SESSION_STORAGE_PATH) ? json_decode(file_get_contents(SESSION_STORAGE_PATH), true) : file_put_contents(SESSION_STORAGE_PATH, json_encode([]));
|
||||
}
|
||||
|
||||
public function save() {
|
||||
file_put_contents(SESSION_STORAGE_PATH, json_encode($this->sessions));
|
||||
}
|
||||
}
|
26
app/Jobs/ExampleJob.php
Executable file
26
app/Jobs/ExampleJob.php
Executable file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
class ExampleJob extends Job
|
||||
{
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
24
app/Jobs/Job.php
Executable file
24
app/Jobs/Job.php
Executable file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
abstract class Job implements ShouldQueue
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queueable Jobs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This job base class provides a central location to place any logic that
|
||||
| is shared across all of your jobs. The trait included with the class
|
||||
| provides access to the "queueOn" and "delay" queue helper methods.
|
||||
|
|
||||
*/
|
||||
|
||||
use InteractsWithQueue, Queueable, SerializesModels;
|
||||
}
|
31
app/Listeners/ExampleListener.php
Executable file
31
app/Listeners/ExampleListener.php
Executable file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\ExampleEvent;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
class ExampleListener
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param ExampleEvent $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(ExampleEvent $event)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
20
app/Providers/AppServiceProvider.php
Executable file
20
app/Providers/AppServiceProvider.php
Executable file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
$this->app->alias('bugsnag.logger', \Illuminate\Contracts\Logging\Log::class);
|
||||
$this->app->alias('bugsnag.logger', \Psr\Log\LoggerInterface::class);
|
||||
}
|
||||
}
|
39
app/Providers/AuthServiceProvider.php
Executable file
39
app/Providers/AuthServiceProvider.php
Executable file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AuthServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot the authentication services for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
// Here you may define how you wish users to be authenticated for your Lumen
|
||||
// application. The callback which receives the incoming request instance
|
||||
// should return either a User instance or null. You're free to obtain
|
||||
// the User instance via an API token or any other method necessary.
|
||||
|
||||
$this->app['auth']->viaRequest('api', function ($request) {
|
||||
if ($request->input('api_token')) {
|
||||
return User::where('api_token', $request->input('api_token'))->first();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
19
app/Providers/EventServiceProvider.php
Executable file
19
app/Providers/EventServiceProvider.php
Executable file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Laravel\Lumen\Providers\EventServiceProvider as ServiceProvider;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* The event listener mappings for the application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $listen = [
|
||||
'App\Events\SomeEvent' => [
|
||||
'App\Listeners\EventListener',
|
||||
],
|
||||
];
|
||||
}
|
32
app/User.php
Executable file
32
app/User.php
Executable file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Auth\Authenticatable;
|
||||
use Laravel\Lumen\Auth\Authorizable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
|
||||
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
|
||||
|
||||
class User extends Model implements AuthenticatableContract, AuthorizableContract
|
||||
{
|
||||
use Authenticatable, Authorizable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name', 'email',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes excluded from the model's JSON form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
];
|
||||
}
|
35
artisan
Executable file
35
artisan
Executable file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Create The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| First we need to get an application instance. This creates an instance
|
||||
| of the application / container and bootstraps the application so it
|
||||
| is ready to receive HTTP / Console requests from the environment.
|
||||
|
|
||||
*/
|
||||
|
||||
$app = require __DIR__.'/bootstrap/app.php';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Run The Artisan Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When we run the console application, the current CLI command will be
|
||||
| executed in this console and the response sent back to a terminal
|
||||
| or another output device for the developers. Here goes nothing!
|
||||
|
|
||||
*/
|
||||
|
||||
$kernel = $app->make(
|
||||
'Illuminate\Contracts\Console\Kernel'
|
||||
);
|
||||
|
||||
exit($kernel->handle(new ArgvInput, new ConsoleOutput));
|
122
bootstrap/app.php
Executable file
122
bootstrap/app.php
Executable file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
try {
|
||||
(new Dotenv\Dotenv(__DIR__.'/../'))->load();
|
||||
} catch (Dotenv\Exception\InvalidPathException $e) {
|
||||
//
|
||||
}
|
||||
|
||||
/*
|
||||
Defines
|
||||
*/
|
||||
define('SESSION_STORAGE_PATH', '/var/www/api.jikan/storage/app/sessions.json'); // depreciated. Using Redis now
|
||||
define('RATE_LIMIT', 5000); // per day
|
||||
define('CACHE_EXPIRE', 3600 * 24 * 3); // 3 days
|
||||
define('CACHE_EXPIRE_SEARCH', 3600 * 6); // 6 hours
|
||||
//define('CACHE_EXPIRE', 4); // 60 seconds | dev
|
||||
//define('CACHE_EXPIRE_SEARCH', 4); // 60 seconds | dev
|
||||
|
||||
define('REST_VERSION', '2.2');
|
||||
define('SOURCE_VERSION', '1.15.8');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Create The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here we will load the environment and create the application instance
|
||||
| that serves as the central piece of this framework. We'll use this
|
||||
| application as an "IoC" container and router for this framework.
|
||||
|
|
||||
*/
|
||||
|
||||
|
||||
$app = new Laravel\Lumen\Application(
|
||||
realpath(__DIR__.'/../')
|
||||
);
|
||||
|
||||
$app->withFacades();
|
||||
$app->withEloquent();
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register Container Bindings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Now we will register a few bindings in the service container. We will
|
||||
| register the exception handler and the console kernel. You may add
|
||||
| your own bindings here if you like or you can make another file.
|
||||
|
|
||||
*/
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Debug\ExceptionHandler::class,
|
||||
App\Exceptions\Handler::class
|
||||
);
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Console\Kernel::class,
|
||||
App\Console\Kernel::class
|
||||
);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Next, we will register the middleware with the application. These can
|
||||
| be global middleware that run before and after each request into a
|
||||
| route or middleware that'll be assigned to some specific routes.
|
||||
|
|
||||
*/
|
||||
|
||||
/*$app->middleware([App\Http\Middleware\Meta::class]);
|
||||
$app->middleware([App\Http\Middleware\Throttle::class]);*/
|
||||
|
||||
// $app->routeMiddleware([
|
||||
// 'auth' => App\Http\Middleware\Authenticate::class,
|
||||
// ]);
|
||||
|
||||
$app->routeMiddleware([
|
||||
'meta' => App\Http\Middleware\Meta::class,
|
||||
'throttle' => App\Http\Middleware\Throttle::class
|
||||
]);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register Service Providers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here we will register all of the application's service providers which
|
||||
| are used to bind services into the container. Service providers are
|
||||
| totally optional, so you are not required to uncomment this line.
|
||||
|
|
||||
*/
|
||||
|
||||
$app->register(Bugsnag\BugsnagLaravel\BugsnagServiceProvider::class);
|
||||
$app->register(Illuminate\Redis\RedisServiceProvider::class);
|
||||
|
||||
// $app->register(App\Providers\AppServiceProvider::class);
|
||||
// $app->register(App\Providers\AuthServiceProvider::class);
|
||||
// $app->register(App\Providers\EventServiceProvider::class);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Load The Application Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Next we will include the routes file so that they can all be added to
|
||||
| the application. This will provide all of the URLs the application
|
||||
| can respond to, as well as the controllers that may handle them.
|
||||
|
|
||||
*/
|
||||
|
||||
$app->router->group([
|
||||
'namespace' => 'App\Http\Controllers',
|
||||
], function ($router) {
|
||||
require __DIR__.'/../routes/web.php';
|
||||
});
|
||||
|
||||
return $app;
|
44
composer.json
Executable file
44
composer.json
Executable file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "laravel/lumen",
|
||||
"description": "The Laravel Lumen Framework.",
|
||||
"keywords": ["framework", "laravel", "lumen"],
|
||||
"license": "MIT",
|
||||
"type": "project",
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"laravel/lumen-framework": "5.5.*",
|
||||
"vlucas/phpdotenv": "~2.2",
|
||||
"jikan-me/jikan": "dev-master",
|
||||
"bugsnag/bugsnag-laravel": "^2.0",
|
||||
"danielmewes/php-rql": "dev-master",
|
||||
"illuminate/redis": "^5.5",
|
||||
"predis/predis": "^1.1",
|
||||
"voku/anti-xss": "^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fzaninotto/faker": "~1.4",
|
||||
"phpunit/phpunit": "~6.0",
|
||||
"mockery/mockery": "~0.9"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"classmap": [
|
||||
"tests/",
|
||||
"database/"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"post-root-package-install": [
|
||||
"php -r \"copy('.env.example', '.env');\""
|
||||
]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"config": {
|
||||
"optimize-autoloader": true
|
||||
}
|
||||
}
|
4941
composer.lock
generated
Executable file
4941
composer.lock
generated
Executable file
File diff suppressed because it is too large
Load Diff
19
database/factories/ModelFactory.php
Executable file
19
database/factories/ModelFactory.php
Executable file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Model Factories
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define all of your model factories. Model factories give
|
||||
| you a convenient way to create models for testing and seeding your
|
||||
| database. Just tell the factory how a default model should look.
|
||||
|
|
||||
*/
|
||||
|
||||
$factory->define(App\User::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'name' => $faker->name,
|
||||
'email' => $faker->email,
|
||||
];
|
||||
});
|
0
database/migrations/.gitkeep
Executable file
0
database/migrations/.gitkeep
Executable file
16
database/seeds/DatabaseSeeder.php
Executable file
16
database/seeds/DatabaseSeeder.php
Executable file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// $this->call('UsersTableSeeder');
|
||||
}
|
||||
}
|
27
phpunit.xml
Executable file
27
phpunit.xml
Executable file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="bootstrap/app.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false">
|
||||
<testsuites>
|
||||
<testsuite name="Application Test Suite">
|
||||
<directory suffix="Test.php">./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">./app</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="CACHE_DRIVER" value="array"/>
|
||||
<env name="QUEUE_DRIVER" value="sync"/>
|
||||
</php>
|
||||
</phpunit>
|
27
public/.htaccess
Executable file
27
public/.htaccess
Executable file
@ -0,0 +1,27 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
<IfModule mod_negotiation.c>
|
||||
Options -MultiViews
|
||||
</IfModule>
|
||||
|
||||
RewriteEngine On
|
||||
|
||||
# Redirect Trailing Slashes If Not A Folder...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)/$ /$1 [L,R=301]
|
||||
|
||||
# Handle Front Controller...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
|
||||
# Handle Authorization Header
|
||||
RewriteCond %{HTTP:Authorization} .
|
||||
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
</IfModule>
|
||||
|
||||
|
||||
# BEGIN GZIP
|
||||
<ifmodule mod_deflate.c>
|
||||
AddOutputFilterByType DEFLATE text/text text/json text/html text/plain text/xml text/css application/x-javascript application/javascript
|
||||
</ifmodule>
|
||||
# END GZIP
|
29
public/index.php
Executable file
29
public/index.php
Executable file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Create The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| First we need to get an application instance. This creates an instance
|
||||
| of the application / container and bootstraps the application so it
|
||||
| is ready to receive HTTP / Console requests from the environment.
|
||||
|
|
||||
*/
|
||||
|
||||
$app = require __DIR__.'/../bootstrap/app.php';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Run The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Once we have the application, we can handle the incoming request
|
||||
| through the kernel, and send the associated response back to
|
||||
| the client's browser allowing them to enjoy the creative
|
||||
| and wonderful application we have prepared for them.
|
||||
|
|
||||
*/
|
||||
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
header("Access-Control-Allow-Methods: *");
|
||||
$app->run();
|
0
resources/views/.gitkeep
Executable file
0
resources/views/.gitkeep
Executable file
74
routes/web.php
Executable file
74
routes/web.php
Executable file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register all of the routes for an application.
|
||||
| It is a breeze. Simply tell Lumen the URIs it should respond to
|
||||
| and give it the Closure to call when that URI is requested.
|
||||
|
|
||||
*/
|
||||
|
||||
|
||||
|
||||
$router->get('/', function () use ($router) {
|
||||
|
||||
|
||||
return response()->json([
|
||||
'Author' => '@irfanDahir',
|
||||
'Contact' => 'contact@jikan.moe',
|
||||
'JikanREST' => REST_VERSION,
|
||||
'JikanPHP' => SOURCE_VERSION,
|
||||
'Home' => 'https://jikan.moe/',
|
||||
'Docs' => 'https://jikan.docs.apiary.io',
|
||||
'GitHub' => 'https://github.com/jikan-me/jikan',
|
||||
'PRODUCTION_API_URL' => 'https://api.jikan.moe/',
|
||||
'STATUS_URL' => 'https://api.jikan.moe/meta/status',
|
||||
'RATE_LIMIT' => RATE_LIMIT,
|
||||
'CACHED_REQUESTS' => app('redis')->dbSize(),
|
||||
]);
|
||||
});
|
||||
|
||||
$router->get('meta/{request:[A-Za-z]+}[/{type:[A-Za-z]+}[/{period:[A-Za-z]+}[/{page:[0-9]+}]]]', [
|
||||
'uses' => 'MetaLiteController@request'
|
||||
]);
|
||||
|
||||
$router->group(['middleware' => ['meta', 'throttle']], function() use ($router) {
|
||||
|
||||
$router->get('anime[/{id:[0-9]+}[/{extend:[A-Za-z_]+}[/{extendArgs}]]]', [
|
||||
'uses' => 'AnimeController@request'
|
||||
]);
|
||||
|
||||
$router->get('manga[/{id:[0-9]+}[/{extend:[A-Za-z]+}]]', [
|
||||
'uses' => 'MangaController@request'
|
||||
]);
|
||||
|
||||
$router->get('person[/{id:[0-9]+}[/{extend:[A-Za-z]+}]]', [
|
||||
'uses' => 'PersonController@request'
|
||||
]);
|
||||
|
||||
$router->get('character[/{id:[0-9]+}[/{extend:[A-Za-z]+}]]', [
|
||||
'uses' => 'CharacterController@request'
|
||||
]);
|
||||
|
||||
$router->get('search[/{type}/{query}[/{page:[0-9]+}]]', [
|
||||
'uses' => 'SearchController@request'
|
||||
]);
|
||||
|
||||
$router->get('season[/{year:[0-9]{4}}/{season:[A-Za-z]+}]', [
|
||||
'uses' => 'SeasonController@request'
|
||||
]);
|
||||
|
||||
$router->get('schedule[/{day:[A-Za-z]+}]', [
|
||||
'uses' => 'ScheduleController@request'
|
||||
]);
|
||||
|
||||
$router->get('top/{type:[A-Za-z]+}[/{page:[0-9]+}[/{subtype:[A-Za-z]+}]]', [
|
||||
'uses' => 'TopController@request'
|
||||
]);
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
2
storage/app/.gitignore
vendored
Executable file
2
storage/app/.gitignore
vendored
Executable file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
2
storage/framework/cache/.gitignore
vendored
Executable file
2
storage/framework/cache/.gitignore
vendored
Executable file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
2
storage/framework/views/.gitignore
vendored
Executable file
2
storage/framework/views/.gitignore
vendored
Executable file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
2
storage/logs/.gitignore
vendored
Executable file
2
storage/logs/.gitignore
vendored
Executable file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
21
tests/ExampleTest.php
Executable file
21
tests/ExampleTest.php
Executable file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
use Laravel\Lumen\Testing\DatabaseMigrations;
|
||||
use Laravel\Lumen\Testing\DatabaseTransactions;
|
||||
|
||||
class ExampleTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* A basic test example.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testExample()
|
||||
{
|
||||
$this->get('/');
|
||||
|
||||
$this->assertEquals(
|
||||
$this->app->version(), $this->response->getContent()
|
||||
);
|
||||
}
|
||||
}
|
14
tests/TestCase.php
Executable file
14
tests/TestCase.php
Executable file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
abstract class TestCase extends Laravel\Lumen\Testing\TestCase
|
||||
{
|
||||
/**
|
||||
* Creates the application.
|
||||
*
|
||||
* @return \Laravel\Lumen\Application
|
||||
*/
|
||||
public function createApplication()
|
||||
{
|
||||
return require __DIR__.'/../bootstrap/app.php';
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user