Skip to content

Instantly share code, notes, and snippets.

@notsopreety
Last active August 25, 2025 07:37
Show Gist options
  • Select an option

  • Save notsopreety/1d84f56dcb71c42281405b4bac8e84d5 to your computer and use it in GitHub Desktop.

Select an option

Save notsopreety/1d84f56dcb71c42281405b4bac8e84d5 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VIDEO_TITLE</title>
<style>
:root {
--primary-color: #3498db;
--controls-bg: rgba(0, 0, 0, 0.6);
--text-color: #ffffff;
--icon-size: 24px;
--font-size: 14px;
}
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #000;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
color: var(--text-color);
}
.player-container {
position: relative;
width: 100%;
height: 100%;
background-color: #000;
display: flex;
justify-content: center;
align-items: center;
}
video {
width: 100%;
height: 100%;
display: block;
}
/* Loading Spinner */
.loading-spinner {
position: absolute;
top: 50%;
left: 50%;
width: 50px;
height: 50px;
border: 4px solid rgba(255, 255, 255, 0.3);
border-top-color: var(--text-color);
border-radius: 50%;
animation: spin 1s linear infinite;
z-index: 10;
display: none; /* Hidden by default */
}
.player-container.loading .loading-spinner {
display: block;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.controls-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
transition: opacity 0.3s ease-in-out;
cursor: pointer;
z-index: 5;
}
.player-container:hover .controls-overlay,
.player-container.paused .controls-overlay,
.player-container.controls-visible .controls-overlay {
opacity: 1;
}
.center-controls {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
}
.player-container.paused .center-controls {
display: block;
}
.big-play-pause-btn {
background: var(--controls-bg);
border: none;
border-radius: 50%;
width: 70px;
height: 70px;
cursor: pointer;
padding-left: 5px;
display: flex;
justify-content: center;
align-items: center;
}
.big-play-pause-btn svg {
width: 40px;
height: 40px;
fill: var(--text-color);
}
.bottom-controls {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 10px;
background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
display: flex;
flex-direction: column;
gap: 5px;
}
.progress-bar-container {
width: 100%;
height: 15px;
cursor: pointer;
position: relative;
display: flex;
align-items: center;
}
.progress-bar-background, .buffered-bar, .progress-bar {
position: absolute;
height: 4px;
width: 100%;
border-radius: 2px;
transition: height 0.2s ease;
}
.progress-bar-container:hover .progress-bar-background,
.progress-bar-container:hover .buffered-bar,
.progress-bar-container:hover .progress-bar {
height: 6px;
}
.progress-bar-background { background-color: rgba(255, 255, 255, 0.3); }
.buffered-bar { background-color: rgba(255, 255, 255, 0.5); width: 0; }
.progress-bar { background-color: var(--primary-color); width: 0; }
.progress-thumb {
position: absolute;
width: 14px;
height: 14px;
background-color: var(--primary-color);
border-radius: 50%;
transform: scale(0);
left: 0;
transition: transform 0.2s ease;
}
.progress-bar-container:hover .progress-thumb {
transform: scale(1);
}
.buttons-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.controls-left, .controls-right {
display: flex;
align-items: center;
gap: 15px;
}
.icon-btn {
background: none;
border: none;
cursor: pointer;
padding: 5px;
display: flex;
align-items: center;
color: var(--text-color);
}
.icon-btn svg {
width: var(--icon-size);
height: var(--icon-size);
fill: var(--text-color);
}
.time-display {
font-size: var(--font-size);
white-space: nowrap;
}
.volume-controls {
display: flex;
align-items: center;
}
.volume-slider {
width: 0;
opacity: 0;
transition: width 0.3s ease, opacity 0.3s ease;
cursor: pointer;
accent-color: var(--primary-color);
}
.volume-controls:hover .volume-slider {
width: 80px;
opacity: 1;
margin-left: 10px;
}
.playback-speed {
position: relative;
}
.speed-menu {
display: none;
position: absolute;
bottom: 120%;
right: 0;
background: var(--controls-bg);
border-radius: 4px;
padding: 5px 0;
list-style: none;
margin: 0;
min-width: 80px;
}
.speed-menu li {
padding: 8px 15px;
cursor: pointer;
font-size: var(--font-size);
}
.speed-menu li:hover { background-color: rgba(255, 255, 255, 0.2); }
.speed-menu li.active { font-weight: bold; color: var(--primary-color); }
.seek-overlay {
position: absolute;
top: 0;
width: 50%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
opacity: 0;
}
.seek-overlay.backward { left: 0; }
.seek-overlay.forward { right: 0; }
.seek-overlay svg {
width: 50px;
height: 50px;
fill: var(--text-color);
background: rgba(0,0,0,0.5);
border-radius: 50%;
padding: 10px;
}
@keyframes seek-animation {
0% { opacity: 1; transform: scale(1); }
100% { opacity: 0; transform: scale(1.3); }
}
.seek-overlay.active { animation: seek-animation 0.5s ease-out forwards; }
/* --- Responsive Design --- */
/* Tablet */
@media (max-width: 768px) {
.controls-left, .controls-right { gap: 10px; }
.volume-controls:hover .volume-slider { width: 70px; }
}
/* Mobile */
@media (max-width: 600px) {
:root {
--icon-size: 20px;
--font-size: 12px;
}
.bottom-controls { padding: 8px; }
.controls-left, .controls-right { gap: 5px; }
.volume-controls:hover .volume-slider { width: 60px; }
.big-play-pause-btn { width: 60px; height: 60px; }
.big-play-pause-btn svg { width: 30px; height: 30px; }
/* Mobile-specific adjustments */
.progress-bar-container { height: 12px; }
.progress-bar-background, .buffered-bar, .progress-bar { height: 3px; }
.progress-bar-container:hover .progress-bar-background,
.progress-bar-container:hover .buffered-bar,
.progress-bar-container:hover .progress-bar { height: 5px; }
.seek-overlay svg {
width: 40px;
height: 40px;
padding: 8px;
}
}
/* Small Mobile */
@media (max-width: 480px) {
.time-display {
display: none; /* Hide time display on very small screens to prevent clutter */
}
.volume-slider {
display: none; /* Hide slider and only keep mute toggle on smallest screens */
}
.volume-controls:hover .volume-slider {
display: none;
}
/* Even smaller adjustments for very small screens */
.bottom-controls { padding: 6px; }
.controls-left, .controls-right { gap: 3px; }
.big-play-pause-btn { width: 50px; height: 50px; }
.big-play-pause-btn svg { width: 25px; height: 25px; }
.speed-menu {
bottom: 110%;
min-width: 70px;
}
.speed-menu li {
padding: 6px 12px;
font-size: 11px;
}
}
/* Portrait orientation adjustments for mobile */
@media (max-width: 600px) and (orientation: portrait) {
.player-container {
/* Ensure proper aspect ratio handling in portrait */
aspect-ratio: 16/9;
max-height: 100vh;
max-width: 100vw;
}
video {
object-fit: contain;
}
}
/* Landscape orientation adjustments for mobile */
@media (max-width: 600px) and (orientation: landscape) {
.player-container {
/* Optimize for landscape viewing */
aspect-ratio: 16/9;
max-height: 100vh;
max-width: 100vw;
}
video {
object-fit: contain;
}
/* Adjust controls for landscape */
.bottom-controls {
padding: 6px 10px;
}
.big-play-pause-btn {
width: 50px;
height: 50px;
}
}
/* Fullscreen mobile optimizations */
.player-container:fullscreen {
background-color: #000;
}
.player-container:fullscreen video {
object-fit: contain;
max-height: 100vh;
max-width: 100vw;
}
/* Webkit fullscreen support */
.player-container:-webkit-full-screen {
background-color: #000;
}
.player-container:-webkit-full-screen video {
object-fit: contain;
max-height: 100vh;
max-width: 100vw;
}
/* Mozilla fullscreen support */
.player-container:-moz-full-screen {
background-color: #000;
}
.player-container:-moz-full-screen video {
object-fit: contain;
max-height: 100vh;
max-width: 100vw;
}
/* Orientation-specific styles */
.player-container.landscape .bottom-controls {
padding: 8px 12px;
}
.player-container.portrait .big-play-pause-btn {
width: 70px;
height: 70px;
}
.player-container.portrait .big-play-pause-btn svg {
width: 35px;
height: 35px;
}
/* Touch-friendly improvements for mobile */
@media (max-width: 600px) {
.icon-btn {
min-width: 44px;
min-height: 44px;
padding: 8px;
}
.progress-bar-container {
min-height: 44px;
padding: 20px 0;
}
/* Improve touch targets */
.volume-controls:hover .volume-slider {
width: 80px;
height: 20px;
}
/* Better spacing for touch */
.controls-left, .controls-right {
gap: 8px;
}
}
/* Prevent text selection on mobile */
.player-container {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
}
</style>
</head>
<body>
<div class="player-container" id="player-container">
<video
id="main-video"
src="VIDEO_URL"
preload="metadata">
</video>
<div class="loading-spinner" id="loading-spinner"></div>
<div class="controls-overlay" id="controls-overlay">
<div class="seek-overlay backward" id="seek-backward-overlay">
<svg viewBox="0 0 24 24"><path d="M11.67 3.87L9.9 2.1 0 12l9.9 9.9 1.77-1.77L3.54 12z"></path><path d="M21.57 3.87L19.8 2.1 9.9 12l9.9 9.9 1.77-1.77L13.44 12z"></path></svg>
</div>
<div class="seek-overlay forward" id="seek-forward-overlay">
<svg viewBox="0 0 24 24"><path d="M12.33 3.87L14.1 2.1 24 12l-9.9 9.9-1.77-1.77L20.46 12z"></path><path d="M2.43 3.87L4.2 2.1l9.9 9.9-9.9 9.9-1.77-1.77L8.56 12z"></path></svg>
</div>
<div class="center-controls">
<button class="icon-btn big-play-pause-btn" id="center-play-pause-btn">
<svg class="play-icon" viewBox="0 0 24 24"><path d="M16.6582 9.28638C18.098 10.1862 18.8178 10.6361 19.0647 11.2122C19.2803 11.7152 19.2803 12.2847 19.0647 12.7878C18.8178 13.3638 18.098 13.8137 16.6582 14.7136L9.896 18.94C8.29805 19.9387 7.49907 20.4381 6.83973 20.385C6.26501 20.3388 5.73818 20.0469 5.3944 19.584C5 19.053 5 18.1108 5 16.2264V7.77357C5 5.88919 5 4.94701 5.3944 4.41598C5.73818 3.9531 6.26501 3.66111 6.83973 3.6149C7.49907 3.5619 8.29805 4.06126 9.896 5.05998L16.6582 9.28638Z" stroke="#FFFFFF" stroke-width="2" stroke-linejoin="round"/></svg>
<svg class="pause-icon" viewBox="0 0 24 24" style="display:none;"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"></path></svg>
</button>
</div>
<div class="bottom-controls">
<div class="progress-bar-container" id="progress-bar-container">
<div class="progress-bar-background"></div>
<div class="buffered-bar" id="buffered-bar"></div>
<div class="progress-bar" id="progress-bar"></div>
<div class="progress-thumb" id="progress-thumb"></div>
</div>
<div class="buttons-row">
<div class="controls-left">
<button class="icon-btn" id="play-pause-btn">
<svg class="play-icon" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"></path></svg>
<svg class="pause-icon" viewBox="0 0 24 24" style="display:none;"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"></path></svg>
</button>
<button class="icon-btn" id="rewind-btn" title="Rewind 10s (j)">
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 8.76844L19.0966 4.30838C20.3991 3.41122 21.9998 4.57895 21.9998 6.42632L21.9998 17.5737C21.9998 19.4211 20.3991 20.5888 19.0966 19.6916L13 15.2316" stroke="#FFFFFF" stroke-width="1.5"/>
<path d="M2.92136 10.1468C1.69288 10.9545 1.69288 13.0455 2.92135 13.8532L10.3388 18.7302C11.5327 19.5152 13 18.4934 13 16.877L13 7.12303C13 5.50658 11.5327 4.48482 10.3388 5.26983L2.92136 10.1468Z" stroke="#FFFFFF" stroke-width="1.5"/>
</svg>
</button>
<button class="icon-btn" id="forward-btn" title="Forward 10s (l)">
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.9998 8.76844L4.90312 4.30838C3.60064 3.41122 2 4.57895 2 6.42632L2 17.5737C2 19.4211 3.60065 20.5888 4.90313 19.6916L10.9998 15.2316" stroke="#FFFFFF" stroke-width="1.5"/>
<path d="M21.0786 10.1468C22.3071 10.9545 22.3071 13.0455 21.0786 13.8532L13.6612 18.7302C12.4673 19.5152 11 18.4934 11 16.877L11 7.12303C11 5.50658 12.4673 4.48482 13.6612 5.26983L21.0786 10.1468Z" stroke="#FFFFFF" stroke-width="1.5"/>
</svg>
</button>
<div class="volume-controls">
<button class="icon-btn" id="mute-btn">
<svg class="volume-high-icon" viewBox="0 0 24 24"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"></path></svg>
<svg class="volume-low-icon" viewBox="0 0 24 24" style="display:none;"><path d="M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z"></path></svg>
<svg class="volume-muted-icon" viewBox="0 0 24 24" style="display:none;"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"></path></svg>
</button>
<input type="range" class="volume-slider" id="volume-slider" min="0" max="1" step="0.01" value="1">
</div>
<div class="time-display" id="time-display">00:00 / 00:00</div>
</div>
<div class="controls-right">
<div class="playback-speed">
<button class="icon-btn" id="speed-btn">
<span style="font-size: var(--font-size); font-weight: bold;">1x</span>
</button>
<ul class="speed-menu" id="speed-menu">
<li data-speed="2">2x</li><li data-speed="1.5">1.5x</li><li data-speed="1.25">1.25x</li><li data-speed="1" class="active">1x</li><li data-speed="0.75">0.75x</li><li data-speed="0.5">0.5x</li>
</ul>
</div>
<button class="icon-btn" id="fullscreen-btn">
<svg class="fullscreen-open-icon" viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"></path></svg>
<svg class="fullscreen-close-icon" viewBox="0 0 24 24" style="display:none;"><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"></path></svg>
</button>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const playerContainer = document.getElementById('player-container');
const video = document.getElementById('main-video');
const controlsOverlay = document.getElementById('controls-overlay');
const playPauseBtn = document.getElementById('play-pause-btn');
const centerPlayPauseBtn = document.getElementById('center-play-pause-btn');
const playIcons = document.querySelectorAll('.play-icon');
const pauseIcons = document.querySelectorAll('.pause-icon');
const rewindBtn = document.getElementById('rewind-btn');
const forwardBtn = document.getElementById('forward-btn');
const progressBarContainer = document.getElementById('progress-bar-container');
const progressBar = document.getElementById('progress-bar');
const bufferedBar = document.getElementById('buffered-bar');
const progressThumb = document.getElementById('progress-thumb');
const timeDisplay = document.getElementById('time-display');
const muteBtn = document.getElementById('mute-btn');
const volumeHighIcon = document.querySelector('.volume-high-icon');
const volumeLowIcon = document.querySelector('.volume-low-icon');
const volumeMutedIcon = document.querySelector('.volume-muted-icon');
const volumeSlider = document.getElementById('volume-slider');
const speedBtn = document.getElementById('speed-btn');
const speedMenu = document.getElementById('speed-menu');
const fullscreenBtn = document.getElementById('fullscreen-btn');
const fullscreenOpenIcon = document.querySelector('.fullscreen-open-icon');
const fullscreenCloseIcon = document.querySelector('.fullscreen-close-icon');
const seekBackwardOverlay = document.getElementById('seek-backward-overlay');
const seekForwardOverlay = document.getElementById('seek-forward-overlay');
let controlsTimeout;
let lastClickTime = 0;
const formatTime = (time) => {
const sec = Math.floor(time % 60);
const min = Math.floor(time / 60) % 60;
const hr = Math.floor(time / 3600);
return hr > 0 ? `${String(hr).padStart(2, '0')}:${String(min).padStart(2, '0')}:${String(sec).padStart(2, '0')}` : `${String(min).padStart(2, '0')}:${String(sec).padStart(2, '0')}`;
};
const updateIconSet = (iconsToShow, iconsToHide) => {
iconsToShow.forEach(i => i.style.display = 'block');
iconsToHide.forEach(i => i.style.display = 'none');
};
const togglePlayPause = () => video.paused ? video.play() : video.pause();
const updatePlayPauseIcons = () => {
if (video.paused) {
updateIconSet(playIcons, pauseIcons);
playerContainer.classList.add('paused');
playerContainer.classList.remove('playing');
} else {
updateIconSet(pauseIcons, playIcons);
playerContainer.classList.add('playing');
playerContainer.classList.remove('paused');
}
};
const updateProgress = () => {
const progressPercent = (video.currentTime / video.duration) * 100;
progressBar.style.width = `${progressPercent}%`;
progressThumb.style.left = `calc(${progressPercent}% - 7px)`;
if (!isNaN(video.duration)) {
timeDisplay.textContent = `${formatTime(video.currentTime)} / ${formatTime(video.duration)}`;
}
};
const updateBuffer = () => {
if (video.buffered.length > 0) {
bufferedBar.style.width = `${(video.buffered.end(video.buffered.length - 1) / video.duration) * 100}%`;
}
};
const seek = (e) => video.currentTime = ((e.clientX - progressBarContainer.getBoundingClientRect().left) / progressBarContainer.clientWidth) * video.duration;
const toggleMute = () => video.muted = !video.muted;
const updateVolumeUI = () => {
if (video.muted || video.volume === 0) {
updateIconSet([volumeMutedIcon], [volumeHighIcon, volumeLowIcon]);
volumeSlider.value = 0;
} else if (video.volume > 0.5) {
updateIconSet([volumeHighIcon], [volumeMutedIcon, volumeLowIcon]);
volumeSlider.value = video.volume;
} else {
updateIconSet([volumeLowIcon], [volumeMutedIcon, volumeHighIcon]);
volumeSlider.value = video.volume;
}
};
const toggleSpeedMenu = () => speedMenu.style.display = speedMenu.style.display === 'block' ? 'none' : 'block';
const setPlaybackSpeed = (speed) => {
video.playbackRate = speed;
speedBtn.querySelector('span').textContent = `${speed}x`;
speedMenu.querySelectorAll('li').forEach(item => item.classList.toggle('active', parseFloat(item.dataset.speed) === speed));
toggleSpeedMenu();
};
const toggleFullscreen = () => {
if (!document.fullscreenElement) {
// Request fullscreen
if (playerContainer.requestFullscreen) {
playerContainer.requestFullscreen().catch(err => console.error(err));
} else if (playerContainer.webkitRequestFullscreen) {
playerContainer.webkitRequestFullscreen().catch(err => console.error(err));
} else if (playerContainer.mozRequestFullScreen) {
playerContainer.mozRequestFullScreen().catch(err => console.error(err));
} else if (playerContainer.msRequestFullscreen) {
playerContainer.msRequestFullscreen().catch(err => console.error(err));
}
// For mobile devices, try to lock to landscape orientation
if (screen.orientation && screen.orientation.lock) {
screen.orientation.lock('landscape').catch(err => {
console.log('Could not lock orientation:', err);
});
}
} else {
// Exit fullscreen
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
// Unlock orientation when exiting fullscreen
if (screen.orientation && screen.orientation.unlock) {
screen.orientation.unlock();
}
}
};
const updateFullscreenIcons = () => {
const isFullscreen = document.fullscreenElement ||
document.webkitFullscreenElement ||
document.mozFullScreenElement ||
document.msFullscreenElement;
updateIconSet(isFullscreen ? [fullscreenCloseIcon] : [fullscreenOpenIcon],
isFullscreen ? [fullscreenOpenIcon] : [fullscreenCloseIcon]);
};
// Handle orientation changes
const handleOrientationChange = () => {
// Adjust player layout based on orientation
if (window.innerWidth < 600) {
if (window.orientation === 90 || window.orientation === -90) {
// Landscape
playerContainer.classList.add('landscape');
playerContainer.classList.remove('portrait');
} else {
// Portrait
playerContainer.classList.add('portrait');
playerContainer.classList.remove('landscape');
}
}
};
// Initialize orientation classes
const initializeOrientation = () => {
handleOrientationChange();
// Set initial orientation class
if (window.innerWidth < 600) {
if (window.orientation === 90 || window.orientation === -90) {
playerContainer.classList.add('landscape');
} else {
playerContainer.classList.add('portrait');
}
}
};
const triggerSeekAnimation = (overlay) => {
overlay.classList.remove('active');
void overlay.offsetWidth;
overlay.classList.add('active');
};
const handleVideoClick = (e) => {
const currentTime = new Date().getTime();
if (currentTime - lastClickTime < 300) {
const rect = video.getBoundingClientRect();
const clickX = e.clientX - rect.left;
if (clickX < rect.width / 3) {
video.currentTime -= 10;
triggerSeekAnimation(seekBackwardOverlay);
} else if (clickX > (rect.width * 2) / 3) {
video.currentTime += 10;
triggerSeekAnimation(seekForwardOverlay);
} else togglePlayPause();
} else togglePlayPause();
lastClickTime = currentTime;
};
const showControls = () => {
playerContainer.classList.add('controls-visible');
clearTimeout(controlsTimeout);
};
const hideControls = () => {
if (video.paused) return;
controlsTimeout = setTimeout(() => {
playerContainer.classList.remove('controls-visible');
if (speedMenu.style.display === 'block') toggleSpeedMenu();
}, 3000);
};
const handleKeyPress = (e) => {
if (e.target.matches('input, textarea, [contenteditable]')) return;
e.preventDefault();
switch(e.key.toLowerCase()) {
case ' ': case 'k': togglePlayPause(); break;
case 'm': toggleMute(); break;
case 'f': toggleFullscreen(); break;
case 'j': video.currentTime -= 10; break;
case 'l': video.currentTime += 10; break;
case 'arrowleft': video.currentTime -= 5; break;
case 'arrowright': video.currentTime += 5; break;
case 'arrowup': video.volume = Math.min(1, video.volume + 0.1); break;
case 'arrowdown': video.volume = Math.max(0, video.volume - 0.1); break;
}
};
video.addEventListener('play', updatePlayPauseIcons);
video.addEventListener('pause', updatePlayPauseIcons);
video.addEventListener('timeupdate', updateProgress);
video.addEventListener('progress', updateBuffer);
video.addEventListener('volumechange', updateVolumeUI);
video.addEventListener('loadedmetadata', updateProgress);
video.addEventListener('waiting', () => playerContainer.classList.add('loading'));
video.addEventListener('playing', () => playerContainer.classList.remove('loading'));
controlsOverlay.addEventListener('click', (e) => e.target === controlsOverlay && handleVideoClick(e));
playPauseBtn.addEventListener('click', togglePlayPause);
centerPlayPauseBtn.addEventListener('click', togglePlayPause);
rewindBtn.addEventListener('click', () => video.currentTime -= 10);
forwardBtn.addEventListener('click', () => video.currentTime += 10);
progressBarContainer.addEventListener('click', seek);
muteBtn.addEventListener('click', toggleMute);
volumeSlider.addEventListener('input', (e) => { video.volume = e.target.value; video.muted = video.volume === 0; });
speedBtn.addEventListener('click', toggleSpeedMenu);
speedMenu.querySelectorAll('li').forEach(item => item.addEventListener('click', () => setPlaybackSpeed(parseFloat(item.dataset.speed))));
fullscreenBtn.addEventListener('click', toggleFullscreen);
document.addEventListener('fullscreenchange', updateFullscreenIcons);
document.addEventListener('webkitfullscreenchange', updateFullscreenIcons);
document.addEventListener('mozfullscreenchange', updateFullscreenIcons);
document.addEventListener('MSFullscreenChange', updateFullscreenIcons);
// Handle orientation and resize changes
window.addEventListener('orientationchange', handleOrientationChange);
window.addEventListener('resize', handleOrientationChange);
playerContainer.addEventListener('mousemove', () => { showControls(); hideControls(); });
playerContainer.addEventListener('mouseleave', () => !video.paused && playerContainer.classList.remove('controls-visible'));
playerContainer.addEventListener('mouseenter', showControls);
document.addEventListener('keydown', handleKeyPress);
updatePlayPauseIcons();
updateVolumeUI();
hideControls();
initializeOrientation();
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment