Update Saqel Platform: 2026-09-11 20:37:10

This commit is contained in:
Hamza-Ayed
2026-09-11 20:37:10 +03:00
parent e61d56c8e1
commit cb4f2a3159
18 changed files with 1440 additions and 148 deletions
+49 -6
View File
@@ -56,7 +56,7 @@ class VideoController
}
try {
$row = Database::selectOne(
"SELECT vv.uuid AS video_version_id, l.id AS lesson_id, l.course_id, l.storage_type, l.video_uuid, l.hls_url, l.ai_video_url, l.bunny_video_id, l.duration_seconds,
"SELECT vv.uuid AS video_version_id, l.id AS lesson_id, l.course_id, l.storage_type, l.video_uuid, l.hls_url, l.r2_url, l.ai_video_url, l.bunny_video_id, l.duration_seconds,
cl.uuid AS curriculum_lesson_id, cl.title, cl.grade_key, ts.uuid AS submission_id
FROM video_versions vv
JOIN teacher_submissions ts ON ts.id=vv.teacher_submission_id AND ts.current_published_video_version_id=vv.id AND ts.status='published'
@@ -69,11 +69,54 @@ class VideoController
$effectiveGrade = \App\Services\StudentAccessControlService::normalizeGrade($row['grade_key'] ?? $course['grade_level'] ?? 'grade_10');
$access=\App\Services\StudentAccessControlService::validateLessonAccess((int)$request->user_id, $request->getHeader('x-national-id'), $effectiveGrade, (int)$row['course_id'], (int)$row['lesson_id']);
if (empty($access['allowed'])) { $response->status(403)->json(['status'=>'forbidden','message'=>$access['message'] ?? 'غير مصرح بمشاهدة هذه الحصة.']); return; }
if ($row['storage_type']==='api_upload') $playback=['storage_type'=>'api_upload','video_url'=>$row['hls_url'] ?: '/api/videos/stream/'.$row['video_uuid'],'hls_url'=>$row['hls_url'] ?: '/api/videos/hls/'.$row['video_uuid'].'/index.m3u8'];
elseif (!empty($row['bunny_video_id'])) $playback=array_merge(['storage_type'=>'bunny_stream'],VideoService::generateBunnySignedPlayback($row['bunny_video_id'],10800));
elseif (!empty($row['ai_video_url'])) $playback=['storage_type'=>'direct_url','video_url'=>$row['ai_video_url'],'hls_url'=>$row['ai_video_url']];
elseif (!empty($row['hls_url'])) $playback=['storage_type'=>'cdn_hls','video_url'=>$row['hls_url'],'hls_url'=>$row['hls_url']];
else { $response->status(409)->json(['status'=>'error','message'=>'تخزين نسخة الفيديو غير جاهز.']); return; }
$token = '';
$authHeader = $request->getHeader('authorization', '');
if ($authHeader && preg_match('/Bearer\s(\S+)/i', $authHeader, $m)) {
$token = $m[1];
} else {
$token = (string)$request->getQuery('token', '');
}
$tokenParam = $token !== '' ? ('?token=' . urlencode($token)) : '';
if (!empty($row['r2_url'])) {
$playback = [
'storage_type' => 'r2',
'video_url' => $row['r2_url'],
'hls_url' => !empty($row['hls_url']) ? $row['hls_url'] : $row['r2_url']
];
} elseif (!empty($row['bunny_video_id'])) {
$playback = array_merge(['storage_type' => 'bunny_stream'], VideoService::generateBunnySignedPlayback($row['bunny_video_id'], 10800));
} elseif (!empty($row['ai_video_url'])) {
$playback = [
'storage_type' => 'direct_url',
'video_url' => $row['ai_video_url'],
'hls_url' => $row['ai_video_url']
];
} elseif (!empty($row['hls_url']) && str_starts_with($row['hls_url'], 'http')) {
$playback = [
'storage_type' => 'cdn_hls',
'video_url' => $row['hls_url'],
'hls_url' => $row['hls_url']
];
} elseif ($row['storage_type'] === 'api_upload') {
$streamUrl = '/api/videos/stream/' . $row['video_uuid'] . $tokenParam;
$hlsUrl = !empty($row['hls_url']) ? ($row['hls_url'] . $tokenParam) : ('/api/videos/hls/' . $row['video_uuid'] . '/index.m3u8' . $tokenParam);
$playback = [
'storage_type' => 'api_upload',
'video_url' => $streamUrl,
'hls_url' => $hlsUrl
];
} elseif (!empty($row['hls_url'])) {
$playback = [
'storage_type' => 'cdn_hls',
'video_url' => $row['hls_url'] . $tokenParam,
'hls_url' => $row['hls_url'] . $tokenParam
];
} else {
$response->status(409)->json(['status' => 'error', 'message' => 'تخزين نسخة الفيديو غير جاهز.']);
return;
}
$response->json(['status'=>'success','data'=>['video_version_id'=>$row['video_version_id'],'submission_id'=>$row['submission_id'],'curriculum_lesson_id'=>$row['curriculum_lesson_id'],'lesson_id'=>(int)$row['lesson_id'],'title'=>$row['title'],'duration_seconds'=>(int)$row['duration_seconds'],'playback'=>$playback,'checkpoints'=>[]]]);
} catch (\Throwable $e) { error_log('Version playback failed: '.$e->getMessage()); $response->status(503)->json(['status'=>'unavailable','message'=>'تعذر تجهيز تشغيل نسخة الفيديو.']); }
}