fix: start video at deep-linked time via #t= media fragment (iOS)
The real iOS issue: it won't load the media until the first tap and ignores JS currentTime until the element is seekable (populated very late), so every load/seek hack started playback from 0. A #t=<seconds> media fragment on the src is honoured by the media loader during the tap-triggered load itself, so it starts at the right frame (and renders that frame instead of black). Bake the deep-linked playhead into the src fragment, cached per clip so live playhead changes don't reload the element; currentTime still drives in-session seeks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a62af2584b
commit
d9059ad132
1 changed files with 38 additions and 15 deletions
|
|
@ -216,21 +216,44 @@
|
||||||
(scroll-to-seg-track! segs local)))))))
|
(scroll-to-seg-track! segs local)))))))
|
||||||
|
|
||||||
(defn video-monitor []
|
(defn video-monitor []
|
||||||
[:video {:src @(rf/subscribe [::subs/clip-url]) :controls true :preload "auto"
|
;; The src carries a #t= media fragment for the deep-linked playhead. That is
|
||||||
:plays-inline true :webkit-playsinline "true"
|
;; the only thing that reliably starts iOS at the right time: iOS won't load
|
||||||
;; (Re)loading a clip resets the element to currentTime 0, so a restored
|
;; the media until the first tap and ignores JS currentTime until the element
|
||||||
;; / deep-linked playhead would show in the UI but play from 0. Seek the
|
;; is seekable (which happens very late), but it honours #t= during the media
|
||||||
;; element to the current playhead once its metadata is ready.
|
;; load itself — so the tap loads-and-starts at the right frame. (#t= also
|
||||||
:on-loaded-metadata
|
;; nudges iOS to render that frame instead of a black box.) currentTime still
|
||||||
(fn [_]
|
;; drives all in-session seeks once the element is loaded.
|
||||||
(when-not @play
|
;;
|
||||||
(let [segs @(rf/subscribe [::subs/segments])
|
;; Cache the src per clip so live playhead changes don't rewrite the fragment
|
||||||
fps @(rf/subscribe [::subs/fps])
|
;; and reload the element — the fragment only matters at (re)load time.
|
||||||
ph @(rf/subscribe [::subs/playhead])]
|
(let [cache (atom nil)] ; {:clip url :src "url#t=secs"}
|
||||||
(seek-video! fps (scene/local->source segs ph)))))
|
(fn []
|
||||||
:on-play (fn [_] (engage-play!))
|
(let [clip @(rf/subscribe [::subs/clip-url])
|
||||||
:on-pause (fn [_] (disengage!))
|
src (cond
|
||||||
:ref (fn [n] (when n (reset! video-el n)))}])
|
(nil? clip) nil
|
||||||
|
(= clip (:clip @cache)) (:src @cache)
|
||||||
|
:else
|
||||||
|
(let [segs @(rf/subscribe [::subs/segments])
|
||||||
|
fps @(rf/subscribe [::subs/fps])
|
||||||
|
ph @(rf/subscribe [::subs/playhead])
|
||||||
|
t (max 0.001 (/ (scene/local->source segs ph) fps))
|
||||||
|
s (str clip "#t=" (.toFixed t 3))]
|
||||||
|
(reset! cache {:clip clip :src s})
|
||||||
|
s))]
|
||||||
|
[:video {:src src :controls true :preload "auto"
|
||||||
|
:plays-inline true :webkit-playsinline "true"
|
||||||
|
;; desktop / once-loaded: align to the playhead when metadata is
|
||||||
|
;; ready (iOS already arrived there via the #t= fragment).
|
||||||
|
:on-loaded-metadata
|
||||||
|
(fn [_]
|
||||||
|
(when-not @play
|
||||||
|
(let [segs @(rf/subscribe [::subs/segments])
|
||||||
|
fps @(rf/subscribe [::subs/fps])
|
||||||
|
ph @(rf/subscribe [::subs/playhead])]
|
||||||
|
(seek-video! fps (scene/local->source segs ph)))))
|
||||||
|
:on-play (fn [_] (engage-play!))
|
||||||
|
:on-pause (fn [_] (disengage!))
|
||||||
|
:ref (fn [n] (when n (reset! video-el n)))}]))))
|
||||||
|
|
||||||
(defn- clip-label
|
(defn- clip-label
|
||||||
"Track-local clip label for the content segment whose :mark is `mid`."
|
"Track-local clip label for the content segment whose :mark is `mid`."
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue