mirror of
https://github.com/talwat/lowfi
synced 2025-03-12 16:12:22 +00:00
feat: improve inevitable communication between frontend & backend
This commit is contained in:
parent
6e457241d2
commit
e0d13792e2
@ -1,5 +1,3 @@
|
|||||||
use std::process::exit;
|
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
mod scrape;
|
mod scrape;
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use std::{collections::VecDeque, sync::Arc, time::Duration};
|
use std::{collections::VecDeque, sync::Arc};
|
||||||
|
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use rodio::{source::SineWave, Decoder, OutputStream, OutputStreamHandle, Sink, Source};
|
use rodio::{Decoder, OutputStream, Sink};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
sync::RwLock,
|
select, sync::{
|
||||||
task, time::sleep,
|
mpsc::{self, Receiver},
|
||||||
|
RwLock,
|
||||||
|
}, task
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The amount of songs to buffer up.
|
/// The amount of songs to buffer up.
|
||||||
@ -12,6 +14,11 @@ const BUFFER_SIZE: usize = 5;
|
|||||||
|
|
||||||
use crate::tracks::Track;
|
use crate::tracks::Track;
|
||||||
|
|
||||||
|
/// Handles communication between the frontend & audio player.
|
||||||
|
pub enum Messages {
|
||||||
|
Skip,
|
||||||
|
}
|
||||||
|
|
||||||
/// Main struct responsible for queuing up tracks.
|
/// Main struct responsible for queuing up tracks.
|
||||||
///
|
///
|
||||||
/// Internally tracks are stored in an [Arc],
|
/// Internally tracks are stored in an [Arc],
|
||||||
@ -21,9 +28,6 @@ pub struct Queue {
|
|||||||
tracks: Arc<RwLock<VecDeque<Track>>>,
|
tracks: Arc<RwLock<VecDeque<Track>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for Queue {}
|
|
||||||
unsafe impl Sync for Queue {}
|
|
||||||
|
|
||||||
impl Queue {
|
impl Queue {
|
||||||
pub async fn new() -> Self {
|
pub async fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -57,28 +61,48 @@ impl Queue {
|
|||||||
Ok(track)
|
Ok(track)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn play(self, sink: Sink) -> eyre::Result<()> {
|
/// This is the main "audio server".
|
||||||
let client = Client::builder().build()?;
|
///
|
||||||
|
/// `rx` is used to communicate with it, for example when to
|
||||||
|
/// skip tracks or pause.
|
||||||
|
pub async fn play(
|
||||||
|
self,
|
||||||
|
sink: Sink,
|
||||||
|
client: Client,
|
||||||
|
mut rx: Receiver<Messages>
|
||||||
|
) -> eyre::Result<()> {
|
||||||
let sink = Arc::new(sink);
|
let sink = Arc::new(sink);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
sink.stop();
|
let clone = sink.clone();
|
||||||
|
let msg = select! {
|
||||||
|
Some(x) = rx.recv() => x,
|
||||||
|
|
||||||
let track = self.next(&client).await?;
|
// This future will finish only at the end of the current track.
|
||||||
sink.append(Decoder::new(track.data)?);
|
Ok(()) = task::spawn_blocking(move || clone.sleep_until_end()) => Messages::Skip,
|
||||||
|
};
|
||||||
|
|
||||||
let sink = sink.clone();
|
match msg {
|
||||||
task::spawn_blocking(move || sink.sleep_until_end()).await?;
|
Messages::Skip => {
|
||||||
|
sink.stop();
|
||||||
|
|
||||||
|
let track = self.next(&client).await?;
|
||||||
|
sink.append(Decoder::new(track.data)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn play() -> eyre::Result<()> {
|
pub async fn play() -> eyre::Result<()> {
|
||||||
let queue = Queue::new().await;
|
let queue = Queue::new().await;
|
||||||
let (stream, handle) = OutputStream::try_default()?;
|
let (tx, rx) = mpsc::channel(8);
|
||||||
|
let (_stream, handle) = OutputStream::try_default()?;
|
||||||
let sink = Sink::try_new(&handle)?;
|
let sink = Sink::try_new(&handle)?;
|
||||||
|
let client = Client::builder().build()?;
|
||||||
|
|
||||||
let audio = task::spawn(queue.clone().play(sink));
|
let audio = task::spawn(queue.clone().play(sink, client.clone(), rx));
|
||||||
|
tx.send(Messages::Skip).await?; // This is responsible for the initial track being played.
|
||||||
|
|
||||||
crossterm::terminal::enable_raw_mode()?;
|
crossterm::terminal::enable_raw_mode()?;
|
||||||
|
|
||||||
@ -88,6 +112,8 @@ pub async fn play() -> eyre::Result<()> {
|
|||||||
crossterm::event::KeyCode::Char(x) => {
|
crossterm::event::KeyCode::Char(x) => {
|
||||||
if x == 'q' {
|
if x == 'q' {
|
||||||
break 'a;
|
break 'a;
|
||||||
|
} else if x == 's' {
|
||||||
|
tx.send(Messages::Skip).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user