viewpoint_core/page/video_io/
mod.rs1use std::path::{Path, PathBuf};
6
7use tracing::info;
8
9use crate::error::PageError;
10
11use super::video::Video;
12
13impl Video {
14 pub async fn save_as(&self, path: impl AsRef<Path>) -> Result<(), PageError> {
29 let current_path = self.path().await?;
30 let target_path = path.as_ref();
31
32 if let Some(parent) = target_path.parent() {
34 tokio::fs::create_dir_all(parent)
35 .await
36 .map_err(|e| PageError::EvaluationFailed(format!("Failed to create directory: {e}")))?;
37 }
38
39 tokio::fs::copy(¤t_path, target_path)
41 .await
42 .map_err(|e| PageError::EvaluationFailed(format!("Failed to copy video: {e}")))?;
43
44 let state = self.state.read().await;
46 if let Some(ref video_path) = state.video_path {
47 if let Ok(content) = tokio::fs::read_to_string(video_path).await {
49 if let Ok(metadata) = serde_json::from_str::<serde_json::Value>(&content) {
50 if let Some(frames_dir) = metadata.get("frames_dir").and_then(|v| v.as_str()) {
51 let source_frames = PathBuf::from(frames_dir);
52 if source_frames.exists() {
53 let target_frames = target_path.with_extension("frames");
54 copy_dir_recursive(&source_frames, &target_frames).await?;
55 }
56 }
57 }
58 }
59 }
60
61 info!("Video saved to {:?}", target_path);
62 Ok(())
63 }
64
65 pub async fn delete(&self) -> Result<(), PageError> {
80 let state = self.state.read().await;
81
82 if let Some(ref video_path) = state.video_path {
83 if let Ok(content) = tokio::fs::read_to_string(video_path).await {
85 if let Ok(metadata) = serde_json::from_str::<serde_json::Value>(&content) {
86 if let Some(frames_dir) = metadata.get("frames_dir").and_then(|v| v.as_str()) {
87 let frames_path = PathBuf::from(frames_dir);
88 if frames_path.exists() {
89 let _ = tokio::fs::remove_dir_all(&frames_path).await;
90 }
91 }
92 }
93 }
94
95 tokio::fs::remove_file(video_path)
97 .await
98 .map_err(|e| PageError::EvaluationFailed(format!("Failed to delete video: {e}")))?;
99
100 info!("Video deleted");
101 }
102
103 Ok(())
104 }
105}
106
107pub(super) async fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<(), PageError> {
109 tokio::fs::create_dir_all(dst)
110 .await
111 .map_err(|e| PageError::EvaluationFailed(format!("Failed to create directory: {e}")))?;
112
113 let mut entries = tokio::fs::read_dir(src)
114 .await
115 .map_err(|e| PageError::EvaluationFailed(format!("Failed to read directory: {e}")))?;
116
117 while let Some(entry) = entries.next_entry().await.map_err(|e| {
118 PageError::EvaluationFailed(format!("Failed to read directory entry: {e}"))
119 })? {
120 let src_path = entry.path();
121 let dst_path = dst.join(entry.file_name());
122
123 if src_path.is_dir() {
124 Box::pin(copy_dir_recursive(&src_path, &dst_path)).await?;
125 } else {
126 tokio::fs::copy(&src_path, &dst_path)
127 .await
128 .map_err(|e| PageError::EvaluationFailed(format!("Failed to copy file: {e}")))?;
129 }
130 }
131
132 Ok(())
133}