make it work

This commit is contained in:
Oleg Sobolev 2024-04-01 09:54:21 +07:00
parent cfd8429188
commit 7bfca6f035
5 changed files with 55 additions and 22 deletions

View file

@ -12,11 +12,11 @@ impl<T, R> Requester<T, R> {
pub fn send(&self, data: T) -> Result<Response<R>, SendError<T>> { pub fn send(&self, data: T) -> Result<Response<R>, SendError<T>> {
let (response_tx, response_rx) = mpsc::channel(); let (response_tx, response_rx) = mpsc::channel();
match self.tx.send(Request { match self.tx.send(Request {
data, data: Some(data),
tx: response_tx, tx: response_tx,
}) { }) {
Ok(_) => Ok(Response { rx: response_rx }), Ok(_) => Ok(Response { rx: response_rx }),
Err(e) => Err(SendError(e.0.data)), Err(e) => Err(SendError(e.0.data.unwrap())),
} }
} }
} }
@ -47,7 +47,7 @@ pub fn channel<T, R>() -> (Requester<T, R>, Responder<T, R>) {
} }
pub struct Request<T, R> { pub struct Request<T, R> {
pub data: T, pub data: Option<T>,
tx: Sender<R>, tx: Sender<R>,
} }

View file

@ -1,6 +1,6 @@
use std::{path::Path, process::Command}; use std::{path::Path, process::Command};
use crate::{file::FileHandle, track::Track}; use crate::{file::FileHandle, track::{Track, TrackInfo}};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct DownloadError; pub struct DownloadError;
@ -17,6 +17,7 @@ pub fn download_from_youtube(url: &str) -> Result<Track, DownloadError> {
"%(id)s", "%(id)s",
"--no-simulate", "--no-simulate",
"--no-playlist", "--no-playlist",
"--no-warnings",
"--", "--",
url, url,
]) ])
@ -24,6 +25,8 @@ pub fn download_from_youtube(url: &str) -> Result<Track, DownloadError> {
.unwrap(); .unwrap();
if !output.stderr.is_empty() || output.stdout.is_empty() { if !output.stderr.is_empty() || output.stdout.is_empty() {
println!("{}", std::str::from_utf8(output.stderr.as_slice()).unwrap());
println!("{}", std::str::from_utf8(output.stdout.as_slice()).unwrap());
return Err(DownloadError); return Err(DownloadError);
} }
@ -32,7 +35,10 @@ pub fn download_from_youtube(url: &str) -> Result<Track, DownloadError> {
.replace('\n', "") .replace('\n', "")
+ ".mp3"; + ".mp3";
let file_handle = FileHandle::new(Path::new(filename.as_str())); println!("{}", filename);
Ok(Track::new(file_handle)) let file_handle = FileHandle::new(Path::new(filename.as_str()));
let info = TrackInfo::new(&filename);
Ok(Track::new(info, file_handle))
} }

View file

