//! Read-only queries for agents (not journaled). use effectcraft_project::{GroupKind, ItemKind, Layer, Node, PropGroup}; use serde_json::{Value, json}; use super::{CommandSpec, b_p, comp_id, layer_p, str_p}; use crate::{EngineError, Result, Session, query}; fn list(s: &mut Session, p: &Value) -> Result { let filter = str_p(p, "filter").map(str::to_ascii_lowercase); let only = b_p(p, "enabledOnly").unwrap_or(false); let v: Vec = super::command_specs() .iter() .filter(|c| filter.as_ref().is_none_or(|f| c.id.to_ascii_lowercase().contains(f) || c.label.to_ascii_lowercase().contains(f))) .filter_map(|c| { let en = (c.enabled)(s); if only && en.is_err() { return None; } Some(json!({"id": c.id, "label": c.label, "menu": c.menu, "shortcut": c.shortcut, "params": c.params, "enabled": en.is_ok(), "why": en.err()})) }) .collect(); Ok(json!(v)) } fn summary(s: &mut Session, _: &Value) -> Result { let items: Vec = s .project .items .values() .map(|i| { let mut o = json!({"id": i.id.0, "name": i.name, "type": i.type_name(), "label": i.label.name(), "parent": i.parent.map(|p| p.0)}); if let Some((w, h)) = i.dimensions() { o["size"] = json!([w, h]); } if let Some(d) = i.duration() { o["duration"] = json!(d.seconds()); } if let ItemKind::Comp(c) = &i.kind { o["layers"] = json!(c.layers.len()); o["frameRate"] = json!(c.frame_rate.as_f64()); } o }) .collect(); Ok(json!({ "path": s.path, "dirty": s.is_dirty(), "bitDepth": s.project.settings.bit_depth.label(), "items": items, "activeComp": s.state.active_comp.map(|c| c.0), "time": s.time().seconds(), "selectedLayers": s.state.selected_layers.iter().map(|l| l.0).collect::>(), "undo": s.history.undo.iter().map(|u| u.0.clone()).collect::>(), })) } fn layer_json(l: &Layer, idx: usize) -> Value { json!({ "id": l.id.0, "index": idx, "name": l.name, "type": l.source.type_name(), "label": l.label.name(), "in": l.in_point.seconds(), "out": l.out_point.seconds(), "start": l.start_time.seconds(), "stretch": l.stretch, "blendMode": l.blend_mode.label(), "parent": l.parent.map(|p| p.0), "trackMatte": l.track_matte.map(|m| json!({"layer": m.layer.0, "kind": m.kind.label()})), "switches": serde_json::to_value(&l.switches).unwrap_or_default(), }) } fn comp_info(s: &mut Session, p: &Value) -> Result { let cid = comp_id(s, p)?; let c = s.project.comp(cid).ok_or(EngineError::NoComp)?; let name = s.project.item(cid).map(|i| i.name.clone()).unwrap_or_default(); Ok(json!({ "id": cid.0, "name": name, "width": c.width, "height": c.height, "frameRate": c.frame_rate.as_f64(), "duration": c.duration.seconds(), "workArea": [c.work_area.0.seconds(), c.work_area.1.seconds()], "background": c.background, "layers": c.layers.iter().enumerate().map(|(i, l)| layer_json(l, i + 1)).collect::>(), })) } fn group_json(g: &PropGroup, l: &Layer, t: effectcraft_time::Tick, depth: usize, max_depth: usize) -> Value { let children: Vec = if depth >= max_depth { vec![] } else { g.children .iter() .map(|c| match c { Node::Prop(p) => { let mut o = json!({"uid": p.uid, "match": p.match_id, "name": p.name, "value": p.value_at(l.layer_time(t)).to_json()}); if !p.keys.is_empty() { o["keys"] = json!( p.keys .iter() .map(|k| json!({"time": k.time.seconds(), "value": k.value.to_json(), "in": k.in_interp.label(), "out": k.out_interp.label()})) .collect::>() ); } if let Some(e) = &p.expr { o["expression"] = json!(e.text); } o } Node::Group(g) => group_json(g, l, t, depth + 1, max_depth), }) .collect() }; let mut o = json!({"uid": g.uid, "match": g.match_id, "name": g.name, "enabled": g.enabled, "children": children}); match &g.kind { GroupKind::Mask { mode, inverted, .. } => { o["mask"] = json!({"mode": mode.label(), "inverted": inverted}); } GroupKind::Effect { effect } => { o["effect"] = json!(effect); } _ => {} } o } fn layer_tree(s: &mut Session, p: &Value) -> Result { let (cid, lid) = layer_p(s, p, "layer.tree")?; let c = s.project.comp(cid).ok_or(EngineError::NoComp)?; let idx = c.index_of(lid).unwrap_or(0); let l = c.layer(lid).ok_or(EngineError::NoComp)?; let depth = p.get("depth").and_then(Value::as_u64).unwrap_or(16) as usize; let mut o = layer_json(l, idx); o["properties"] = group_json(&l.props, l, s.time(), 0, depth); Ok(o) } fn state(s: &mut Session, _: &Value) -> Result { Ok(serde_json::to_value(&s.state).unwrap_or_default()) } pub fn specs() -> Vec { vec![ query!("command.list", "List Commands", "{filter?, enabledOnly?}", list), query!("project.summary", "Project Summary", "{}", summary), query!("comp.info", "Composition Info", "{comp?}", comp_info), query!("layer.tree", "Layer Property Tree", "{layer?, depth?}", layer_tree), query!("editor.state", "Editor State", "{}", state), ] }