use std::sync::atomic::Ordering;
use crossbeam_channel::{bounded, Receiver, Sender};
use diskit::VoidDiskit;
use id3::frame::Picture;
use legacytranslate::MessageBuffer;
use crate::{
audio::print_info,
commands::impls::{
self, disable_repeat, pause, pause_after_song, quit_after_song, repeat_forever,
repeat_once, resume, skip, skip_to_previous,
},
config::Config,
l10n::messages::Message,
matcher::BigAction,
songs::Repeat,
};
pub enum Request
{
GetLikelihood,
SetLikelihood(u32),
Quit,
Pause,
Resume,
Skip(u32),
GetVolume,
SetVolume(f32),
GetDuration,
QuitAfterSong,
PauseAfterSong,
IsPlaying,
GetInfo,
Repeat(Repeat),
Previous(u32),
GetCover,
Localize(Message),
}
pub enum Response
{
Likelihood(u32),
Volume(f32),
Duration(f64, Option<f64>),
IsPlaying(bool),
Info(Vec<Message>),
Cover(Vec<Picture>),
Localized(String),
Finished,
}
#[allow(clippy::module_name_repetitions)]
#[derive(Debug)]
pub struct ApiRequester
{
request: Sender<Request>,
response: Receiver<Response>,
}
#[allow(clippy::module_name_repetitions)]
#[derive(Debug)]
pub struct ApiResponder
{
pub(crate) request: Receiver<Request>,
pub(crate) response: Sender<Response>,
}
#[allow(missing_docs)]
impl ApiRequester
{
#[must_use]
pub fn new() -> (Self, ApiResponder)
{
let (tx_request, rx_request) = bounded(1);
let (tx_response, rx_response) = bounded(1);
(
Self {
request: tx_request,
response: rx_response,
},
ApiResponder {
request: rx_request,
response: tx_response,
},
)
}
#[must_use]
pub fn request(&self, request: Request) -> Option<Response>
{
self.request.send(request).ok()?;
self.response.recv().ok()
}
#[must_use]
pub fn get_likelihood(&self) -> Option<u32>
{
if let Response::Likelihood(rv) = self.request(Request::GetLikelihood)?
{
Some(rv)
}
else
{
None
}
}
#[must_use]
pub fn set_likelihood(&self, likelihood: u32) -> Option<()>
{
if matches!(
self.request(Request::SetLikelihood(likelihood))?,
Response::Finished
)
{
Some(())
}
else
{
None
}
}
#[must_use]
pub fn quit(&self) -> Option<()>
{
if matches!(self.request(Request::Quit)?, Response::Finished)
{
Some(())
}
else
{
None
}
}
#[must_use]
pub fn pause(&self) -> Option<()>
{
if matches!(self.request(Request::Pause)?, Response::Finished)
{
Some(())
}
else
{
None
}
}
#[must_use]
pub fn resume(&self) -> Option<()>
{
if matches!(self.request(Request::Resume)?, Response::Finished)
{
Some(())
}
else
{
None
}
}
#[must_use]
pub fn skip(&self, count: u32) -> Option<()>
{
if matches!(self.request(Request::Skip(count))?, Response::Finished)
{
Some(())
}
else
{
None
}
}
#[must_use]
pub fn get_volume(&self) -> Option<f32>
{
if let Response::Volume(rv) = self.request(Request::GetVolume)?
{
Some(rv)
}
else
{
None
}
}
#[must_use]
pub fn set_volume(&self, loud: f32) -> Option<()>
{
if matches!(self.request(Request::SetVolume(loud))?, Response::Finished)
{
Some(())
}
else
{
None
}
}
#[must_use]
pub fn get_duration(&self) -> Option<(f64, Option<f64>)>
{
if let Response::Duration(cur, end) = self.request(Request::GetDuration)?
{
Some((cur, end))
}
else
{
None
}
}
#[must_use]
pub fn quit_after_song(&self) -> Option<()>
{
if matches!(self.request(Request::QuitAfterSong)?, Response::Finished)
{
Some(())
}
else
{
None
}
}
#[must_use]
pub fn pause_after_song(&self) -> Option<()>
{
if matches!(self.request(Request::PauseAfterSong)?, Response::Finished)
{
Some(())
}
else
{
None
}
}
#[must_use]
pub fn is_playing(&self) -> Option<bool>
{
if let Response::IsPlaying(rv) = self.request(Request::IsPlaying)?
{
Some(rv)
}
else
{
None
}
}
#[must_use]
pub fn get_info(&self) -> Option<Vec<Message>>
{
if let Response::Info(rv) = self.request(Request::GetInfo)?
{
Some(rv)
}
else
{
None
}
}
#[must_use]
pub fn get_cover(&self) -> Option<Vec<Picture>>
{
if let Response::Cover(rv) = self.request(Request::GetCover)?
{
Some(rv)
}
else
{
None
}
}
#[must_use]
pub fn repeat(&self, repeat: Repeat) -> Option<()>
{
if matches!(self.request(Request::Repeat(repeat))?, Response::Finished)
{
Some(())
}
else
{
None
}
}
#[must_use]
pub fn previous(&self, count: u32) -> Option<()>
{
if matches!(self.request(Request::Previous(count))?, Response::Finished)
{
Some(())
}
else
{
None
}
}
#[must_use]
pub fn localize(&self, mes: Message) -> Option<String>
{
if let Response::Localized(rv) = self.request(Request::Localize(mes))?
{
Some(rv)
}
else
{
None
}
}
}
impl ApiResponder
{
#[allow(clippy::too_many_lines)]
pub(crate) fn handle(&self, config: &mut Config) -> BigAction
{
if let Ok(request) = self.request.try_recv()
{
let mut quit = false;
let diskit = VoidDiskit::default();
let response = match request
{
Request::GetLikelihood => Response::Likelihood(config.num),
Request::SetLikelihood(num) =>
{
config.num = num;
Response::Finished
}
Request::Quit =>
{
impls::quit(1, config, diskit);
quit = true;
Response::Finished
}
Request::Pause =>
{
pause(1, config, diskit);
Response::Finished
}
Request::Resume =>
{
resume(1, config, diskit);
Response::Finished
}
Request::Skip(count) =>
{
skip(count, config, diskit);
Response::Finished
}
Request::SetVolume(loud) =>
{
config.loud = loud;
config.audio_handler.set_volume(config.loud);
Response::Finished
}
Request::GetVolume => Response::Volume(config.loud),
Request::GetDuration =>
{
let pos = config.source.get_pos() as f64
/ config.source.sample_rate as f64
/ config.arc_config.channels.load(Ordering::SeqCst) as f64;
if let Some(len) = config.source.samples_len()
{
let len = len as f64
/ config.source.sample_rate as f64
/ config.arc_config.channels.load(Ordering::SeqCst) as f64;
Response::Duration(pos, Some(len))
}
else
{
Response::Duration(pos, None)
}
}
Request::QuitAfterSong =>
{
quit_after_song(1, config, diskit);
Response::Finished
}
Request::PauseAfterSong =>
{
pause_after_song(1, config, diskit);
Response::Finished
}
Request::IsPlaying => Response::IsPlaying(!config.paused),
Request::GetInfo =>
{
let mut buf = MessageBuffer::new();
print_info(&config.tag, &&mut buf);
Response::Info(buf.get_messages())
}
Request::GetCover => Response::Cover(
config
.tag
.as_ref()
.and_then(|x| x.as_ref().ok())
.map(|tag| tag.pictures().cloned().collect::<Vec<Picture>>())
.unwrap_or_default(),
),
Request::Repeat(Repeat::Not) =>
{
disable_repeat(1, config, diskit);
Response::Finished
}
Request::Repeat(Repeat::Once) =>
{
repeat_once(1, config, diskit);
Response::Finished
}
Request::Repeat(Repeat::Always) =>
{
repeat_forever(1, config, diskit);
Response::Finished
}
Request::Previous(count) =>
{
skip_to_previous(count, config, diskit);
Response::Finished
}
Request::Localize(mes) => Response::Localized(config.l10n.get(mes)),
};
self.response
.send(response)
.expect("This send shouldn't have failed");
if quit
{
return BigAction::Quit;
}
}
BigAction::Nothing
}
}