diff --git a/src/components/VapMp4Player.vue b/src/components/VapMp4Player.vue index 1f493c2..492af73 100644 --- a/src/components/VapMp4Player.vue +++ b/src/components/VapMp4Player.vue @@ -92,6 +92,7 @@ const loading = ref(false) const errorMessage = ref('') let player = null let playToken = 0 +let cleanupPlayerVideoGuards = null const teleportToBody = computed(() => props.mode === 'overlay') const resolvedSrc = computed(() => resolveProtectedAssetUrl(props.src)) @@ -101,10 +102,36 @@ function enforceVideoPlaybackAttributes(video, shouldMute) { return } + video.autoplay = false + video.controls = false video.playsInline = true video.setAttribute('playsinline', '') video.setAttribute('webkit-playsinline', '') video.setAttribute('x5-playsinline', '') + video.setAttribute('controlslist', 'nofullscreen noplaybackrate noremoteplayback') + video.setAttribute('disablepictureinpicture', '') + video.setAttribute('x-webkit-airplay', 'deny') + video.setAttribute('preload', 'auto') + + if ('disablePictureInPicture' in video) { + video.disablePictureInPicture = true + } + + if ('disableRemotePlayback' in video) { + video.disableRemotePlayback = true + } + + // Keep the source video alive for canvas sampling without letting Safari + // promote it into the native fullscreen player. + video.style.display = 'block' + video.style.position = 'fixed' + video.style.left = '-9999px' + video.style.top = '0' + video.style.width = '1px' + video.style.height = '1px' + video.style.opacity = '0' + video.style.pointerEvents = 'none' + video.style.zIndex = '-1' if (shouldMute) { video.muted = true @@ -117,7 +144,51 @@ function enforceVideoPlaybackAttributes(video, shouldMute) { } } +function installInlinePlaybackGuards(video) { + if (!video) { + return () => {} + } + + const keepInlinePlayback = () => { + enforceVideoPlaybackAttributes(video, props.mute) + + if (typeof video.webkitSetPresentationMode === 'function') { + try { + video.webkitSetPresentationMode('inline') + } catch (error) { + console.warn('Failed to force inline presentation mode:', error) + } + } + } + + keepInlinePlayback() + + const guardEvents = [ + 'loadedmetadata', + 'canplay', + 'play', + 'playing', + 'webkitbeginfullscreen', + 'webkitpresentationmodechanged', + ] + + guardEvents.forEach((eventName) => { + video.addEventListener(eventName, keepInlinePlayback) + }) + + return () => { + guardEvents.forEach((eventName) => { + video.removeEventListener(eventName, keepInlinePlayback) + }) + } +} + function destroyPlayer() { + if (cleanupPlayerVideoGuards) { + cleanupPlayerVideoGuards() + cleanupPlayerVideoGuards = null + } + if (player) { player.destroy() player = null @@ -199,12 +270,7 @@ async function startPlay() { }) enforceVideoPlaybackAttributes(player?.video, props.mute) - player?.video?.addEventListener('loadedmetadata', () => { - enforceVideoPlaybackAttributes(player?.video, props.mute) - }) - player?.video?.addEventListener('canplay', () => { - enforceVideoPlaybackAttributes(player?.video, props.mute) - }) + cleanupPlayerVideoGuards = installInlinePlaybackGuards(player?.video) player.on('ended', handleEnded) player.on('playing', () => { diff --git a/src/views/Activities/DailyRecharge/index.vue b/src/views/Activities/DailyRecharge/index.vue index acbb358..a0693f6 100644 --- a/src/views/Activities/DailyRecharge/index.vue +++ b/src/views/Activities/DailyRecharge/index.vue @@ -1,21 +1,21 @@