224 lines
12 KiB
PHP
224 lines
12 KiB
PHP
<?php
|
||
|
||
use Illuminate\Support\Facades\Route;
|
||
use App\Http\Controllers\Api\ImportApiController;
|
||
use App\Http\Controllers\Api\AuthApiController;
|
||
use App\Http\Controllers\Api\AnimeApiController;
|
||
use App\Http\Controllers\Api\UserApiController;
|
||
use App\Http\Controllers\Api\CommentApiController;
|
||
use App\Http\Controllers\Api\AiApiController;
|
||
use App\Http\Controllers\Api\SocialApiController;
|
||
use App\Http\Controllers\Api\TribunalApiController;
|
||
use App\Http\Controllers\Api\MessageApiController;
|
||
use App\Http\Controllers\Api\PlanApiController;
|
||
|
||
// ── Import API (internal Python scraper) ─────────────────────────────────────
|
||
Route::middleware('import.api')->prefix('import')->group(function () {
|
||
Route::get('test', [ImportApiController::class, 'test']);
|
||
Route::get('stats', [ImportApiController::class, 'stats']);
|
||
Route::get('settings', [ImportApiController::class, 'settings']);
|
||
Route::get('next-job', [ImportApiController::class, 'nextJob']);
|
||
Route::post('jobs', [ImportApiController::class, 'createJob']); // AUTO-IMPORT
|
||
Route::get('imported-ids', [ImportApiController::class, 'importedIds']);
|
||
Route::get('imported-titles', [ImportApiController::class, 'importedTitles']);
|
||
Route::get('ongoing', [ImportApiController::class, 'ongoingAnimes']);
|
||
Route::get('all-animes', [ImportApiController::class, 'allAniziumAnimes']);
|
||
Route::get('jobs/{job}', [ImportApiController::class, 'getJob']);
|
||
Route::post('jobs/{job}/status', [ImportApiController::class, 'updateStatus']);
|
||
Route::post('jobs/{job}/episode', [ImportApiController::class, 'saveEpisode']);
|
||
Route::post('jobs/{job}/subtitle', [ImportApiController::class, 'saveSubtitle']);
|
||
Route::get('jobs/{job}/done-episodes', [ImportApiController::class, 'doneEpisodes']);
|
||
|
||
// Altyazı yenileme
|
||
Route::get('anizium-episodes', [ImportApiController::class, 'aniziumEpisodes']);
|
||
Route::post('subtitle-direct', [ImportApiController::class, 'saveSubtitleDirect']);
|
||
|
||
// Sağlık kontrolü + deaktivasyon
|
||
Route::get('anizium-health', [ImportApiController::class, 'aniziumHealthData']);
|
||
Route::post('deactivate-anime', [ImportApiController::class, 'deactivateAnime']);
|
||
|
||
// Animecix-specific
|
||
Route::get('animecix/pending', [ImportApiController::class, 'animecixPendingJobs']);
|
||
Route::post('episodes/{episode}/video-sources', [ImportApiController::class, 'saveVideoSources']);
|
||
|
||
// Çapraz kaynak desteği
|
||
Route::get('anime/lookup', [ImportApiController::class, 'animeLookup']);
|
||
Route::get('published-animes-with-jobs', [ImportApiController::class, 'publishedAnimesWithJobs']);
|
||
});
|
||
|
||
// ── Mobile App API ────────────────────────────────────────────────────────────
|
||
|
||
// App status (public — called on startup to check maintenance/force-update)
|
||
Route::get('app-status', function () {
|
||
$minVersion = \App\Models\Setting::get('mobile_min_version', '1.0.0');
|
||
$currentVersion = \App\Models\Setting::get('mobile_current_version', '1.0.0');
|
||
$maintenance = \App\Models\Setting::get('mobile_maintenance_mode', '0') === '1';
|
||
$maintMsg = \App\Models\Setting::get('mobile_maintenance_message', 'Uygulama şu anda bakımda.');
|
||
$apkUrl = \App\Models\Setting::get('mobile_apk_url', '');
|
||
$forceMsg = \App\Models\Setting::get('mobile_force_update_msg', 'Lütfen uygulamayı güncelleyin.');
|
||
|
||
// Determine force_update by comparing appVersion (sent as ?v=x.y.z) with minVersion
|
||
$appVersion = request('v', '0.0.0');
|
||
$forceUpdate = version_compare($appVersion, $minVersion, '<');
|
||
|
||
return response()->json([
|
||
'maintenance' => $maintenance,
|
||
'maintenance_message' => $maintMsg,
|
||
'min_version' => $minVersion,
|
||
'current_version' => $currentVersion,
|
||
'apk_url' => $apkUrl ?: null,
|
||
'force_update' => $forceUpdate,
|
||
'force_update_message'=> $forceMsg,
|
||
]);
|
||
});
|
||
|
||
// Auth (public)
|
||
Route::prefix('auth')->group(function () {
|
||
Route::post('register', [AuthApiController::class, 'register']);
|
||
Route::post('login', [AuthApiController::class, 'login']);
|
||
});
|
||
|
||
// Public content
|
||
Route::get('home', [AnimeApiController::class, 'home']);
|
||
Route::get('animes', [AnimeApiController::class, 'index']);
|
||
Route::get('animes/{slug}', [AnimeApiController::class, 'show']);
|
||
Route::get('genres', [AnimeApiController::class, 'genres']);
|
||
Route::get('genres/{slug}', [AnimeApiController::class, 'genre']);
|
||
Route::get('watch/{slug}/{season}/{episode}', [AnimeApiController::class, 'watch']);
|
||
|
||
// AniSkip (public — no auth needed, does Jikan+AniSkip lookup with caching)
|
||
Route::get('aniskip/{slug}/{season}/{episode}', [AnimeApiController::class, 'aniSkip']);
|
||
|
||
// Skip segments (public — no auth needed)
|
||
Route::get('episodes/{episode}/skip-segments', [AnimeApiController::class, 'skipSegments']);
|
||
Route::post('episodes/{episode}/skip-event', [AnimeApiController::class, 'recordSkipEvent'])
|
||
->middleware('throttle:60,1'); // max 60 events per minute per IP
|
||
|
||
// HEVC flag — player tarafından HEVC hatası alınan kaynakları işaretler
|
||
Route::post('sources/flag-hevc', [AnimeApiController::class, 'flagHevc'])
|
||
->middleware('throttle:30,1');
|
||
|
||
// Reklam istatistikleri — path bilerek nötr ('ads' değil), adblocker /api/ads/ engelliyor
|
||
Route::post('slot/{ad}/view', [\App\Http\Controllers\Api\AdApiController::class, 'impression'])
|
||
->middleware('throttle:30,1');
|
||
Route::post('slot/{ad}/hit', [\App\Http\Controllers\Api\AdApiController::class, 'click'])
|
||
->middleware('throttle:30,1');
|
||
|
||
// Comments (public read, auth write)
|
||
Route::get('comments', [CommentApiController::class, 'index']);
|
||
|
||
// NicoNico timestamp comments (public read)
|
||
Route::get('episodes/{episode}/nico-comments', [SocialApiController::class, 'timestampComments']);
|
||
|
||
// Predictions (public read)
|
||
Route::get('episodes/{episode}/predictions', [SocialApiController::class, 'predictions']);
|
||
|
||
// Spoiler boxes (public read)
|
||
Route::get('episodes/{episode}/spoiler-boxes', [SocialApiController::class, 'spoilerBoxes']);
|
||
|
||
// Tribunal (public read)
|
||
Route::get('tribunals', [TribunalApiController::class, 'index']);
|
||
Route::get('tribunals/{tribunal}', [TribunalApiController::class, 'show']);
|
||
|
||
// Watch party info (public)
|
||
Route::get('party/{roomCode}', [SocialApiController::class, 'partyInfo']);
|
||
|
||
// Mood engine (public)
|
||
Route::post('mood/recommend', [SocialApiController::class, 'moodRecommend']);
|
||
|
||
// Anime requests (public list)
|
||
Route::get('anime-request', [UserApiController::class, 'requestIndex']);
|
||
|
||
// Notifications count (optional auth)
|
||
Route::get('notifications/count', [UserApiController::class, 'notificationsCount'])
|
||
->middleware('auth:sanctum');
|
||
|
||
// ── Auth required ─────────────────────────────────────────────────────────────
|
||
Route::middleware('auth:sanctum')->group(function () {
|
||
// Auth
|
||
Route::post('auth/logout', [AuthApiController::class, 'logout']);
|
||
Route::get('auth/me', [AuthApiController::class, 'me']);
|
||
Route::post('auth/profile', [AuthApiController::class, 'updateProfile']);
|
||
Route::post('auth/fcm-token', [AuthApiController::class, 'saveFcmToken']);
|
||
|
||
// Profile stats
|
||
Route::get('profile/stats', [UserApiController::class, 'profileStats']);
|
||
|
||
// Watchlist
|
||
Route::get('watchlist', [UserApiController::class, 'watchlist']);
|
||
Route::post('watchlist/{anime}/toggle', [UserApiController::class, 'watchlistToggle']);
|
||
|
||
// Continue watching
|
||
Route::post('continue-watching', [UserApiController::class, 'continueWatchingUpdate']);
|
||
|
||
// Rate & Follow
|
||
Route::post('anime/{anime}/rate', [UserApiController::class, 'animeRate']);
|
||
Route::post('anime/{anime:slug}/follow', [UserApiController::class, 'followToggle']);
|
||
|
||
// Notifications
|
||
Route::get('notifications', [UserApiController::class, 'notifications']);
|
||
|
||
// Achievements
|
||
Route::get('achievements', [UserApiController::class, 'achievements']);
|
||
|
||
// Episode notes
|
||
Route::post('episode/{episode}/note', [UserApiController::class, 'noteStore']);
|
||
Route::delete('notes/{note}', [UserApiController::class, 'noteDelete']);
|
||
Route::get('episode/{episode}/notes', [UserApiController::class, 'episodeNotesList']);
|
||
|
||
// Comments
|
||
Route::post('comments', [CommentApiController::class, 'store']);
|
||
Route::post('comments/{comment}/like', [CommentApiController::class, 'like']);
|
||
|
||
// Anime requests
|
||
Route::post('anime-request', [UserApiController::class, 'requestStore']);
|
||
Route::post('anime-request/{animeRequest}/vote', [UserApiController::class, 'requestVote']);
|
||
|
||
// AI
|
||
Route::post('ai/chat', [AiApiController::class, 'chat']);
|
||
Route::post('ai/recommend', [AiApiController::class, 'recommend']);
|
||
Route::post('ai/similar', [AiApiController::class, 'similar']);
|
||
Route::post('ai/search', [AiApiController::class, 'search']);
|
||
|
||
// NicoNico (auth write)
|
||
Route::post('episodes/{episode}/nico-comments', [SocialApiController::class, 'timestampCommentStore']);
|
||
|
||
// Predictions (auth write)
|
||
Route::post('episodes/{episode}/predictions', [SocialApiController::class, 'predictionStore']);
|
||
Route::post('predictions/{prediction}/vote', [SocialApiController::class, 'predictionVote']);
|
||
|
||
// Spoiler boxes (auth write)
|
||
Route::post('episodes/{episode}/spoiler-boxes', [SocialApiController::class, 'spoilerBoxStore']);
|
||
Route::post('spoiler-boxes/{box}/like', [SocialApiController::class, 'spoilerBoxLike']);
|
||
|
||
// Time capsule
|
||
Route::get('capsules', [SocialApiController::class, 'capsuleIndex']);
|
||
Route::post('capsules', [SocialApiController::class, 'capsuleStore']);
|
||
Route::post('capsules/{capsule}/open', [SocialApiController::class, 'capsuleOpen']);
|
||
|
||
// Tribunal (auth write)
|
||
Route::post('tribunals', [TribunalApiController::class, 'store']);
|
||
Route::post('tribunals/{tribunal}/vote', [TribunalApiController::class, 'vote']);
|
||
Route::post('tribunals/{tribunal}/argue', [TribunalApiController::class, 'argue']);
|
||
Route::post('tribunal-arguments/{argument}/vote', [TribunalApiController::class, 'argVote']);
|
||
|
||
// Watch party
|
||
Route::post('party/create', [SocialApiController::class, 'partyCreate']);
|
||
Route::post('party/{roomCode}/join', [SocialApiController::class, 'partyJoin']);
|
||
Route::post('party/{roomCode}/sync', [SocialApiController::class, 'partySync']);
|
||
Route::post('party/{roomCode}/leave', [SocialApiController::class, 'partyLeave']);
|
||
|
||
// User follow
|
||
Route::post('users/{user}/follow', [SocialApiController::class, 'followToggle']);
|
||
|
||
// Plans
|
||
Route::get('plans', [PlanApiController::class, 'index']);
|
||
|
||
// ── Mesajlar (Mobile Chat) — sabit rotalar önce gelmeli
|
||
Route::get('messages', [MessageApiController::class, 'conversations']);
|
||
Route::post('messages/start/{user}', [MessageApiController::class, 'startConversation']);
|
||
Route::get('messages/{conversation}', [MessageApiController::class, 'show']);
|
||
Route::post('messages/{conversation}', [MessageApiController::class, 'send']);
|
||
Route::get('messages/{conversation}/poll', [MessageApiController::class, 'poll']);
|
||
});
|