fix(playback): isolate curriculum keys and prevent non-uploaded lessons from falling back to previous video
This commit is contained in:
@@ -533,14 +533,23 @@ class VideoController
|
||||
|
||||
// 1. Match by curriculum_key if provided
|
||||
if ($curriculumKey !== '') {
|
||||
$baseKey = basename($curriculumKeyNoExt);
|
||||
$matched = Database::select(
|
||||
"SELECT * FROM lessons
|
||||
WHERE curriculum_key = ? OR curriculum_key = ?
|
||||
OR curriculum_key LIKE ? OR local_path LIKE ? OR markdown_content LIKE ?
|
||||
ORDER BY (hls_url IS NOT NULL AND hls_url != '') DESC, id DESC LIMIT 5",
|
||||
[$curriculumKey, $curriculumKeyNoExt, '%' . $baseKey . '%', '%' . $curriculumKeyNoExt . '%', '%' . $curriculumKeyNoExt . '%']
|
||||
);
|
||||
if (str_contains($curriculumKeyNoExt, '/')) {
|
||||
// Structured hierarchical key: match exact or qualified path suffix
|
||||
$matched = Database::select(
|
||||
"SELECT * FROM lessons
|
||||
WHERE curriculum_key = ? OR curriculum_key = ?
|
||||
OR curriculum_key LIKE ? OR local_path LIKE ? OR markdown_content LIKE ?
|
||||
ORDER BY (hls_url IS NOT NULL AND hls_url != '') DESC, id DESC LIMIT 5",
|
||||
[$curriculumKey, $curriculumKeyNoExt, "%{$curriculumKeyNoExt}%", "%{$curriculumKeyNoExt}%", "%{$curriculumKeyNoExt}%"]
|
||||
);
|
||||
} else {
|
||||
$matched = Database::select(
|
||||
"SELECT * FROM lessons
|
||||
WHERE curriculum_key = ? OR curriculum_key LIKE ?
|
||||
ORDER BY (hls_url IS NOT NULL AND hls_url != '') DESC, id DESC LIMIT 5",
|
||||
[$curriculumKey, "%/{$curriculumKeyNoExt}%"]
|
||||
);
|
||||
}
|
||||
if (!empty($matched)) {
|
||||
$candidates = array_merge($candidates, $matched);
|
||||
}
|
||||
@@ -549,14 +558,16 @@ class VideoController
|
||||
// 2. Match by title if provided
|
||||
if (!empty($title)) {
|
||||
$cleanTitle = trim(preg_replace('/^(الدرس\s*\d+:\s*|معملُ\s*[^:]+:\s*|مقدمة\s*[^:]+:\s*)/u', '', $title));
|
||||
$matchedTitle = Database::select(
|
||||
"SELECT * FROM lessons
|
||||
WHERE title = ? OR title LIKE ? OR title LIKE ?
|
||||
ORDER BY (hls_url IS NOT NULL AND hls_url != '') DESC, id DESC LIMIT 5",
|
||||
[$title, "%{$title}%", "%{$cleanTitle}%"]
|
||||
);
|
||||
if (!empty($matchedTitle)) {
|
||||
$candidates = array_merge($candidates, $matchedTitle);
|
||||
if (mb_strlen($cleanTitle) >= 6) {
|
||||
$matchedTitle = Database::select(
|
||||
"SELECT * FROM lessons
|
||||
WHERE title = ? OR title LIKE ?
|
||||
ORDER BY (hls_url IS NOT NULL AND hls_url != '') DESC, id DESC LIMIT 5",
|
||||
[$title, "%{$cleanTitle}%"]
|
||||
);
|
||||
if (!empty($matchedTitle)) {
|
||||
$candidates = array_merge($candidates, $matchedTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,28 +581,17 @@ class VideoController
|
||||
|
||||
// 4. Manifest slug lookup
|
||||
if (empty($candidates) && !empty($rawId)) {
|
||||
$rawIdNoExt = preg_replace('/\.md$/i', '', $rawId);
|
||||
$matchedRaw = Database::select(
|
||||
"SELECT * FROM lessons
|
||||
WHERE curriculum_key = ? OR curriculum_key = ? OR title LIKE ? OR local_path LIKE ? OR markdown_content LIKE ?
|
||||
ORDER BY (hls_url IS NOT NULL AND hls_url != '') DESC, id DESC LIMIT 5",
|
||||
[$rawId, $rawIdNoExt, "%{$rawId}%", "%{$rawIdNoExt}%", "%{$rawIdNoExt}%"]
|
||||
);
|
||||
if (!empty($matchedRaw)) {
|
||||
$candidates = array_merge($candidates, $matchedRaw);
|
||||
}
|
||||
if (empty($candidates)) {
|
||||
$manifestLesson = CurriculumService::findLessonById($rawId);
|
||||
if ($manifestLesson && !empty($manifestLesson['title'])) {
|
||||
$matchedManifest = Database::select(
|
||||
"SELECT * FROM lessons
|
||||
WHERE title = ? OR title LIKE ? OR markdown_content LIKE ?
|
||||
ORDER BY (hls_url IS NOT NULL AND hls_url != '') DESC, id DESC LIMIT 5",
|
||||
[$manifestLesson['title'], '%' . $manifestLesson['title'] . '%', '%' . ($manifestLesson['file'] ?? '') . '%']
|
||||
);
|
||||
if (!empty($matchedManifest)) {
|
||||
$candidates = array_merge($candidates, $matchedManifest);
|
||||
}
|
||||
$manifestLesson = CurriculumService::findLessonById($rawId);
|
||||
if ($manifestLesson && !empty($manifestLesson['file'])) {
|
||||
$fileNoExt = preg_replace('/\.md$/i', '', $manifestLesson['file']);
|
||||
$matchedManifest = Database::select(
|
||||
"SELECT * FROM lessons
|
||||
WHERE curriculum_key = ? OR curriculum_key = ? OR local_path LIKE ?
|
||||
ORDER BY (hls_url IS NOT NULL AND hls_url != '') DESC, id DESC LIMIT 5",
|
||||
[$manifestLesson['file'], $fileNoExt, "%{$fileNoExt}%"]
|
||||
);
|
||||
if (!empty($matchedManifest)) {
|
||||
$candidates = array_merge($candidates, $matchedManifest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -604,24 +604,13 @@ class VideoController
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$lesson) {
|
||||
$lesson = $candidates[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$lesson) {
|
||||
// Fallback to latest available lesson in DB with a video
|
||||
$lesson = Database::selectOne(
|
||||
"SELECT * FROM lessons
|
||||
WHERE hls_url IS NOT NULL AND hls_url != ''
|
||||
ORDER BY id DESC LIMIT 1"
|
||||
);
|
||||
}
|
||||
|
||||
if (!$lesson) {
|
||||
// Strict verification: if no matching lesson with an uploaded video is found, return 404
|
||||
if (!$lesson || empty($lesson['hls_url'])) {
|
||||
$response->status(404)->json([
|
||||
'status' => 'error',
|
||||
'message' => 'الدرس غير موجود أو لم يتم نشر الفيديو الخاص به بعد'
|
||||
'message' => 'لم يتم رفع ونشر فيديو شرح لهذا الدرس بعد.'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user