dfd / index.html
Subham9126's picture
Update index.html
51cd2d2 verified
Raw
History Blame
21.8 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Video Library</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: #f5f5f5;
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.container {
display: flex;
flex-direction: column;
gap: 20px;
}
.header {
background-color: #333;
color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.search-container {
padding: 15px;
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
#search {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
.video-list {
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
padding: 15px;
}
.video-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 15px;
}
.video-item {
padding: 15px;
border: 1px solid #eee;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
background-color: white;
}
.video-item:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.video-thumbnail {
width: 100%;
height: 156px;
background-color: #333;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 10px;
overflow: hidden;
}
.video-thumbnail i {
font-size: 48px;
color: white;
}
.video-item-title {
font-weight: 500;
margin-top: 10px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.pagination {
display: flex;
justify-content: center;
gap: 5px;
margin-top: 20px;
}
.page-btn {
padding: 8px 12px;
background-color: white;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s;
}
.page-btn:hover {
background-color: #f0f0f0;
}
.page-btn.active {
background-color: #333;
color: white;
border-color: #333;
}
.popup-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s, visibility 0.3s;
}
.popup-overlay.active {
opacity: 1;
visibility: visible;
}
.popup-content {
width: 90%;
max-width: 1024px;
background-color: #222;
border-radius: 8px;
overflow: hidden;
position: relative;
box-shadow: 0 10px 25px rgba(0,0,0,0.5);
}
.close-popup {
position: absolute;
top: 10px;
right: 10px;
background-color: rgba(0,0,0,0.5);
color: white;
border: none;
width: 30px;
height: 30px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 10;
font-size: 18px;
}
.player-wrapper {
position: relative;
width: 100%;
padding-top: 56.25%; /* 16:9 Aspect Ratio */
}
#videoPlayer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000;
}
.popup-title {
color: white;
padding: 15px;
font-size: 1.2em;
background-color: #111;
}
.controls {
display: flex;
gap: 10px;
padding: 15px;
background-color: #111;
flex-wrap: wrap;
}
.btn {
padding: 8px 16px;
background-color: #333;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s;
}
.btn:hover {
background-color: #555;
}
.instructions {
color: #ccc;
padding: 10px 15px;
background-color: #111;
font-size: 0.9em;
}
.play-icon {
font-size: 50px;
color: white;
opacity: 0.8;
transition: opacity 0.2s;
}
.video-item:hover .play-icon {
opacity: 1;
}
@media (max-width: 768px) {
.video-grid {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.popup-content {
width: 95%;
}
}
.no-videos {
padding: 20px;
text-align: center;
color: #777;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Video Library</h1>
</div>
<div class="search-container">
<input type="text" id="search" placeholder="Search videos...">
</div>
<div class="video-list">
<div class="video-grid" id="videoGrid">
<div class="video-item">
<div class="video-thumbnail">Loading...</div>
</div>
</div>
<div class="pagination" id="pagination"></div>
</div>
</div>
<!-- Video Player Popup -->
<div class="popup-overlay" id="playerPopup">
<div class="popup-content">
<button class="close-popup" id="closePopup"></button>
<div class="popup-title" id="currentTitle">Video Title</div>
<div class="player-wrapper">
<video id="videoPlayer" controls>
Your browser does not support the video tag.
</video>
</div>
<div class="controls">
<button class="btn" id="backwardBtn">⏪ 10s</button>
<button class="btn" id="playPauseBtn">⏯️ Play/Pause</button>
<button class="btn" id="forwardBtn">⏩ 10s</button>
<button class="btn" id="fullscreenBtn">⛶ Fullscreen</button>
<button class="btn" id="muteBtn">🔊 Mute/Unmute</button>
</div>
<div class="instructions">
<p><strong>Keyboard Controls:</strong> Space (Play/Pause) • ← (Back 10s) • → (Forward 10s) • F (Fullscreen) • M (Mute/Unmute)</p>
<p><strong>Double-tap:</strong> Left side (Back 10s) • Center (Play/Pause) • Right side (Forward 10s)</p>
</div>
</div>
</div>
<script>
// Global variables
let videoData = [];
let filteredVideos = [];
let currentVideo = null;
let currentPage = 1;
const videosPerPage = 10;
// DOM Elements
const videoGrid = document.getElementById('videoGrid');
const pagination = document.getElementById('pagination');
const searchInput = document.getElementById('search');
const playerPopup = document.getElementById('playerPopup');
const videoPlayer = document.getElementById('videoPlayer');
const currentTitle = document.getElementById('currentTitle');
const closePopup = document.getElementById('closePopup');
const playPauseBtn = document.getElementById('playPauseBtn');
const backwardBtn = document.getElementById('backwardBtn');
const forwardBtn = document.getElementById('forwardBtn');
const fullscreenBtn = document.getElementById('fullscreenBtn');
const muteBtn = document.getElementById('muteBtn');
// Function to fetch video data
async function fetchVideoData() {
try {
const response = await fetch('database.json');
if (!response.ok) {
throw new Error('Failed to fetch video data');
}
const data = await response.json();
// Check if data has videos array or is itself an array
videoData = Array.isArray(data) ? data :
(data.videos && Array.isArray(data.videos) ? data.videos : []);
filteredVideos = [...videoData];
renderPagination();
renderVideoGrid();
} catch (error) {
console.error('Error fetching video data:', error);
videoGrid.innerHTML = `<div class="no-videos">Error loading videos: ${error.message}</div>`;
}
}
// Function to render video grid
function renderVideoGrid() {
if (filteredVideos.length === 0) {
videoGrid.innerHTML = '<div class="no-videos">No videos found</div>';
pagination.innerHTML = '';
return;
}
const startIndex = (currentPage - 1) * videosPerPage;
const endIndex = Math.min(startIndex + videosPerPage, filteredVideos.length);
const currentVideos = filteredVideos.slice(startIndex, endIndex);
videoGrid.innerHTML = currentVideos.map((video, index) => `
<div class="video-item" data-index="${startIndex + index}">
<div class="video-thumbnail">
<div class="play-icon">▶</div>
</div>
<div class="video-item-title">${video.title}</div>
</div>
`).join('');
document.querySelectorAll('.video-item').forEach(item => {
item.addEventListener('click', function() {
const index = parseInt(this.getAttribute('data-index'));
if (!isNaN(index) && index >= 0 && index < filteredVideos.length) {
// Call the async function to play the video
playVideo(filteredVideos[index]);
}
});
});
}
// Function to render pagination
function renderPagination() {
const totalPages = Math.ceil(filteredVideos.length / videosPerPage);
if (totalPages <= 1) {
pagination.innerHTML = '';
return;
}
let buttons = [];
if (totalPages <= 7) {
for (let i = 1; i <= totalPages; i++) {
buttons.push(i);
}
} else {
buttons.push(1);
if (currentPage > 3) {
buttons.push('...');
}
const startPage = Math.max(2, currentPage - 1);
const endPage = Math.min(totalPages - 1, currentPage + 1);
for (let i = startPage; i <= endPage; i++) {
buttons.push(i);
}
if (currentPage < totalPages - 2) {
buttons.push('...');
}
buttons.push(totalPages);
}
pagination.innerHTML = buttons.map(button => {
if (button === '...') {
return '<span class="page-btn">...</span>';
}
return `<button class="page-btn ${button === currentPage ? 'active' : ''}" data-page="${button}">${button}</button>`;
}).join('');
document.querySelectorAll('.page-btn[data-page]').forEach(button => {
button.addEventListener('click', function() {
currentPage = parseInt(this.getAttribute('data-page'));
renderPagination();
renderVideoGrid();
window.scrollTo(0, 0);
});
});
}
// Async function to play a video and handle HF Model Hub authentication if needed
async function playVideo(video) {
currentVideo = video;
currentTitle.textContent = video.title;
let videoUrl = video.url;
let finalUrl = videoUrl;
// Check if the URL is from HF Model Hub and might require authentication.
if (videoUrl.includes("huggingface.co")) {
// Try to get token from localStorage or prompt the user.
let token = localStorage.getItem('hf_token');
if (!token) {
token = prompt("Enter your HuggingFace token:");
if (!token) {
alert("Authentication token required to access HuggingFace video.");
return;
}
localStorage.setItem('hf_token', token);
}
try {
const response = await fetch(videoUrl, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error(`Failed to load video: ${response.status} ${response.statusText}`);
}
const blob = await response.blob();
finalUrl = URL.createObjectURL(blob);
} catch (error) {
alert("Error loading HuggingFace video: " + error.message);
return;
}
}
videoPlayer.src = finalUrl;
videoPlayer.load();
// Show popup and disable background scrolling
playerPopup.classList.add('active');
document.body.style.overflow = 'hidden';
// Play video after a short delay to allow the popup to render
setTimeout(() => {
videoPlayer.play().catch(error => {
console.error("Error playing video:", error);
alert(`Error playing video: ${error.message}. Make sure the URL is accessible.`);
});
}, 300);
}
// Close popup function
function closePlayerPopup() {
videoPlayer.pause();
playerPopup.classList.remove('active');
document.body.style.overflow = '';
}
// Search functionality
searchInput.addEventListener('input', function() {
const searchTerm = this.value.toLowerCase();
filteredVideos = videoData.filter(video =>
video.title.toLowerCase().includes(searchTerm)
);
currentPage = 1; // Reset to first page on search
renderPagination();
renderVideoGrid();
});
// Close popup when clicking close button
closePopup.addEventListener('click', closePlayerPopup);
// Close popup when clicking outside the popup content
playerPopup.addEventListener('click', function(e) {
if (e.target === playerPopup) {
closePlayerPopup();
}
});
// Video control buttons
playPauseBtn.addEventListener('click', function() {
if (videoPlayer.paused) {
videoPlayer.play();
} else {
videoPlayer.pause();
}
});
backwardBtn.addEventListener('click', function() {
videoPlayer.currentTime = Math.max(0, videoPlayer.currentTime - 10);
});
forwardBtn.addEventListener('click', function() {
videoPlayer.currentTime = Math.min(videoPlayer.duration, videoPlayer.currentTime + 10);
});
fullscreenBtn.addEventListener('click', function() {
if (videoPlayer.requestFullscreen) {
videoPlayer.requestFullscreen();
} else if (videoPlayer.webkitRequestFullscreen) {
videoPlayer.webkitRequestFullscreen();
} else if (videoPlayer.msRequestFullscreen) {
videoPlayer.msRequestFullscreen();
}
});
muteBtn.addEventListener('click', function() {
videoPlayer.muted = !videoPlayer.muted;
});
// Keyboard controls (active when popup is visible)
document.addEventListener('keydown', function(e) {
if (!playerPopup.classList.contains('active')) return;
switch(e.key) {
case ' ':
if (videoPlayer.paused) {
videoPlayer.play();
} else {
videoPlayer.pause();
}
e.preventDefault();
break;
case 'ArrowRight':
videoPlayer.currentTime = Math.min(videoPlayer.duration, videoPlayer.currentTime + 10);
e.preventDefault();
break;
case 'ArrowLeft':
videoPlayer.currentTime = Math.max(0, videoPlayer.currentTime - 10);
e.preventDefault();
break;
case 'f':
case 'F':
if (document.fullscreenElement) {
document.exitFullscreen();
} else if (videoPlayer.requestFullscreen) {
videoPlayer.requestFullscreen();
}
e.preventDefault();
break;
case 'm':
case 'M':
videoPlayer.muted = !videoPlayer.muted;
e.preventDefault();
break;
case 'Escape':
closePlayerPopup();
e.preventDefault();
break;
}
});
// Double-tap controls for mobile/touch devices
let lastTap = 0;
let tapTimeout;
videoPlayer.addEventListener('click', function(e) {
const currentTime = new Date().getTime();
const tapLength = currentTime - lastTap;
clearTimeout(tapTimeout);
if (tapLength < 500 && tapLength > 0) {
const playerRect = videoPlayer.getBoundingClientRect();
const clickX = e.clientX - playerRect.left;
const playerWidth = playerRect.width;
if (clickX < playerWidth / 3) {
videoPlayer.currentTime = Math.max(0, videoPlayer.currentTime - 10);
} else if (clickX > (playerWidth * 2) / 3) {
videoPlayer.currentTime = Math.min(videoPlayer.duration, videoPlayer.currentTime + 10);
} else {
if (videoPlayer.paused) {
videoPlayer.play();
} else {
videoPlayer.pause();
}
}
e.preventDefault();
} else {
tapTimeout = setTimeout(function() {
// Single tap action (no default action here)
}, 300);
}
lastTap = currentTime;
});
// Fix for fullscreen mode changes
document.addEventListener('fullscreenchange', handleFullscreenChange);
document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
document.addEventListener('mozfullscreenchange', handleFullscreenChange);
document.addEventListener('MSFullscreenChange', handleFullscreenChange);
function handleFullscreenChange() {
if (document.fullscreenElement ||
document.webkitFullscreenElement ||
document.mozFullScreenElement) {
console.log('Entered fullscreen mode');
const fullscreenVideo = document.fullscreenElement ||
document.webkitFullscreenElement ||
document.mozFullScreenElement;
if (fullscreenVideo === videoPlayer) {
videoPlayer.style.width = '100%';
videoPlayer.style.height = '100%';
}
} else {
console.log('Exited fullscreen mode');
videoPlayer.style.width = '100%';
videoPlayer.style.height = '100%';
}
}
// Initialize video data on page load
fetchVideoData();
</script>
</body>
</html>