validate([ 'episode_id' => 'required', ]); $episode = Episode::where('id', $request->input('episode_id'))->firstOrFail(); $subtitles = $episode->subtitles ->mapWithKeys(fn ($sub) => [$sub->subtitle->slug => $sub->subtitle->name]) ->toArray(); return response()->json([ 'title' => $episode->title.' - '.$episode->episode, 'poster' => $episode->gallery()->first()->image_url, 'interpolated' => $episode->interpolated, 'interpolated_uhd' => $episode->interpolated_uhd, 'stream_url' => $episode->dmca_takedown ? 'stuff/dmca' : $episode->url, 'stream_domains' => config('hstream.stream_domain'), 'asia_stream_domains' => config('hstream.asia_stream_domain'), 'extra_subtitles' => $subtitles, ], 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); } }