aether_renderer_core/utils/
unzip_frames.rs1use std::fs::File;
2use std::path::{Path, PathBuf};
3use tempfile::tempdir;
4use zip::ZipArchive;
5
6pub fn unzip_frames(
8 zip_path: &Path,
9) -> Result<(PathBuf, tempfile::TempDir), Box<dyn std::error::Error>> {
10 let file = File::open(zip_path)
11 .map_err(|e| format!("❌ Failed to open zip file '{}': {}", zip_path.display(), e))?;
12
13 let mut archive =
14 ZipArchive::new(file).map_err(|e| format!("❌ Failed to read zip archive: {}", e))?;
15
16 let temp_dir = tempdir().map_err(|e| format!("❌ Failed to create temp dir: {}", e))?;
17
18 let temp_path = temp_dir.path().to_path_buf();
19
20 let mut extracted = 0u32;
21 for i in 0..archive.len() {
22 let mut file = archive
23 .by_index(i)
24 .map_err(|e| format!("❌ Failed to access file in zip at index {}: {}", i, e))?;
25
26 let filename = file.name().rsplit('/').next().unwrap_or("");
27 if !filename.ends_with(".png") {
28 continue;
29 }
30
31 let full_out_path = temp_path.join(filename);
32 let mut out_file = File::create(&full_out_path).map_err(|e| {
33 format!(
34 "❌ Failed to create output file '{}': {}",
35 full_out_path.display(),
36 e
37 )
38 })?;
39
40 std::io::copy(&mut file, &mut out_file).map_err(|e| {
41 format!(
42 "❌ Failed to copy content to '{}': {}",
43 full_out_path.display(),
44 e
45 )
46 })?;
47
48 println!("✅ Extracting: {}", full_out_path.display());
49 extracted += 1;
50 }
51
52 if extracted == 0 {
53 return Err("❌ No PNG files found in zip archive".into());
54 }
55
56 println!("🗂️ Extracted frames to: {}", temp_path.display());
57 Ok((temp_path.clone(), temp_dir))
58}
59
60#[cfg(test)]
61mod tests {
62 use super::unzip_frames;
63 use std::fs::File;
64 use std::io::Write;
65 use std::path::Path;
66 use tempfile::tempdir;
67 use zip::write::{FileOptions, ZipWriter};
68 use zip::CompressionMethod;
69
70 fn create_test_zip(path: &Path) -> zip::result::ZipResult<()> {
72 let file = File::create(path)?;
73 let mut zip = ZipWriter::new(file);
74 let options = FileOptions::default().compression_method(CompressionMethod::Stored);
75
76 zip.start_file("frame_0000.png", options)?;
77 zip.write_all(b"png0")?;
78 zip.start_file("frame_0001.png", options)?;
79 zip.write_all(b"png1")?;
80 zip.finish()?;
81 Ok(())
82 }
83
84 #[test]
85 fn unzip_frames_extracts_pngs() -> Result<(), Box<dyn std::error::Error>> {
86 let dir = tempdir()?;
87 let zip_path = dir.path().join("frames.zip");
88 create_test_zip(&zip_path)?;
89
90 let (out_dir, _guard) = unzip_frames(&zip_path)?;
91
92 let count = std::fs::read_dir(&out_dir)?.count();
93 assert_eq!(count, 2);
94 assert!(out_dir.join("frame_0000.png").exists());
95 assert!(out_dir.join("frame_0001.png").exists());
96
97 Ok(())
98 }
99}