function video_shortcode($atts) {
$atts = shortcode_atts(array('download' => 'true'), $atts);
preg_match('/\[video.*?mp4="([^"]+)"/i', get_the_content(), $video_match);
if (empty($video_match[1])) return "No video found.";
$video_link = $video_match[1];
$poster_image_url = has_post_thumbnail(get_the_ID()) ? get_the_post_thumbnail_url(get_the_ID(), 'full') : 'path/to/default/poster.jpg';
$video_id = 'video-' . get_the_ID();
//Detect Free user
$current_user = wp_get_current_user();
$isFreeUser = in_array('subscriber', (array) $current_user->roles);
$top_up_wrapper = do_shortcode('[render_top_up_wrapper]');
$html = '<div class="video-container" id="' . esc_attr($video_id) . '">
<video class="cus-video" poster="' . esc_url($poster_image_url) . '" muted playsinline>
<source src="' . esc_url($video_link) . '" type="video/mp4">
</video>
</div>';
$isFreeUser_js = $isFreeUser ? 'true' : 'false';
$top_up_wrapper_js = json_encode($top_up_wrapper);
$script = <<<JS
<script>
(function(){
if (window.__cus_video_handler_added) return;
window.__cus_video_handler_added = true;
const isFreeUser = {$isFreeUser_js};
const topUpHTML = {$top_up_wrapper_js};
function formatTime(seconds) {
const m = Math.floor(seconds / 60);
const s = Math.floor(seconds % 60);
return m + ':' + (s < 10 ? '0' + s : s);
}
function initVideoContainer(container) {
if (container.dataset.observed) return;
container.dataset.observed = "true";
const video = container.querySelector("video");
if (!video) return;
// Free-user 10-second countdown tracking
let freeTimeout = null;
let elapsed = 0;
const limit = 10000; // 10 seconds
let lastTimestamp = null;
function startCountdown() {
if (!video.paused) {
lastTimestamp = performance.now();
freeTimeout = requestAnimationFrame(tick);
}
}
function tick(timestamp) {
if (video.paused) {
lastTimestamp = null;
return; // pause countdown
}
if (lastTimestamp !== null) {
elapsed += timestamp - lastTimestamp;
lastTimestamp = timestamp;
}
if (elapsed >= limit) {
const parent = container.closest('.cus-video01');
if (parent) {
container.style.display = 'none';
parent.innerHTML = topUpHTML;
}
} else {
freeTimeout = requestAnimationFrame(tick);
}
}
const getElems = () => {
const wrapper = container.closest(".main-wrapper01");
return {
wrapper,
playBtn: wrapper ? wrapper.querySelector(".cus-play-div") : null,
icon: wrapper ? wrapper.querySelector(".cus-play-icon") : null,
duration: wrapper ? wrapper.querySelector(".cus-duration") : null,
playWrapper: wrapper ? wrapper.querySelector(".cus-play-wrapper") : null
};
};
//Setup duration display
video.addEventListener("loadedmetadata", () => {
const { duration } = getElems();
if (duration) duration.innerHTML = "0:00 / " + formatTime(video.duration);
});
video.addEventListener("timeupdate", () => {
const { duration } = getElems();
if (duration) duration.innerHTML = formatTime(video.currentTime) + " / " + formatTime(video.duration);
});
if (isFreeUser) {
video.addEventListener("play", startCountdown);
video.addEventListener("pause", () => {
if (freeTimeout) cancelAnimationFrame(freeTimeout);
lastTimestamp = null;
});
}
// Observer: autoplay when visible, pause when not
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
const { playBtn, icon, playWrapper } = getElems();
if (entry.isIntersecting) {
video.play().catch(()=>{});
video.muted = false;
playBtn?.classList.add("playing");
if (icon) icon.innerHTML = '<i class="fa-solid fa-pause"></i>';
if (playWrapper) {
clearTimeout(playWrapper.hideTimeout);
playWrapper.hideTimeout = setTimeout(() => {
playWrapper.style.display = 'none';
playWrapper.hideTimeout = null;
}, 2000);
}
} else {
video.pause();
playBtn?.classList.remove("playing");
if (icon) icon.innerHTML = '<i class="fa-solid fa-play"></i>';
if (playWrapper) {
clearTimeout(playWrapper.hideTimeout);
playWrapper.style.display = 'block';
}
}
});
}, { threshold: 0.5 });
observer.observe(container);
// Sync UI on native play/pause
video.addEventListener('play', () => {
const { playBtn, icon, playWrapper } = getElems();
playBtn?.classList.add('playing');
if (icon) icon.innerHTML = '<i class="fa-solid fa-pause"></i>';
if (playWrapper) {
clearTimeout(playWrapper.hideTimeout);
playWrapper.hideTimeout = setTimeout(() => {
playWrapper.style.display = 'none';
playWrapper.hideTimeout = null;
}, 2000);
}
});
video.addEventListener('pause', () => {
const { playBtn, icon, playWrapper } = getElems();
playBtn?.classList.remove('playing');
if (icon) icon.innerHTML = '<i class="fa-solid fa-play"></i>';
if (playWrapper) {
clearTimeout(playWrapper.hideTimeout);
playWrapper.style.display = 'block';
playWrapper.hideTimeout = null;
}
});
}
// init existing
document.querySelectorAll('.video-container').forEach(initVideoContainer);
// watch for new ones (tabs/ajax)
const mo = new MutationObserver(mutations => {
for (const m of mutations) {
for (const node of m.addedNodes) {
if (node.nodeType !== 1) continue;
if (node.matches && node.matches('.video-container')) initVideoContainer(node);
else node.querySelectorAll && node.querySelectorAll('.video-container').forEach(initVideoContainer);
}
}
});
mo.observe(document.body, { childList: true, subtree: true });
function ensurePlayWrapperTracking(playWrapper, video) {
if (!playWrapper || playWrapper._trackingSetup) return;
playWrapper._trackingSetup = true;
const reset = () => {
if (video && !video.paused) {
clearTimeout(playWrapper.hideTimeout);
playWrapper.hideTimeout = setTimeout(() => {
playWrapper.style.display = 'none';
playWrapper.hideTimeout = null;
}, 2000);
} else {
clearTimeout(playWrapper.hideTimeout);
playWrapper.hideTimeout = null;
playWrapper.style.display = 'block';
}
};
['mousemove','touchstart','click'].forEach(ev => playWrapper.addEventListener(ev, reset));
}
document.addEventListener('click', function(e){
if (e.target.closest('.cus-award-btn') || e.target.closest('.award-points-btn')) return;
const playDivClick = e.target.closest('.cus-play-div');
const articleClick = e.target.closest('.cus-video01');
if (!playDivClick && !articleClick) return;
const origin = playDivClick || articleClick;
const wrapper = origin.closest('.main-wrapper01');
if (!wrapper) return;
const video = wrapper.querySelector('.cus-video');
const playDiv = wrapper.querySelector('.cus-play-div');
const icon = playDiv ? playDiv.querySelector('.cus-play-icon') : null;
const playWrapper = wrapper.querySelector('.cus-play-wrapper');
if (!video || !icon) return;
if (articleClick && playWrapper) {
playWrapper.style.display = 'block';
clearTimeout(playWrapper.hideTimeout);
ensurePlayWrapperTracking(playWrapper, video);
if (!video.paused) {
playWrapper.hideTimeout = setTimeout(() => {
playWrapper.style.display = 'none';
playWrapper.hideTimeout = null;
}, 2000);
} else {
clearTimeout(playWrapper.hideTimeout);
playWrapper.hideTimeout = null;
playWrapper.style.display = 'block';
}
}
if (video.paused) {
video.play().catch(()=>{});
video.muted = false;
playDiv?.classList.add('playing');
if (icon) icon.innerHTML = '<i class="fa-solid fa-pause"></i>';
if (playWrapper) {
clearTimeout(playWrapper.hideTimeout);
playWrapper.hideTimeout = setTimeout(() => {
playWrapper.style.display = 'none';
playWrapper.hideTimeout = null;
}, 2000);
ensurePlayWrapperTracking(playWrapper, video);
}
} else {
video.pause();
playDiv?.classList.remove('playing');
if (icon) icon.innerHTML = '<i class="fa-solid fa-play"></i>';
if (playWrapper) {
clearTimeout(playWrapper.hideTimeout);
playWrapper.hideTimeout = null;
playWrapper.style.display = 'block';
}
}
}, false);
// Pause all videos when clicking outside video elements
document.body.addEventListener('click', e => {
if (e.target.closest('.video-container, .cus-play-div, .cus-play-wrapper, video, .cus-award-btn, .like-button-wrapper, .repost-button-wrapper, .short-excerpt03, .menu03-excerpt')) return;
document.querySelectorAll('.cus-video').forEach(v => {
if (!v.paused) v.pause();
});
}, false);
})();
</script>
JS;
return $html . $script;
}
add_shortcode("video_player","video_shortcode");