anycoder-6021ac51 / index.html
zp1112's picture
Upload folder using huggingface_hub
364776e verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Modern Mobile H5 Video Player</title>
<!-- FontAwesome for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #3b82f6;
--primary-glow: rgba(59, 130, 246, 0.5);
--bg-dark: #0f172a;
--bg-panel: rgba(30, 41, 59, 0.8);
--text-main: #f8fafc;
--text-muted: #94a3b8;
--control-height: 60px;
--radius: 12px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
-webkit-tap-highlight-color: transparent;
}
body {
font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
background-color: var(--bg-dark);
color: var(--text-main);
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden; /* Prevent scrolling on mobile */
}
/* --- Header --- */
header {
padding: 15px 20px;
background: rgba(15, 23, 42, 0.9);
backdrop-filter: blur(10px);
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
z-index: 100;
}
.brand {
font-weight: 700;
font-size: 1.1rem;
display: flex;
align-items: center;
gap: 10px;
}
.brand i {
color: var(--primary-color);
}
.built-with {
font-size: 0.8rem;
color: var(--text-muted);
text-decoration: none;
transition: color 0.3s ease;
}
.built-with:hover {
color: var(--primary-color);
}
/* --- Main Video Area --- */
main {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
position: relative;
background: radial-gradient(circle at center, #1e293b 0%, #0f172a 100%);
}
.player-container {
width: 100%;
max-width: 800px;
aspect-ratio: 16 / 9;
background: #000;
border-radius: var(--radius);
box-shadow: 0 20px 50px -12px rgba(0, 0, 0, 0.7);
position: relative;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.05);
}
video {
width: 100%;
height: 100%;
display: block;
object-fit: contain; /* Ensures video fits without cropping */
}
/* --- Controls Overlay --- */
.controls-overlay {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 20px;
background: linear-gradient(to top, rgba(0,0,0,0.9), transparent);
opacity: 0;
transition: opacity 0.3s ease;
display: flex;
flex-direction: column;
gap: 10px;
}
/* Show controls on hover or when playing */
.player-container:hover .controls-overlay,
.controls-overlay.active {
opacity: 1;
}
/* --- Progress Bar --- */
.progress-container {
width: 100%;
height: 5px;
background: rgba(255, 255, 255, 0.2);
border-radius: 5px;
cursor: pointer;
position: relative;
transition: height 0.2s;
}
.progress-container:hover {
height: 8px;
}
.progress-fill {
height: 100%;
background: var(--primary-color);
border-radius: 5px;
width: 0%;
position: relative;
box-shadow: 0 0 10px var(--primary-glow);
}
.progress-thumb {
width: 14px;
height: 14px;
background: #fff;
border-radius: 50%;
position: absolute;
right: -7px;
top: 50%;
transform: translateY(-50%) scale(0);
transition: transform 0.2s;
}
.progress-container:hover .progress-thumb {
transform: translateY(-50%) scale(1);
}
/* --- Control Buttons Row --- */
.controls-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.left-controls, .right-controls {
display: flex;
align-items: center;
gap: 15px;
}
.btn-control {
background: none;
border: none;
color: var(--text-main);
font-size: 1.2rem;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 50%;
transition: background 0.2s, transform 0.1s;
}
.btn-control:hover {
background: rgba(255, 255, 255, 0.1);
}
.btn-control:active {
transform: scale(0.95);
}
.btn-play {
width: 44px;
height: 44px;
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(5px);
}
.btn-play:hover {
background: var(--primary-color);
box-shadow: 0 0 15px var(--primary-glow);
}
/* --- Volume Slider --- */
.volume-container {
display: flex;
align-items: center;
gap: 8px;
width: 100px;
}
.volume-slider {
-webkit-appearance: none;
width: 100%;
height: 4px;
background: rgba(255, 255, 255, 0.2);
border-radius: 2px;
outline: none;
}
.volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 12px;
height: 12px;
background: #fff;
border-radius: 50%;
cursor: pointer;
display: none; /* Hidden unless hovered */
}
.volume-container:hover .volume-slider::-webkit-slider-thumb {
display: block;
}
/* --- Time Display --- */
.time-display {
font-size: 0.85rem;
color: var(--text-muted);
font-variant-numeric: tabular-nums;
min-width: 100px;
text-align: right;
}
/* --- Upload Section --- */
.upload-section {
padding: 10px 20px 20px;
text-align: center;
}
.file-input-wrapper {
position: relative;
overflow: hidden;
display: inline-block;
}
.file-input-btn {
border: 1px dashed var(--text-muted);
color: var(--text-muted);
background: transparent;
padding: 10px 20px;
border-radius: 20px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s;
display: flex;
align-items: center;
gap: 8px;
}
.file-input-btn:hover {
border-color: var(--primary-color);
color: var(--primary-color);
}
input[type=file] {
font-size: 100px;
position: absolute;
left: 0;
top: 0;
opacity: 0;
cursor: pointer;
}
/* --- Loading Spinner --- */
.spinner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: var(--primary-color);
font-size: 3rem;
display: none;
z-index: 5;
}
/* --- Fullscreen --- */
.player-container:fullscreen {
border-radius: 0;
}
.player-container:fullscreen video {
object-fit: contain;
}
/* Mobile Specific Adjustments */
@media (max-width: 600px) {
.player-container {
border-radius: 0;
width: 100vw;
height: 100vh; /* Full screen video on mobile */
max-width: 100%;
position: absolute;
top: 0;
left: 0;
}
main {
padding: 0;
display: block;
}
header {
position: absolute;
top: 0;
width: 100%;
z-index: 50;
background: rgba(15, 23, 42, 0.5);
}
.controls-overlay {
background: linear-gradient(to top, rgba(0,0,0,0.95), transparent);
padding: 30px 20px 20px;
}
.time-display {
position: absolute;
bottom: 80px;
left: 20px;
right: 20px;
text-align: left;
text-shadow: 0 1px 2px rgba(0,0,0,0.8);
z-index: 10;
}
.volume-container {
width: 60px;
}
}
</style>
</head>
<body>
<header>
<div class="brand">
<i class="fa-solid fa-play-circle"></i>
<span>FlexPlayer</span>
</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with">Built with anycoder</a>
</header>
<main>
<div class="player-container" id="playerContainer">
<!-- Default Sample Video -->
<video id="videoPlayer" poster="https://images.pexels.com/photos/3129671/pexels-photo-3129671.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1">
<source src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<div class="spinner" id="loadingSpinner">
<i class="fa-solid fa-circle-notch fa-spin"></i>
</div>
<div class="controls-overlay" id="controlsOverlay">
<!-- Progress -->
<div class="progress-container" id="progressContainer">
<div class="progress-fill" id="progressFill">
<div class="progress-thumb"></div>
</div>
</div>
<!-- Controls Row -->
<div class="controls-row">
<div class="left-controls">
<button class="btn-control btn-play" id="playPauseBtn" aria-label="Play/Pause">
<i class="fa-solid fa-play"></i>
</button>
<button class="btn-control" id="muteBtn" aria-label="Mute">
<i class="fa-solid fa-volume-high"></i>
</button>
<div class="volume-container">
<input type="range" class="volume-slider" id="volumeSlider" min="0" max="1" step="0.1" value="1">
</div>
<div class="time-display">
<span id="currentTime">0:00</span> / <span id="duration">0:00</span>
</div>
</div>
<div class="right-controls">
<button class="btn-control" id="pipBtn" aria-label="Picture in Picture">
<i class="fa-solid fa-clone"></i>
</button>
<button class="btn-control" id="fsBtn" aria-label="Fullscreen">
<i class="fa-solid fa-expand"></i>
</button>
</div>
</div>
</div>
</div>
</main>
<div class="upload-section">
<div class="file-input-wrapper">
<button class="file-input-btn">
<i class="fa-solid fa-upload"></i> Load Local Video
</button>
<input type="file" id="videoUpload" accept="video/*">
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const video = document.getElementById('videoPlayer');
const container = document.getElementById('playerContainer');
const playPauseBtn = document.getElementById('playPauseBtn');
const muteBtn = document.getElementById('muteBtn');
const volumeSlider = document.getElementById('volumeSlider');
const progressContainer = document.getElementById('progressContainer');
const progressFill = document.getElementById('progressFill');
const currentTimeEl = document.getElementById('currentTime');
const durationEl = document.getElementById('duration');
const fsBtn = document.getElementById('fsBtn');
const pipBtn = document.getElementById('pipBtn');
const uploadInput = document.getElementById('videoUpload');
const spinner = document.getElementById('loadingSpinner');
// --- Utility Functions ---
// Format seconds to MM:SS
function formatTime(seconds) {
if (isNaN(seconds)) return "0:00";
const m = Math.floor(seconds / 60);
const s = Math.floor(seconds % 60);
return `${m}:${s < 10 ? '0' : ''}${s}`;
}
// --- Video Control Logic ---
function togglePlay() {
if (video.paused || video.ended) {
video.play();
playPauseBtn.innerHTML = '<i class="fa-solid fa-pause"></i>';
} else {
video.pause();
playPauseBtn.innerHTML = '<i class="fa-solid fa-play"></i>';
}
}
function updatePlayButtonIcon() {
if (video.paused) {
playPauseBtn.innerHTML = '<i class="fa-solid fa-play"></i>';
} else {
playPauseBtn.innerHTML = '<i class="fa-solid fa-pause"></i>';
}
}
function updateProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressFill.style.width = `${percent}%`;
currentTimeEl.textContent = formatTime(video.currentTime);
}
function setProgress(e) {
const width = progressContainer.clientWidth;
const clickX = e.offsetX;
const duration = video.duration;
video.currentTime = (clickX / width) * duration;
}
function toggleMute() {
video.muted = !video.muted;
if (video.muted) {
muteBtn.innerHTML = '<i class="fa-solid fa-volume-xmark"></i>';
volumeSlider.value = 0;
} else {
muteBtn.innerHTML = '<i class="fa-solid fa-volume-high"></i>';
volumeSlider.value = video.volume;
}
}
function updateVolume() {
video.volume = volumeSlider.value;
video.muted = false;
if (video.volume === 0) {
muteBtn.innerHTML = '<i class="fa-solid fa-volume-xmark"></i>';
} else if (video.volume < 0.5) {
muteBtn.innerHTML = '<i class="fa-solid fa-volume-low"></i>';
} else {
muteBtn.innerHTML = '<i class="fa-solid fa-volume-high"></i>';
}
}
// --- Fullscreen Logic ---
function toggleFullscreen() {
if (!document.fullscreenElement) {
container.requestFullscreen().catch(err => {
alert(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
});
} else {
document.exitFullscreen();
}
}
// --- Pip Logic ---
async function togglePiP() {
try {
if (video !== document.pictureInPictureElement) {
await video.requestPictureInPicture();
} else {
await document.exitPictureInPicture();
}
} catch (error) {
console.error("PiP Error:", error);
}
}
// --- Event Listeners ---
playPauseBtn.addEventListener('click', togglePlay);
// Auto hide controls on mobile after 3 seconds of inactivity
let controlsTimeout;
const showControls = () => {
document.getElementById('controlsOverlay').classList.add('active');
clearTimeout(controlsTimeout);
// On mobile, keep controls visible longer or until play
if(window.innerWidth <= 600) {
// Don't auto hide on mobile to ensure usability
} else {
controlsTimeout = setTimeout(() => {
if (!video.paused) {
document.getElementById('controlsOverlay').classList.remove('active');
}
}, 3000);
}
};
video.addEventListener('click', togglePlay);
video.addEventListener('play', () => {
updatePlayButtonIcon();
showControls();
});
video.addEventListener('pause', () => {
updatePlayButtonIcon();
showControls();
});
video.addEventListener('timeupdate', updateProgress);
video.addEventListener('loadedmetadata', () => {
durationEl.textContent = formatTime(video.duration);
});
progressContainer.addEventListener('click', setProgress);
muteBtn.addEventListener('click', toggleMute);
volumeSlider.addEventListener('input', updateVolume);
fsBtn.addEventListener('click', toggleFullscreen);
pipBtn.addEventListener('click', togglePiP);
// Handle fullscreen changes
document.addEventListener('fullscreenchange', () => {
const icon = fsBtn.querySelector('i');
if (document.fullscreenElement) {
icon.classList.remove('fa-expand');
icon.classList.add('fa-compress');
} else {
icon.classList.remove('fa-compress');
icon.classList.add('fa-expand');
}
});
// Handle File Upload
uploadInput.addEventListener('change', function() {
const file = this.files[0];
if (file) {
const fileURL = URL.createObjectURL(file);
video.src = fileURL;
video.play();
updatePlayButtonIcon();
}
});
// Keyboard Shortcuts
document.addEventListener('keydown', (e) => {
if (e.code === 'Space' && e.target.tagName !== 'INPUT') {
e.preventDefault();
togglePlay();
}
});
});
</script>
</body>
</html>