Rust音频元数据处理库lofty的使用:高效读写MP3、FLAC等格式的ID3v2和APE标签

Rust音频元数据处理库lofty的使用:高效读写MP3、FLAC等格式的ID3v2和APE标签

Lofty logo

Lofty是一个用于解析、转换和写入各种音频格式元数据的Rust库。

支持的格式

Lofty支持多种音频格式的元数据处理,包括MP3、FLAC等格式的ID3v2和APE标签。

示例

以下是使用lofty库处理音频元数据的完整示例:

读取音频文件元数据

use lofty::{AudioFile, TaggedFileExt};
use std::path::Path;

fn read_audio_tags(file_path: &str) -> Result<(), lofty::error::LoftyError> {
    // 打开音频文件
    let path = Path::new(file_path);
    let tagged_file = lofty::read_from_path(path)?;

    // 获取主要标签(通常是最相关的标签)
    if let Some(tag) = tagged_file.primary_tag() {
        println!("主要标签类型: {:?}", tag.tag_type());
        
        // 读取常见元数据字段
        println!("标题: {:?}", tag.title());
        println!("艺术家: {:?}", tag.artist());
        println!("专辑: {:?}", tag.album());
        println!("年份: {:?}", tag.year());
        println!("音轨号: {:?}", tag.track());
        println!("流派: {:?}", tag.genre());
    }

    // 处理所有标签
    for tag in tagged_file.tags() {
        println!("标签类型: {:?}", tag.tag_type());
        // 可以在这里处理特定标签类型的特殊逻辑
    }

    Ok(())
}

写入音频文件元数据

use lofty::{Tag, TagType, ItemKey};
use std::path::Path;

fn write_audio_tags(file_path: &str) -> Result<(), lofty::error::LoftyError> {
    let path = Path::new(file_path);
    
    // 创建一个新的ID3v2标签
    let mut tag = Tag::new(TagType::Id3v2);
    
    // 设置常见元数据字段
    tag.insert_text(ItemKey::TrackTitle, "歌曲标题");
    tag.insert_text(ItemKey::TrackArtist, "艺术家名称");
    tag.insert_text(ItemKey::AlbumTitle, "专辑名称");
    tag.insert_text(ItemKey::TrackNumber, "1");
    tag.insert_text(ItemKey::Year, "2023");
    tag.insert_text(ItemKey::Genre, "流行");
    
    // 写入文件
    lofty::write_to_path(path, &tag)?;
    
    Ok(())
}

删除音频文件中的所有标签

use std::path::Path;

fn strip_all_tags(file_path: &str) -> Result<(), lofty::error::LoftyError> {
    let path = Path::new(file_path);
    
    // 从文件中读取所有标签
    let mut tagged_file = lofty::read_from_path(path)?;
    
    // 删除所有标签
    tagged_file.clear();
    
    // 保存修改
    tagged_file.save_to_path(path)?;
    
    Ok(())
}

完整示例

以下是一个完整的示例程序,演示了如何读取、修改和删除音频文件的元数据:

use lofty::{AudioFile, TaggedFileExt, Tag, TagType, ItemKey};
use std::path::Path;

fn main() -> Result<(), lofty::error::LoftyError> {
    let file_path = "test.mp3";
    
    // 示例1: 读取元数据
    println!("=== 读取音频元数据 ===");
    read_audio_metadata(file_path)?;
    
    // 示例2: 写入元数据
    println!("\n=== 写入音频元数据 ===");
    write_audio_metadata(file_path)?;
    read_audio_metadata(file_path)?;
    
    // 示例3: 删除所有元数据
    println!("\n=== 删除所有元数据 ===");
    remove_all_metadata(file_path)?;
    read_audio_metadata(file_path)?;
    
    Ok(())
}

fn read_audio_metadata(file_path: &str) -> Result<(), lofty::error::LoftyError> {
    let path = Path::new(file_path);
    let tagged_file = lofty::read_from_path(path)?;

    if let Some(tag) = tagged_file.primary_tag() {
        println!("主要标签类型: {:?}", tag.tag_type());
        println!("标题: {:?}", tag.title());
        println!("艺术家: {:?}", tag.artist());
        println!("专辑: {:?}", tag.album());
    } else {
        println!("文件没有元数据标签");
    }

    Ok(())
}

