first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View File

@@ -0,0 +1,197 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Plays\LogVideoPlay;
use App\Actions\Titles\Retrieve\GetRelatedTitles;
use App\Models\Episode;
use App\Models\Title;
use App\Models\Video;
use Common\Core\BaseController;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Str;
class WatchController extends BaseController
{
public function __invoke(Video $video)
{
$this->authorize('show', $video);
$video = $this->loadVideoRelations($video);
(new LogVideoPlay())->execute($video);
$title = $this->loadTitle($video);
$episode = $video->episode_id
? Episode::findOrFail($video->episode_id)
: null;
$data = [
'loader' => 'watchPage',
'title' => $title,
'episode' => $episode,
'video' => $video,
'related_videos' => $this->videosByTags($video->title),
'alternative_videos' => settings('streaming.show_video_selector')
? $this->loadAlternativeVideos($video)
: [],
];
return $this->renderClientOrApi([
'data' => $data,
'pageName' => 'watch-page',
]);
}
protected function loadTitle(Video $video)
{
$title = Title::select([
'id',
'name',
'description',
'backdrop',
'poster',
'is_series',
])
->withCount('seasons')
->findOrFail($video->title_id);
$title->description = Str::limit($title->description, 310);
return $title;
}
protected function loadVideoRelations(Video $video)
{
$video->load([
'captions',
'reports' => fn($q) => $q
->where('user_id', auth()->id())
->orWhere('user_ip', getIp()),
'latestPlay' => function (HasOne $builder) {
$builder
->forCurrentUser()
->whereNotNull('time_watched')
->select(['id', 'video_id', 'time_watched']);
},
]);
if ($video->reports->first()) {
$video->current_user_reported = true;
}
return $video;
}
private function videosByEpisode(Title $title, int $seasonNum)
{
[$col, $direction] = explode(':', settings('streaming.default_sort'));
$currSeasonNum = $seasonNum;
$prevSeasonNum = $seasonNum - 1;
$nextSeasonNum = $seasonNum + 1;
$videos = $title
->videos()
->with(['captions', 'episode', 'title' => fn($q) => $q->compact()])
->where('approved', true)
->where('category', 'full')
->whereNotNull('episode_id')
->whereIn('season_num', [
$currSeasonNum,
$nextSeasonNum,
$prevSeasonNum,
])
->orderBy($col, $direction)
->groupBy(['season_num', 'episode_num'])
->get();
if ($videos->isEmpty()) {
return [];
}
$grouped = $videos
->groupBy('season_num')
->map(function (Collection $videos, $seasonNum) use (
$prevSeasonNum,
$nextSeasonNum,
) {
if ($seasonNum === $prevSeasonNum) {
return $videos->sortByDesc('episode_num')->first();
} elseif ($seasonNum === $nextSeasonNum) {
return $videos->sortByDesc('episode_num')->last();
} else {
// current season episodes
return $videos->sortBy('season')->sortBy('episode_num');
}
});
$videos = $grouped->get($currSeasonNum)->values();
// make sure prev season last episode appears first
if ($prevSeason = $grouped->get($prevSeasonNum)) {
$videos->prepend($prevSeason);
}
// make sure next season first episode appears last
if ($nextSeason = $grouped->get($nextSeasonNum)) {
$videos->push($nextSeason);
}
return $videos->values();
}
private function videosByTags(Title $title)
{
$title->load(['keywords', 'genres']);
$related = app(GetRelatedTitles::class)->execute($title, [
'limit' => 6,
'compact' => true,
]);
$videos = [];
if ($related->isNotEmpty()) {
$related->load([
'videos' => fn(HasMany $builder) => $builder
->where('approved', true)
->fromConfiguredCategory(),
]);
$videos = $related
->map(function (Title $title) {
if ($video = $title->videos->first()) {
$title->setRelation('videos', []);
$video->title = $title;
return $video;
}
})
->filter()
->values();
}
return $videos;
}
protected function loadAlternativeVideos(Video $video)
{
$builder = Video::where('title_id', $video->title_id);
if ($video->season_num) {
$builder->where('season_num', $video->season_num);
}
if ($video->episode_num) {
$builder->where('episode_num', $video->episode_num);
}
return $builder
->where('approved', true)
->limit(10)
->when(
settings('streaming.prefer_full'),
fn($query) => $query->where('category', 'full'),
)
->applySelectedSort()
->get();
}
}