started work on controller protoype

This commit is contained in:
MrDulfin 2024-02-11 15:54:11 -05:00
parent 96069fd9bc
commit 3ad8b78e9d
3 changed files with 226 additions and 13 deletions

View file

@ -2,25 +2,219 @@
//! player. It manages queues, playback, library access, and //! player. It manages queues, playback, library access, and
//! other functions //! other functions
use std::path::PathBuf;
use std::sync::{Arc, RwLock}; 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::{ use crate::{
music_player::Player, music_player::Player,
music_storage::library::Song, music_storage::{
config::config::Config library::{MusicLibrary, Song}
},
config::config::Config,
}; };
struct Queue { struct Queue {
player: Player, player: Player,
name: String, name: String,
songs: Vec<Song>, songs: Playlist,
}
impl Queue {
fn new() -> Result<Self, Box<dyn Error>> {
Ok(
Queue {
player: Player::new()?,
name: String::new(),
songs: Playlist::new()
}
)
}
} }
pub struct Controller { pub struct Controller {
queues: Vec<Queue>, // queues: Vec<Queue>,
config: Arc<RwLock<Config>>, config: Arc<RwLock<Config>>,
// library: MusicLibrary,
controller_mail: MailMan<ControllerCommand, ControllerResponse>,
db_mail: MailMan<DatabaseCommand, DatabaseResponse>,
queue_mail: Vec<MailMan<QueueCommand, QueueResponse>>,
}
#[derive(Debug)]
pub enum ControllerCommand {
Default,
Test
}
#[derive(Debug)]
enum ControllerResponse {
Empty,
QueueMailMan(MailMan<QueueCommand, QueueResponse>),
}
#[derive(Debug)]
pub enum DatabaseCommand {
Default,
Test,
GetSongs,
}
#[derive(Debug)]
enum DatabaseResponse {
Empty,
Songs(Vec<Song>),
}
#[derive(Debug)]
enum QueueCommand {
Default,
Test,
Play,
Pause,
}
#[derive(Debug)]
enum QueueResponse {
Default,
Test,
} }
impl Controller { #[derive(Debug)]
// more stuff to come
struct MailMan<T, U> {
pub tx: Sender<T>,
rx: Receiver<U>
} }
impl<T> MailMan<T, T> {
pub fn new() -> Self {
let (tx, rx) = unbounded::<T>();
MailMan { tx, rx }
}
}
impl<T, U> MailMan<T, U> {
pub fn double() -> (MailMan<T, U>, MailMan<U, T>) {
let (tx, rx) = unbounded::<T>();
let (tx1, rx1) = unbounded::<U>();
(
MailMan { tx, rx: rx1 },
MailMan { tx: tx1, rx }
)
}
pub fn send(&self, mail: T) -> Result<(), Box<dyn Error>> {
&self.tx.send(mail).unwrap();
Ok(())
}
pub fn recv(&self) -> Result<U, Box<dyn Error>> {
let u = self.rx.recv().unwrap();
Ok(u)
}
}
#[allow(unused_variables)]
impl Controller {
pub fn start(config: PathBuf) -> Result<Self, Box<dyn Error>> {
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<Song> {
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::<QueueCommand, QueueResponse>::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));
}

View file

@ -2,17 +2,20 @@ use file_format::FileFormat;
use lofty::{AudioFile, LoftyError, ParseOptions, Probe, TagType, TaggedFileExt}; use lofty::{AudioFile, LoftyError, ParseOptions, Probe, TagType, TaggedFileExt};
use quick_xml::events::Event; use quick_xml::events::Event;
use quick_xml::reader::Reader; use quick_xml::reader::Reader;
use uuid::Uuid;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::fs::File; use std::fs::File;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, RwLock};
use std::time::Duration as StdDur; use std::time::Duration as StdDur;
use std::vec::Vec; use std::vec::Vec;
use chrono::prelude::*; use chrono::prelude::*;
use crate::config::config::{Config, ConfigLibrary};
use crate::music_storage::db_reader::extern_library::ExternalLibrary; 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 crate::music_storage::utils;
use urlencoding::decode; use urlencoding::decode;
@ -320,4 +323,20 @@ impl ITunesSong {
// println!("{:.2?}", song); // println!("{:.2?}", song);
Ok(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();
} }

View file

@ -23,15 +23,15 @@ pub enum SortOrder {
Tag(Tag) Tag(Tag)
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Playlist<'a> { pub struct Playlist {
title: String, title: String,
cover: Option<&'a AlbumArt>, cover: Option<AlbumArt>,
tracks: Vec<Uuid>, tracks: Vec<Uuid>,
sort_order: SortOrder, sort_order: SortOrder,
play_count: i32, play_count: i32,
play_time: Duration, play_time: Duration,
} }
impl<'a> Playlist<'a> { impl Playlist {
pub fn new() -> Self { pub fn new() -> Self {
Default::default() Default::default()
} }
@ -109,7 +109,7 @@ impl<'a> Playlist<'a> {
.unwrap(); .unwrap();
m3u8.write_to(&mut file).unwrap(); m3u8.write_to(&mut file).unwrap();
} }
pub fn from_m3u8(path: &str) -> Result<Playlist<'a>, Error> { pub fn from_m3u8(path: &str) -> Result<Playlist, Error> {
let mut file = match File::open(path) { let mut file = match File::open(path) {
Ok(file) => file, Ok(file) => file,
Err(e) => return Err(e), Err(e) => return Err(e),
@ -137,7 +137,7 @@ impl<'a> Playlist<'a> {
&self.title &self.title
} }
fn cover(&self) -> Option<&AlbumArt> { fn cover(&self) -> Option<&AlbumArt> {
match self.cover { match &self.cover {
Some(e) => Some(e), Some(e) => Some(e),
None => None, None => None,
} }
@ -149,7 +149,7 @@ impl<'a> Playlist<'a> {
impl Default for Playlist<'_> { impl Default for Playlist {
fn default() -> Self { fn default() -> Self {
Playlist { Playlist {
title: String::default(), title: String::default(),