Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>YouTube Frame Randomizer</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #ff0000; | |
| --primary-dark: #cc0000; | |
| --background: #f9f9f9; | |
| --card-bg: #ffffff; | |
| --text: #333333; | |
| --text-light: #606060; | |
| --border: #e0e0e0; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Roboto', Arial, sans-serif; | |
| } | |
| body { | |
| background-color: var(--background); | |
| color: var(--text); | |
| min-height: 100vh; | |
| padding: 20px; | |
| } | |
| header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 30px; | |
| padding-bottom: 15px; | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .logo i { | |
| color: var(--primary); | |
| font-size: 2rem; | |
| } | |
| .logo h1 { | |
| font-size: 1.8rem; | |
| font-weight: 500; | |
| } | |
| .controls { | |
| display: flex; | |
| gap: 15px; | |
| align-items: center; | |
| } | |
| .count-selector { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| select { | |
| padding: 8px 12px; | |
| border-radius: 4px; | |
| border: 1px solid var(--border); | |
| background-color: var(--card-bg); | |
| color: var(--text); | |
| cursor: pointer; | |
| } | |
| button { | |
| padding: 8px 16px; | |
| background-color: var(--primary); | |
| color: white; | |
| border: none; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-weight: 500; | |
| transition: background-color 0.2s; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| button:hover { | |
| background-color: var(--primary-dark); | |
| } | |
| .grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
| gap: 20px; | |
| margin-top: 20px; | |
| } | |
| .video-card { | |
| background-color: var(--card-bg); | |
| border-radius: 8px; | |
| overflow: hidden; | |
| box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | |
| transition: transform 0.2s; | |
| } | |
| .video-card:hover { | |
| transform: translateY(-5px); | |
| } | |
| .thumbnail { | |
| width: 100%; | |
| height: 180px; | |
| object-fit: cover; | |
| cursor: pointer; | |
| } | |
| .video-info { | |
| padding: 12px; | |
| } | |
| .video-title { | |
| font-size: 1rem; | |
| font-weight: 500; | |
| margin-bottom: 8px; | |
| display: -webkit-box; | |
| -webkit-line-clamp: 2; | |
| -webkit-box-orient: vertical; | |
| overflow: hidden; | |
| } | |
| .video-channel { | |
| font-size: 0.9rem; | |
| color: var(--text-light); | |
| margin-bottom: 4px; | |
| } | |
| .video-views { | |
| font-size: 0.8rem; | |
| color: var(--text-light); | |
| } | |
| .attribution { | |
| margin-top: 30px; | |
| text-align: center; | |
| color: var(--text-light); | |
| font-size: 0.9rem; | |
| } | |
| .attribution a { | |
| color: var(--primary); | |
| text-decoration: none; | |
| } | |
| .attribution a:hover { | |
| text-decoration: underline; | |
| } | |
| @media (max-width: 768px) { | |
| header { | |
| flex-direction: column; | |
| gap: 15px; | |
| align-items: flex-start; | |
| } | |
| .controls { | |
| width: 100%; | |
| flex-direction: column; | |
| align-items: flex-start; | |
| } | |
| .grid { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| /* Loading animation */ | |
| .loading { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| height: 100px; | |
| } | |
| .spinner { | |
| width: 40px; | |
| height: 40px; | |
| border: 4px solid rgba(0, 0, 0, 0.1); | |
| border-radius: 50%; | |
| border-top-color: var(--primary); | |
| animation: spin 1s ease-in-out infinite; | |
| } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="logo"> | |
| <i class="fab fa-youtube"></i> | |
| <h1>YouTube Frame Randomizer</h1> | |
| </div> | |
| <div class="controls"> | |
| <div class="count-selector"> | |
| <label for="count">Frames:</label> | |
| <select id="count"> | |
| <option value="4">4</option> | |
| <option value="8" selected>8</option> | |
| <option value="12">12</option> | |
| <option value="16">16</option> | |
| </select> | |
| </div> | |
| <button id="randomize"> | |
| <i class="fas fa-random"></i> | |
| Randomize | |
| </button> | |
| </div> | |
| </header> | |
| <div id="loading" class="loading"> | |
| <div class="spinner"></div> | |
| </div> | |
| <div id="grid" class="grid"></div> | |
| <div class="attribution"> | |
| <p>Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a></p> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const grid = document.getElementById('grid'); | |
| const randomizeBtn = document.getElementById('randomize'); | |
| const countSelect = document.getElementById('count'); | |
| const loading = document.getElementById('loading'); | |
| // Sample video data (in a real app, you might fetch this from an API) | |
| const videoDatabase = [ | |
| { id: 'dQw4w9WgXcQ', title: 'Never Gonna Give You Up', channel: 'Rick Astley', views: '1.2B views' }, | |
| { id: '9bZkp7q19f0', title: 'Gangnam Style', channel: 'PSY', views: '4.5B views' }, | |
| { id: 'kJQP7kiw5Fk', title: 'Despacito', channel: 'Luis Fonsi', views: '7.9B views' }, | |
| { id: 'JGwWNGJdvx8', title: 'Shape of You', channel: 'Ed Sheeran', views: '5.9B views' }, | |
| { id: 'RgKAFK5djSk', title: 'See You Again', channel: 'Wiz Khalifa', views: '5.9B views' }, | |
| { id: 'OPf0YbXqDm0', title: 'Uptown Funk', channel: 'Mark Ronson', views: '4.7B views' }, | |
| { id: 'kJQP7kiw5Fk', title: 'Minecraft Theme', channel: 'C418', views: '200M views' }, | |
| { id: 'JGwWNGJdvx8', title: 'Baby Shark Dance', channel: 'Pinkfong', views: '13B views' }, | |
| { id: 'RgKAFK5djSk', title: 'Learning to Fly', channel: 'Pink Floyd', views: '45M views' }, | |
| { id: 'OPf0YbXqDm0', title: 'Bohemian Rhapsody', channel: 'Queen', views: '1.8B views' }, | |
| { id: 'dQw4w9WgXcQ', title: 'Sweet Child O\' Mine', channel: 'Guns N\' Roses', views: '1.5B views' }, | |
| { id: '9bZkp7q19f0', title: 'Hotel California', channel: 'Eagles', views: '1B views' }, | |
| { id: 'kJQP7kiw5Fk', title: 'Smells Like Teen Spirit', channel: 'Nirvana', views: '1.4B views' }, | |
| { id: 'JGwWNGJdvx8', title: 'Imagine', channel: 'John Lennon', views: '500M views' }, | |
| { id: 'RgKAFK5djSk', title: 'Billie Jean', channel: 'Michael Jackson', views: '1.2B views' }, | |
| { id: 'OPf0YbXqDm0', title: 'Like a Rolling Stone', channel: 'Bob Dylan', views: '300M views' } | |
| ]; | |
| // Function to get random videos | |
| function getRandomVideos(count) { | |
| const shuffled = [...videoDatabase].sort(() => 0.5 - Math.random()); | |
| return shuffled.slice(0, count); | |
| } | |
| // Function to generate thumbnail URL | |
| function getThumbnailUrl(videoId) { | |
| // Randomly select a thumbnail version (1-4) for variety | |
| const version = Math.floor(Math.random() * 4) + 1; | |
| return `https://img.youtube.com/vi/${videoId}/${version}.jpg`; | |
| } | |
| // Function to display videos | |
| function displayVideos(videos) { | |
| grid.innerHTML = ''; | |
| videos.forEach(video => { | |
| const card = document.createElement('div'); | |
| card.className = 'video-card'; | |
| card.innerHTML = ` | |
| <img src="${getThumbnailUrl(video.id)}" alt="${video.title}" class="thumbnail"> | |
| <div class="video-info"> | |
| <h3 class="video-title">${video.title}</h3> | |
| <p class="video-channel">${video.channel}</p> | |
| <p class="video-views">${video.views}</p> | |
| </div> | |
| `; | |
| grid.appendChild(card); | |
| }); | |
| } | |
| // Initial load | |
| function loadVideos() { | |
| loading.style.display = 'flex'; | |
| grid.style.display = 'none'; | |
| // Simulate loading delay | |
| setTimeout(() => { | |
| const count = parseInt(countSelect.value); | |
| const randomVideos = getRandomVideos(count); | |
| displayVideos(randomVideos); | |
| loading.style.display = 'none'; | |
| grid.style.display = 'grid'; | |
| }, 800); | |
| } | |
| // Event listeners | |
| randomizeBtn.addEventListener('click', loadVideos); | |
| countSelect.addEventListener('change', loadVideos); | |
| // First load | |
| loadVideos(); | |
| }); | |
| </script> | |
| </body> | |
| </html> |