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,11 +216,34 @@
|
|||
(scroll-to-seg-track! segs local)))))))
|
||||
|
||||
(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
|
||||
;; the only thing that reliably starts iOS at the right time: iOS won't load
|
||||
;; the media until the first tap and ignores JS currentTime until the element
|
||||
;; is seekable (which happens very late), but it honours #t= during the media
|
||||
;; load itself — so the tap loads-and-starts at the right frame. (#t= also
|
||||
;; nudges iOS to render that frame instead of a black box.) currentTime still
|
||||
;; drives all in-session seeks once the element is loaded.
|
||||
;;
|
||||
;; Cache the src per clip so live playhead changes don't rewrite the fragment
|
||||
;; and reload the element — the fragment only matters at (re)load time.
|
||||
(let [cache (atom nil)] ; {:clip url :src "url#t=secs"}
|
||||
(fn []
|
||||
(let [clip @(rf/subscribe [::subs/clip-url])
|
||||
src (cond
|
||||
(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"
|
||||
;; (Re)loading a clip resets the element to currentTime 0, so a restored
|
||||
;; / deep-linked playhead would show in the UI but play from 0. Seek the
|
||||
;; element to the current playhead once its metadata is ready.
|
||||
;; 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
|
||||
|
|
@ -230,7 +253,7 @@
|
|||
(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)))}])
|
||||
:ref (fn [n] (when n (reset! video-el n)))}]))))
|
||||
|
||||
(defn- clip-label
|
||||
"Track-local clip label for the content segment whose :mark is `mid`."
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue