diff --git a/src/music_controller/controller.rs b/src/music_controller/controller.rs index 7f62871..98c3ca8 100644 --- a/src/music_controller/controller.rs +++ b/src/music_controller/controller.rs @@ -2,25 +2,219 @@ //! player. It manages queues, playback, library access, and //! other functions +use std::path::PathBuf; use std::sync::{Arc, RwLock}; +use std::time::Duration; +use crossbeam_channel::{Sender, Receiver}; +// use std::sync::mpsc; +use crossbeam_channel; +use gstreamer::format::Default; +use gstreamer::query::Uri; +use std::thread::{self, sleep, spawn}; +use std::error::Error; +use crossbeam_channel::unbounded; +use rayon::iter::Rev; +use uuid::Uuid; + +use crate::config; +use crate::music_storage::library::Tag; +use crate::music_storage::playlist::Playlist; use crate::{ music_player::Player, - music_storage::library::Song, - config::config::Config + music_storage::{ + library::{MusicLibrary, Song} + }, + config::config::Config, }; struct Queue { player: Player, name: String, - songs: Vec, + songs: Playlist, +} +impl Queue { + fn new() -> Result> { + Ok( + Queue { + player: Player::new()?, + name: String::new(), + songs: Playlist::new() + } + ) + } } pub struct Controller { - queues: Vec, + // queues: Vec, config: Arc>, + // library: MusicLibrary, + controller_mail: MailMan, + db_mail: MailMan, + queue_mail: Vec>, +} +#[derive(Debug)] + +pub enum ControllerCommand { + Default, + Test +} +#[derive(Debug)] + +enum ControllerResponse { + Empty, + QueueMailMan(MailMan), + +} +#[derive(Debug)] + +pub enum DatabaseCommand { + Default, + Test, + GetSongs, + +} +#[derive(Debug)] + +enum DatabaseResponse { + Empty, + Songs(Vec), +} +#[derive(Debug)] +enum QueueCommand { + Default, + Test, + Play, + Pause, +} +#[derive(Debug)] +enum QueueResponse { + Default, + Test, } -impl Controller { - // more stuff to come +#[derive(Debug)] + +struct MailMan { + pub tx: Sender, + rx: Receiver } +impl MailMan { + pub fn new() -> Self { + let (tx, rx) = unbounded::(); + MailMan { tx, rx } + } +} +impl MailMan { + pub fn double() -> (MailMan, MailMan) { + let (tx, rx) = unbounded::(); + let (tx1, rx1) = unbounded::(); + + ( + MailMan { tx, rx: rx1 }, + MailMan { tx: tx1, rx } + ) + } + + pub fn send(&self, mail: T) -> Result<(), Box> { + &self.tx.send(mail).unwrap(); + Ok(()) + } + + pub fn recv(&self) -> Result> { + let u = self.rx.recv().unwrap(); + Ok(u) + } +} + +#[allow(unused_variables)] +impl Controller { + pub fn start(config: PathBuf) -> Result> { + let config = Config::read_file(config)?; + let uuid = config.libraries.get_default()?.uuid; + + let config = Arc::new(RwLock::from(config)); + let lib = MusicLibrary::init(config.clone(), uuid)?; + + let (out_thread_controller, in_thread) = MailMan::double(); + let monitor_thread = spawn(move || { + use ControllerCommand::*; + loop { + let command = in_thread.recv().unwrap(); + + match command { + Default => (), + Test => { + in_thread.send(ControllerResponse::Empty).unwrap(); + }, + } + } + }); + + + let (out_thread_db, in_thread) = MailMan::double(); + let db_monitor = spawn(move || { + use DatabaseCommand::*; + loop { + let command = in_thread.recv().unwrap(); + + match command { + Default => {}, + Test => { + in_thread.send(DatabaseResponse::Empty).unwrap(); + }, + GetSongs => { + let songs = lib.query_tracks(&String::from(""), &(vec![Tag::Title]), &(vec![Tag::Title])).unwrap().iter().cloned().cloned().collect(); + in_thread.send(DatabaseResponse::Songs(songs)).unwrap(); + }, + + } + } + }); + + + + Ok( + Controller { + // queues: Vec::new(), + config, + controller_mail: out_thread_controller, + db_mail: out_thread_db, + queue_mail: Vec::new(), + } + ) + } + fn get_db_songs(&self) -> Vec { + self.db_mail.send(DatabaseCommand::GetSongs); + match self.db_mail.recv().unwrap() { + DatabaseResponse::Songs(songs) => songs, + _ => Vec::new() + } + + } + pub fn new_queue(&mut self) { + let (out_thread_queue, in_thread) = MailMan::::double(); + let queues_monitor = spawn(move || { + use QueueCommand::*; + loop { + let command = in_thread.recv().unwrap(); + match command { + Default => {}, + Test => {}, + Play => {}, + Pause => {}, + } + } + }); + self.queue_mail.push(out_thread_queue); + } +} + +#[test] +fn name() { + let a = Controller::start(PathBuf::from("test-config/config_test.json")).unwrap(); + // sleep(Duration::from_millis(5000)); + _ = a.controller_mail.send(ControllerCommand::Test); + // dbg!(a.get_db_songs()); + // sleep(Duration::from_secs(6)); +} \ No newline at end of file diff --git a/src/music_storage/db_reader/itunes/reader.rs b/src/music_storage/db_reader/itunes/reader.rs index c2063c0..3bc73f6 100644 --- a/src/music_storage/db_reader/itunes/reader.rs +++ b/src/music_storage/db_reader/itunes/reader.rs @@ -2,17 +2,20 @@ use file_format::FileFormat; use lofty::{AudioFile, LoftyError, ParseOptions, Probe, TagType, TaggedFileExt}; use quick_xml::events::Event; use quick_xml::reader::Reader; +use uuid::Uuid; use std::collections::{BTreeMap, HashMap}; use std::fs::File; use std::path::{Path, PathBuf}; use std::str::FromStr; +use std::sync::{Arc, RwLock}; use std::time::Duration as StdDur; use std::vec::Vec; use chrono::prelude::*; +use crate::config::config::{Config, ConfigLibrary}; use crate::music_storage::db_reader::extern_library::ExternalLibrary; -use crate::music_storage::library::{AlbumArt, Service, Song, Tag, URI}; +use crate::music_storage::library::{AlbumArt, MusicLibrary, Service, Song, Tag, URI}; use crate::music_storage::utils; use urlencoding::decode; @@ -320,4 +323,20 @@ impl ITunesSong { // println!("{:.2?}", song); Ok(song) } +} + +#[test] +fn itunes_lib_test() { + let mut config = Config::read_file(PathBuf::from("test-config/config_test.json")).unwrap(); + let config_lib = ConfigLibrary::new(PathBuf::from("test-config/library2"), String::from("library2"), None); + config.libraries.libraries.push(config_lib.clone()); + + let songs = ITunesLibrary::from_file(Path::new("test-config\\iTunesLib.xml")).to_songs(); + + let mut library = MusicLibrary::init(Arc::new(RwLock::from(config.clone())), config_lib.uuid).unwrap(); + + songs.iter().for_each(|song| library.add_song(song.to_owned()).unwrap()); + + config.write_file().unwrap(); + library.save(config).unwrap(); } \ No newline at end of file diff --git a/src/music_storage/playlist.rs b/src/music_storage/playlist.rs index c2c6b74..69ae390 100644 --- a/src/music_storage/playlist.rs +++ b/src/music_storage/playlist.rs @@ -23,15 +23,15 @@ pub enum SortOrder { Tag(Tag) } #[derive(Debug, Clone)] -pub struct Playlist<'a> { +pub struct Playlist { title: String, - cover: Option<&'a AlbumArt>, + cover: Option, tracks: Vec, sort_order: SortOrder, play_count: i32, play_time: Duration, } -impl<'a> Playlist<'a> { +impl Playlist { pub fn new() -> Self { Default::default() } @@ -109,7 +109,7 @@ impl<'a> Playlist<'a> { .unwrap(); m3u8.write_to(&mut file).unwrap(); } - pub fn from_m3u8(path: &str) -> Result, Error> { + pub fn from_m3u8(path: &str) -> Result { let mut file = match File::open(path) { Ok(file) => file, Err(e) => return Err(e), @@ -137,7 +137,7 @@ impl<'a> Playlist<'a> { &self.title } fn cover(&self) -> Option<&AlbumArt> { - match self.cover { + match &self.cover { Some(e) => Some(e), None => None, } @@ -149,7 +149,7 @@ impl<'a> Playlist<'a> { -impl Default for Playlist<'_> { +impl Default for Playlist { fn default() -> Self { Playlist { title: String::default(),