【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
}
相关推荐
清心9155 小时前
Windows系统Rust安装与配置,解决安装慢问题
rust
清心9155 小时前
Windows系统Rust安装,自定义安装目录
rust
恒云客8 小时前
Rust开发环境配置
开发语言·后端·rust
红烧code1 天前
【Rust GUI开发入门】编写一个本地音乐播放器(1. 主要技术选型&架构设计)
rust·gui·slint·rodio·lofty
JordanHaidee1 天前
【Rust GUI开发入门】编写一个本地音乐播放器(3. UI与后台线程通信)
rust
Source.Liu2 天前
【mdBook】1 安装
笔记·rust·markdown
Vallelonga2 天前
Rust 中的 static 和 const
开发语言·经验分享·rust
s9123601012 天前
【rust】 pub(crate) 的用法
开发语言·后端·rust
新石器程序员2 天前
借鉴bevy实现适用于Godot-rust的状态管理
rust·游戏引擎·godot·bevy