Fix inflated watch metrics: one row per viewing instead of per 30s ping

The player pings /track/watch every 30s with the CUMULATIVE position, and each
ping inserted a new row (~18 rows per viewing, 254k/day). SUM(seconds_watched)
therefore summed cumulative snapshots: a single 58-minute viewing reported as
4238 minutes (~73x), skewing TrendingController's watch-minute ranking and the
admin "total_sec"/"plays" figures.

Upsert per (session_id, episode_id) so SUM is the real watch time and COUNT is
the real play count. Adds the supporting index.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 14:59:00 +03:00
co-authored by Claude Opus 4.8
parent 87e0d7dcf5
commit 2ef6916891
2 changed files with 49 additions and 12 deletions
@@ -74,18 +74,28 @@ class TrackingController extends Controller
'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(),
]);
// Oynatıcı 30 saniyede bir ping atar ve her ping o ana kadarki KÜMÜLATİF
// konumu gönderir. Ping başına yeni satır atmak hem tabloyu şişiriyor
// (izleme başına ~18 satır) hem de SUM(seconds_watched) ile hesaplanan
// izleme süresini katbekat şişiriyordu. İzleme (session + bölüm) başına
// tek satır tutup güncelliyoruz: SUM artık gerçek süreyi, COUNT gerçek
// oynatma sayısını veriyor.
WatchEvent::updateOrCreate(
[
'session_id' => session()->getId(),
'episode_id' => $data['episode_id'] ?? null,
],
[
'user_id' => auth()->id(),
'anime_id' => $data['anime_id'],
'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 {
@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* TrackingController::watch() artık izleme (session + bölüm) başına tek
* satır tutup güncelliyor; bu index olmadan her ping tabloyu tarardı.
*/
public function up(): void
{
if (! Schema::hasIndex('analytics_watch_events', 'analytics_watch_events_session_id_episode_id_index')) {
Schema::table('analytics_watch_events', function (Blueprint $table) {
$table->index(['session_id', 'episode_id']);
});
}
}
public function down(): void
{
Schema::table('analytics_watch_events', function (Blueprint $table) {
$table->dropIndex('analytics_watch_events_session_id_episode_id_index');
});
}
};