From a2f37bf3f37f9977815f4f7850b8316b1700712a Mon Sep 17 00:00:00 2001 From: Emi Simpson Date: Sat, 1 Jan 2022 12:28:23 -0500 Subject: [PATCH] Add basic metadata parsing for songs --- Cargo.lock | 180 ++++++++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 5 ++ src/app.rs | 6 +- src/load_song.rs | 79 +++++++++++++++++++++ src/main.rs | 1 + 5 files changed, 261 insertions(+), 10 deletions(-) create mode 100644 src/load_song.rs diff --git a/Cargo.lock b/Cargo.lock index 763420b..2531375 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + [[package]] name = "ash" version = "0.31.0" @@ -663,6 +669,7 @@ dependencies = [ "iced_native", "image", "rfd", + "symphonia", ] [[package]] @@ -781,6 +788,15 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "encoding_rs" +version = "0.8.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "error-code" version = "2.3.0" @@ -1118,7 +1134,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f851d03c2e8f117e3702bf41201a4fafa447d5cb1276d5375870ae7573d069dd" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "bitflags", "gfx-auxil", "gfx-hal", @@ -1140,7 +1156,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5032d716a2a5f4dafb4675a794c5dc32081af8fbc7303c93ad93ff5413c6559f" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "bit-set", "bitflags", "d3d12", @@ -1173,7 +1189,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6717c50ab601efe4a669bfb44db615e3888695ac8263222aeaa702642b9fbc2" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "bitflags", "gfx-auxil", "gfx-hal", @@ -1196,7 +1212,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dc54b456ece69ef49f8893269ebf24ac70969ed34ba2719c3f3abcc8fbff14e" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "bitflags", "block", "cocoa-foundation", @@ -1221,7 +1237,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dabe88b1a5c91e0f969b441cc57e70364858066e4ba937deeb62065654ef9bd9" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "ash", "byteorder", "core-graphics-types", @@ -1801,7 +1817,7 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce4e12203c428a58200b8cf1c0a3aad1cda907008ea11310bb3729593e5f933" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "euclid", "num-traits", ] @@ -1821,7 +1837,7 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ecf3d769bec66396957d7c5cb91f998c4182e53fdc96cc435b6ebcd46a63cd9" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "lyon_path", "sid", ] @@ -2807,6 +2823,152 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2" +[[package]] +name = "symphonia" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e5f38aa07e792f4eebb0faa93cee088ec82c48222dd332897aae1569d9a4b7" +dependencies = [ + "lazy_static", + "symphonia-bundle-flac", + "symphonia-bundle-mp3", + "symphonia-codec-aac", + "symphonia-codec-pcm", + "symphonia-codec-vorbis", + "symphonia-core", + "symphonia-format-isomp4", + "symphonia-format-ogg", + "symphonia-format-wav", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-bundle-flac" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "116e5412f5fb4e5d07efd6628d50d6fcd7a61ebef43d98f5012f3cf763b25d02" +dependencies = [ + "log", + "symphonia-core", + "symphonia-metadata", + "symphonia-utils-xiph", +] + +[[package]] +name = "symphonia-bundle-mp3" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4d97c4a61ece4651751dddb393ebecb7579169d9e758ae808fe507a5250790" +dependencies = [ + "bitflags", + "lazy_static", + "log", + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-codec-aac" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd3d7ab37eb9b7df16ddedd7adb7cc382afe708ff078e525a14dc9b05e57558f" +dependencies = [ + "lazy_static", + "log", + "symphonia-core", +] + +[[package]] +name = "symphonia-codec-pcm" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1d54738758993546107e3a4be2c1da827f2d4489fcffee0fa47867254e44c7" +dependencies = [ + "log", + "symphonia-core", +] + +[[package]] +name = "symphonia-codec-vorbis" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a29ed6748078effb35a05064a451493a78038918981dc1a76bdf5a2752d441fa" +dependencies = [ + "log", + "symphonia-core", + "symphonia-utils-xiph", +] + +[[package]] +name = "symphonia-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa135e97be0f4a666c31dfe5ef4c75435ba3d355fd6a73d2100aa79b14c104c9" +dependencies = [ + "arrayvec 0.7.2", + "bitflags", + "bytemuck", + "lazy_static", + "log", +] + +[[package]] +name = "symphonia-format-isomp4" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feee3a7711e7ec1b7540756f3868bbb3cbb0d1195569b9bc26471a24a02f57b5" +dependencies = [ + "encoding_rs", + "log", + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-format-ogg" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7b2357288a79adfec532cfd86049696cfa5c58efeff83bd51687a528f18a519" +dependencies = [ + "log", + "symphonia-core", + "symphonia-metadata", + "symphonia-utils-xiph", +] + +[[package]] +name = "symphonia-format-wav" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3586e944a951f3ff19ae14d3f46643c063784f119bffb091fc536102909575" +dependencies = [ + "log", + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-metadata" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5260599daba18d8fe905ca3eb3b42ba210529a6276886632412cc74984e79b1a" +dependencies = [ + "encoding_rs", + "lazy_static", + "log", + "symphonia-core", +] + +[[package]] +name = "symphonia-utils-xiph" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a37026c6948ff842e0bf94b4008579cc71ab16ed0ff9ca70a331f60f4f1e1e9" +dependencies = [ + "symphonia-core", + "symphonia-metadata", +] + [[package]] name = "syn" version = "1.0.65" @@ -3275,7 +3437,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79a0a0a63fac9492cfaf6e7e4bdf9729c128f1e94124b9e4cbc4004b8cb6d1d8" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "js-sys", "naga", "parking_lot", @@ -3296,7 +3458,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c89fa2cc5d72236461ac09c5be967012663e29cb62f1a972654cbf35e49dffa8" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "bitflags", "cfg_aliases", "copyless", diff --git a/Cargo.toml b/Cargo.toml index 494ba79..cbf8c8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,11 @@ iced_native = "0.4.0" # Native file dialogs rfd = "0.6.3" +[dependencies.symphonia] +# Music decoding, playing, and metadata parsing +features = ["isomp4", "aac", "mp3"] +version = "0.4.0" + [dependencies.iced] # Display windows & graphics features = ["canvas"] diff --git a/src/app.rs b/src/app.rs index 69a8611..c63576f 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,3 +1,5 @@ +use crate::load_song::extract_cover; +use crate::load_song::load_song; use crate::lyrics::Lyrics; use crate::file_select::FileSelector; use crate::styles::Theme; @@ -96,11 +98,13 @@ impl Application for DelyriumApp { }, Message::FileOpened(path) => { println!("File opened! {}", path.display()); + let mut song = load_song(&path).unwrap(); + extract_cover(&mut song); }, Message::PromptForFile => { let task = async { let handle = AsyncFileDialog::new() - .add_filter("Song Files", &["mp3", "flac", "ogg", "opus", "wav"]) + .add_filter("Song Files", &["mp3", "flac", "ogg", "opus", "wav", "mkv"]) .set_title("Select a song") .pick_file() .await; diff --git a/src/load_song.rs b/src/load_song.rs new file mode 100644 index 0000000..80bbac3 --- /dev/null +++ b/src/load_song.rs @@ -0,0 +1,79 @@ +use std::error::Error; +use std::fs::OpenOptions; +use std::path::Path; +use std::io; +use std::fmt; +use std::ffi::OsStr; +use symphonia::default; +use symphonia::core::io::MediaSourceStream; +use symphonia::core::probe::{Hint, ProbeResult}; + +pub fn load_song(path: &Path) -> Result { + let codecs = default::get_codecs(); + let probe = default::get_probe(); + + let file = OpenOptions::new() + .read(true) + .write(false) + .open(path) + .map_err(LoadError::OpenError)?; + let media_source_stream = MediaSourceStream::new(Box::new(file), Default::default()); + + let ext_hint = path.extension() + .and_then(OsStr::to_str) + .map(|ext| { + let mut h = Hint::new(); + h.with_extension(ext); + h + }) + .unwrap_or_else(Hint::new); + + probe.format( + &ext_hint, + media_source_stream, + &Default::default(), + &Default::default(), + ).map_err(LoadError::SymphoniaError) +} + +pub fn extract_cover(ProbeResult { format, metadata }: &mut ProbeResult) { + if let Some(metadata) = metadata.get() { + if let Some(current) = metadata.current() { + for tag in current.tags() { + println!("Probed Tag: {}", tag); + } + println!("{} Visuals in Probed Metadata", current.visuals().len()); + } else { + println!("No current probed metadata"); + } + } else { + println!("No probed metadata"); + } + + let normal_metadata = format.metadata(); + if let Some(current) = normal_metadata.current() { + for tag in current.tags() { + println!("Probed Tag: {}", tag); + } + println!("{} Visuals in Normal Metadata", current.visuals().len()); + } else { + println!("No current normal metadata"); + } +} + +#[derive(Debug)] +pub enum LoadError { + OpenError(io::Error), + SymphoniaError(symphonia::core::errors::Error), +} + +impl fmt::Display for LoadError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::OpenError(e) => write!(f, "Problem opening song: {}", e), + Self::SymphoniaError(e) => write!(f, "Symphonia encountered a problem: {}", e), + } + } +} + +impl Error for LoadError {} diff --git a/src/main.rs b/src/main.rs index f030b1d..c11d553 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod app; mod lyrics; mod styles; mod file_select; +mod load_song; fn main() { app::DelyriumApp::run(Settings::default()).unwrap();