Add region filter bar and navigation buttons for video clips

This commit is contained in:
zwitschi committed 2026-07-27 10:35:20 +02:00
1 parent d12d5e5414
commit 1c7ce1dd0a
4 files changed
+410 -29

No files matched your search

+103 -7
View File
@@ -10,6 +10,10 @@
const nowPlaying = document.getElementById("nowPlaying");
const npName = document.getElementById("npName");
const npTime = document.getElementById("npTime");
const npLocation = document.getElementById("npLocation");
const prevBtn = document.getElementById("prevBtn");
const nextBtn = document.getElementById("nextBtn");
const regionBar = document.getElementById("regionBar");
const csBtns = document.querySelectorAll(".cs-btn[data-cam]");
// ---- State ----
@@ -126,6 +130,33 @@
}
}
// ---- Prev/Next navigation ----
function findClipIndex(clip) {
const sameCam = (allVideos[clip.cam] && allVideos[clip.cam].videos) || [];
return sameCam.findIndex(function (c) {
return c.timestamp === clip.timestamp && c.filename === clip.filename;
});
}
function prevClip() {
if (!currentClip) return;
const sameCam =
(allVideos[currentClip.cam] && allVideos[currentClip.cam].videos) || [];
const idx = findClipIndex(currentClip);
if (idx > 0) playClip(sameCam[idx - 1]);
}
function nextClip() {
if (!currentClip) return;
const sameCam =
(allVideos[currentClip.cam] && allVideos[currentClip.cam].videos) || [];
const idx = findClipIndex(currentClip);
if (idx > -1 && sameCam[idx + 1]) playClip(sameCam[idx + 1]);
}
prevBtn.addEventListener("click", prevClip);
nextBtn.addEventListener("click", nextClip);
// ---- Playback ----
function playClip(clip) {
if (!clip) return;
@@ -160,6 +191,7 @@
nowPlaying.hidden = false;
npName.textContent = clip.filename;
npTime.textContent = prettyTs(clip.timestamp);
npLocation.textContent = clip.location || "";
updateCamButtons(clip.cam);
}
@@ -180,6 +212,7 @@
badgeText.textContent = target.camDisplay;
npName.textContent = target.filename;
npLocation.textContent = target.location || "";
player.addEventListener("loadedmetadata", function onMeta() {
player.removeEventListener("loadedmetadata", onMeta);
@@ -206,12 +239,7 @@
if (!currentClip) return;
const sameCam =
(allVideos[currentClip.cam] && allVideos[currentClip.cam].videos) || [];
const idx = sameCam.findIndex(function (c) {
return (
c.timestamp === currentClip.timestamp &&
c.filename === currentClip.filename
);
});
const idx = findClipIndex(currentClip);
if (idx > -1 && sameCam[idx + 1]) playClip(sameCam[idx + 1]);
});
@@ -234,7 +262,7 @@
}
});
// ---- Keyboard shortcuts: 1-6 for camera angles ----
// ---- Keyboard shortcuts: 1-6 for camera angles, ArrowLeft/Right for prev/next ----
const camOrder = [
"front",
"left_repeater",
@@ -258,10 +286,78 @@
if (videos.length > 0) playClip(videos[0]);
}
}
if (e.key === "ArrowLeft") {
e.preventDefault();
prevClip();
}
if (e.key === "ArrowRight") {
e.preventDefault();
nextClip();
}
});
// ---- Region filter ----
let regionData = {};
function fetchRegions() {
fetch("/api/regions")
.then(function (r) {
return r.json();
})
.then(function (data) {
regionData = data.regions || {};
buildRegionButtons();
})
.catch(function (err) {
console.error("Failed to load regions:", err);
});
}
function buildRegionButtons() {
// Keep "All" button, remove any existing region buttons
var existing = regionBar.querySelectorAll(
".region-btn:not([data-region=''])",
);
existing.forEach(function (b) {
b.remove();
});
Object.keys(regionData).forEach(function (name) {
var btn = document.createElement("button");
btn.className = "region-btn";
btn.setAttribute("data-region", name);
btn.textContent = name + " (" + regionData[name].count + ")";
regionBar.appendChild(btn);
});
}
regionBar.addEventListener("click", function (e) {
var btn = e.target.closest(".region-btn");
if (!btn) return;
var region = btn.getAttribute("data-region");
// Update active state
regionBar.querySelectorAll(".region-btn").forEach(function (b) {
b.classList.toggle("active", b === btn);
});
if (!region) return; // "All" selected — no jump
var info = regionData[region];
if (!info || !info.first_timestamp) return;
// Jump to first front-camera clip for this region
var frontVideos = (allVideos["front"] && allVideos["front"].videos) || [];
var clip = frontVideos.find(function (c) {
return c.timestamp === info.first_timestamp;
});
if (clip) playClip(clip);
});
// ---- Init: fetch full video data, then auto-play front ----
function init() {
// Fetch regions data for the filter bar
fetchRegions();
fetch("/api/videos")
.then(function (r) {
return r.json();