fix: defer video seek until seekable, flush on loadedmetadata (iOS)
The previous fix still failed on iOS: at the first tap the element isn't seekable (readyState 0), so the seek in engage-play! was dropped, and the existing on-loadedmetadata seek is guarded by (when-not @play) — already true by then — so it was skipped too, playing from 0. Now seek-video! stashes the target when the element isn't seekable yet, and loadedmetadata/canplay flush it (regardless of play state). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
5c58af9036
commit
7585dd4e7f
1 changed files with 27 additions and 6 deletions
|
|
@ -15,6 +15,7 @@
|
|||
(defonce body-scroll-el (atom nil)) ; the vertical (tracks) scroll container
|
||||
(defonce playhead-el (atom nil)) ; the single full-height playhead overlay
|
||||
(defonce played-track (atom nil)) ; last track auto-scrolled into view during playback
|
||||
(defonce pending-seek (atom nil)) ; seconds to seek to once the element is seekable (iOS)
|
||||
(defonce play (atom nil)) ; {:ctx :segs :fps :idx} while playing, else nil
|
||||
(defonce active-insert! (atom nil)) ; the live content-editor's (insert! link) fn
|
||||
(declare commit-link!)
|
||||
|
|
@ -67,7 +68,22 @@
|
|||
|
||||
(defn- seek-video! [fps source-frame]
|
||||
(when (and @video-el source-frame)
|
||||
(set! (.-currentTime @video-el) (/ source-frame fps))))
|
||||
(let [v @video-el secs (/ source-frame fps)]
|
||||
;; iOS only honours currentTime once the element is seekable (readyState
|
||||
;; >= HAVE_METADATA). Before that — a deep link, or the very first tap that
|
||||
;; triggers loading — stash the target and apply it on loadedmetadata.
|
||||
(if (>= (.-readyState v) 1)
|
||||
(do (reset! pending-seek nil) (set! (.-currentTime v) secs))
|
||||
(reset! pending-seek secs)))))
|
||||
|
||||
(defn- flush-pending-seek!
|
||||
"Apply a seek that was deferred while the element wasn't seekable. Returns true
|
||||
if it did one."
|
||||
[]
|
||||
(when-let [secs @pending-seek]
|
||||
(reset! pending-seek nil)
|
||||
(when-let [v @video-el] (set! (.-currentTime v) secs))
|
||||
true))
|
||||
|
||||
(defn- follow!
|
||||
([fps zoom playhead] (follow! fps zoom playhead false))
|
||||
|
|
@ -219,13 +235,18 @@
|
|||
;; (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.
|
||||
;; metadata is now loaded ⇒ the element is finally seekable. Apply any
|
||||
;; seek we deferred (the iOS deep-link / first-tap case); otherwise, if
|
||||
;; we're not driving playback, align the element to the playhead.
|
||||
: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)))))
|
||||
(when-not (flush-pending-seek!)
|
||||
(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-can-play (fn [_] (flush-pending-seek!)) ; belt-and-suspenders for iOS
|
||||
:on-play (fn [_] (engage-play!))
|
||||
:on-pause (fn [_] (disengage!))
|
||||
:ref (fn [n] (when n (reset! video-el n)))}])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue