spotify_dl/encoder/
mod.rs

1mod flac;
2#[cfg(feature = "mp3")]
3mod mp3;
4pub mod tags;
5
6use std::{path::Path, str::FromStr};
7
8use anyhow::Result;
9
10use self::{flac::FlacEncoder, mp3::Mp3Encoder};
11
12#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
13pub enum Format {
14    Flac,
15    #[cfg(feature = "mp3")]
16    Mp3,
17}
18
19impl FromStr for Format {
20    type Err = anyhow::Error;
21
22    fn from_str(s: &str) -> Result<Self> {
23        match s {
24            "flac" => Ok(Format::Flac),
25            #[cfg(feature = "mp3")]
26            "mp3" => Ok(Format::Mp3),
27            _ => Err(anyhow::anyhow!("Unsupported format")),
28        }
29    }
30}
31
32impl Format {
33    pub fn extension(&self) -> &'static str {
34        match self {
35            Format::Flac => "flac",
36            #[cfg(feature = "mp3")]
37            Format::Mp3 => "mp3",
38        }
39    }
40}
41
42const FLAC_ENCODER: &FlacEncoder = &FlacEncoder;
43#[cfg(feature = "mp3")]
44const MP3_ENCODER: &Mp3Encoder = &Mp3Encoder;
45
46pub fn get_encoder(format: Format) -> &'static dyn Encoder {
47    match format {
48        Format::Flac => FLAC_ENCODER,
49        #[cfg(feature = "mp3")]
50        Format::Mp3 => MP3_ENCODER,
51    }
52}
53
54#[async_trait::async_trait]
55pub trait Encoder {
56    async fn encode(&self, samples: Samples) -> Result<EncodedStream>;
57}
58
59pub struct Samples {
60    pub samples: Vec<i32>,
61    pub sample_rate: u32,
62    pub channels: u32,
63    pub bits_per_sample: u32,
64}
65
66impl Samples {
67    pub fn new(samples: Vec<i32>, sample_rate: u32, channels: u32, bits_per_sample: u32) -> Self {
68        Samples {
69            samples,
70            sample_rate,
71            channels,
72            bits_per_sample,
73        }
74    }
75
76    pub fn to_s24(&self) -> Vec<i32> {
77        self.samples
78            .iter()
79            .map(|&sample| (sample >> 8) as i32) // Convert to S24 by shifting down
80            .collect()
81    }
82
83}
84
85impl Default for Samples {
86    fn default() -> Self {
87        Samples {
88            samples: Vec::new(),
89            sample_rate: 44100,
90            channels: 2,
91            bits_per_sample: 32,
92        }
93    }
94}
95
96pub struct EncodedStream {
97    pub stream: Vec<u8>,
98}
99
100impl EncodedStream {
101    pub fn new(stream: Vec<u8>) -> Self {
102        EncodedStream { stream }
103    }
104
105    pub async fn write_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
106        if !path.as_ref().exists() {
107            tokio::fs::create_dir_all(
108                path.as_ref()
109                    .parent()
110                    .ok_or(anyhow::anyhow!("Could not create path"))?,
111            )
112            .await?;
113        }
114        tokio::fs::write(path, &self.stream).await?;
115        Ok(())
116    }
117}