Last active
January 12, 2026 19:40
-
-
Save gphg/40ce3a19fff039cbbb1a1830ea72e0d1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Lite Loop (Dufs Auto-List)</title> | |
| <style> | |
| * { box-sizing: border-box; } | |
| body, html { | |
| margin: 0; padding: 0; height: 100%; | |
| background: #000; color: #fff; | |
| font-family: system-ui, sans-serif; | |
| display: flex; flex-direction: column; overflow: hidden; | |
| } | |
| /* Video at the top */ | |
| #player { | |
| flex: 1; display: flex; align-items: center; justify-content: center; | |
| background: #000; overflow: hidden; | |
| } | |
| video { max-width: 100%; max-height: 100%; outline: none; } | |
| /* Controls at the bottom */ | |
| #ui { | |
| background: #111; padding: 15px; | |
| display: flex; flex-direction: column; gap: 10px; | |
| border-top: 1px solid #333; | |
| } | |
| .nav-group { | |
| display: flex; | |
| gap: 10px; | |
| width: 100%; | |
| } | |
| select, button { | |
| padding: 12px; border-radius: 8px; border: 1px solid #444; | |
| background: #222; color: #fff; font-size: 16px; width: 100%; | |
| } | |
| button { | |
| background: #333; | |
| border: 1px solid #555; | |
| font-weight: bold; | |
| cursor: pointer; | |
| transition: background 0.2s; | |
| } | |
| button:hover { background: #444; } | |
| button:active { background: #555; } | |
| @media (min-width: 600px) { | |
| #ui { flex-direction: row; padding: 15px 10%; align-items: center; } | |
| .nav-group { width: auto; flex-shrink: 0; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="player"> | |
| <video id="v" autoplay loop playsinline controls></video> | |
| </div> | |
| <div id="ui"> | |
| <select id="list" onchange="playSelected()"> | |
| <option>Loading files...</option> | |
| </select> | |
| <div class="nav-group"> | |
| <button onclick="prev()">Prev</button> | |
| <button onclick="next()">Next</button> | |
| </div> | |
| </div> | |
| <script> | |
| const v = document.getElementById('v'); | |
| const list = document.getElementById('list'); | |
| // Fetch from Dufs | |
| async function load() { | |
| try { | |
| // Get dufs here: https://github.com/sigoden/dufs | |
| const res = await fetch('./?json'); | |
| const data = await res.json(); | |
| // Match "File" and common video extensions | |
| const files = data.paths.filter(i => | |
| i.path_type === "File" && | |
| i.name.match(/\.(mp4|webm|mov|m4v)$/i) | |
| ); | |
| list.innerHTML = ''; // Clear loading | |
| if (files.length === 0) { | |
| list.innerHTML = '<option>No videos found</option>'; | |
| return; | |
| } | |
| files.forEach(f => { | |
| const opt = document.createElement('option'); | |
| opt.value = f.name; | |
| opt.textContent = f.name; | |
| list.appendChild(opt); | |
| }); | |
| // Auto-play first video | |
| playSelected(); | |
| } catch (e) { | |
| list.innerHTML = '<option>Error loading list</option>'; | |
| } | |
| } | |
| function playSelected() { | |
| const name = list.value; | |
| if (!name) return; | |
| v.src = encodeURIComponent(name); | |
| v.load(); | |
| v.play(); | |
| } | |
| function next() { | |
| if (list.options.length <= 1) return; | |
| let nextIndex = list.selectedIndex + 1; | |
| if (nextIndex >= list.options.length) nextIndex = 0; | |
| list.selectedIndex = nextIndex; | |
| playSelected(); | |
| } | |
| function prev() { | |
| if (list.options.length <= 1) return; | |
| let prevIndex = list.selectedIndex - 1; | |
| if (prevIndex < 0) prevIndex = list.options.length - 1; | |
| list.selectedIndex = prevIndex; | |
| playSelected(); | |
| } | |
| // Listen for video end to auto-advance if loop is removed | |
| // (currently video has 'loop' attribute, but these functions allow manual override) | |
| load(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment