diff --git a/src/channel.rs b/src/channel.rs index 7d8d33f..f7ef12f 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -12,11 +12,11 @@ impl Requester { pub fn send(&self, data: T) -> Result, SendError> { let (response_tx, response_rx) = mpsc::channel(); match self.tx.send(Request { - data: Some(data), + data, tx: response_tx, }) { Ok(_) => Ok(Response { rx: response_rx }), - Err(e) => Err(SendError(e.0.data.unwrap())), + Err(e) => Err(SendError(e.0.data)), } } } @@ -40,14 +40,14 @@ impl Responder { pub fn channel() -> (Requester, Responder) { let (requester_tx, responder_rx) = mpsc::channel(); - ( + return ( Requester { tx: requester_tx }, Responder { rx: responder_rx }, - ) + ); } pub struct Request { - pub data: Option, + pub data: T, tx: Sender, } diff --git a/src/download.rs b/src/download.rs index f29b533..37125fb 100644 --- a/src/download.rs +++ b/src/download.rs @@ -1,33 +1,11 @@ use std::{path::Path, process::Command}; -use crate::{file::FileHandle, track::{Track, TrackInfo}}; +use crate::track::TrackInfo; #[derive(Debug, Clone, Copy)] pub struct DownloadError; -pub fn download_from_youtube(url: &str) -> Result { - let output = Command::new("yt-dlp") - .args([ - "--print", - "%(id)s %(duration)i", - "--no-playlist", - "--no-warnings", - "--", - url, - ]).output().unwrap(); - - let items: Vec = std::str::from_utf8(&output.stdout).unwrap().split(' ').map(|s| s.replace("\n", "")).collect(); - - let filename = items[0].clone() + ".mp3"; - let duration: u32 = items[1].parse().unwrap(); - - println!("{}", filename); - println!("{}", duration); - - if duration > 900 { - return Err(DownloadError); - } - +pub fn download_from_youtube(url: &str) -> Result { let output = Command::new("yt-dlp") .args([ "-o", @@ -35,22 +13,22 @@ pub fn download_from_youtube(url: &str) -> Result { "--extract-audio", "--audio-format", "mp3", - "--no-playlist", - "--no-warnings", - "--", + "--print", + "%(id)s", + "--no-simulate", url, ]) .output() .unwrap(); 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); } - let file_handle = FileHandle::new(Path::new(filename.as_str())); - let info = TrackInfo::new(&filename); + let filename = std::str::from_utf8(output.stdout.as_slice()) + .unwrap() + .replace('\n', "") + + ".mp3"; - Ok(Track::new(info, file_handle)) + Ok(TrackInfo::new(&Path::new(filename.as_str()))) } diff --git a/src/file.rs b/src/file.rs deleted file mode 100644 index 1ccf365..0000000 --- a/src/file.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::fs; -use std::path::{Path, PathBuf}; - -#[derive(Debug, Clone)] -pub struct FileHandle { - path: PathBuf, -} - -impl FileHandle { - pub fn new(path: &Path) -> FileHandle { - FileHandle { - path: PathBuf::from(path), - } - } - - pub fn get_path(&self) -> &Path { - &self.path - } -} - -impl Drop for FileHandle { - fn drop(&mut self) { - let _ = fs::remove_file(self.path.clone()); - } -} diff --git a/src/lib.rs b/src/lib.rs index 059045d..6f1f52b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,7 @@ pub mod channel; pub mod download; -pub mod file; pub mod player; pub mod telegram; mod track; -pub use track::Track; +pub use track::TrackInfo; diff --git a/src/main.rs b/src/main.rs index 329e05e..fceed9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use music_bot::{player::MusicPlayer, telegram}; fn main() { - let player = MusicPlayer::build(); + let player = MusicPlayer::new(); let mut bot = telegram::TelegramBot::build(player); bot.telegram_main(); } diff --git a/src/player.rs b/src/player.rs index 4ea60a7..2aa004b 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,12 +1,12 @@ -use rodio::{Decoder, OutputStream, OutputStreamHandle, Sink}; use std::{collections::VecDeque, fs::File, io::BufReader, thread, thread::JoinHandle}; +use rodio::{Decoder, OutputStream, OutputStreamHandle, Sink}; use crate::channel::{self, Requester, Responder, TryRecvError}; -use crate::track::{Track, TrackInfo}; +use crate::track::TrackInfo; -#[derive(Debug)] +#[derive(Debug, Clone)] enum WorkerRequest { - AddTrack(Track), + AddTrack(TrackInfo), Pause, Play, Stop, @@ -14,7 +14,7 @@ enum WorkerRequest { ListTracks, } -#[derive(Debug)] +#[derive(Debug, Clone)] enum WorkerResponse { TrackList(VecDeque), None, @@ -25,20 +25,19 @@ use WorkerResponse::*; pub struct MusicPlayer { requester: Requester, - worker: Option>, + _worker: JoinHandle<()>, } struct Worker { _stream: OutputStream, _handle: OutputStreamHandle, sink: Sink, - queue: VecDeque, - current: Option, + queue: VecDeque, responder: Responder, } -fn get_source(track: &Track) -> Decoder> { - let file = BufReader::new(File::open(track.file.get_path()).unwrap()); +fn get_source(track: TrackInfo) -> Decoder> { + let file = BufReader::new(File::open(&track.path).unwrap()); Decoder::new(file).unwrap() } @@ -60,34 +59,28 @@ impl Worker { Stop => { self.sink.stop(); self.queue.clear(); - self.current.take(); None } SkipOne => { self.sink.skip_one(); - self.current.take(); None } - ListTracks => TrackList(self.queue.iter().map(|track| track.info.clone()).collect::>().clone()), + ListTracks => TrackList(self.queue.clone()), } } pub fn main(&mut self) { loop { match self.responder.try_recv() { - Ok(mut req) => { - let data = req.data.take().unwrap(); - let _ = req.respond(self.match_request(data)); + Ok(req) => { + let _ = req.respond(self.match_request(req.data.clone())); } Err(TryRecvError::Empty) => {} Err(TryRecvError::Disconnected) => break, }; if self.sink.empty() && !self.queue.is_empty() { let next_track = self.queue.pop_front().unwrap(); - self.sink.append(get_source(&next_track)); - self.current = Some(next_track); - } else if self.sink.empty() { - self.current.take(); + self.sink.append(get_source(next_track)); } } } @@ -95,26 +88,25 @@ impl Worker { pub fn build(responder: Responder) -> Worker { let (_stream, _handle) = OutputStream::try_default().unwrap(); let sink = Sink::try_new(&_handle).unwrap(); - let queue: VecDeque = VecDeque::new(); + let queue: VecDeque = VecDeque::new(); Worker { _stream, _handle, sink, queue, - current: Option::None, responder, } } } impl MusicPlayer { - pub fn build() -> MusicPlayer { + pub fn new() -> MusicPlayer { let (requester, responder) = channel::channel(); - let worker = thread::spawn(move || Worker::build(responder).main()); - MusicPlayer { requester, worker: Some(worker) } + let _worker = thread::spawn(move || Worker::build(responder).main()); + MusicPlayer { requester, _worker } } - pub fn enqueue(&mut self, track: Track) { + pub fn enqueue(&mut self, track: TrackInfo) { self.requester.send(AddTrack(track)).unwrap(); } @@ -142,10 +134,3 @@ impl MusicPlayer { } } } - -impl Drop for MusicPlayer { - fn drop(&mut self) { - self.stop(); - self.worker.take().unwrap().join().unwrap(); - } -} diff --git a/src/telegram.rs b/src/telegram.rs index 076c812..d777e77 100644 --- a/src/telegram.rs +++ b/src/telegram.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, Mutex}; use teloxide::{prelude::*, utils::command::BotCommands}; -use crate::{download, player::MusicPlayer}; +use crate::{player::MusicPlayer, download}; #[derive(BotCommands, Clone)] #[command( @@ -41,15 +41,17 @@ impl TelegramBot { cmd: Command, ) -> Result<(), teloxide::RequestError> { match cmd { - Command::Play(url) => match download::download_from_youtube(&url) { - Ok(track_info) => { - player.lock().unwrap().enqueue(track_info); - bot.send_message(msg.chat.id, "Added to the queue.").await?; + Command::Play(url) => { + match download::download_from_youtube(&url) { + Ok(track_info) => { + player.lock().unwrap().enqueue(track_info); + bot.send_message(msg.chat.id, "Added to the queue.").await?; + }, + Err(_) => { + bot.send_message(msg.chat.id, format!("Failed to download.")).await?; + } } - Err(_) => { - bot.send_message(msg.chat.id, "Failed to download.").await?; - } - }, + } Command::Stop => { player.lock().unwrap().stop(); bot.send_message(msg.chat.id, "Stopped.").await?; @@ -68,17 +70,15 @@ impl TelegramBot { } Command::List => { let tracks = player.lock().unwrap().list_tracks(); - let message: String; - if tracks.is_empty() { - message = String::from("The queue is empty."); - } else { - message = tracks + bot.send_message( + msg.chat.id, + tracks .iter() - .map(|t| t.name.as_str()) + .map(|t| t.path.to_str().unwrap()) .collect::>() - .join("\n"); - } - bot.send_message(msg.chat.id, message).await?; + .join("\n"), + ) + .await?; } }; Ok(()) diff --git a/src/track.rs b/src/track.rs index 820abc9..b96f8de 100644 --- a/src/track.rs +++ b/src/track.rs @@ -1,24 +1,13 @@ -use crate::file::FileHandle; - +use std::path::{Path, PathBuf}; #[derive(Debug, Clone)] pub struct TrackInfo { - pub name: String, + pub path: PathBuf, } impl TrackInfo { - pub fn new(name: &str) -> TrackInfo { - TrackInfo { name: String::from(name) } - } -} - -#[derive(Debug)] -pub struct Track { - pub info: TrackInfo, - pub file: FileHandle, -} - -impl Track { - pub fn new(info: TrackInfo, file: FileHandle) -> Track { - Track { info, file } + pub fn new(path: &Path) -> TrackInfo { + TrackInfo { + path: PathBuf::from(path), + } } }