Mobile remote: per-track trim (in/out) + waveform + times + scrub/seek + gap
- Queue cards expand to a detail panel with the waveform, elapsed/total/remaining times, draggable in/out handles, scrub-to-seek and a 'pausa dopo' gap. - /api/peaks now also returns exact duration (samples/8000) so non-playing tracks have correct times/trim without relying on the output media probe. - Service worker switched to network-first (+v2) so UI updates aren't masked by a stale cache; output.js probeDurations hardened (load()+timeout fallback). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
f3f4d0f81e
commit
c0230ee1d6
5 files changed
+167
-19
No files matched your search
+7
-3
@@ -287,10 +287,14 @@ function probeDurations(paths) {
|
||||
paths.forEach(p => {
|
||||
// A <video> element reads duration for both audio and video files.
|
||||
const a = document.createElement('video');
|
||||
a.preload = 'metadata';
|
||||
a.onloadedmetadata = () => { results.push({ path: p, duration: isFinite(a.duration) ? a.duration : 0 }); finish(); };
|
||||
a.onerror = () => { results.push({ path: p, duration: 0 }); finish(); };
|
||||
a.preload = 'metadata'; a.muted = true;
|
||||
let done = false;
|
||||
const ok = (dur) => { if (done) return; done = true; results.push({ path: p, duration: isFinite(dur) && dur > 0 ? dur : 0 }); finish(); };
|
||||
a.onloadedmetadata = () => ok(a.duration);
|
||||
a.onerror = () => ok(0);
|
||||
setTimeout(() => ok(0), 6000); // never hang if metadata never fires
|
||||
a.src = toFileURL(p);
|
||||
a.load(); // some Chromium builds need an explicit load() for detached media
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user