Skip to content

Instantly share code, notes, and snippets.

@gphg
Last active January 12, 2026 19:40
Show Gist options
  • Select an option

  • Save gphg/40ce3a19fff039cbbb1a1830ea72e0d1 to your computer and use it in GitHub Desktop.

Select an option

Save gphg/40ce3a19fff039cbbb1a1830ea72e0d1 to your computer and use it in GitHub Desktop.
<!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