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).await.map_err(|e| {
35 PageError::EvaluationFailed(format!("Failed to create directory: {e}"))
36 })?;
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
118 .next_entry()
119 .await
120 .map_err(|e| PageError::EvaluationFailed(format!("Failed to read directory entry: {e}")))?
121 {
122 let src_path = entry.path();
123 let dst_path = dst.join(entry.file_name());
124
125 if src_path.is_dir() {
126 Box::pin(copy_dir_recursive(&src_path, &dst_path)).await?;
127 } else {
128 tokio::fs::copy(&src_path, &dst_path)
129 .await
130 .map_err(|e| PageError::EvaluationFailed(format!("Failed to copy file: {e}")))?;
131 }
132 }
133
134 Ok(())
135}