portable_audio_library/serialization/
mod.rs1use crate::{
2 compression::{get_compression, CompressionType},
3 error::PortableAudioLibraryResult,
4};
5use serde::{Deserialize, Serialize};
6use std::{
7 fs::File,
8 io::{Cursor, Read, Seek, Write},
9 path::PathBuf,
10};
11
12pub type Playlist = String;
14
15const U64_SIZE: usize = std::mem::size_of::<u64>();
16const PROGRESS_BAR_TEMPLATE: &str = "{spinner:.green} {msg} [{wide_bar}] {pos}/{len} ({eta})";
17const PROGRESS_CHARS: &str = "=> ";
18const CHECK_GREEN: &str = "\x1b[32m✓\x1b[0m";
19
20#[derive(Debug, Clone, Default, PartialEq, PartialOrd, Serialize, Deserialize)]
22pub struct Metadata {
23 pub name: String,
24 pub compression_type: CompressionType,
25 pub audios: Vec<AudioMetadata>,
26}
27
28#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
30pub struct AudioMetadata {
31 pub name: String,
32 pub size: u64,
33 pub playlists: Vec<Playlist>,
34
35 #[serde(skip_serializing, skip_deserializing)]
36 pub path: PathBuf,
37}
38
39impl Metadata {
40 pub fn write_to_file(&mut self, path: impl Into<PathBuf>) -> PortableAudioLibraryResult<()> {
42 let path = path.into();
43
44 let compression = get_compression(&self.compression_type);
45 let mut compressed_audio_cursors = vec![];
46
47 let progress_bar = indicatif::ProgressBar::new(self.audios.len() as u64);
48 progress_bar.set_style(
49 indicatif::ProgressStyle::default_bar()
50 .template(PROGRESS_BAR_TEMPLATE)
51 .unwrap()
52 .progress_chars(PROGRESS_CHARS),
53 );
54 progress_bar.set_message("Compressing audio files");
55
56 for audio in &mut self.audios {
57 let mut audio_file = std::fs::File::open(&audio.path)?;
58 let mut compressed_audio_cursor = Cursor::new(Vec::new());
59
60 compression.compress(&mut audio_file, &mut compressed_audio_cursor)?;
61
62 audio.size = compressed_audio_cursor.get_ref().len() as u64;
63 compressed_audio_cursors.push(compressed_audio_cursor);
64
65 progress_bar.inc(1);
66 }
67
68 progress_bar.finish_and_clear();
69 println!("{} Compression done!", CHECK_GREEN);
70
71 let progress_bar = indicatif::ProgressBar::new(compressed_audio_cursors.len() as u64 + 1);
72 progress_bar.set_style(
73 indicatif::ProgressStyle::default_bar()
74 .template(PROGRESS_BAR_TEMPLATE)
75 .unwrap()
76 .progress_chars(PROGRESS_CHARS),
77 );
78 progress_bar.set_message("Writing to file");
79
80 let mut portable_audio_library_file = std::fs::File::create(path)?;
81 let serialized_portable_audio_library = bincode::serialize(&self)?;
82 let metadata_size = serialized_portable_audio_library.len() as u64;
83 portable_audio_library_file.write_all(&metadata_size.to_be_bytes())?;
84 portable_audio_library_file.write_all(&serialized_portable_audio_library)?;
85 progress_bar.inc(1);
86
87 for compressed_audio_cursor in compressed_audio_cursors {
88 portable_audio_library_file.write_all(compressed_audio_cursor.get_ref())?;
89 progress_bar.inc(1);
90 }
91
92 progress_bar.finish_and_clear();
93 println!("{} Writing done!", CHECK_GREEN);
94
95 Ok(())
96 }
97
98 pub fn read_from_file(
100 path: impl Into<PathBuf>,
101 directory_store: impl Into<PathBuf>,
102 ) -> PortableAudioLibraryResult<Metadata> {
103 let path = path.into();
104 let directory_store: PathBuf = directory_store.into();
105
106 let mut portable_audio_library_file = std::fs::File::open(path)?;
107
108 let mut metadata_size_buf = vec![0; U64_SIZE];
109 portable_audio_library_file.read_exact(&mut metadata_size_buf)?;
110 let metadata_size = u64::from_be_bytes(metadata_size_buf.try_into().unwrap());
111
112 let mut metadata_buf = vec![0; metadata_size as usize];
113 portable_audio_library_file.read_exact(&mut metadata_buf)?;
114 let mut metadata: Metadata = bincode::deserialize(&metadata_buf)?;
115
116 let compression_type = &metadata.compression_type;
117 let compression = get_compression(compression_type);
118
119 let progress_bar = indicatif::ProgressBar::new(metadata.audios.len() as u64);
120 progress_bar.set_style(
121 indicatif::ProgressStyle::default_bar()
122 .template(PROGRESS_BAR_TEMPLATE)
123 .unwrap()
124 .progress_chars(PROGRESS_CHARS),
125 );
126 progress_bar.set_message("Decompressing audio files");
127
128 let mut offset = metadata_size + U64_SIZE as u64;
129 for audio_metadata in &mut metadata.audios {
130 let mut buf = vec![0; audio_metadata.size as usize];
131 portable_audio_library_file.seek(std::io::SeekFrom::Start(offset))?;
132 portable_audio_library_file.read_exact(&mut buf)?;
133
134 let path = directory_store.join(&audio_metadata.name);
135
136 let mut audio_file = File::create(&path)?;
137
138 compression.decompress(&mut Cursor::new(buf), &mut audio_file)?;
139
140 audio_metadata.path = path;
141
142 offset += audio_metadata.size;
143
144 progress_bar.inc(1);
145 }
146
147 progress_bar.finish_and_clear();
148 println!("{} Decompression done!", CHECK_GREEN);
149
150 Ok(metadata)
151 }
152}