Cover support for ape

This commit is contained in:
Serial 2021-05-16 21:12:38 -04:00
parent 26cfd2e59b
commit 16f4ecce0d
3 changed files with 58 additions and 11 deletions

View file

@ -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<Vec<Picture>> {
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<Picture> {
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<usize> =
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::<LittleEndian>() {
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

View file

@ -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,

View file

@ -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));