90 lines
2.2 KiB
Rust
90 lines
2.2 KiB
Rust
use std::{convert::Infallible, fmt::Display};
|
|
|
|
use opendal::Operator;
|
|
use opus2::Application;
|
|
use time::{UtcDateTime, format_description::StaticFormatDescription, macros::format_description};
|
|
use twilight_model::id::{
|
|
Id,
|
|
marker::{ChannelMarker, GuildMarker},
|
|
};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct RenderManager {
|
|
operator: Operator,
|
|
}
|
|
|
|
impl RenderManager {
|
|
pub fn new(operator: Operator) -> Self {
|
|
Self { operator }
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Render {
|
|
pub start: UtcDateTime,
|
|
pub end: UtcDateTime,
|
|
pub guild_id: Id<GuildMarker>,
|
|
pub voice_channel_id: Id<ChannelMarker>,
|
|
}
|
|
|
|
const DATE_FORMAT: StaticFormatDescription =
|
|
format_description!("[year]-[month]-[day]T[hour]-[minute]-[second].[subsecond]Z");
|
|
|
|
impl Display for Render {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
let Self {
|
|
start,
|
|
end,
|
|
guild_id,
|
|
voice_channel_id,
|
|
} = self;
|
|
|
|
let start = start.format(&DATE_FORMAT).unwrap();
|
|
let end = end.format(&DATE_FORMAT).unwrap();
|
|
|
|
write!(f, "{guild_id}/{voice_channel_id}/{start}_{end}.opus")
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct RenderData {
|
|
pub channels: opus2::Channels,
|
|
pub sample_rate: u32,
|
|
pub samples: Vec<i16>,
|
|
}
|
|
|
|
impl RenderManager {
|
|
pub async fn write(
|
|
&self,
|
|
render: &Render,
|
|
RenderData {
|
|
channels,
|
|
sample_rate,
|
|
samples,
|
|
}: RenderData,
|
|
) -> Result<
|
|
(),
|
|
Infallible, // TODO: a real error type
|
|
> {
|
|
let mut encoder =
|
|
opus2::Encoder::new(sample_rate, channels, Application::Audio).expect("TODO");
|
|
|
|
const MAX_SIZE: usize = usize::MAX / 4;
|
|
let encode_result = encoder.encode_vec(&samples, MAX_SIZE);
|
|
if let Err(error) = &encode_result {
|
|
tracing::error!(?error);
|
|
} else {
|
|
tracing::info!("encode ok");
|
|
}
|
|
encode_result.expect("TODO");
|
|
|
|
let path = render.to_string();
|
|
|
|
let write_result = self.operator.write(&path, bytes).await;
|
|
tracing::info!(?write_result);
|
|
write_result.expect("TODO");
|
|
|
|
Ok(())
|
|
}
|
|
}
|