【Rust GUI开发入门】编写一个本地音乐播放器(8. 从文件中提取歌曲元信息)

本系列教程对应的代码已开源在 Github zeedle

目的是从.mp3/.flac/.wav/...文件中提取歌曲名称/艺术家/音频时长信息/歌词信息/专辑封面

添加依赖

使用lofty这个全能解析库,将其添加到Cargo.toml中:

toml 复制代码
lofty = "0.22.4"

解析元信息

解析歌名/歌手/时长

这些信息在应用启动后,即刻被加载到音乐列表面板中(SongInfo已于前几篇文章中定义):

rust 复制代码
/// Read meta info from audio file `fp`, return a SongInfo
pub fn read_meta_info(fp: &PathBuf) -> Option<SongInfo> {
    if let Ok(tagged) = lofty::read_from_path(fp) {
        let dura = tagged.properties().duration().as_secs_f32();
        if let Some(tag) = tagged.primary_tag() {
            let song_name = tag.title();
            let song_name = song_name.as_deref().unwrap_or(
                fp.file_stem()
                    .map(|x| x.to_str())
                    .flatten()
                    .unwrap_or("unknown"),
            );
            let singer_name = tag.artist();
            let singer_name = singer_name.as_deref().unwrap_or("unknown");

            let item = SongInfo {
                id: 0,
                song_path: fp.display().to_shared_string(),
                song_name: song_name.into(),
                singer: singer_name.into(),
                duration: format!("{:02}:{:02}", (dura as u32) / 60, (dura as u32) % 60)
                    .to_shared_string(),
            };
            return Some(item);
        }
    }
    None
}

解析歌词

歌词只有在播放该文件时才应该被加载,所以单独解析:

rust 复制代码
/// Read lyrics from audio file `p`, return a list of LyricItem
pub fn read_lyrics(p: PathBuf) -> Vec<LyricItem> {
    if let Ok(tagged) = lofty::read_from_path(&p) {
        if let Some(tag) = tagged.primary_tag() {
            if let Some(lyric_item) = tag.get(&ItemKey::Lyrics) {
                let mut lyrics = lyric_item
                    .value()
                    .text()
                    .unwrap()
                    .split("\n")
                    .map(|line| {
                        let (time_str, text) = line.split_once(']').unwrap_or(("", ""));
                        let time_str = time_str.trim_start_matches('[');
                        let dura = time_str
                            .split(':')
                            .map(|x| x.parse::<f32>().unwrap_or(0.))
                            .rev()
                            .reduce(|acc, x| acc + x * 60.)
                            .unwrap_or(0.);
                        LyricItem {
                            time: dura,
                            text: text.to_shared_string(),
                            duration: 0.0,
                        }
                    })
                    .filter(|ins| ins.time > 0. && !ins.text.is_empty())
                    .collect::<Vec<_>>();
                for i in 0..lyrics.len() - 1 {
                    lyrics[i].duration = lyrics[i + 1].time - lyrics[i].time;
                }
                lyrics.last_mut().map(|ins| ins.duration = 100.0);
                return lyrics;
            }
        }
    }
    return Vec::new();
}

解析专辑封面

同上,该图像只有在播放该文件时才应该被加载,所以单独解析:

rust 复制代码
/// Read album cover from audio file `p`
pub fn read_album_cover(p: PathBuf) -> Option<(Vec<u8>, u32, u32)> {
    if let Ok(tagged) = lofty::read_from_path(&p) {
        if let Some(tag) = tagged.primary_tag() {
            if let Some(picture) = tag.pictures().iter().find(|pic| {
                pic.pic_type() == PictureType::CoverFront
                    || pic.pic_type() == PictureType::CoverBack
            }) {
                if let Ok(img) = image::load_from_memory(picture.data()) {
                    let rgba = img.into_rgba8();
                    let (width, height) = rgba.dimensions();
                    let buffer = rgba.into_vec();
                    return Some((buffer, width, height));
                }
            }
        }
    }
    None
}
相关推荐
百锦再11 小时前
第11章 泛型、trait与生命周期
android·网络·人工智能·python·golang·rust·go
芳草萋萋鹦鹉洲哦11 小时前
【Windows】tauri+rust运行打包工具链安装
开发语言·windows·rust
s91236010114 小时前
【Rust】m2 mac 编译linux 、aarch、win 程序
rust
Source.Liu14 小时前
【ISO8601库】日期时间解析器测试套件详解(tests.rs)
rust·time·iso8601
alwaysrun15 小时前
Rust中数组简介
rust·数组·array·切片
百锦再15 小时前
第12章 测试编写
android·java·开发语言·python·rust·go·erlang
s91236010118 小时前
【Rust】时间轮的数据结构于设计模式
rust
盒马盒马18 小时前
Rust:Trait 抽象接口 & 特征约束
开发语言·rust
I still …18 小时前
Rust内存问题检测
rust·程序分析·漏洞检测
百锦再21 小时前
大型省级政务平台采用金仓数据库(KingbaseES)
开发语言·数据库·后端·rust·eclipse