Newer
Older
<?php
declare(strict_types=1);
/**
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace Modules\Admin\Controllers;

Yassine Doghri
committed
use App\Entities\Clip\VideoClip;
use App\Entities\Episode;
use App\Entities\Podcast;

Yassine Doghri
committed
use App\Models\ClipModel;
use App\Models\EpisodeModel;
use App\Models\PodcastModel;
use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\RedirectResponse;
use Modules\Media\Entities\Transcript;
use Modules\Media\Models\MediaModel;
class VideoClipsController extends BaseController
{
public function _remap(string $method, string ...$params): mixed
{

Yassine Doghri
committed
if ($params === []) {
throw PageNotFoundException::forPageNotFound();
}

Yassine Doghri
committed
if (count($params) === 1) {
if (! ($podcast = (new PodcastModel())->getPodcastById((int) $params[0])) instanceof Podcast) {
throw PageNotFoundException::forPageNotFound();
}

Yassine Doghri
committed
return $this->{$method}($podcast);
}

Yassine Doghri
committed
if (
! ($episode = (new EpisodeModel())->getEpisodeById((int) $params[1])) instanceof Episode

Yassine Doghri
committed
) {
throw PageNotFoundException::forPageNotFound();

Yassine Doghri
committed
unset($params[0]);
unset($params[1]);
return $this->{$method}($episode, ...$params);

Yassine Doghri
committed
public function list(Episode $episode): string
{

Yassine Doghri
committed
$videoClipsBuilder = (new ClipModel('video'))

Yassine Doghri
committed
->where([

Yassine Doghri
committed
'podcast_id' => $episode->podcast_id,
'episode_id' => $episode->id,
'type' => 'video',

Yassine Doghri
committed
])
->orderBy('created_at', 'desc');

Yassine Doghri
committed
$clips = $videoClipsBuilder->paginate(10);
$videoClips = [];
foreach ($clips as $clip) {
$videoClips[] = new VideoClip($clip->toArray());
}
$data = [

Yassine Doghri
committed
'podcast' => $episode->podcast,
'episode' => $episode,

Yassine Doghri
committed
'videoClips' => $videoClips,
'pager' => $videoClipsBuilder->pager,
];

Yassine Doghri
committed
$this->setHtmlHead(lang('VideoClip.list.title'));
replace_breadcrumb_params([

Yassine Doghri
committed
0 => $episode->podcast->at_handle,
1 => $episode->title,
]);
return view('episode/video_clips_list', $data);
}

Yassine Doghri
committed
public function view(Episode $episode, string $videoClipId): string
{
$videoClip = (new ClipModel())->getVideoClipById((int) $videoClipId);
$data = [

Yassine Doghri
committed
'podcast' => $episode->podcast,
'episode' => $episode,
'videoClip' => $videoClip,
];

Yassine Doghri
committed
$this->setHtmlHead(lang('VideoClip.title', [
'videoClipLabel' => esc($videoClip->title),
]));
replace_breadcrumb_params([

Yassine Doghri
committed
0 => $episode->podcast->at_handle,
1 => $episode->title,

Yassine Doghri
committed
2 => $videoClip->title,
]);
return view('episode/video_clip', $data);
}

Yassine Doghri
committed
public function createView(Episode $episode): string

Yassine Doghri
committed
'podcast' => $episode->podcast,
'episode' => $episode,
];
replace_breadcrumb_params([

Yassine Doghri
committed
0 => $episode->podcast->at_handle,
1 => $episode->title,

Yassine Doghri
committed

Yassine Doghri
committed
// First, check that requirements to create a video clip are met
$ffmpeg = shell_exec('which ffmpeg');

Yassine Doghri
committed
$checks = [
'ffmpeg' => $ffmpeg !== null,
'gd' => extension_loaded('gd'),
'freetype' => extension_loaded('gd') && gd_info()['FreeType Support'],

Yassine Doghri
committed
'transcript' => $episode->transcript instanceof Transcript,

Yassine Doghri
committed
];

Yassine Doghri
committed
$this->setHtmlHead(lang('VideoClip.form.title'));
if (array_any($checks, fn (bool $value): bool => ! $value)) {

Yassine Doghri
committed
$data['checks'] = $checks;
return view('episode/video_clips_requirements', $data);
}
helper('form');
return view('episode/video_clips_new', $data);

Yassine Doghri
committed
public function createAction(Episode $episode): RedirectResponse
'title' => 'required',

Yassine Doghri
committed
'start_time' => 'required|greater_than_equal_to[0]',
'duration' => 'required|greater_than[0]',
'format' => 'required|in_list[' . implode(',', array_keys(config('MediaClipper')->formats)) . ']',
'theme' => 'required|in_list[' . implode(',', array_keys(config('Colors')->themes)) . ']',
];
if (! $this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}

Yassine Doghri
committed
$validData = $this->validator->getValidated();
$themeName = $validData['theme'];
$themeColors = config('MediaClipper')

Yassine Doghri
committed
->themes[$themeName];
$theme = [
'name' => $themeName,

Yassine Doghri
committed
'preview' => $themeColors['preview'],
];

Yassine Doghri
committed
$videoClip = new VideoClip([

Yassine Doghri
committed
'title' => $validData['title'],
'start_time' => (float) $validData['start_time'],
'duration' => (float) $validData['duration'],
'theme' => $theme,

Yassine Doghri
committed
'format' => $validData['format'],
'type' => 'video',
'status' => 'queued',

Yassine Doghri
committed
'podcast_id' => $episode->podcast_id,
'episode_id' => $episode->id,

Yassine Doghri
committed
'created_by' => user_id(),
'updated_by' => user_id(),
]);

Yassine Doghri
committed
// Check if video clip exists before inserting a new line
if ((new ClipModel())->doesVideoClipExist($videoClip)) {
// video clip already exists
return redirect()
->back()
->withInput()
->with('error', lang('VideoClip.messages.alreadyExistingError'));
}

Yassine Doghri
committed
(new ClipModel())->insert($videoClip);

Yassine Doghri
committed
return redirect()->route('video-clips-list', [$episode->podcast_id, $episode->id])->with(
lang('VideoClip.messages.addToQueueSuccess'),

Yassine Doghri
committed

Yassine Doghri
committed
public function retryAction(Episode $episode, string $videoClipId): RedirectResponse

Yassine Doghri
committed
{
$videoClip = (new ClipModel())->getVideoClipById((int) $videoClipId);

Yassine Doghri
committed
if (! $videoClip instanceof VideoClip) {

Yassine Doghri
committed
throw PageNotFoundException::forPageNotFound();
}
(new ClipModel())->update($videoClip->id, [
'status' => 'queued',

Yassine Doghri
committed
'job_started_at' => null,
'job_ended_at' => null,

Yassine Doghri
committed
]);
return redirect()->back();
}

Yassine Doghri
committed
public function deleteAction(Episode $episode, string $videoClipId): RedirectResponse

Yassine Doghri
committed
{
$videoClip = (new ClipModel())->getVideoClipById((int) $videoClipId);

Yassine Doghri
committed
if (! $videoClip instanceof VideoClip) {

Yassine Doghri
committed
throw PageNotFoundException::forPageNotFound();
}
if ($videoClip->media === null) {
// delete Clip directly

Yassine Doghri
committed
(new ClipModel())->deleteVideoClip($episode->podcast_id, $episode->id, $videoClip->id);

Yassine Doghri
committed
} else {
(new ClipModel())->clearVideoClipCache($videoClip->id);

Yassine Doghri
committed
$mediaModel = new MediaModel();
// delete the videoClip file, the clip will be deleted on cascade

Yassine Doghri
committed
if (! $mediaModel->deleteMedia($videoClip->media)) {
return redirect()
->back()
->withInput()
->with('errors', $mediaModel->errors());
}
}
return redirect()->back();
}