【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
}
相关推荐
SomeB1oody9 小时前
【RustyML入门】5.0. 模型评估
开发语言·后端·机器学习·rust·教程
今天AI了吗12 小时前
Agent & AI 名词大扫盲
数据库·人工智能·python·sql·rust
SomeB1oody1 天前
【RustyML入门】4.2. 标准化与归一化
开发语言·后端·机器学习·rust·教程
leoZ2311 天前
Vue3 还原一个企业级后台-14-项目总结
开发语言·人工智能·后端·opencv·计算机视觉·数据挖掘·rust
特立独行的猫a2 天前
Tauri v2的Rust应用 → HarmonyOS(鸿蒙 PC)移植30分钟速成指南
开发语言·rust·harmonyos·tauri·移植·鸿蒙pc
程序员爱钓鱼2 天前
Rust 方法 Method详解:self、方法调用与API设计
后端·面试·rust
Patrick_Wilson2 天前
sccache 用在 Rust 上为什么常「不省编译」:原理、限制与 Windows 接入
ci/cd·rust·编译器
k4m7v2pz2 天前
rvs 26.8.43 → 26.8.53 更新概览:MCP 落地、审计增强与谬误澄清
rust·repl·mcp server·rust-verb-shell·rvs·shell 工具
程序员爱钓鱼3 天前
Rust impl详解:为Struct定义方法与关联函数
前端·后端·rust
k4m7v2pz3 天前
Rust 程序在 ReactOS 上“加载即崩“:从崩溃地址 0x6107104d 到 CRT 依赖的深度排查
rust·交叉编译·逆向工程·reactos·pe格式·windows兼容