use crate::mp4::{MP4, MP4Tags};
use crate::{AudexError, FileType, Result};
use std::path::Path;
pub fn parse_full_atom(data: &[u8]) -> Result<(u8, u32, &[u8])> {
if data.len() < 4 {
return Err(AudexError::ParseError("not enough data".to_string()));
}
let version = data[0];
let flags = u32::from_be_bytes([0, data[1], data[2], data[3]]);
let payload = &data[4..];
Ok((version, flags, payload))
}
pub fn name2key(name: &[u8]) -> String {
name.iter().map(|&b| b as char).collect()
}
pub fn key2name(key: &str) -> Result<Vec<u8>> {
let mut bytes = Vec::with_capacity(key.len());
for c in key.chars() {
let code = c as u32;
if code <= 255 {
bytes.push(code as u8);
} else {
return Err(AudexError::InvalidData(format!(
"Non-Latin-1 character U+{:04X} in atom key \"{}\"",
code, key
)));
}
}
Ok(bytes)
}
pub fn clear<P: AsRef<Path>>(path: P) -> Result<()> {
let mut mp4 = MP4::load(&path)?;
if mp4.tags.is_some() {
mp4.tags = Some(MP4Tags::default());
mp4.save()?;
}
Ok(())
}
#[cfg(feature = "async")]
pub async fn clear_async<P: AsRef<Path>>(path: P) -> Result<()> {
use crate::mp4::atom::Atoms;
let path = path.as_ref();
let mut file = tokio::fs::File::open(path).await?;
let atoms = Atoms::parse_async(&mut file).await?;
drop(file);
if atoms.path("moov.udta.meta.ilst").is_some() {
let empty_tags = MP4Tags::default();
empty_tags.save_async(path).await?;
}
Ok(())
}
pub fn item_sort_key(key: &str, value: &str) -> (usize, usize, String) {
let order = [
"©nam", "©ART", "©wrt", "©alb", "©gen", "gnre", "trkn", "disk", "©day", "cpil", "pgap",
"pcst", "tmpo", "©too", "----", "covr", "©lyr",
];
let key_prefix = if key.starts_with('©') && key.len() >= 4 {
key
} else {
key.get(..4).unwrap_or(key)
};
let order_index = order
.iter()
.position(|&x| x == key_prefix)
.unwrap_or(order.len());
(order_index, value.len(), value.to_string())
}
pub fn find_padding(
meta_children: &[crate::mp4::atom::MP4Atom],
) -> Option<&crate::mp4::atom::MP4Atom> {
let ilst_index = meta_children
.iter()
.position(|child| child.name == *b"ilst")?;
if ilst_index > 0 {
let prev = &meta_children[ilst_index - 1];
if prev.name == *b"free" {
return Some(prev);
}
}
if ilst_index + 1 < meta_children.len() {
let next = &meta_children[ilst_index + 1];
if next.name == *b"free" {
return Some(next);
}
}
None
}