tarekziade HF Staff commited on
Commit
5995ba2
·
unverified ·
2 Parent(s): e0185eeb1ec984

Merge pull request #12 from huggingface/fix-video-paths

Browse files
Files changed (2) hide show
  1. backend/server.py +11 -2
  2. ui/static/app.js +25 -8
backend/server.py CHANGED
@@ -20,11 +20,20 @@ import argparse
20
  import json
21
  import mimetypes
22
  import os
 
23
  import sys
24
  import urllib.parse
25
  from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
26
  from pathlib import Path
27
 
 
 
 
 
 
 
 
 
28
  REPO_ROOT = Path(__file__).resolve().parent.parent
29
  INDEXING_DIR = REPO_ROOT / "indexing"
30
  UI_STATIC_DIR = REPO_ROOT / "ui" / "static"
@@ -55,9 +64,9 @@ def _load_allowed_paths() -> set[str]:
55
  if isinstance(data, list):
56
  for entry in data:
57
  if isinstance(entry, str):
58
- allowed.add(entry)
59
  elif isinstance(entry, dict) and "path" in entry:
60
- allowed.add(entry["path"])
61
  return allowed
62
 
63
 
 
20
  import json
21
  import mimetypes
22
  import os
23
+ import re
24
  import sys
25
  import urllib.parse
26
  from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
27
  from pathlib import Path
28
 
29
+ # Video meta entries are stored as "<path> @ <t>s"; strip the timestamp so the
30
+ # allow-list contains the underlying file path.
31
+ _VIDEO_FRAME_SUFFIX = re.compile(r" @ \d+(?:\.\d+)?s$")
32
+
33
+
34
+ def _strip_frame_suffix(entry: str) -> str:
35
+ return _VIDEO_FRAME_SUFFIX.sub("", entry)
36
+
37
  REPO_ROOT = Path(__file__).resolve().parent.parent
38
  INDEXING_DIR = REPO_ROOT / "indexing"
39
  UI_STATIC_DIR = REPO_ROOT / "ui" / "static"
 
64
  if isinstance(data, list):
65
  for entry in data:
66
  if isinstance(entry, str):
67
+ allowed.add(_strip_frame_suffix(entry))
68
  elif isinstance(entry, dict) and "path" in entry:
69
+ allowed.add(_strip_frame_suffix(entry["path"]))
70
  return allowed
71
 
72
 
ui/static/app.js CHANGED
@@ -214,41 +214,58 @@ function makeCard(hit, kind, modality, dark) {
214
  const card = document.createElement("div");
215
  card.className = "card" + (dark ? " dark" : "");
216
 
217
- const path = hit.path;
218
- const name = path.split("/").pop();
219
- const parent = path.replace(/\/[^/]+$/, "");
 
 
 
 
 
 
 
 
 
 
 
220
 
221
  if (kind === "image") {
222
  const thumb = document.createElement("a");
223
  thumb.className = "thumb";
224
- thumb.href = fileUrl(path);
225
  thumb.target = "_blank";
226
  thumb.rel = "noopener";
227
  const img = document.createElement("img");
228
  img.loading = "lazy";
229
  img.alt = name;
230
  img.addEventListener("load", () => img.classList.add("loaded"));
231
- img.src = fileUrl(path);
232
  thumb.appendChild(img);
233
  card.appendChild(thumb);
234
  } else if (kind === "video") {
235
  const thumb = document.createElement("a");
236
  thumb.className = "thumb";
237
- thumb.href = fileUrl(path);
 
238
  thumb.target = "_blank";
239
  thumb.rel = "noopener";
240
  const v = document.createElement("video");
241
  v.muted = true;
242
  v.preload = "metadata";
243
  v.addEventListener("loadeddata", () => v.classList.add("loaded"));
244
- v.src = fileUrl(path);
 
 
 
 
 
245
  thumb.appendChild(v);
246
  card.appendChild(thumb);
247
  }
248
 
249
  const nameEl = document.createElement("a");
250
  nameEl.className = "card-name";
251
- nameEl.href = fileUrl(path);
252
  nameEl.target = "_blank";
253
  nameEl.rel = "noopener";
254
  nameEl.style.color = "inherit";
 
214
  const card = document.createElement("div");
215
  card.className = "card" + (dark ? " dark" : "");
216
 
217
+ // Video meta entries are stored as "<path> @ <t>s" — split them so the
218
+ // file request uses the real path and the player can seek to that frame.
219
+ const rawPath = hit.path;
220
+ let filePath = rawPath;
221
+ let timestamp = null;
222
+ if (kind === "video") {
223
+ const m = rawPath.match(/^(.*) @ (\d+(?:\.\d+)?)s$/);
224
+ if (m) {
225
+ filePath = m[1];
226
+ timestamp = parseFloat(m[2]);
227
+ }
228
+ }
229
+ const name = rawPath.split("/").pop();
230
+ const parent = filePath.replace(/\/[^/]+$/, "");
231
 
232
  if (kind === "image") {
233
  const thumb = document.createElement("a");
234
  thumb.className = "thumb";
235
+ thumb.href = fileUrl(filePath);
236
  thumb.target = "_blank";
237
  thumb.rel = "noopener";
238
  const img = document.createElement("img");
239
  img.loading = "lazy";
240
  img.alt = name;
241
  img.addEventListener("load", () => img.classList.add("loaded"));
242
+ img.src = fileUrl(filePath);
243
  thumb.appendChild(img);
244
  card.appendChild(thumb);
245
  } else if (kind === "video") {
246
  const thumb = document.createElement("a");
247
  thumb.className = "thumb";
248
+ const frag = timestamp != null ? `#t=${timestamp}` : "";
249
+ thumb.href = fileUrl(filePath) + frag;
250
  thumb.target = "_blank";
251
  thumb.rel = "noopener";
252
  const v = document.createElement("video");
253
  v.muted = true;
254
  v.preload = "metadata";
255
  v.addEventListener("loadeddata", () => v.classList.add("loaded"));
256
+ if (timestamp != null) {
257
+ v.addEventListener("loadedmetadata", () => {
258
+ try { v.currentTime = timestamp; } catch (_) {}
259
+ });
260
+ }
261
+ v.src = fileUrl(filePath) + frag;
262
  thumb.appendChild(v);
263
  card.appendChild(thumb);
264
  }
265
 
266
  const nameEl = document.createElement("a");
267
  nameEl.className = "card-name";
268
+ nameEl.href = fileUrl(filePath);
269
  nameEl.target = "_blank";
270
  nameEl.rel = "noopener";
271
  nameEl.style.color = "inherit";