lofty-rs icon indicating copy to clipboard operation
lofty-rs copied to clipboard

Writing metadata to specific mp3 causes error BadFrame("MODE", Text)

Open obsoleszenz opened this issue 2 years ago • 1 comments

Reproducer

Code

#!/usr/bin/env -S cargo +nightly -Zscript
```cargo
[dependencies]
lofty = "0.17.1"
```
use lofty::{ItemKey, LoftyError, Probe, Tag, TagExt, TaggedFileExt};
use std::path::Path;

#[derive(Default, Debug, Clone)]
pub struct Metadata {
    pub artist: String,
    pub title: String,
    pub bpm: f32,
    pub key: String,
    pub comment: String,
    pub mood: String,
}

pub fn write_metadata(
    path: impl AsRef<Path> + Copy,
    metadata: &Metadata,
) -> Result<(), LoftyError> {
    let mut tagged_file = Probe::open(path)?.read()?;

    let tag = match tagged_file.primary_tag_mut() {
        Some(primary_tag) => primary_tag,
        None => {
            if let Some(first_tag) = tagged_file.first_tag_mut() {
                first_tag
            } else {
                let tag_type = tagged_file.primary_tag_type();

                eprintln!("WARN: No tags found, creating a new tag of type `{tag_type:?}`");
                tagged_file.insert_tag(Tag::new(tag_type));

                tagged_file.primary_tag_mut().unwrap()
            }
        }
    };

    tag.insert_text(ItemKey::TrackArtist, metadata.artist.clone());
    tag.insert_text(ItemKey::TrackTitle, metadata.title.clone());
    tag.insert_text(ItemKey::Bpm, metadata.bpm.to_string());
    tag.insert_text(ItemKey::InitialKey, metadata.key.clone());
    tag.insert_text(ItemKey::Comment, metadata.comment.clone());
    tag.insert_text(ItemKey::Mood, metadata.mood.clone());
    tag.save_to_path(path)?;
    Ok(())
}


fn main() {
    write_metadata("./07-tehotu-encoder-6c2b060a.mp3", &Metadata {
        artist: "tehotu".to_string(),
        title: "encoder".to_string(),
        bpm: 42.0,
        key: "12A".to_string(),
        comment: "testcomment".to_string(),
        mood: "testmood".to_string()
    }).expect("Failed writing metadata");

Summary

Writing metadata fails because of error

Expected behavior

Writing metadata doesn't fail

Assets

https://we.tl/t-zYjiGOjteR 07-tehotu-encoder-6c2b060a.mp3 e2

obsoleszenz avatar Dec 30 '23 20:12 obsoleszenz

So what's happening:

  1. The file has a TXXX:MODE frame
  2. The Id3v2Tag -> Tag conversion tries to convert all TXXX descriptions to ItemKeys
  3. TXXX:MODE is stored as ItemKey::Unknown("MODE")
  4. The Tag -> Id3v2Tag creates a MODE text frame (not a TXXX frame!), as the description is 4 characters long, it is believed to be a normal frame ID
  5. The Id3v2Tag now fails verification, as text frames are expected to start with 'T'

That's a pretty major oversight on my part. I hadn't accounted for 4 character descriptions. :smile:

When I get to implementing #302, I can further restrict the TXXX -> TagItem conversion.

Serial-ATA avatar Dec 31 '23 09:12 Serial-ATA