From aa04c6ef5b05a9fea0cf4d041a1bc76aff11881a Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 25 Mar 2024 17:20:03 +0700 Subject: [PATCH 01/10] implement clippy suggestions --- src/channel.rs | 4 ++-- src/download.rs | 2 +- src/main.rs | 2 +- src/player.rs | 4 ++-- src/telegram.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/channel.rs b/src/channel.rs index f7ef12f..6c45f5d 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -40,10 +40,10 @@ 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 { diff --git a/src/download.rs b/src/download.rs index 37125fb..0dd5668 100644 --- a/src/download.rs +++ b/src/download.rs @@ -30,5 +30,5 @@ pub fn download_from_youtube(url: &str) -> Result { .replace('\n', "") + ".mp3"; - Ok(TrackInfo::new(&Path::new(filename.as_str()))) + Ok(TrackInfo::new(Path::new(filename.as_str()))) } diff --git a/src/main.rs b/src/main.rs index fceed9a..329e05e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use music_bot::{player::MusicPlayer, telegram}; fn main() { - let player = MusicPlayer::new(); + let player = MusicPlayer::build(); let mut bot = telegram::TelegramBot::build(player); bot.telegram_main(); } diff --git a/src/player.rs b/src/player.rs index 2aa004b..3fd424c 100644 --- a/src/player.rs +++ b/src/player.rs @@ -37,7 +37,7 @@ struct Worker { } fn get_source(track: TrackInfo) -> Decoder> { - let file = BufReader::new(File::open(&track.path).unwrap()); + let file = BufReader::new(File::open(track.path).unwrap()); Decoder::new(file).unwrap() } @@ -100,7 +100,7 @@ impl Worker { } impl MusicPlayer { - pub fn new() -> MusicPlayer { + pub fn build() -> MusicPlayer { let (requester, responder) = channel::channel(); let _worker = thread::spawn(move || Worker::build(responder).main()); MusicPlayer { requester, _worker } diff --git a/src/telegram.rs b/src/telegram.rs index d777e77..b3527b3 100644 --- a/src/telegram.rs +++ b/src/telegram.rs @@ -48,7 +48,7 @@ impl TelegramBot { bot.send_message(msg.chat.id, "Added to the queue.").await?; }, Err(_) => { - bot.send_message(msg.chat.id, format!("Failed to download.")).await?; + bot.send_message(msg.chat.id, "Failed to download.").await?; } } } From 9a924c8c0d6051fe2831c871e37bbe80a0311f89 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 25 Mar 2024 17:21:28 +0700 Subject: [PATCH 02/10] formatting --- src/player.rs | 2 +- src/telegram.rs | 20 +++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/player.rs b/src/player.rs index 3fd424c..bdc5e42 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,5 +1,5 @@ -use std::{collections::VecDeque, fs::File, io::BufReader, thread, thread::JoinHandle}; use rodio::{Decoder, OutputStream, OutputStreamHandle, Sink}; +use std::{collections::VecDeque, fs::File, io::BufReader, thread, thread::JoinHandle}; use crate::channel::{self, Requester, Responder, TryRecvError}; use crate::track::TrackInfo; diff --git a/src/telegram.rs b/src/telegram.rs index b3527b3..c8b453f 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::{player::MusicPlayer, download}; +use crate::{download, player::MusicPlayer}; #[derive(BotCommands, Clone)] #[command( @@ -41,17 +41,15 @@ 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?; - }, - Err(_) => { - bot.send_message(msg.chat.id, "Failed to download.").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, "Failed to download.").await?; + } + }, Command::Stop => { player.lock().unwrap().stop(); bot.send_message(msg.chat.id, "Stopped.").await?; From 285384be229a4ea3805fba7fc38e7ace8ebe68ee Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 25 Mar 2024 17:36:02 +0700 Subject: [PATCH 03/10] add -- separator when calling yt-dlp --- src/download.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/download.rs b/src/download.rs index 0dd5668..f319b14 100644 --- a/src/download.rs +++ b/src/download.rs @@ -16,6 +16,7 @@ pub fn download_from_youtube(url: &str) -> Result { "--print", "%(id)s", "--no-simulate", + "--", url, ]) .output() From d6b2b54d13aa20af593092ec0bcea6a5a88e2acf Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 25 Mar 2024 17:46:29 +0700 Subject: [PATCH 04/10] add --no-playlist tag when calling yt-dlp --- src/download.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/download.rs b/src/download.rs index f319b14..603297d 100644 --- a/src/download.rs +++ b/src/download.rs @@ -16,6 +16,7 @@ pub fn download_from_youtube(url: &str) -> Result { "--print", "%(id)s", "--no-simulate", + "--no-playlist", "--", url, ]) From 959f954d9dd8adc053f30628f556fb48ef01b9e0 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 26 Mar 2024 10:09:26 +0700 Subject: [PATCH 05/10] send message when queue is empty --- src/telegram.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/telegram.rs b/src/telegram.rs index c8b453f..b3a39b1 100644 --- a/src/telegram.rs +++ b/src/telegram.rs @@ -68,15 +68,17 @@ impl TelegramBot { } Command::List => { let tracks = player.lock().unwrap().list_tracks(); - bot.send_message( - msg.chat.id, - tracks + let message: String; + if tracks.is_empty() { + message = String::from("The queue is empty."); + } else { + message = tracks .iter() .map(|t| t.path.to_str().unwrap()) .collect::>() - .join("\n"), - ) - .await?; + .join("\n"); + } + bot.send_message(msg.chat.id, message).await?; } }; Ok(()) From b278a6aa52acb583b3393790e198302fa0a60c16 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 1 Apr 2024 09:06:48 +0700 Subject: [PATCH 06/10] implement FileHandle --- src/file.rs | 21 +++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 22 insertions(+) create mode 100644 src/file.rs diff --git a/src/file.rs b/src/file.rs new file mode 100644 index 0000000..37375a7 --- /dev/null +++ b/src/file.rs @@ -0,0 +1,21 @@ +use std::path::{Path, PathBuf}; +use std::fs; + +#[derive(Debug, Clone)] +pub struct FileHandle { + path: PathBuf, +} + +impl FileHandle { + pub fn new(path: &Path) -> FileHandle { + FileHandle { + path: PathBuf::from(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 6f1f52b..61ca117 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod channel; pub mod download; +pub mod file; pub mod player; pub mod telegram; mod track; From 0448b3eced9d70becea0cce2dceb7b23ebf5b8dc Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 1 Apr 2024 09:08:21 +0700 Subject: [PATCH 07/10] rename TrackInfo to Track --- src/download.rs | 6 +++--- src/lib.rs | 2 +- src/player.rs | 16 ++++++++-------- src/track.rs | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/download.rs b/src/download.rs index 603297d..3c6bb96 100644 --- a/src/download.rs +++ b/src/download.rs @@ -1,11 +1,11 @@ use std::{path::Path, process::Command}; -use crate::track::TrackInfo; +use crate::track::Track; #[derive(Debug, Clone, Copy)] pub struct DownloadError; -pub fn download_from_youtube(url: &str) -> Result { +pub fn download_from_youtube(url: &str) -> Result { let output = Command::new("yt-dlp") .args([ "-o", @@ -32,5 +32,5 @@ pub fn download_from_youtube(url: &str) -> Result { .replace('\n', "") + ".mp3"; - Ok(TrackInfo::new(Path::new(filename.as_str()))) + Ok(Track::new(Path::new(filename.as_str()))) } diff --git a/src/lib.rs b/src/lib.rs index 61ca117..059045d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,4 +5,4 @@ pub mod player; pub mod telegram; mod track; -pub use track::TrackInfo; +pub use track::Track; diff --git a/src/player.rs b/src/player.rs index bdc5e42..3e2adac 100644 --- a/src/player.rs +++ b/src/player.rs @@ -2,11 +2,11 @@ use rodio::{Decoder, OutputStream, OutputStreamHandle, Sink}; use std::{collections::VecDeque, fs::File, io::BufReader, thread, thread::JoinHandle}; use crate::channel::{self, Requester, Responder, TryRecvError}; -use crate::track::TrackInfo; +use crate::track::Track; #[derive(Debug, Clone)] enum WorkerRequest { - AddTrack(TrackInfo), + AddTrack(Track), Pause, Play, Stop, @@ -16,7 +16,7 @@ enum WorkerRequest { #[derive(Debug, Clone)] enum WorkerResponse { - TrackList(VecDeque), + TrackList(VecDeque), None, } @@ -32,11 +32,11 @@ struct Worker { _stream: OutputStream, _handle: OutputStreamHandle, sink: Sink, - queue: VecDeque, + queue: VecDeque, responder: Responder, } -fn get_source(track: TrackInfo) -> Decoder> { +fn get_source(track: Track) -> Decoder> { let file = BufReader::new(File::open(track.path).unwrap()); Decoder::new(file).unwrap() } @@ -88,7 +88,7 @@ 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, @@ -106,7 +106,7 @@ impl MusicPlayer { MusicPlayer { requester, _worker } } - pub fn enqueue(&mut self, track: TrackInfo) { + pub fn enqueue(&mut self, track: Track) { self.requester.send(AddTrack(track)).unwrap(); } @@ -126,7 +126,7 @@ impl MusicPlayer { self.requester.send(Stop).unwrap(); } - pub fn list_tracks(&self) -> VecDeque { + pub fn list_tracks(&self) -> VecDeque { let response = self.requester.send(ListTracks).unwrap(); match response.recv().unwrap() { TrackList(tracks) => tracks, diff --git a/src/track.rs b/src/track.rs index b96f8de..62af41c 100644 --- a/src/track.rs +++ b/src/track.rs @@ -1,12 +1,12 @@ use std::path::{Path, PathBuf}; #[derive(Debug, Clone)] -pub struct TrackInfo { +pub struct Track { pub path: PathBuf, } -impl TrackInfo { - pub fn new(path: &Path) -> TrackInfo { - TrackInfo { +impl Track { + pub fn new(path: &Path) -> Track { + Track { path: PathBuf::from(path), } } From cfd8429188dc9ed6470d4458e7a0c25427a2a1bb Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 1 Apr 2024 09:12:55 +0700 Subject: [PATCH 08/10] use FileHandle in Track --- src/download.rs | 6 ++++-- src/file.rs | 6 +++++- src/player.rs | 2 +- src/telegram.rs | 2 +- src/track.rs | 11 +++++------ 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/download.rs b/src/download.rs index 3c6bb96..e67172c 100644 --- a/src/download.rs +++ b/src/download.rs @@ -1,6 +1,6 @@ use std::{path::Path, process::Command}; -use crate::track::Track; +use crate::{file::FileHandle, track::Track}; #[derive(Debug, Clone, Copy)] pub struct DownloadError; @@ -32,5 +32,7 @@ pub fn download_from_youtube(url: &str) -> Result { .replace('\n', "") + ".mp3"; - Ok(Track::new(Path::new(filename.as_str()))) + let file_handle = FileHandle::new(Path::new(filename.as_str())); + + Ok(Track::new(file_handle)) } diff --git a/src/file.rs b/src/file.rs index 37375a7..1ccf365 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,5 +1,5 @@ -use std::path::{Path, PathBuf}; use std::fs; +use std::path::{Path, PathBuf}; #[derive(Debug, Clone)] pub struct FileHandle { @@ -12,6 +12,10 @@ impl FileHandle { path: PathBuf::from(path), } } + + pub fn get_path(&self) -> &Path { + &self.path + } } impl Drop for FileHandle { diff --git a/src/player.rs b/src/player.rs index 3e2adac..f2edbbc 100644 --- a/src/player.rs +++ b/src/player.rs @@ -37,7 +37,7 @@ struct Worker { } fn get_source(track: Track) -> Decoder> { - let file = BufReader::new(File::open(track.path).unwrap()); + let file = BufReader::new(File::open(track.file.get_path()).unwrap()); Decoder::new(file).unwrap() } diff --git a/src/telegram.rs b/src/telegram.rs index b3a39b1..cd82a21 100644 --- a/src/telegram.rs +++ b/src/telegram.rs @@ -74,7 +74,7 @@ impl TelegramBot { } else { message = tracks .iter() - .map(|t| t.path.to_str().unwrap()) + .map(|t| t.file.get_path().to_str().unwrap()) .collect::>() .join("\n"); } diff --git a/src/track.rs b/src/track.rs index 62af41c..df1d0e5 100644 --- a/src/track.rs +++ b/src/track.rs @@ -1,13 +1,12 @@ -use std::path::{Path, PathBuf}; +use crate::file::FileHandle; + #[derive(Debug, Clone)] pub struct Track { - pub path: PathBuf, + pub file: FileHandle, } impl Track { - pub fn new(path: &Path) -> Track { - Track { - path: PathBuf::from(path), - } + pub fn new(file: FileHandle) -> Track { + Track { file } } } From 7bfca6f03545cfba9e4a0a21774b0aa359c3f789 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 1 Apr 2024 09:54:21 +0700 Subject: [PATCH 09/10] make it work --- src/channel.rs | 6 +++--- src/download.rs | 12 +++++++++--- src/player.rs | 41 ++++++++++++++++++++++++++++------------- src/telegram.rs | 2 +- src/track.rs | 16 ++++++++++++++-- 5 files changed, 55 insertions(+), 22 deletions(-) diff --git a/src/channel.rs b/src/channel.rs index 6c45f5d..7d8d33f 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, + data: Some(data), tx: response_tx, }) { 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() -> (Requester, Responder) { } pub struct Request { - pub data: T, + pub data: Option, tx: Sender, } diff --git a/src/download.rs b/src/download.rs index e67172c..501839c 100644 --- a/src/download.rs +++ b/src/download.rs @@ -1,6 +1,6 @@ use std::{path::Path, process::Command}; -use crate::{file::FileHandle, track::Track}; +use crate::{file::FileHandle, track::{Track, TrackInfo}}; #[derive(Debug, Clone, Copy)] pub struct DownloadError; @@ -17,6 +17,7 @@ pub fn download_from_youtube(url: &str) -> Result { "%(id)s", "--no-simulate", "--no-playlist", + "--no-warnings", "--", url, ]) @@ -24,6 +25,8 @@ pub fn download_from_youtube(url: &str) -> Result { .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); } @@ -32,7 +35,10 @@ pub fn download_from_youtube(url: &str) -> Result { .replace('\n', "") + ".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)) } diff --git a/src/player.rs b/src/player.rs index f2edbbc..4ea60a7 100644 --- a/src/player.rs +++ b/src/player.rs @@ -2,9 +2,9 @@ use rodio::{Decoder, OutputStream, OutputStreamHandle, Sink}; use std::{collections::VecDeque, fs::File, io::BufReader, thread, thread::JoinHandle}; use crate::channel::{self, Requester, Responder, TryRecvError}; -use crate::track::Track; +use crate::track::{Track, TrackInfo}; -#[derive(Debug, Clone)] +#[derive(Debug)] enum WorkerRequest { AddTrack(Track), Pause, @@ -14,9 +14,9 @@ enum WorkerRequest { ListTracks, } -#[derive(Debug, Clone)] +#[derive(Debug)] enum WorkerResponse { - TrackList(VecDeque), + TrackList(VecDeque), None, } @@ -25,7 +25,7 @@ use WorkerResponse::*; pub struct MusicPlayer { requester: Requester, - _worker: JoinHandle<()>, + worker: Option>, } struct Worker { @@ -33,10 +33,11 @@ struct Worker { _handle: OutputStreamHandle, sink: Sink, queue: VecDeque, + current: Option, responder: Responder, } -fn get_source(track: Track) -> Decoder> { +fn get_source(track: &Track) -> Decoder> { let file = BufReader::new(File::open(track.file.get_path()).unwrap()); Decoder::new(file).unwrap() } @@ -59,28 +60,34 @@ 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.clone()), + ListTracks => TrackList(self.queue.iter().map(|track| track.info.clone()).collect::>().clone()), } } pub fn main(&mut self) { loop { match self.responder.try_recv() { - Ok(req) => { - let _ = req.respond(self.match_request(req.data.clone())); + Ok(mut req) => { + let data = req.data.take().unwrap(); + let _ = req.respond(self.match_request(data)); } 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.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, sink, queue, + current: Option::None, responder, } } @@ -102,8 +110,8 @@ impl Worker { impl MusicPlayer { pub fn build() -> MusicPlayer { let (requester, responder) = channel::channel(); - let _worker = thread::spawn(move || Worker::build(responder).main()); - MusicPlayer { requester, _worker } + let worker = thread::spawn(move || Worker::build(responder).main()); + MusicPlayer { requester, worker: Some(worker) } } pub fn enqueue(&mut self, track: Track) { @@ -126,7 +134,7 @@ impl MusicPlayer { self.requester.send(Stop).unwrap(); } - pub fn list_tracks(&self) -> VecDeque { + pub fn list_tracks(&self) -> VecDeque { let response = self.requester.send(ListTracks).unwrap(); match response.recv().unwrap() { 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(); + } +} diff --git a/src/telegram.rs b/src/telegram.rs index cd82a21..076c812 100644 --- a/src/telegram.rs +++ b/src/telegram.rs @@ -74,7 +74,7 @@ impl TelegramBot { } else { message = tracks .iter() - .map(|t| t.file.get_path().to_str().unwrap()) + .map(|t| t.name.as_str()) .collect::>() .join("\n"); } diff --git a/src/track.rs b/src/track.rs index df1d0e5..820abc9 100644 --- a/src/track.rs +++ b/src/track.rs @@ -1,12 +1,24 @@ use crate::file::FileHandle; #[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 info: TrackInfo, pub file: FileHandle, } impl Track { - pub fn new(file: FileHandle) -> Track { - Track { file } + pub fn new(info: TrackInfo, file: FileHandle) -> Track { + Track { info, file } } } From 17b426be66491d73ad68e3e4cec4ea59ae0fd0e0 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 4 Apr 2024 10:22:30 +0700 Subject: [PATCH 10/10] split download --- src/download.rs | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/download.rs b/src/download.rs index 501839c..f29b533 100644 --- a/src/download.rs +++ b/src/download.rs @@ -6,6 +6,28 @@ use crate::{file::FileHandle, track::{Track, TrackInfo}}; 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); + } + let output = Command::new("yt-dlp") .args([ "-o", @@ -13,9 +35,6 @@ pub fn download_from_youtube(url: &str) -> Result { "--extract-audio", "--audio-format", "mp3", - "--print", - "%(id)s", - "--no-simulate", "--no-playlist", "--no-warnings", "--", @@ -30,13 +49,6 @@ pub fn download_from_youtube(url: &str) -> Result { return Err(DownloadError); } - let filename = std::str::from_utf8(output.stdout.as_slice()) - .unwrap() - .replace('\n', "") - + ".mp3"; - - println!("{}", filename); - let file_handle = FileHandle::new(Path::new(filename.as_str())); let info = TrackInfo::new(&filename);