diff --git a/src/components/tags/ape_tag.rs b/src/components/tags/ape_tag.rs index 5c0bb924..20f89d28 100644 --- a/src/components/tags/ape_tag.rs +++ b/src/components/tags/ape_tag.rs @@ -1,15 +1,17 @@ #![cfg(feature = "monkey")] use crate::{ - impl_tag, Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, Picture, Result, TagType, - ToAny, ToAnyTag, + impl_tag, Album, AnyTag, AudioTag, AudioTagEdit, AudioTagWrite, MimeType, Picture, PictureType, + Result, TagType, ToAny, ToAnyTag, }; pub use ape::Tag as ApeInnerTag; use ape::Item; +use byteorder::{LittleEndian, ReadBytesExt}; use filepath::FilePath; use std::fs::File; +use std::io::{Cursor, Seek, SeekFrom}; use std::path::Path; #[cfg(feature = "duration")] @@ -153,7 +155,11 @@ impl AudioTagEdit for ApeTag { } fn set_front_cover(&mut self, cover: Picture) { - // TODO + self.remove_front_cover(); + + if let Ok(item) = ape::Item::from_binary("Cover Art (Front)", cover.data) { + self.inner.set_item(item) + } } fn remove_front_cover(&mut self) { @@ -169,7 +175,11 @@ impl AudioTagEdit for ApeTag { } fn set_back_cover(&mut self, cover: Picture) { - // TODO + self.remove_back_cover(); + + if let Ok(item) = ape::Item::from_binary("Cover Art (Back)", cover.data) { + self.inner.set_item(item) + } } fn remove_back_cover(&mut self) { @@ -177,7 +187,8 @@ impl AudioTagEdit for ApeTag { } fn pictures(&self) -> Option> { - todo!() + // TODO + None } // Track number and total tracks are stored together as num/total? @@ -274,7 +285,42 @@ impl AudioTagEdit for ApeTag { fn get_picture(item: &Item) -> Option { if let ape::ItemValue::Binary(bin) = &item.value { - // TODO + if !bin.is_empty() { + let pic_type = match &*item.key { + "Cover Art (Front)" => PictureType::CoverFront, + "Cover Art (Back)" => PictureType::CoverBack, + _ => PictureType::Other, + }; + + let data_pos: Option = + if bin.starts_with(&[b'\xff']) || bin.starts_with(&[b'\x89']) { + Some(0) + } else { + bin.iter().find(|x| x == &&b'\0').map(|pos| *pos as usize) + }; + + if let Some(pos) = data_pos { + let mut cursor = Cursor::new(bin.clone()); + + if cursor.seek(SeekFrom::Start((pos + 1) as u64)).is_ok() { + if let Ok(mime) = cursor.read_u32::() { + if let Some(mime_type) = match &mime.to_le_bytes() { + b"PNG\0" => Some(MimeType::Png), + b"JPEG" => Some(MimeType::Jpeg), + _ => None, + } { + cursor.set_position(0_u64); + + return Some(Picture { + pic_type, + mime_type, + data: cursor.into_inner(), + }); + } + } + } + } + } } None diff --git a/src/lib.rs b/src/lib.rs index 25b1213c..b7e35dfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,7 +74,7 @@ clippy::cast_precision_loss, clippy::cast_sign_loss, clippy::cast_possible_wrap, - clippy::clippy::cast_possible_truncation, + clippy::cast_possible_truncation, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::doc_markdown, diff --git a/tests/io.rs b/tests/io.rs index 7154cc18..1307ec75 100644 --- a/tests/io.rs +++ b/tests/io.rs @@ -39,18 +39,19 @@ macro_rules! add_tags { Picture { pic_type: PictureType::CoverFront, mime_type: MimeType::Jpeg, - data: vec![0; 10], + data: vec![0, 74, 80, 69, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0], }, Picture { pic_type: PictureType::CoverBack, mime_type: MimeType::Jpeg, - data: vec![0; 11], + data: vec![0, 74, 80, 69, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0], }, ); - let file_name = stringify!($file); + let file = stringify!($file); - if file_name != stringify!("tests/assets/a.wav") { + // Skip this since RIFF INFO doesn't store images + if file != stringify!("tests/assets/a.wav") { println!("Setting front cover"); tag.set_front_cover(covers.0.clone()); assert_eq!(tag.front_cover(), Some(covers.0));