selene-core 0.4.2

selene-core is the backend for Selene, a local-first music player
Documentation
use std::{
    fs::File,
    io::{Seek, SeekFrom},
    path::{Path, PathBuf},
};

use crate::{decoding::SYMPHONIA_PROBE, errors::ContainerError, utils::pair_extension};
use serde::{Deserialize, Serialize};
use symphonia::core::{
    formats::FormatOptions, io::MediaSourceStream, meta::MetadataOptions, probe::Hint,
};

mod channel_layout;
pub use channel_layout::*;

mod codec;
pub use codec::*;

mod format;
pub use format::*;

mod sample_format;
pub use sample_format::*;

mod stream;
pub use stream::*;

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct MediaContainer {
    path: PathBuf,
    format: ContainerFormat,
    stream: Stream,
}

impl MediaContainer {
    pub(crate) fn set_path(&mut self, path: PathBuf) {
        self.path = path;
    }
}

impl MediaContainer {
    /// Returns the [`MediaContainer`] of the input file
    ///
    /// # Errors
    ///
    /// Errors when the input file either has invalid or unsupported/unrecognized data
    pub(crate) fn from_file(mut file: File, path: PathBuf) -> Result<Self, ContainerError> {
        let container_format = ContainerFormat::from_file(&mut file)
            .ok_or_else(|| ContainerError::InvalidSource(path.clone()))?;
        file.seek(SeekFrom::Start(0))?;

        let mss = MediaSourceStream::new(Box::new(file), Default::default());

        let fmt_opts = FormatOptions::default();
        let metadata_opts = MetadataOptions::default();
        let probed = SYMPHONIA_PROBE.format(&Hint::new(), mss, &fmt_opts, &metadata_opts)?;

        let track = probed.format.default_track().unwrap().codec_params.clone();
        let stream = Stream::try_from(track)?;

        Ok(Self {
            path,
            format: container_format,
            stream,
        })
    }

    #[must_use]
    pub fn path(&self) -> &Path {
        &self.path
    }

    #[must_use]
    pub fn container(&self) -> &ContainerFormat {
        &self.format
    }

    #[must_use]
    pub fn codec(&self) -> &Codec {
        &self.stream.codec
    }

    /// Returns the file extension this [`MediaContainer`] uses. Returns [`Option::None`] for invalid or unrecognized pairs
    #[must_use]
    pub fn extension(&self) -> Option<&str> {
        pair_extension(self.format, self.stream.codec)
    }

    #[must_use]
    pub fn stream(&self) -> &Stream {
        &self.stream
    }
}