diff --git a/um_audio/src/__fixtures__/mp3_with_id3v2_x3.bin b/um_audio/src/__fixtures__/mp3_with_id3v2_x3.bin new file mode 100644 index 0000000..dc4e1ba Binary files /dev/null and b/um_audio/src/__fixtures__/mp3_with_id3v2_x3.bin differ diff --git a/um_audio/src/lib.rs b/um_audio/src/lib.rs index 9a44b30..301449a 100644 --- a/um_audio/src/lib.rs +++ b/um_audio/src/lib.rs @@ -140,4 +140,11 @@ mod tests { let result = detect_audio_type(mp3_data).expect("failed to parse mp3"); assert_eq!(result, AudioType::MP3); } + + #[test] + fn test_mp3_multiple_id3() { + let mp3_data = include_bytes!("__fixtures__/mp3_with_id3v2_x3.bin"); + let result = detect_audio_type(mp3_data).expect("failed to parse mp3"); + assert_eq!(result, AudioType::MP3); + } } diff --git a/um_audio/src/metadata.rs b/um_audio/src/metadata.rs index 17afd46..6ad9f82 100644 --- a/um_audio/src/metadata.rs +++ b/um_audio/src/metadata.rs @@ -26,10 +26,12 @@ fn parse_id3_sync_safe_int(buffer: &[u8]) -> i32 { const MIN_ID3_HEADER_LEN: usize = 10; fn get_id3_header_size(buffer: &[u8], offset: usize) -> Result { - if buffer.len() < MIN_ID3_HEADER_LEN { + if buffer.len() < offset + MIN_ID3_HEADER_LEN { Err(AudioError::NeedMoreHeader(offset + MIN_ID3_HEADER_LEN))?; } + let buffer = &buffer[offset..]; + // TAG: ID3v1, 128 bytes if buffer.starts_with(b"TAG") { return Ok(128); @@ -66,10 +68,20 @@ fn get_ape_v2_size(buffer: &[u8], offset: usize) -> Result { } pub fn get_header_metadata_size(buffer: &[u8], offset: usize) -> Result { - let len = get_id3_header_size(buffer, offset)?; - if len != 0 { - Ok(len) - } else { - get_ape_v2_size(buffer, offset) + let mut offset = offset; + + // Workaround: Some files have multiple ID3v2 tags, max 5 times. + for _ in 0..5 { + let len = match get_id3_header_size(buffer, offset)? { + 0 => get_ape_v2_size(buffer, offset)?, + len => len, + }; + + if len == 0 { + break; + } + offset += len; } + + Ok(offset) }