101 lines
3.0 KiB
Rust
101 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_or_else(
|
|
Hint::new,
|
|
|ext| {
|
|
let mut h = Hint::new();
|
|
h.with_extension(ext);
|
|
h
|
|
}
|
|
);
|
|
|
|
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 {}
|