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']); });