deLyrium/src/load_song.rs

99 lines
3.0 KiB
Rust

use std::fs::File;
use image::DynamicImage;
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};
use symphonia::core::meta::StandardVisualKey;
use symphonia::core::formats::FormatReader;
pub fn load_song(path: &Path) -> Result<(File, ProbeResult), LoadError> {
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.try_clone()
.map_err(LoadError::OpenError)?
),
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)
.map(|fr| (file, fr))
}
pub fn extract_cover(format: &mut dyn FormatReader) -> Option<DynamicImage>{
#[allow(clippy::zero_prefixed_literal)]
format.metadata()
.current()
.into_iter()
// Replace this whole closure with MetadataRef::usage once we update
.flat_map(|meta| meta.visuals().iter().map(|v|(v.data.clone(), v.usage)).collect::<Vec<_>>())
.filter_map(|(data, usage)| image::load_from_memory(&data).ok().map(|img| (usage, img)))
.max_by_key(|(usage, _)|
usage.map(|usage| match usage {
StandardVisualKey::FrontCover => 00,
StandardVisualKey::FileIcon => 01,
StandardVisualKey::Illustration => 02,
StandardVisualKey::BandArtistLogo => 03,
StandardVisualKey::BackCover => 04,
StandardVisualKey::Media => 05,
StandardVisualKey::Leaflet => 06,
StandardVisualKey::OtherIcon => 07,
StandardVisualKey::LeadArtistPerformerSoloist => 08,
StandardVisualKey::ArtistPerformer => 09,
StandardVisualKey::Conductor => 10,
StandardVisualKey::BandOrchestra => 11,
StandardVisualKey::Composer => 12,
StandardVisualKey::Lyricist => 13,
StandardVisualKey::RecordingLocation => 14,
StandardVisualKey::RecordingSession => 15,
StandardVisualKey::Performance => 16,
StandardVisualKey::ScreenCapture => 17,
StandardVisualKey::PublisherStudioLogo => 18,
}).unwrap_or(u32::MAX)
)
.map(|(_, img)| img)
}
#[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 {}