fn write_audio_metadata(file_path: &str) -> Result<(), lofty::error::LoftyError> {
    let path = Path::new(file_path);
    let mut tag = Tag::new(TagType::Id3v2);
    
    tag.insert_text(ItemKey::TrackTitle, "我的歌曲");
    tag.insert_text(ItemKey::TrackArtist, "音乐人");
    tag.insert_text(ItemKey::AlbumTitle, "我的专辑");
    
    lofty::write_to_path(path, &tag)?;
    Ok(())
}

fn remove_all_metadata(file_path: &str) -> Result<(), lofty::error::LoftyError> {
    let path = Path::new(file_path);
    let mut tagged_file = lofty::read_from_path(path)?;
    
    tagged_file.clear();
    tagged_file.save_to_path(path)?;
    
    Ok(())
}

使用说明

要使用lofty库,请将以下内容添加到您的Cargo.toml中:

[dependencies]
lofty = "0.22.4"

许可证

Lofty采用双重许可:

  • Apache License, Version 2.0
  • MIT license

您可以选择其中任一许可证。


1 回复

Rust音频元数据处理库lofty的使用指南

介绍

lofty是一个用于读取和写入音频文件元数据的Rust库,支持多种音频格式和标签类型。它可以高效处理MP3、FLAC、WAV、AAC等常见音频格式的ID3v2、APE和Vorbis注释等元数据标签。

主要特性:

  • 支持多种音频格式:MP3、FLAC、WAV、AIFF、MP4、AAC等
  • 支持多种标签类型:ID3v2、APE、Vorbis注释等
  • 提供统一的API处理不同格式的元数据
  • 高性能的元数据读写操作
  • 纯Rust实现,无外部依赖

安装

在Cargo.toml中添加依赖:

[dependencies]
lofty = "0.15"

基本使用方法

读取音频文件元数据

use lofty::{read_from_path, TaggedFileExt};

fn main() {
    // 读取音频文件
    let tagged_file = read_from_path("song.mp3").expect("Failed to read file");
    
    // 获取主标签(通常是ID3v2)
    if let Some(tag) = tagged_file.primary_tag() {
        println!("标题: {:?}", tag.title());
        println!("艺术家: {:?}", tag.artist());
        println!("专辑: {:?}", tag.album());
    }
    
    // 也可以访问特定类型的标签
    if let Some(id3v2_tag) = tagged_file.id3v2() {
        println!("ID3v2标签中的年份: {:?}", id3v2_tag.get("TYER").and_then(|f| f.text()));
    }
}

写入元数据

use lofty::{read_from_path, TaggedFileExt, Tag};
use lofty::id3::v2::Id3v2Tag;

fn main() {
    // 读取文件
    let mut tagged_file = read_from_path("song.mp3").expect("Failed to read file");
    
    // 创建或获取ID3v2标签
    let id3v2_tag = match tagged_file.id3v2() {
        Some(tag) => tag,
        None => {
            let new_tag = Id3v2Tag::new();
            tagged_file.insert_tag(new_tag);
            tagged_file.id3v2().unwrap()
        }
    };
    
    // 设置元数据
    id3v2_tag.set_title("新标题");
    id3v2_tag.set_artist("新艺术家");
    id3v2_tag.set_album("新专辑");
    
    // 保存修改
    tagged_file.save_to_path("song_updated.mp3").expect("Failed to save file");
}

处理FLAC文件的Vorbis注释

use lofty::{read_from_path, TaggedFileExt};

fn main() {
    let tagged_file = read_from_path("song.flac").expect("Failed to read file");
    
    if let Some(vorbis_comments) = tagged_file.vorbis_comments() {
        println!("FLAC Vorbis注释:");
        for (key, value) in vorbis_comments.iter() {
            println!("{}: {}", key, value);
        }
        
        // 添加自定义字段
        vorbis_comments.push("COMMENT", "这是一个Rust添加的注释");
    }
}

高级用法

批量处理音频文件

use std::path::Path;
use lofty::{read_from_path, TaggedFileExt};

fn process_directory(dir_path: &str) {
    let dir = Path::new(dir_path);
    
    for entry in dir.read_dir().expect("读取目录失败").flatten() {
        if let Some(ext) = entry.path().extension() {
            if ext == "mp3" || ext == "flac" {
                if let Ok(tagged_file) = read_from_path(entry.path()) {
                    println!("处理文件: {}", entry.path().display());
                    
                    if let Some(tag) = tagged_file.primary_tag() {
                        println!("  标题: {:?}", tag.title());
                    }
                }
            }
        }
    }
}