@ -2,9 +2,9 @@ use rodio::{Decoder, OutputStream, OutputStreamHandle, Sink};
use std::{collections::VecDeque, fs::File, io::BufReader, thread, thread::JoinHandle}; use std::{collections::VecDeque, fs::File, io::BufReader, thread, thread::JoinHandle};
use crate::channel::{self, Requester, Responder, TryRecvError}; use crate::channel::{self, Requester, Responder, TryRecvError};
use crate::track::Track; use crate::track::{Track, TrackInfo};
#[derive(Debug, Clone)] #[derive(Debug)]
enum WorkerRequest { enum WorkerRequest {
AddTrack(Track), AddTrack(Track),
Pause, Pause,
@ -14,9 +14,9 @@ enum WorkerRequest {
ListTracks, ListTracks,
} }
#[derive(Debug, Clone)] #[derive(Debug)]
enum WorkerResponse { enum WorkerResponse {
TrackList(VecDeque<Track>), TrackList(VecDeque<TrackInfo>),
None, None,
} }
@ -25,7 +25,7 @@ use WorkerResponse::*;
pub struct MusicPlayer { pub struct MusicPlayer {
requester: Requester<WorkerRequest, WorkerResponse>, requester: Requester<WorkerRequest, WorkerResponse>,
_worker: JoinHandle<()>, worker: Option<JoinHandle<()>>,
} }
struct Worker { struct Worker {
@ -33,10 +33,11 @@ struct Worker {
_handle: OutputStreamHandle, _handle: OutputStreamHandle,
sink: Sink, sink: Sink,
queue: VecDeque<Track>, queue: VecDeque<Track>,
current: Option<Track>,
responder: Responder<WorkerRequest, WorkerResponse>, responder: Responder<WorkerRequest, WorkerResponse>,
} }
fn get_source(track: Track) -> Decoder<BufReader<File>> { fn get_source(track: &Track) -> Decoder<BufReader<File>> {
let file = BufReader::new(File::open(track.file.get_path()).unwrap()); let file = BufReader::new(File::open(track.file.get_path()).unwrap());
Decoder::new(file).unwrap() Decoder::new(file).unwrap()
} }
@ -59,28 +60,34 @@ impl Worker {
Stop => { Stop => {
self.sink.stop(); self.sink.stop();
self.queue.clear(); self.queue.clear();
self.current.take();
None None
} }
SkipOne => { SkipOne => {
self.sink.skip_one(); self.sink.skip_one();
self.current.take();
None None
} }
ListTracks => TrackList(self.queue.clone()), ListTracks => TrackList(self.queue.iter().map(|track| track.info.clone()).collect::<VecDeque<TrackInfo>>().clone()),
} }
} }
pub fn main(&mut self) { pub fn main(&mut self) {
loop { loop {
match self.responder.try_recv() { match self.responder.try_recv() {
Ok(req) => { Ok(mut req) => {
let _ = req.respond(self.match_request(req.data.clone())); let data = req.data.take().unwrap();
let _ = req.respond(self.match_request(data));
} }
Err(TryRecvError::Empty) => {} Err(TryRecvError::Empty) => {}
Err(TryRecvError::Disconnected) => break, Err(TryRecvError::Disconnected) => break,
}; };
if self.sink.empty() && !self.queue.is_empty() { if self.sink.empty() && !self.queue.is_empty() {
let next_track = self.queue.pop_front().unwrap(); let next_track = self.queue.pop_front().unwrap();
self.sink.append(get_source(next_track)); self.sink.append(get_source(&next_track));
self.current = Some(next_track);
} else if self.sink.empty() {
self.current.take();
} }
} }
} }
@ -94,6 +101,7 @@ impl Worker {
_handle, _handle,
sink, sink,
queue, queue,
current: Option::None,
responder, responder,
} }
} }
@ -102,8 +110,8 @@ impl Worker {
impl MusicPlayer { impl MusicPlayer {
pub fn build() -> MusicPlayer { pub fn build() -> MusicPlayer {
let (requester, responder) = channel::channel(); let (requester, responder) = channel::channel();
let _worker = thread::spawn(move || Worker::build(responder).main()); let worker = thread::spawn(move || Worker::build(responder).main());
MusicPlayer { requester, _worker } MusicPlayer { requester, worker: Some(worker) }
} }
pub fn enqueue(&mut self, track: Track) { pub fn enqueue(&mut self, track: Track) {
@ -126,7 +134,7 @@ impl MusicPlayer {
self.requester.send(Stop).unwrap(); self.requester.send(Stop).unwrap();
} }
pub fn list_tracks(&self) -> VecDeque<Track> { pub fn list_tracks(&self) -> VecDeque<TrackInfo> {
let response = self.requester.send(ListTracks).unwrap(); let response = self.requester.send(ListTracks).unwrap();
match response.recv().unwrap() { match response.recv().unwrap() {
TrackList(tracks) => tracks, TrackList(tracks) => tracks,
@ -134,3 +142,10 @@ impl MusicPlayer {
} }
} }
} }
impl Drop for MusicPlayer {
fn drop(&mut self) {
self.stop();
self.worker.take().unwrap().join().unwrap();
}
}

View file

@ -74,7 +74,7 @@ impl TelegramBot {
} else { } else {
message = tracks message = tracks
.iter() .iter()
.map(|t| t.file.get_path().to_str().unwrap()) .map(|t| t.name.as_str())
.collect::<Vec<&str>>() .collect::<Vec<&str>>()
.join("\n"); .join("\n");
} }

View file

@ -1,12 +1,24 @@
use crate::file::FileHandle; use crate::file::FileHandle;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TrackInfo {
pub name: String,
}
impl TrackInfo {
pub fn new(name: &str) -> TrackInfo {
TrackInfo { name: String::from(name) }
}
}
#[derive(Debug)]
pub struct Track { pub struct Track {
pub info: TrackInfo,
pub file: FileHandle, pub file: FileHandle,
} }
impl Track { impl Track {
pub fn new(file: FileHandle) -> Track { pub fn new(info: TrackInfo, file: FileHandle) -> Track {
Track { file } Track { info, file }
} }
} }