Initial commit: Animexe Laravel platform
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Frontend;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Analytics\PageView;
|
||||
use App\Models\Analytics\WatchEvent;
|
||||
use App\Models\Analytics\VisitorSession;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class TrackingController extends Controller
|
||||
{
|
||||
/**
|
||||
* POST /track/pageview
|
||||
*/
|
||||
public function pageview(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'page_type' => 'nullable|string|max:30',
|
||||
'anime_id' => 'nullable|integer',
|
||||
'episode_id' => 'nullable|integer',
|
||||
'referrer' => 'nullable|string|max:500',
|
||||
'url' => 'nullable|string|max:500',
|
||||
'time_on_page'=> 'nullable|integer|min:0|max:86400',
|
||||
]);
|
||||
|
||||
$ip = $request->ip();
|
||||
$ua = $request->userAgent() ?? '';
|
||||
$isBot = (bool) $request->attributes->get('is_bot', false);
|
||||
$botType= $request->attributes->get('bot_type', null);
|
||||
$geo = self::geoIp($ip);
|
||||
$sessId = session()->getId();
|
||||
|
||||
PageView::create([
|
||||
'user_id' => auth()->id(),
|
||||
'session_id' => $sessId,
|
||||
'url' => mb_substr($data['url'] ?? $request->header('Referer', ''), 0, 500),
|
||||
'page_type' => $data['page_type'] ?? 'other',
|
||||
'anime_id' => $data['anime_id'] ?? null,
|
||||
'episode_id' => $data['episode_id'] ?? null,
|
||||
'ip' => $ip,
|
||||
'country' => $geo['country'] ?? null,
|
||||
'city' => $geo['city'] ?? null,
|
||||
'device' => self::detectDevice($ua),
|
||||
'browser' => self::detectBrowser($ua),
|
||||
'referrer' => mb_substr($data['referrer'] ?? '', 0, 500) ?: null,
|
||||
'is_bot' => $isBot ? 1 : 0,
|
||||
'user_agent' => mb_substr($ua, 0, 500),
|
||||
'time_on_page'=> $data['time_on_page'] ?? 0,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
// Oturum kaydını oluştur / güncelle
|
||||
$this->trackSession($sessId, $ip, $ua, $geo, $isBot, $botType, $data);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /track/watch
|
||||
*/
|
||||
public function watch(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'anime_id' => 'required|integer',
|
||||
'episode_id' => 'nullable|integer',
|
||||
'season_number' => 'required|integer|min:1',
|
||||
'episode_number' => 'required|integer|min:1',
|
||||
'seconds' => 'required|integer|min:0',
|
||||
'total' => 'nullable|integer|min:0',
|
||||
'percent' => 'nullable|integer|min:0|max:100',
|
||||
]);
|
||||
|
||||
WatchEvent::create([
|
||||
'user_id' => auth()->id(),
|
||||
'session_id' => session()->getId(),
|
||||
'anime_id' => $data['anime_id'],
|
||||
'episode_id' => $data['episode_id'] ?? null,
|
||||
'season_number' => $data['season_number'],
|
||||
'episode_number' => $data['episode_number'],
|
||||
'seconds_watched' => $data['seconds'],
|
||||
'total_seconds' => $data['total'] ?? 0,
|
||||
'percent_complete'=> $data['percent'] ?? 0,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
// Oturum izleme süresini güncelle
|
||||
try {
|
||||
DB::table('analytics_sessions')
|
||||
->where('session_id', session()->getId())
|
||||
->increment('total_seconds', (int)$data['seconds']);
|
||||
} catch (\Exception) {}
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /track/session-end — sayfa kapanırken JS'ten gönderilir
|
||||
*/
|
||||
public function sessionEnd(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'time_on_page' => 'nullable|integer|min:0|max:86400',
|
||||
]);
|
||||
|
||||
try {
|
||||
DB::table('analytics_sessions')
|
||||
->where('session_id', session()->getId())
|
||||
->update([
|
||||
'last_seen_at' => now(),
|
||||
'total_seconds'=> DB::raw('total_seconds + ' . (int)($data['time_on_page'] ?? 0)),
|
||||
]);
|
||||
} catch (\Exception) {}
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
// ── Private helpers ──────────────────────────────────────────────────────
|
||||
|
||||
private function trackSession(string $sessId, string $ip, string $ua, array $geo, bool $isBot, ?string $botType, array $data): void
|
||||
{
|
||||
try {
|
||||
$existing = DB::table('analytics_sessions')->where('session_id', $sessId)->first();
|
||||
|
||||
if ($existing) {
|
||||
DB::table('analytics_sessions')
|
||||
->where('session_id', $sessId)
|
||||
->update([
|
||||
'pages_visited' => DB::raw('pages_visited + 1'),
|
||||
'last_seen_at' => now(),
|
||||
'user_id' => auth()->id() ?? $existing->user_id,
|
||||
]);
|
||||
} else {
|
||||
DB::table('analytics_sessions')->insert([
|
||||
'session_id' => $sessId,
|
||||
'user_id' => auth()->id(),
|
||||
'ip' => $ip,
|
||||
'country' => $geo['country'] ?? null,
|
||||
'city' => $geo['city'] ?? null,
|
||||
'device' => self::detectDevice($ua),
|
||||
'browser' => self::detectBrowser($ua),
|
||||
'referrer' => mb_substr($data['referrer'] ?? '', 0, 500) ?: null,
|
||||
'landing_page' => mb_substr($data['url'] ?? '', 0, 500) ?: null,
|
||||
'pages_visited'=> 1,
|
||||
'total_seconds'=> 0,
|
||||
'is_bot' => $isBot ? 1 : 0,
|
||||
'bot_type' => $botType,
|
||||
'user_agent' => mb_substr($ua, 0, 500),
|
||||
'started_at' => now(),
|
||||
'last_seen_at' => now(),
|
||||
]);
|
||||
}
|
||||
} catch (\Exception) {}
|
||||
}
|
||||
|
||||
private static function geoIp(string $ip): array
|
||||
{
|
||||
if ($ip === '127.0.0.1' || str_starts_with($ip, '192.168.') || str_starts_with($ip, '10.')) {
|
||||
return ['country' => 'Yerel', 'city' => 'Localhost'];
|
||||
}
|
||||
|
||||
return Cache::remember("geo_{$ip}", 86400 * 7, function () use ($ip) {
|
||||
try {
|
||||
$r = Http::timeout(2)->get("http://ip-api.com/json/{$ip}?fields=country,city,status");
|
||||
if ($r->ok() && $r->json('status') === 'success') {
|
||||
return ['country' => $r->json('country'), 'city' => $r->json('city')];
|
||||
}
|
||||
} catch (\Exception) {}
|
||||
return ['country' => null, 'city' => null];
|
||||
});
|
||||
}
|
||||
|
||||
private static function detectDevice(string $ua): string
|
||||
{
|
||||
$ua = strtolower($ua);
|
||||
if (str_contains($ua, 'tablet') || str_contains($ua, 'ipad')) return 'tablet';
|
||||
if (str_contains($ua, 'mobile') || str_contains($ua, 'android') || str_contains($ua, 'iphone')) return 'mobile';
|
||||
return 'desktop';
|
||||
}
|
||||
|
||||
private static function detectBrowser(string $ua): string
|
||||
{
|
||||
if (str_contains($ua, 'Edg/')) return 'Edge';
|
||||
if (str_contains($ua, 'OPR/') || str_contains($ua, 'Opera')) return 'Opera';
|
||||
if (str_contains($ua, 'Chrome')) return 'Chrome';
|
||||
if (str_contains($ua, 'Firefox')) return 'Firefox';
|
||||
if (str_contains($ua, 'Safari')) return 'Safari';
|
||||
if (str_contains($ua, 'MSIE') || str_contains($ua, 'Trident')) return 'IE';
|
||||
return 'Other';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user