feat(views): skip owner views, 30-minute device dedupe
- Insert is skipped entirely when the authenticated viewer owns the video. Owners re-watching, previewing an edit, or impersonating no longer inflate their own view counts. - Dedupe window drops 1h -> 30min for both auth and guest paths. - Auth-path dedupe now also matches on device fingerprint / device_id cookie, so signing out and back in during the same session doesn't double-count a single viewer. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
1 parent
48c947d171
commit
c7d2f25ef6
1 file changed
+24
-6
@@ -691,11 +691,28 @@ class VideoController extends Controller
|
||||
$viewFp = $request->cookie('_fp');
|
||||
$viewFp = ($viewFp && preg_match('/^[a-f0-9]{64}$/', $viewFp)) ? $viewFp : null;
|
||||
|
||||
if (Auth::check()) {
|
||||
// Owners don't count toward their own view totals. Previews, re-watches
|
||||
// from the owner's own account, and even owner-impersonation sessions
|
||||
// would otherwise inflate the number. The share/analytics screens
|
||||
// already filter owner_id separately, so skipping the insert is safe.
|
||||
$isOwnerViewing = Auth::check() && Auth::id() === (int) $video->user_id;
|
||||
|
||||
if (Auth::check() && ! $isOwnerViewing) {
|
||||
// 30-minute user-level dedupe. Also dedupe against the strongest
|
||||
// device signal available (fingerprint > device_id cookie) so a
|
||||
// user signing out and back in during the same session doesn't
|
||||
// double-count.
|
||||
$exists = \DB::table('video_views')
|
||||
->where('user_id', Auth::id())
|
||||
->where('video_id', $video->id)
|
||||
->where('watched_at', '>', now()->subHour())
|
||||
->where('watched_at', '>', now()->subMinutes(30))
|
||||
->where(function ($q) use ($viewFp, $viewDid) {
|
||||
$q->where('user_id', Auth::id());
|
||||
if ($viewFp) {
|
||||
$q->orWhere('device_hash', $viewFp);
|
||||
} elseif ($viewDid) {
|
||||
$q->orWhere('device_id', $viewDid);
|
||||
}
|
||||
})
|
||||
->exists();
|
||||
|
||||
if (! $exists) {
|
||||
@@ -711,12 +728,13 @@ class VideoController extends Controller
|
||||
'watched_at' => now(),
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
// Guest: prefer the fingerprint hash for dedup (strongest signal); fall back to device_id cookie
|
||||
} elseif (! $isOwnerViewing) {
|
||||
// Guest: 30-minute dedupe keyed on the strongest device signal
|
||||
// (fingerprint hash > device_id cookie).
|
||||
$exists = \DB::table('video_views')
|
||||
->whereNull('user_id')
|
||||
->where('video_id', $video->id)
|
||||
->where('watched_at', '>', now()->subHour())
|
||||
->where('watched_at', '>', now()->subMinutes(30))
|
||||
->where(function ($q) use ($viewFp, $viewDid) {
|
||||
if ($viewFp) $q->where('device_hash', $viewFp);
|
||||
else $q->where('device_id', $viewDid);
|
||||
|
||||
Reference in new issue
Block a user