Only track was watched if more than 10s is played #6

This commit is contained in:
2026-07-19 16:10:24 +02:00
parent 859a35847a
commit 4f81164b44
4 changed files with 65 additions and 14 deletions
@@ -4,7 +4,11 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Episode; use App\Models\Episode;
use App\Models\Watched;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
class StreamApiController extends Controller class StreamApiController extends Controller
{ {
@@ -34,4 +38,36 @@ class StreamApiController extends Controller
'extra_subtitles' => $subtitles, 'extra_subtitles' => $subtitles,
], 200); ], 200);
} }
/**
* Track that the authenticated user has watched the episode.
* Called client-side after 10 seconds of playback.
*/
public function trackWatched(Request $request): JsonResponse
{
$validated = $request->validate([
'episode_id' => 'required|integer|exists:episodes,id',
]);
$user = Auth::user();
if (! $user) {
return response()->json(['watched' => false], 401);
}
$episodeId = $request->input('episode_id');
// 1-hour cooldown to prevent duplicate entries
$time = Carbon::now()->subHour(1);
$alreadyWatched = Watched::where('user_id', $user->id)
->where('episode_id', $episodeId)
->where('created_at', '>=', $time)
->exists();
if (! $alreadyWatched) {
Watched::create(['user_id' => $user->id, 'episode_id' => $episodeId]);
cache()->forget('user'.$user->id.'watched'.$episodeId);
}
return response()->json(['watched' => true], 200);
}
} }
-14
View File
@@ -8,10 +8,8 @@ use App\Models\Gallery;
use App\Models\Hentai; use App\Models\Hentai;
use App\Models\Playlist; use App\Models\Playlist;
use App\Models\PlaylistEpisode; use App\Models\PlaylistEpisode;
use App\Models\Watched;
use hisorange\BrowserDetect\Facade as Browser; use hisorange\BrowserDetect\Facade as Browser;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\View\View; use Illuminate\View\View;
@@ -52,18 +50,6 @@ class StreamController extends Controller
// Increment Popular Count // Increment Popular Count
$episode->incrementPopularCount(); $episode->incrementPopularCount();
if (! Auth::guest()) {
$user = Auth::user();
// Add to user watched list
$time = Carbon::now()->subHour(1);
$alreadyWatched = Watched::where('user_id', $user->id)->where('episode_id', $episode->id)->where('created_at', '>=', $time)->exists();
if (! $alreadyWatched) {
Watched::create(['user_id' => $user->id, 'episode_id' => $episode->id]);
cache()->forget('user'.$user->id.'watched'.$episode->id);
}
}
// Mobile Detection // Mobile Detection
$isMobile = Browser::isMobile(); $isMobile = Browser::isMobile();
+28
View File
@@ -38,6 +38,24 @@ var streamServerCount = 0;
var ambientMode = true; var ambientMode = true;
var serverFallback = false; var serverFallback = false;
var saveInterval; var saveInterval;
var watchTracked = false;
// Track that the user watched at least 10 seconds of the video
function trackWatchTime() {
if (watchTracked) return;
var video = document.getElementsByTagName('video')[0];
if (video && video.currentTime >= 10) {
watchTracked = true;
var episodeId = document.getElementById('e_id').value;
window.axios.post('/watched/track', {
episode_id: episodeId
}).then(function (response) {
console.log('Watch tracked for episode ' + episodeId);
}).catch(function (error) {
console.error('Failed to track watch: ' + error);
});
}
}
var subtitleInstance = null; var subtitleInstance = null;
@@ -322,6 +340,11 @@ function initPlayer() {
playNextPlaylistVideo(); playNextPlaylistVideo();
}); });
// Track watch time after 10 seconds of playback
player.on('timeupdate', () => {
trackWatchTime();
});
player.on('languagechange', (event) => { player.on('languagechange', (event) => {
let lang = event.detail.plyr.captions.language; let lang = event.detail.plyr.captions.language;
@@ -437,6 +460,11 @@ async function initVidstackPlayer() {
} }
})(); })();
}); });
// Track watch time after 10 seconds of playback
player.addEventListener('time-update', () => {
trackWatchTime();
});
} }
// Get Data from API // Get Data from API
+1
View File
@@ -27,6 +27,7 @@ Route::get('/v1/monthly-views', [HentaiApiController::class, 'getMonthlyViews'])
// Stream Page // Stream Page
Route::get('/hentai/{title}', [StreamController::class, 'index'])->name('hentai.index'); Route::get('/hentai/{title}', [StreamController::class, 'index'])->name('hentai.index');
Route::post('/player/api', [StreamApiController::class, 'getStream'])->name('hentai.player'); Route::post('/player/api', [StreamApiController::class, 'getStream'])->name('hentai.player');
Route::post('/watched/track', [StreamApiController::class, 'trackWatched'])->name('hentai.watched');
// Search // Search
Route::get('/search', [HomeController::class, 'search'])->name('hentai.search'); Route::get('/search', [HomeController::class, 'search'])->name('hentai.search');