Initial commit: Animexe Laravel platform

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 00:01:48 +03:00
co-authored by Claude Opus 4.8
commit a63515cfc6
366 changed files with 74773 additions and 0 deletions
+223
View File
@@ -0,0 +1,223 @@
<?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']);
});