处理图片数据

use lofty::{read_from_path, TaggedFileExt};

fn extract_cover_art(file_path: &str) {
    let tagged_file = read_from_path(file_path).expect("Failed to read file");
    
    if let Some(id3v2_tag) = tagged_file.id3v2() {
        for frame in id3v2_tag.get("APIC").into_iter().flatten() {
            if let Some(picture) = frame.picture() {
                println!("发现封面图片: {}x{}, {}字节", 
                    picture.width(),
                    picture.height(),
                    picture.data().len());
                
                // 可以将图片数据保存到文件
                std::fs::write("cover.jpg", picture.data()).expect("写入图片失败");
            }
        }
    }
}

完整示例

下面是一个完整的音频元数据管理工具示例:

use lofty::{read_from_path, TaggedFileExt, Tag};
use lofty::id3::v2::Id3v2Tag;
use std::io::{self, Write};
use std::path::Path;

fn main() -> io::Result<()> {
    println!("音频元数据管理工具");
    
    // 获取用户输入的文件路径
    print!("请输入音频文件路径: ");
    io::stdout().flush()?;
    let mut file_path = String::new();
    io::stdin().read_line(&mut file_path)?;
    let file_path = file_path.trim();
    
    // 读取音频文件
    let mut tagged_file = match read_from_path(file_path) {
        Ok(file) => file,
        Err(e) => {
            eprintln!("读取文件失败: {}", e);
            return Ok(());
        }
    };
    
    // 显示当前元数据
    display_metadata(&tagged_file);
    
    // 询问用户是否要修改元数据
    print!("是否要修改元数据? (y/n): ");
    io::stdout().flush()?;
    let mut choice = String::new();
    io::stdin().read_line(&mut choice)?;
    
    if choice.trim().to_lowercase() == "y" {
        // 获取用户输入的新元数据
        let mut title = String::new();
        let mut artist = String::new();
        let mut album = String::new();
        
        print!("输入新标题: ");
        io::stdout().flush()?;
        io::stdin().read_line(&mut title)?;
        
        print!("输入新艺术家: ");
        io::stdout().flush()?;
        io::stdin().read_line(&mut artist)?;
        
        print!("输入新专辑: ");
        io::stdout().flush()?;
        io::stdin().read_line(&mut album)?;
        
        // 创建或获取ID3v2标签
        let id3v2_tag = match tagged_file.id3v2() {
            Some(tag) => tag,
            None => {
                let new_tag = Id3v2Tag::new();
                tagged_file.insert_tag(new_tag);
                tagged_file.id3v2().unwrap()
            }
        };
        
        // 更新元数据
        id3v2_tag.set_title(title.trim());
        id3v2_tag.set_artist(artist.trim());
        id3v2_tag.set_album(album.trim());
        
        // 保存修改
        if let Err(e) = tagged_file.save_to_path(file_path) {
            eprintln!("保存修改失败: {}", e);
        } else {
            println!("元数据已成功更新!");
        }
    }
    
    Ok(())
}

fn display_metadata(tagged_file: &impl TaggedFileExt) {
    println!("\n当前元数据:");
    
    // 显示主标签信息
    if let Some(tag) = tagged_file.primary_tag() {
        println!("标题: {:?}", tag.title().unwrap_or("无"));
        println!("艺术家: {:?}", tag.artist().unwrap_or("无"));
        println!("专辑: {:?}", tag.album().unwrap_or("无"));
    }
    
    // 显示特定格式的额外信息
    if let Some(id3v2_tag) = tagged_file.id3v2() {
        if let Some(year) = id3v2_tag.get("TYER").and_then(|f| f.text()) {
            println!("年份: {}", year);
        }
    }
    
    if let Some(vorbis_comments) = tagged_file.vorbis_comments() {
        println!("\nVorbis注释:");
        for (key, value) in vorbis_comments.iter() {
            println!("{}: {}", key, value);
        }
    }
}

注意事项

  1. 修改文件时,建议先备份原始文件
  2. 不同音频格式支持的标签类型不同:
    • MP3: ID3v1, ID3v2, APE
    • FLAC: Vorbis注释
    • MP4/AAC: iTunes风格标签
  3. 某些字段在不同标签类型中的名称可能不同

lofty提供了强大的音频元数据处理能力,适合构建音乐播放器、音乐库管理工具等需要处理音频元数据的应用。

回到顶部