2022-05-12 00:18:58 +02:00
|
|
|
use std::path::Path;
|
2020-10-25 01:39:20 +02:00
|
|
|
|
2022-05-12 00:18:58 +02:00
|
|
|
use audiotags::{Tag, TagType};
|
2024-01-12 12:41:26 +01:00
|
|
|
use librespot::playback::{
|
|
|
|
audio_backend::{Open, Sink, SinkError},
|
|
|
|
config::AudioFormat,
|
|
|
|
convert::Converter,
|
|
|
|
decoder::AudioPacket,
|
|
|
|
};
|
2022-05-12 00:18:58 +02:00
|
|
|
|
|
|
|
// extern crate flac_bound;
|
2020-10-25 01:39:20 +02:00
|
|
|
|
2024-01-12 12:41:26 +01:00
|
|
|
use flac_bound::FlacEncoder;
|
2020-10-25 01:39:20 +02:00
|
|
|
|
2022-05-12 00:18:58 +02:00
|
|
|
use crate::TrackMetadata;
|
|
|
|
|
2020-10-25 01:39:20 +02:00
|
|
|
pub struct FileSink {
|
|
|
|
sink: String,
|
2022-05-12 00:18:58 +02:00
|
|
|
content: Vec<i32>,
|
2024-01-12 12:41:26 +01:00
|
|
|
metadata: Option<TrackMetadata>,
|
|
|
|
compression: u32,
|
2022-05-12 00:18:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FileSink {
|
|
|
|
pub fn add_metadata(&mut self, meta: TrackMetadata) {
|
|
|
|
self.metadata = Some(meta);
|
|
|
|
}
|
2024-01-12 12:41:26 +01:00
|
|
|
pub fn set_compression(&mut self, compression: u32) {
|
|
|
|
self.compression = compression;
|
|
|
|
}
|
2020-10-25 01:39:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Open for FileSink {
|
2022-05-12 00:18:58 +02:00
|
|
|
fn open(path: Option<String>, _audio_format: AudioFormat) -> Self {
|
2023-02-03 19:01:03 +01:00
|
|
|
let file_path = path.unwrap_or_else(|| panic!());
|
2023-02-01 20:34:23 +01:00
|
|
|
FileSink {
|
2023-02-03 19:01:03 +01:00
|
|
|
sink: file_path,
|
2023-02-01 20:34:23 +01:00
|
|
|
content: Vec::new(),
|
2024-01-17 13:07:52 +01:00
|
|
|
metadata: None,
|
|
|
|
compression: 4,
|
2020-10-25 01:39:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Sink for FileSink {
|
2022-05-12 00:18:58 +02:00
|
|
|
fn start(&mut self) -> Result<(), SinkError> {
|
2020-10-25 01:39:20 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-05-12 00:18:58 +02:00
|
|
|
fn stop(&mut self) -> Result<(), SinkError> {
|
2024-01-12 12:41:26 +01:00
|
|
|
let mut encoder = FlacEncoder::new()
|
|
|
|
.unwrap()
|
|
|
|
.channels(2)
|
|
|
|
.bits_per_sample(16)
|
|
|
|
.compression_level(*&self.compression)
|
|
|
|
.init_file(&self.sink)
|
|
|
|
.unwrap();
|
|
|
|
encoder
|
|
|
|
.process_interleaved(self.content.as_slice(), (self.content.len() / 2) as u32)
|
|
|
|
.unwrap();
|
2020-10-25 01:39:20 +02:00
|
|
|
encoder.finish().unwrap();
|
2022-05-12 00:18:58 +02:00
|
|
|
|
|
|
|
match &self.metadata {
|
|
|
|
Some(meta) => {
|
2024-01-12 12:41:26 +01:00
|
|
|
let mut tag = Tag::new()
|
|
|
|
.with_tag_type(TagType::Flac)
|
|
|
|
.read_from_path(Path::new(&self.sink))
|
|
|
|
.unwrap();
|
2022-05-12 00:18:58 +02:00
|
|
|
|
|
|
|
tag.set_album_title(&meta.album);
|
|
|
|
for artist in &meta.artists {
|
|
|
|
tag.add_artist(artist);
|
|
|
|
}
|
|
|
|
tag.set_title(&meta.track_name);
|
2024-01-12 12:41:26 +01:00
|
|
|
tag.write_to_path(&self.sink)
|
|
|
|
.expect("Failed to write metadata");
|
|
|
|
}
|
2022-05-12 00:18:58 +02:00
|
|
|
None => (),
|
|
|
|
}
|
2020-10-25 01:39:20 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-05-12 00:18:58 +02:00
|
|
|
fn write(&mut self, packet: &AudioPacket, converter: &mut Converter) -> Result<(), SinkError> {
|
|
|
|
let data = converter.f64_to_s16(packet.samples().unwrap());
|
|
|
|
let mut data32: Vec<i32> = data.iter().map(|el| i32::from(*el)).collect();
|
|
|
|
self.content.append(&mut data32);
|
2020-10-25 01:39:20 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
2022-05-12 00:18:58 +02:00
|
|
|
}
|