From b4cf290f4da2e7336312a55e0f576f620c82f0f8 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Tue, 1 Jul 2025 19:16:13 +0530 Subject: [PATCH] fix: allow backward seek but prevent forward seek --- frontend/src/components/VideoBlock.vue | 6 +++++- frontend/src/pages/Lesson.vue | 7 ++++++- frontend/src/utils/index.js | 29 ++++++++++++++++++++++---- lms/lms/utils.py | 1 + 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/VideoBlock.vue b/frontend/src/components/VideoBlock.vue index 86ddfa87..693d6d26 100644 --- a/frontend/src/components/VideoBlock.vue +++ b/frontend/src/components/VideoBlock.vue @@ -74,7 +74,6 @@ v-model="currentTime" @input="changeCurrentTime" class="duration-slider h-1" - :disabled="preventSkippingVideos.data" />
@@ -299,6 +298,11 @@ const toggleMute = () => { } const changeCurrentTime = () => { + if ( + preventSkippingVideos.data && + currentTime.value > videoRef.value.currentTime + ) + return videoRef.value.currentTime = currentTime.value updateNextQuiz() } diff --git a/frontend/src/pages/Lesson.vue b/frontend/src/pages/Lesson.vue index afb36b4e..48dbb6e4 100644 --- a/frontend/src/pages/Lesson.vue +++ b/frontend/src/pages/Lesson.vue @@ -511,6 +511,7 @@ const getVideoDetails = () => { const videos = document.querySelectorAll('video') if (videos.length > 0) { videos.forEach((video) => { + if (video.currentTime == video.duration) markProgress() details.push({ source: video.src, watch_time: video.currentTime, @@ -523,6 +524,7 @@ const getVideoDetails = () => { const getPlyrSourceDetails = () => { let details = [] plyrSources.value.forEach((source) => { + if (source.currentTime == source.duration) markProgress() let src = cleanYouTubeUrl(source.source) details.push({ source: src, @@ -544,6 +546,7 @@ watch( async (data) => { setupLesson(data) getPlyrSource() + if (data.icon == 'icon-youtube') clearInterval(timerInterval) } ) @@ -551,7 +554,6 @@ const getPlyrSource = async () => { await nextTick() if (plyrSources.value.length == 0) { plyrSources.value = await enablePlyr() - console.log(plyrSources.value) } updateVideoWatchDuration() } @@ -570,6 +572,9 @@ const updateVideoWatchDuration = () => { const updatePlyrVideoTime = (video) => { plyrSources.value.forEach((plyrSource) => { + let lastWatchedTime = 0 + let isSeeking = false + plyrSource.on('ready', () => { if (plyrSource.source === video.source) { plyrSource.embed.seekTo(video.watch_time, true) diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js index 79ec05ee..836912b9 100644 --- a/frontend/src/utils/index.js +++ b/frontend/src/utils/index.js @@ -566,18 +566,39 @@ const setupPlyrForVideo = (video, players) => { 'fullscreen', ] - if (useSettings().preventSkippingVideos.data) { - controls.splice(controls.indexOf('progress'), 1) - } - const player = new Plyr(video, { youtube: { noCookie: true }, controls: controls, + listeners: { + seek: function customSeekBehavior(e) { + const current_time = player.currentTime + const newTime = getTargetTime(player, e) + if ( + useSettings().preventSkippingVideos.data && + parseFloat(newTime) > current_time + ) { + e.preventDefault() + player.currentTime = current_time + return false + } + }, + }, }) players.push(player) } +const getTargetTime = (plyr, input) => { + if ( + typeof input === 'object' && + (input.type === 'input' || input.type === 'change') + ) { + return (input.target.value / input.target.max) * plyr.duration + } else { + return Number(input) + } +} + const extractYouTubeId = (url) => { try { const parsedUrl = new URL(url) diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 131fff51..4ec61ba1 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -1320,6 +1320,7 @@ def get_lesson(course, chapter, lesson): lesson_details.progress = progress lesson_details.prev = neighbours["prev"] lesson_details.membership = membership + lesson_details.icon = get_lesson_icon(lesson_details.body, lesson_details.content) lesson_details.instructors = get_instructors("LMS Course", course) lesson_details.course_title = course_info.title lesson_details.paid_certificate = course_info.paid_certificate