huggingtube / all_videos.html
vericudebuget's picture
Upload 11 files
4c11f5a verified
raw
history blame
14 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HuggingTube</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Montserrat', sans-serif;
}
:root {
--bg-primary: #0a0f18;
--bg-secondary: #141e2f;
--text-primary: #ffffff;
--text-secondary: #adbac7;
--accent: #2188ff;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: var(--bg-primary);
color: var(--text-primary);
}
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem 1rem;
background-color: var(--bg-secondary);
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
}
.logo {
color: var(--text-primary);
font-size: 1.2rem;
font-weight: bold;
display: flex;
align-items: center;
}
.logo i {
color: var(--accent);
margin-right: 0.5rem;
}
.search-bar {
flex-grow: 1;
max-width: 600px;
margin: 0 1rem;
}
.search-bar input {
width: 100%;
padding: 0.5rem 1rem;
border-radius: 20px;
border: 1px solid var(--text-secondary);
background-color: var(--bg-primary);
color: var(--text-primary);
}
.user-actions i {
margin-left: 1rem;
cursor: pointer;
}
main {
display: flex;
margin-top: 56px; /* Header height */
}
.sidebar {
width: 240px;
padding: 1rem;
position: fixed;
top: 56px;
bottom: 0;
overflow-y: auto;
background-color: var(--bg-primary);
}
.sidebar-item {
display: flex;
align-items: center;
padding: 0.75rem 1rem;
cursor: pointer;
border-radius: 10px;
}
.sidebar-item:hover {
background-color: var(--bg-secondary);
}
.sidebar-item i {
margin-right: 1rem;
width: 20px;
}
.content {
flex-grow: 1;
padding: 1rem;
margin-left: 240px;
}
.video-grid {
display: flex;
flex-direction: column;
}
.video-card {
display: flex;
align-items: center;
padding: 0.5rem;
border-bottom: 1px solid var(--text-secondary);
}
.thumbnail {
width: 80px;
height: 80px;
margin-right: 1rem;
border-radius: 10px;
overflow: hidden;
}
.thumbnail img {
width: 100%;
height: 100%;
object-fit: cover;
}
.video-info {
flex-grow: 1;
}
.video-title {
font-size: 1rem;
font-weight: bold;
margin-bottom: 0.25rem;
}
.video-uploader {
font-size: 0.9rem;
color: var(--text-secondary);
}
.video-date {
font-size: 0.9rem;
color: var(--text-secondary);
}
.subtitle {
display: flex;
align-items: center;
margin-left: 1rem;
padding: 0.25rem 0.5rem;
border-radius: 5px;
background-color: rgb(0, 72, 85);
}
.subtitle_icon {
width: auto;
height: 1em;
margin-right: 0.5rem;
}
.subtitle_text {
font-size: 0.9rem;
color: #000000;
}
.video-url {
font-size: 0.8rem;
color: var(--text-secondary);
margin-top: 0.25rem;
}
/* Mobile styles */
@media (max-width: 768px) {
.video-card {
flex-direction: column;
align-items: flex-start;
}
.thumbnail {
width: 100%;
height: 150px;
margin-bottom: 1rem;
}
.video-info {
width: 100%;
}
}
</style>
</head>
<body>
<header>
<div class="logo">
<i class="fab fa-youtube"></i>
<span>HuggingTube</span>
</div>
<div class="search-bar">
<input type="text" placeholder="Search">
</div>
<div class="user-actions" onclick="toggleVideoUpload()">
<i class="fas fa-video"></i>
<i class="fas fa-info-circle" onclick="toggleInfo()"></i>
</div>
<script>
function toggleVideoUpload() {
window.location.href = "upload.html";
}
function toggleInfo() {
window.location.href = "about.html";
}
</script>
</header>
<main>
<aside class="sidebar">
<div class="sidebar-item">
<i class="fas fa-home" onclick="homeInfo()"></i> Home
</div>
<div class="sidebar-item" onclick="toggleVideoUpload()">
<i class="fas fa-upload"></i> Upload
</div>
<div class="sidebar-item">
<i class="fas fa-photo-video"></i> All videos
</div>
</aside>
<section class="content" style="max-width: 100vw;">
<div class="video-grid" id="videoGrid">
<!-- Dynamic video cards will be inserted here -->
</div>
</section>
</main>
<nav class="mobile-nav">
<div class="mobile-nav-items">
<div class="mobile-nav-item">
<i class="fas fa-home"></i> Home
</div>
<div class="mobile-nav-item" onclick="toggleVideoUpload()">
<i class="fas fa-upload"></i> Upload
</div>
<div class="mobile-nav-item">
<i class="fas fa-photo-video"></i> Library
</div>
</div>
</nav>
<script>
async function fetchVideoMetadata() {
try {
// Clear the 'video_to_watch' key from localStorage on page load
localStorage.removeItem('video_to_watch');
// Fetch the video-index JSON data
const response = await fetch('https://huggingface.co/spaces/vericudebuget/ok4231/raw/main/metadata/video-index.json');
const videoIndexData = await response.json();
// Sort the video index data from latest to oldest
videoIndexData.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
// Base URLs for metadata and thumbnails
const baseUrl = 'https://huggingface.co/spaces/vericudebuget/ok4231/raw/main/metadata/';
const thumbnailBaseUrl = 'https://huggingface.co/spaces/vericudebuget/ok4231/raw/main/thumbnails/';
// Function to insert a video card in the correct position based on uploadTimestamp
const insertVideoCard = (videoCard, videoTimestamp) => {
const existingCards = document.querySelectorAll('.video-card');
let inserted = false;
for (const card of existingCards) {
const cardTimestamp = new Date(card.getAttribute('data-timestamp'));
if (videoTimestamp > cardTimestamp) {
card.parentNode.insertBefore(videoCard, card);
inserted = true;
break;
}
}
// If no cards are newer, append it to the end
if (!inserted) {
videoGrid.appendChild(videoCard);
}
};
// Function to encrypt the link
const encryptLink = (link, key) => {
// Simple XOR encryption for demonstration purposes
const encrypted = link.split('').map((char, i) => {
return String.fromCharCode(char.charCodeAt(0) ^ key.charCodeAt(i % key.length));
}).join('');
return btoa(encrypted); // base64 encode
};
// Loop through each URL in the sorted list and fetch the respective metadata
const videoGrid = document.getElementById('videoGrid');
for (let i = 0; i < videoIndexData.length; i++) {
let videoIndexUrl = videoIndexData[i].url;
// Extract only the file name (last part of the URL)
let fileName = videoIndexUrl.substring(videoIndexUrl.lastIndexOf('/') + 1);
// Create the full URL by appending the file name to the base URL
let finalUrl = baseUrl + encodeURIComponent(fileName);
try {
// Fetch metadata from the properly encoded URL
const videoResponse = await fetch(finalUrl);
const videoData = await videoResponse.json();
// Fix thumbnail URL by using the online location
let thumbnailUrl = thumbnailBaseUrl + encodeURIComponent(videoData.thumbnailLocation.substring(videoData.thumbnailLocation.lastIndexOf('/') + 1));
// Convert duration from seconds to mm:ss
const formatDuration = (duration) => {
if (duration === null || duration === undefined) return 'N/A';
const minutes = Math.floor(duration / 60);
const seconds = duration % 60;
return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
};
// Function to handle click event and store video index URL in localStorage
const handleVideoClick = () => {
const encryptedLink = encryptLink(finalUrl, 'JesusIsGod');
window.location.href = `video-player.html#${encryptedLink}`;
};
// Create a video card dynamically
const videoCard = document.createElement('div');
videoCard.classList.add('video-card');
videoCard.setAttribute('data-timestamp', new Date(videoData.uploadTimestamp).toISOString());
videoCard.innerHTML = `
<div class="thumbnail">
<img src="${thumbnailUrl}" alt="${videoData.title}">
</div>
<div class="video-info">
<h3 class="video-title">${videoData.title}</h3>
<p class="video-uploader">${videoData.uploader}</p>
<p class="video-date">${new Intl.DateTimeFormat('en-US', { month: 'long', day: 'numeric', year: 'numeric' }).format(new Date(videoData.uploadTimestamp))}</p>
${videoData.subtitleLocation && videoData.subtitleLocation.trim() !== "" ? `
<div class="subtitle">
<img class="subtitle_icon" src="https://cdn.iconscout.com/icon/free/png-512/free-subtitles-icon-download-in-svg-png-gif-file-formats--subtitle-text-translate-basic-multimedia-pack-user-interface-icons-4083807.png?f=webp&w=256">
<span class="subtitle_text">Subtitles</span>
</div>
` : ''}
</div>
`;
// Add event listeners for the thumbnail and title
videoCard.querySelector('.thumbnail img').addEventListener('click', handleVideoClick);
videoCard.querySelector('.video-title').addEventListener('click', handleVideoClick);
// Insert the video card in the correct position based on uploadTimestamp
const videoTimestamp = new Date(videoData.uploadTimestamp);
insertVideoCard(videoCard, videoTimestamp);
// Wait 0.3 seconds before fetching the next URL
await new Promise(resolve => setTimeout(resolve, 10));
} catch (videoError) {
;
}
}
} catch (error) {
console.error('Error fetching video metadata:', error);
}
}
// Call the function on page load
window.onload = fetchVideoMetadata;
</script>
</body>
</html>