anni_flac/blocks/
comment.rs1use crate::prelude::*;
2use crate::utils::*;
3use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4use std::collections::HashMap;
5use std::fmt;
6use std::fmt::Display;
7use std::io::{Read, Write};
8
9pub struct BlockVorbisComment {
23 pub vendor_string: String,
27
28 pub comments: Vec<UserComment>,
32 }
35
36impl BlockVorbisComment {
37 pub fn push(&mut self, comment: UserComment) {
38 self.comments.push(comment);
39 }
40
41 #[inline]
42 pub fn len(&self) -> usize {
43 self.comments.len()
44 }
45
46 #[inline]
47 pub fn is_empty(&self) -> bool {
48 self.len() == 0
49 }
50
51 pub fn clear(&mut self) {
52 self.comments.clear()
53 }
54
55 pub fn to_map(&self) -> HashMap<String, &UserComment> {
56 let mut map: HashMap<_, _> = Default::default();
57 for comment in self.comments.iter() {
58 if !(map.contains_key(&comment.key()) && comment.value().is_empty()) {
60 map.insert(comment.key(), comment);
61 }
62 }
63 map
64 }
65}
66
67impl Decode for BlockVorbisComment {
68 fn from_reader<R: Read>(reader: &mut R) -> Result<Self> {
69 let vendor_length = reader.read_u32::<LittleEndian>()?;
70 let vendor_string = take_string(reader, vendor_length as usize)?;
71 let comment_number = reader.read_u32::<LittleEndian>()?;
72 let mut comments = Vec::with_capacity(comment_number as usize);
73
74 for _ in 0..comment_number {
75 comments.push(UserComment::from_reader(reader)?);
76 }
77
78 Ok(BlockVorbisComment {
79 vendor_string,
80 comments,
81 })
82 }
83}
84
85#[cfg(feature = "async")]
86#[async_trait::async_trait]
87impl AsyncDecode for BlockVorbisComment {
88 async fn from_async_reader<R>(reader: &mut R) -> Result<Self>
89 where
90 R: AsyncRead + Unpin + Send,
91 {
92 let vendor_length = reader.read_u32_le().await?;
93 let vendor_string = take_string_async(reader, vendor_length as usize).await?;
94 let comment_number = reader.read_u32_le().await?;
95 let mut comments = Vec::with_capacity(comment_number as usize);
96
97 for _ in 0..comment_number {
98 comments.push(UserComment::from_async_reader(reader).await?);
99 }
100
101 Ok(BlockVorbisComment {
102 vendor_string,
103 comments,
104 })
105 }
106}
107
108impl Encode for BlockVorbisComment {
109 fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
110 writer.write_u32::<LittleEndian>(self.vendor_string.len() as u32)?;
111 writer.write_all(self.vendor_string.as_bytes())?;
112 writer.write_u32::<LittleEndian>(self.comments.len() as u32)?;
113 for comment in self.comments.iter() {
114 comment.write_to(writer)?;
115 }
116 Ok(())
117 }
118}
119
120impl fmt::Debug for BlockVorbisComment {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 let mut prefix = "".to_owned();
123 if let Some(width) = f.width() {
124 prefix = " ".repeat(width);
125 }
126 writeln!(
127 f,
128 "{prefix}vendor string: {}",
129 self.vendor_string,
130 prefix = prefix
131 )?;
132 writeln!(f, "{prefix}comments: {}", self.len(), prefix = prefix)?;
133 for (i, c) in self.comments.iter().enumerate() {
134 write!(f, "{}", prefix)?;
135 writeln!(
136 f,
137 "{prefix}comment[{}]: {}={}",
138 i,
139 c.key_raw(),
140 c.value(),
141 prefix = prefix
142 )?;
143 }
144 Ok(())
145 }
146}
147
148impl fmt::Display for BlockVorbisComment {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 for c in self.comments.iter() {
151 writeln!(f, "{}", c.comment)?;
152 }
153 Ok(())
154 }
155}
156
157#[derive(Debug)]
158pub struct UserComment {
159 comment: String,
163 value_offset: Option<usize>,
164}
165
166impl UserComment {
167 pub fn new(comment: String) -> Self {
168 let value_offset = comment.find('=');
169 Self {
170 comment,
171 value_offset,
172 }
173 }
174
175 pub fn key(&self) -> String {
176 self.key_raw().to_ascii_uppercase()
177 }
178
179 pub fn key_raw(&self) -> &str {
180 match self.value_offset {
181 Some(offset) => &self.comment[..offset],
182 None => &self.comment,
183 }
184 }
185
186 pub fn is_key_uppercase(&self) -> bool {
187 let key = match self.value_offset {
188 Some(offset) => &self.comment[..offset],
189 None => &self.comment,
190 };
191
192 key.chars().all(|c| !c.is_ascii_lowercase())
193 }
194
195 pub fn value(&self) -> &str {
196 match self.value_offset {
197 Some(offset) => &self.comment[offset + 1..],
198 None => &self.comment[self.comment.len()..],
199 }
200 }
201
202 pub fn len(&self) -> usize {
203 self.comment.len()
204 }
205
206 pub fn entry(&self) -> String {
207 self.comment.clone()
208 }
209
210 pub fn is_empty(&self) -> bool {
211 self.comment.is_empty()
212 }
213
214 pub fn clear(&mut self) {
215 self.comment.clear();
216 self.value_offset = None;
217 }
218}
219
220impl Decode for UserComment {
221 fn from_reader<R: Read>(reader: &mut R) -> Result<Self> {
222 let length = reader.read_u32::<LittleEndian>()?;
223 let comment = take_string(reader, length as usize)?;
224 Ok(UserComment::new(comment))
225 }
226}
227
228#[cfg(feature = "async")]
229#[async_trait::async_trait]
230impl AsyncDecode for UserComment {
231 async fn from_async_reader<R>(reader: &mut R) -> Result<Self>
232 where
233 R: AsyncRead + Unpin + Send,
234 {
235 let length = reader.read_u32_le().await?;
236 let comment = take_string_async(reader, length as usize).await?;
237 Ok(UserComment::new(comment))
238 }
239}
240
241impl Encode for UserComment {
242 fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
243 writer.write_u32::<LittleEndian>(self.comment.len() as u32)?;
244 writer.write_all(self.comment.as_bytes())?;
245 Ok(())
246 }
247}
248
249pub trait UserCommentExt {
250 fn title<S>(value: S) -> Self
251 where
252 S: Display;
253 fn artist<S>(value: S) -> Self
254 where
255 S: Display;
256 fn album<S>(value: S) -> Self
257 where
258 S: Display;
259 fn date<S>(value: S) -> Self
260 where
261 S: Display;
262 fn track_number<S>(value: S) -> Self
263 where
264 S: Display;
265 fn track_total<S>(value: S) -> Self
266 where
267 S: Display;
268 fn disc_number<S>(value: S) -> Self
269 where
270 S: Display;
271 fn disc_total<S>(value: S) -> Self
272 where
273 S: Display;
274 fn album_artist<S>(value: S) -> Self
275 where
276 S: Display;
277}
278
279impl UserCommentExt for UserComment {
280 fn title<S>(value: S) -> Self
281 where
282 S: Display,
283 {
284 Self::new(format!("TITLE={}", value))
285 }
286
287 fn artist<S>(value: S) -> Self
288 where
289 S: Display,
290 {
291 Self::new(format!("ARTIST={}", value))
292 }
293
294 fn album<S>(value: S) -> Self
295 where
296 S: Display,
297 {
298 Self::new(format!("ALBUM={}", value))
299 }
300
301 fn date<S>(value: S) -> Self
302 where
303 S: Display,
304 {
305 Self::new(format!("DATE={}", value))
306 }
307
308 fn track_number<S>(value: S) -> Self
309 where
310 S: Display,
311 {
312 Self::new(format!("TRACKNUMBER={}", value))
313 }
314
315 fn track_total<S>(value: S) -> Self
316 where
317 S: Display,
318 {
319 Self::new(format!("TRACKTOTAL={}", value))
320 }
321
322 fn disc_number<S>(value: S) -> Self
323 where
324 S: Display,
325 {
326 Self::new(format!("DISCNUMBER={}", value))
327 }
328
329 fn disc_total<S>(value: S) -> Self
330 where
331 S: Display,
332 {
333 Self::new(format!("DISCTOTAL={}", value))
334 }
335
336 fn album_artist<S>(value: S) -> Self
337 where
338 S: Display,
339 {
340 Self::new(format!("ALBUMARTIST={}", value))
341 }
342}