首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Rust GUI开发入门】编写一个本地音乐播放器(8. 从文件中提取歌曲元信息)

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

原创
作者头像
用户11855011
发布2025-09-30 18:19:10
发布2025-09-30 18:19:10
750
举报

本系列教程对应的代码已开源在 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
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 添加依赖
  • 解析元信息
    • 解析歌名/歌手/时长
    • 解析歌词
    • 解析专辑封面
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档