make it work
This commit is contained in:
parent
cfd8429188
commit
7bfca6f035
5 changed files with 55 additions and 22 deletions
|
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
16
src/track.rs
16
src/track.rs
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue