Fix annotations not persisting across reload (keyword round-trip)
Keyword *values* don't survive JSON: clj->js stringifies :annotation/:root/clip refs and js->clj only re-keywordizes keys, so a reloaded annotation had string :type/:parent/:ref and was filtered out of the scene. Re-keywordize those fields on load (scene/restore-annotations) and give marks string ids (random-uuid was serializing as a UUID object). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0a842c8852
commit
ceccec8060
3 changed files with 32 additions and 2 deletions
|
|
@ -47,7 +47,7 @@
|
||||||
(fn [db [_ detail otio-raw scene-resp]]
|
(fn [db [_ detail otio-raw scene-resp]]
|
||||||
(let [parsed (otio/parse otio-raw)
|
(let [parsed (otio/parse otio-raw)
|
||||||
base (scene/from-otio parsed)
|
base (scene/from-otio parsed)
|
||||||
anns (get-in scene-resp [:scene :groups] {})] ; saved annotation layer
|
anns (scene/restore-annotations (get-in scene-resp [:scene :groups] {}))]
|
||||||
(-> db
|
(-> db
|
||||||
(assoc :project detail :page :editor)
|
(assoc :project detail :page :editor)
|
||||||
(assoc :fps (or (:fps scene-resp) (:fps parsed)))
|
(assoc :fps (or (:fps scene-resp) (:fps parsed)))
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@
|
||||||
(mapv (fn [{:keys [mark src]}]
|
(mapv (fn [{:keys [mark src]}]
|
||||||
(let [{:keys [xs]} (target-range scene mark)
|
(let [{:keys [xs]} (target-range scene mark)
|
||||||
[a b] src]
|
[a b] src]
|
||||||
{:id (random-uuid)
|
{:id (str (random-uuid)) ; string so it survives JSON
|
||||||
:start {:ref mark :at (- a xs)}
|
:start {:ref mark :at (- a xs)}
|
||||||
:end {:ref mark :at (- b xs)}}))
|
:end {:ref mark :at (- b xs)}}))
|
||||||
(slice (content-segments scene ctx) la lb)))
|
(slice (content-segments scene ctx) la lb)))
|
||||||
|
|
@ -219,6 +219,24 @@
|
||||||
(let [{:keys [xs xe]} (target-range scene ref)] (+ (- xe xs) at 1))
|
(let [{:keys [xs xe]} (target-range scene ref)] (+ (- xe xs) at 1))
|
||||||
at))
|
at))
|
||||||
|
|
||||||
|
(defn- restore-mark [m]
|
||||||
|
(cond-> m
|
||||||
|
(get-in m [:start :ref]) (update-in [:start :ref] keyword)
|
||||||
|
(get-in m [:end :ref]) (update-in [:end :ref] keyword)
|
||||||
|
(:track m) (update :track keyword)))
|
||||||
|
|
||||||
|
(defn restore-annotations
|
||||||
|
"Re-keywordize the fields that lose their keyword-ness through JSON: a saved
|
||||||
|
annotation round-trips with string :type/:parent and string mark :refs, so
|
||||||
|
put them back before merging into the (keyword-keyed) scene."
|
||||||
|
[anns]
|
||||||
|
(into {} (map (fn [[gid g]]
|
||||||
|
[gid (-> g
|
||||||
|
(update :type keyword)
|
||||||
|
(update :parent keyword)
|
||||||
|
(update :marks #(mapv restore-mark (or % []))))]))
|
||||||
|
anns))
|
||||||
|
|
||||||
(defn marks->rows
|
(defn marks->rows
|
||||||
"Render single-clip `marks` as editor rows (one {:s … :e …} per mark, frames
|
"Render single-clip `marks` as editor rows (one {:s … :e …} per mark, frames
|
||||||
normalised to mark time). 1:1 with `marks`, so row i pairs with mark i."
|
normalised to mark time). 1:1 with `marks`, so row i pairs with mark i."
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,18 @@
|
||||||
(is (= 0 (get-in (first marks) [:start :at])))
|
(is (= 0 (get-in (first marks) [:start :at])))
|
||||||
(is (= 30 (get-in (first marks) [:end :at])))))))
|
(is (= 30 (get-in (first marks) [:end :at])))))))
|
||||||
|
|
||||||
|
(deftest restore-annotations-rekeywordizes-json
|
||||||
|
(testing "a JSON-roundtripped annotation (string :type/:parent/:ref) is restored + resolves"
|
||||||
|
(let [json-like {:ann-1 {:type "annotation" :parent "root" :name "x"
|
||||||
|
:marks [{:id "m1" :start {:ref "clip-a" :at 0}
|
||||||
|
:end {:ref "clip-a" :at -1}}]}}
|
||||||
|
g (:ann-1 (s/restore-annotations json-like))]
|
||||||
|
(is (= :annotation (:type g)))
|
||||||
|
(is (= :root (:parent g)))
|
||||||
|
(is (= :clip-a (get-in g [:marks 0 :start :ref])))
|
||||||
|
(let [scene (assoc-in base [:groups :ann-1] g)]
|
||||||
|
(is (= [0 100] (:src (first (s/resolve scene :ann-1)))))))))
|
||||||
|
|
||||||
(deftest marks-to-rows-normalises-frames
|
(deftest marks-to-rows-normalises-frames
|
||||||
(testing "marks->rows is 1:1 with marks and normalises :at -1 to the length"
|
(testing "marks->rows is 1:1 with marks and normalises :at -1 to the length"
|
||||||
(let [rows (s/marks->rows base [{:id :m :start {:ref :clip-a :at 0}
|
(let [rows (s/marks->rows base [{:id :m :start {:ref :clip-a :at 0}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue