mirror of
				https://github.com/Dummi26/musicdb.git
				synced 2025-11-04 05:16:17 +01:00 
			
		
		
		
	lib_dir is no longer saved in dbfile
This commit is contained in:
		
							parent
							
								
									4a729c596c
								
							
						
					
					
						commit
						3093ec1a25
					
				@ -6,6 +6,7 @@ edition = "2021"
 | 
				
			|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
					# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
 | 
					clap = { version = "4.4.6", features = ["derive"] }
 | 
				
			||||||
directories = "5.0.1"
 | 
					directories = "5.0.1"
 | 
				
			||||||
musicdb-lib = { version = "0.1.0", path = "../musicdb-lib" }
 | 
					musicdb-lib = { version = "0.1.0", path = "../musicdb-lib" }
 | 
				
			||||||
regex = "1.9.3"
 | 
					regex = "1.9.3"
 | 
				
			||||||
 | 
				
			|||||||
@ -198,7 +198,7 @@ impl Gui {
 | 
				
			|||||||
                | Command::Pause
 | 
					                | Command::Pause
 | 
				
			||||||
                | Command::Stop
 | 
					                | Command::Stop
 | 
				
			||||||
                | Command::Save
 | 
					                | Command::Save
 | 
				
			||||||
                | Command::SetLibraryDirectory(..) => {}
 | 
					                | Command::InitComplete => {}
 | 
				
			||||||
                Command::NextSong
 | 
					                Command::NextSong
 | 
				
			||||||
                | Command::QueueUpdate(..)
 | 
					                | Command::QueueUpdate(..)
 | 
				
			||||||
                | Command::QueueAdd(..)
 | 
					                | Command::QueueAdd(..)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    eprintln, fs,
 | 
					 | 
				
			||||||
    io::{BufReader, Write},
 | 
					    io::{BufReader, Write},
 | 
				
			||||||
    net::{SocketAddr, TcpStream},
 | 
					    net::{SocketAddr, TcpStream},
 | 
				
			||||||
    path::PathBuf,
 | 
					    path::PathBuf,
 | 
				
			||||||
@ -8,15 +7,12 @@ use std::{
 | 
				
			|||||||
    time::Duration,
 | 
					    time::Duration,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use clap::{Parser, Subcommand};
 | 
				
			||||||
use gui::GuiEvent;
 | 
					use gui::GuiEvent;
 | 
				
			||||||
use musicdb_lib::{
 | 
					use musicdb_lib::{
 | 
				
			||||||
    data::{
 | 
					    data::{
 | 
				
			||||||
        album::Album,
 | 
					        database::{ClientIo, Database},
 | 
				
			||||||
        artist::Artist,
 | 
					        CoverId, SongId,
 | 
				
			||||||
        database::{ClientIo, Cover, Database},
 | 
					 | 
				
			||||||
        queue::QueueContent,
 | 
					 | 
				
			||||||
        song::Song,
 | 
					 | 
				
			||||||
        CoverId, DatabaseLocation, GeneralData, SongId,
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    load::ToFromBytes,
 | 
					    load::ToFromBytes,
 | 
				
			||||||
    player::Player,
 | 
					    player::Player,
 | 
				
			||||||
@ -44,12 +40,24 @@ mod gui_text;
 | 
				
			|||||||
mod gui_wrappers;
 | 
					mod gui_wrappers;
 | 
				
			||||||
mod textcfg;
 | 
					mod textcfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Copy)]
 | 
					#[derive(Parser, Debug)]
 | 
				
			||||||
 | 
					struct Args {
 | 
				
			||||||
 | 
					    /// the address to be used for the tcp connection to the server
 | 
				
			||||||
 | 
					    addr: SocketAddr,
 | 
				
			||||||
 | 
					    /// what to do
 | 
				
			||||||
 | 
					    #[command(subcommand)]
 | 
				
			||||||
 | 
					    mode: Mode,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Subcommand, Debug, Clone)]
 | 
				
			||||||
enum Mode {
 | 
					enum Mode {
 | 
				
			||||||
    Cli,
 | 
					    #[cfg(feature = "speedy2d")]
 | 
				
			||||||
 | 
					    /// graphical user interface
 | 
				
			||||||
    Gui,
 | 
					    Gui,
 | 
				
			||||||
    SyncPlayer,
 | 
					    /// play in sync with the server, but load the songs from a local copy of the lib-dir
 | 
				
			||||||
    SyncPlayerWithoutData,
 | 
					    SyncplayerLocal { lib_dir: PathBuf },
 | 
				
			||||||
 | 
					    /// play in sync with the server, and fetch the songs from it too. slower than the local variant for obvious reasons
 | 
				
			||||||
 | 
					    SyncplayerNetwork,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn get_config_file_path() -> PathBuf {
 | 
					fn get_config_file_path() -> PathBuf {
 | 
				
			||||||
@ -57,36 +65,15 @@ fn get_config_file_path() -> PathBuf {
 | 
				
			|||||||
        .unwrap()
 | 
					        .unwrap()
 | 
				
			||||||
        .config_dir()
 | 
					        .config_dir()
 | 
				
			||||||
        .to_path_buf()
 | 
					        .to_path_buf()
 | 
				
			||||||
    // if let Ok(config_home) = std::env::var("XDG_CONFIG_HOME") {
 | 
					 | 
				
			||||||
    //     let mut config_home: PathBuf = config_home.into();
 | 
					 | 
				
			||||||
    //     config_home.push("musicdb-client");
 | 
					 | 
				
			||||||
    //     config_home
 | 
					 | 
				
			||||||
    // } else if let Ok(home) = std::env::var("HOME") {
 | 
					 | 
				
			||||||
    //     let mut config_home: PathBuf = home.into();
 | 
					 | 
				
			||||||
    //     config_home.push(".config");
 | 
					 | 
				
			||||||
    //     config_home.push("musicdb-client");
 | 
					 | 
				
			||||||
    //     config_home
 | 
					 | 
				
			||||||
    // } else {
 | 
					 | 
				
			||||||
    //     eprintln!("No config directory!");
 | 
					 | 
				
			||||||
    //     std::process::exit(24);
 | 
					 | 
				
			||||||
    // }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
    let mut args = std::env::args().skip(1);
 | 
					    // parse args
 | 
				
			||||||
    let mode = match args.next().as_ref().map(|v| v.trim()) {
 | 
					    let args = Args::parse();
 | 
				
			||||||
        Some("cli") => Mode::Cli,
 | 
					    // start
 | 
				
			||||||
        Some("gui") => Mode::Gui,
 | 
					    let addr = args.addr;
 | 
				
			||||||
        Some("syncplayer") => Mode::SyncPlayer,
 | 
					 | 
				
			||||||
        Some("syncplayernd") => Mode::SyncPlayerWithoutData,
 | 
					 | 
				
			||||||
        _ => {
 | 
					 | 
				
			||||||
            println!("Run with argument <cli/gui/syncplayer/syncplayernd>!");
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    let addr = args.next().unwrap_or("127.0.0.1:26314".to_string());
 | 
					 | 
				
			||||||
    let addr = addr.parse::<SocketAddr>().unwrap();
 | 
					 | 
				
			||||||
    let mut con = TcpStream::connect(addr).unwrap();
 | 
					    let mut con = TcpStream::connect(addr).unwrap();
 | 
				
			||||||
 | 
					    let mode = args.mode;
 | 
				
			||||||
    writeln!(con, "main").unwrap();
 | 
					    writeln!(con, "main").unwrap();
 | 
				
			||||||
    let database = Arc::new(Mutex::new(Database::new_clientside()));
 | 
					    let database = Arc::new(Mutex::new(Database::new_clientside()));
 | 
				
			||||||
    #[cfg(feature = "speedy2d")]
 | 
					    #[cfg(feature = "speedy2d")]
 | 
				
			||||||
@ -95,16 +82,21 @@ fn main() {
 | 
				
			|||||||
    #[cfg(feature = "speedy2d")]
 | 
					    #[cfg(feature = "speedy2d")]
 | 
				
			||||||
    let sender = Arc::clone(&update_gui_sender);
 | 
					    let sender = Arc::clone(&update_gui_sender);
 | 
				
			||||||
    let con_thread = {
 | 
					    let con_thread = {
 | 
				
			||||||
 | 
					        let mode = mode.clone();
 | 
				
			||||||
        let database = Arc::clone(&database);
 | 
					        let database = Arc::clone(&database);
 | 
				
			||||||
        let mut con = con.try_clone().unwrap();
 | 
					        let mut con = con.try_clone().unwrap();
 | 
				
			||||||
        // this is all you need to keep the db in sync
 | 
					        // this is all you need to keep the db in sync
 | 
				
			||||||
        thread::spawn(move || {
 | 
					        thread::spawn(move || {
 | 
				
			||||||
            let mut player = if matches!(mode, Mode::SyncPlayer | Mode::SyncPlayerWithoutData) {
 | 
					            let mut player =
 | 
				
			||||||
                Some(Player::new().unwrap())
 | 
					                if matches!(mode, Mode::SyncplayerLocal { .. } | Mode::SyncplayerNetwork) {
 | 
				
			||||||
 | 
					                    Some(Player::new().unwrap())
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					            if let Mode::SyncplayerLocal { lib_dir } = mode {
 | 
				
			||||||
 | 
					                let mut db = database.lock().unwrap();
 | 
				
			||||||
 | 
					                db.lib_directory = lib_dir;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                None
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
            if matches!(mode, Mode::SyncPlayerWithoutData) {
 | 
					 | 
				
			||||||
                let mut db = database.lock().unwrap();
 | 
					                let mut db = database.lock().unwrap();
 | 
				
			||||||
                let client_con: Box<dyn ClientIo> = Box::new(TcpStream::connect(addr).unwrap());
 | 
					                let client_con: Box<dyn ClientIo> = Box::new(TcpStream::connect(addr).unwrap());
 | 
				
			||||||
                db.remote_server_as_song_file_source = Some(Arc::new(Mutex::new(
 | 
					                db.remote_server_as_song_file_source = Some(Arc::new(Mutex::new(
 | 
				
			||||||
@ -114,7 +106,7 @@ fn main() {
 | 
				
			|||||||
            loop {
 | 
					            loop {
 | 
				
			||||||
                if let Some(player) = &mut player {
 | 
					                if let Some(player) = &mut player {
 | 
				
			||||||
                    let mut db = database.lock().unwrap();
 | 
					                    let mut db = database.lock().unwrap();
 | 
				
			||||||
                    if !db.lib_directory.as_os_str().is_empty() {
 | 
					                    if db.is_client_init() {
 | 
				
			||||||
                        player.update(&mut db);
 | 
					                        player.update(&mut db);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -131,15 +123,8 @@ fn main() {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    match mode {
 | 
					    match mode {
 | 
				
			||||||
        Mode::Cli => {
 | 
					        #[cfg(feature = "speedy2d")]
 | 
				
			||||||
            Looper {
 | 
					 | 
				
			||||||
                con: &mut con,
 | 
					 | 
				
			||||||
                database: &database,
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            .cmd_loop();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        Mode::Gui => {
 | 
					        Mode::Gui => {
 | 
				
			||||||
            #[cfg(feature = "speedy2d")]
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                let occasional_refresh_sender = Arc::clone(&sender);
 | 
					                let occasional_refresh_sender = Arc::clone(&sender);
 | 
				
			||||||
                thread::spawn(move || loop {
 | 
					                thread::spawn(move || loop {
 | 
				
			||||||
@ -159,162 +144,12 @@ fn main() {
 | 
				
			|||||||
                )
 | 
					                )
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Mode::SyncPlayer | Mode::SyncPlayerWithoutData => {
 | 
					        Mode::SyncplayerLocal { .. } | Mode::SyncplayerNetwork => {
 | 
				
			||||||
            con_thread.join().unwrap();
 | 
					            con_thread.join().unwrap();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
struct Looper<'a> {
 | 
					 | 
				
			||||||
    pub con: &'a mut TcpStream,
 | 
					 | 
				
			||||||
    pub database: &'a Arc<Mutex<Database>>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
impl<'a> Looper<'a> {
 | 
					 | 
				
			||||||
    pub fn cmd_loop(&mut self) {
 | 
					 | 
				
			||||||
        loop {
 | 
					 | 
				
			||||||
            println!();
 | 
					 | 
				
			||||||
            let line = self.read_line(" > enter a command (help for help)");
 | 
					 | 
				
			||||||
            let line = line.trim();
 | 
					 | 
				
			||||||
            match line {
 | 
					 | 
				
			||||||
                "resume" => Command::Resume,
 | 
					 | 
				
			||||||
                "pause" => Command::Pause,
 | 
					 | 
				
			||||||
                "stop" => Command::Stop,
 | 
					 | 
				
			||||||
                "next" => Command::NextSong,
 | 
					 | 
				
			||||||
                "set-lib-dir" => {
 | 
					 | 
				
			||||||
                    let line = self.read_line("Enter the new (absolute) library directory, or leave empty to abort");
 | 
					 | 
				
			||||||
                    if !line.is_empty() {
 | 
					 | 
				
			||||||
                        Command::SetLibraryDirectory(line.into())
 | 
					 | 
				
			||||||
                    } else {
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                "add-song" => {
 | 
					 | 
				
			||||||
                    let song = Song {
 | 
					 | 
				
			||||||
                        id: 0,
 | 
					 | 
				
			||||||
                        location: self.read_line("The songs file is located, relative to the library root, at...").into(),
 | 
					 | 
				
			||||||
                        title: self.read_line("The songs title is..."),
 | 
					 | 
				
			||||||
                        album: self.read_line_ido("The song is part of the album with the id... (empty for None)"),
 | 
					 | 
				
			||||||
                        artist: self.read_line_id("The song is made by the artist with the id..."),
 | 
					 | 
				
			||||||
                        more_artists: accumulate(|| self.read_line_ido("The song is made with support by other artist, one of which has the id... (will ask repeatedly; leave empty once done)")),
 | 
					 | 
				
			||||||
                        cover: self.read_line_ido("The song should use the cover with the id... (empty for None - will default to album or artist cover, if available)"),
 | 
					 | 
				
			||||||
                        general: GeneralData::default(),
 | 
					 | 
				
			||||||
                        cached_data: Arc::new(Mutex::new(None)),
 | 
					 | 
				
			||||||
                    };
 | 
					 | 
				
			||||||
                    println!("You are about to add the following song to the database:");
 | 
					 | 
				
			||||||
                    println!("  + {song}");
 | 
					 | 
				
			||||||
                    if self.read_line("Are you sure? (type 'yes' to continue)").to_lowercase().trim() == "yes" {
 | 
					 | 
				
			||||||
                            Command::AddSong(song)
 | 
					 | 
				
			||||||
                    } else {
 | 
					 | 
				
			||||||
                        println!("[-] Aborted - no event will be sent to the database.");
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                "update-song" => {
 | 
					 | 
				
			||||||
                    let song_id = self.read_line_id("The ID of the song is...");
 | 
					 | 
				
			||||||
                    if let Some(mut song) = self.database.lock().unwrap().get_song(&song_id).cloned() {
 | 
					 | 
				
			||||||
                        println!("You are now editing the song {song}.");
 | 
					 | 
				
			||||||
                        loop {
 | 
					 | 
				
			||||||
                            match self.read_line("What do you want to edit? (title/album/artist/location or done)").to_lowercase().trim() {
 | 
					 | 
				
			||||||
                                "done" => break,
 | 
					 | 
				
			||||||
                                "title" => {
 | 
					 | 
				
			||||||
                                    println!("prev: '{}'", song.title);
 | 
					 | 
				
			||||||
                                    song.title = self.read_line("");
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                                "album" => {
 | 
					 | 
				
			||||||
                                    println!("prev: '{}'", song.album.map_or(String::new(), |v| v.to_string()));
 | 
					 | 
				
			||||||
                                    song.album = self.read_line_ido("");
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                                "artist" => {
 | 
					 | 
				
			||||||
                                    println!("prev: '{}'", song.artist);
 | 
					 | 
				
			||||||
                                    song.artist = self.read_line_id("");
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                                "location" => {
 | 
					 | 
				
			||||||
                                    println!("prev: '{:?}'", song.location);
 | 
					 | 
				
			||||||
                                    song.location = self.read_line("").into();
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                                _ => println!("[-] must be title/album/artist/location or done"),
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        println!("You are about to update the song:");
 | 
					 | 
				
			||||||
                        println!("  + {song}");
 | 
					 | 
				
			||||||
                        if self.read_line("Are you sure? (type 'yes' to continue)").to_lowercase().trim() == "yes" {
 | 
					 | 
				
			||||||
                            Command::ModifySong(song)
 | 
					 | 
				
			||||||
                        } else {
 | 
					 | 
				
			||||||
                            println!("[-] Aborted - no event will be sent to the database.");
 | 
					 | 
				
			||||||
                            continue;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    } else {
 | 
					 | 
				
			||||||
                        println!("[-] No song with that ID found, aborting.");
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                "queue-clear" => Command::QueueUpdate(vec![], QueueContent::Folder(0, vec![], String::new()).into()),
 | 
					 | 
				
			||||||
                "queue-add-to-end" => Command::QueueAdd(vec![], QueueContent::Song(self.read_line_id("The ID of the song that should be added to the end of the queue is...")).into()),
 | 
					 | 
				
			||||||
                "save" => Command::Save,
 | 
					 | 
				
			||||||
                "status" => {
 | 
					 | 
				
			||||||
                    let db = self.database.lock().unwrap();
 | 
					 | 
				
			||||||
                    println!("DB contains {} songs:", db.songs().len());
 | 
					 | 
				
			||||||
                    for song in db.songs().values() {
 | 
					 | 
				
			||||||
                        println!("> [{}]: {}", song.id, song);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    println!("Queue: {:?}, then {:?}", db.queue.get_current(), db.queue.get_next());
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                "exit" => {
 | 
					 | 
				
			||||||
                    println!("<< goodbye");
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                _ => {
 | 
					 | 
				
			||||||
                    println!("Type 'exit' to exit, 'status' to see the db, 'resume', 'pause', 'stop', 'next', 'queue-clear', 'queue-add-to-end', 'add-song', 'add-album', 'add-artist', 'update-song', 'update-album', 'update-artist', 'set-lib-dir', or 'save' to control playback or update the db.");
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            .to_bytes(self.con)
 | 
					 | 
				
			||||||
            .unwrap();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn read_line(&mut self, q: &str) -> String {
 | 
					 | 
				
			||||||
        loop {
 | 
					 | 
				
			||||||
            if !q.is_empty() {
 | 
					 | 
				
			||||||
                println!("{q}");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            let mut line = String::new();
 | 
					 | 
				
			||||||
            std::io::stdin().read_line(&mut line).unwrap();
 | 
					 | 
				
			||||||
            while line.ends_with('\n') || line.ends_with('\r') {
 | 
					 | 
				
			||||||
                line.pop();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if line.trim() == "#" {
 | 
					 | 
				
			||||||
                self.cmd_loop();
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                return line;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn read_line_id(&mut self, q: &str) -> u64 {
 | 
					 | 
				
			||||||
        loop {
 | 
					 | 
				
			||||||
            if let Ok(v) = self.read_line(q).trim().parse() {
 | 
					 | 
				
			||||||
                return v;
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                println!("[-] Must be a positive integer.");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn read_line_ido(&mut self, q: &str) -> Option<u64> {
 | 
					 | 
				
			||||||
        loop {
 | 
					 | 
				
			||||||
            let line = self.read_line(q);
 | 
					 | 
				
			||||||
            let line = line.trim();
 | 
					 | 
				
			||||||
            if line.is_empty() {
 | 
					 | 
				
			||||||
                return None;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if let Ok(v) = line.parse() {
 | 
					 | 
				
			||||||
                return Some(v);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                println!("[-] Must be a positive integer or nothing for None.");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
pub fn accumulate<F: FnMut() -> Option<T>, T>(mut f: F) -> Vec<T> {
 | 
					pub fn accumulate<F: FnMut() -> Option<T>, T>(mut f: F) -> Vec<T> {
 | 
				
			||||||
    let mut o = vec![];
 | 
					    let mut o = vec![];
 | 
				
			||||||
    loop {
 | 
					    loop {
 | 
				
			||||||
 | 
				
			|||||||
@ -38,6 +38,8 @@ pub struct Database {
 | 
				
			|||||||
    pub command_sender: Option<mpsc::Sender<Command>>,
 | 
					    pub command_sender: Option<mpsc::Sender<Command>>,
 | 
				
			||||||
    pub remote_server_as_song_file_source:
 | 
					    pub remote_server_as_song_file_source:
 | 
				
			||||||
        Option<Arc<Mutex<crate::server::get::Client<Box<dyn ClientIo>>>>>,
 | 
					        Option<Arc<Mutex<crate::server::get::Client<Box<dyn ClientIo>>>>>,
 | 
				
			||||||
 | 
					    /// only relevant for clients. true if init is done
 | 
				
			||||||
 | 
					    client_is_init: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
pub trait ClientIo: Read + Write + Send {}
 | 
					pub trait ClientIo: Read + Write + Send {}
 | 
				
			||||||
impl<T: Read + Write + Send> ClientIo for T {}
 | 
					impl<T: Read + Write + Send> ClientIo for T {}
 | 
				
			||||||
@ -60,6 +62,9 @@ impl Database {
 | 
				
			|||||||
    pub fn is_client(&self) -> bool {
 | 
					    pub fn is_client(&self) -> bool {
 | 
				
			||||||
        self.db_file.as_os_str().is_empty()
 | 
					        self.db_file.as_os_str().is_empty()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn is_client_init(&self) -> bool {
 | 
				
			||||||
 | 
					        self.client_is_init
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    pub fn get_path(&self, location: &DatabaseLocation) -> PathBuf {
 | 
					    pub fn get_path(&self, location: &DatabaseLocation) -> PathBuf {
 | 
				
			||||||
        self.lib_directory.join(&location.rel_path)
 | 
					        self.lib_directory.join(&location.rel_path)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -220,7 +225,7 @@ impl Database {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        // since this is so easy to check for, it comes last.
 | 
					        // since this is so easy to check for, it comes last.
 | 
				
			||||||
        // this allows clients to find out when init_connection is done.
 | 
					        // this allows clients to find out when init_connection is done.
 | 
				
			||||||
        Command::SetLibraryDirectory(self.lib_directory.clone()).to_bytes(con)?;
 | 
					        Command::InitComplete.to_bytes(con)?;
 | 
				
			||||||
        // is initialized now - client can receive updates after this point.
 | 
					        // is initialized now - client can receive updates after this point.
 | 
				
			||||||
        // NOTE: Don't write to connection anymore - the db will dispatch updates on its own.
 | 
					        // NOTE: Don't write to connection anymore - the db will dispatch updates on its own.
 | 
				
			||||||
        // we just need to handle commands (receive from the connection).
 | 
					        // we just need to handle commands (receive from the connection).
 | 
				
			||||||
@ -341,8 +346,8 @@ impl Database {
 | 
				
			|||||||
            Command::RemoveArtist(artist) => {
 | 
					            Command::RemoveArtist(artist) => {
 | 
				
			||||||
                _ = self.remove_artist(artist);
 | 
					                _ = self.remove_artist(artist);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Command::SetLibraryDirectory(new_dir) => {
 | 
					            Command::InitComplete => {
 | 
				
			||||||
                self.lib_directory = new_dir;
 | 
					                self.client_is_init = true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -368,6 +373,7 @@ impl Database {
 | 
				
			|||||||
            playing: false,
 | 
					            playing: false,
 | 
				
			||||||
            command_sender: None,
 | 
					            command_sender: None,
 | 
				
			||||||
            remote_server_as_song_file_source: None,
 | 
					            remote_server_as_song_file_source: None,
 | 
				
			||||||
 | 
					            client_is_init: false,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn new_empty(path: PathBuf, lib_dir: PathBuf) -> Self {
 | 
					    pub fn new_empty(path: PathBuf, lib_dir: PathBuf) -> Self {
 | 
				
			||||||
@ -385,13 +391,12 @@ impl Database {
 | 
				
			|||||||
            playing: false,
 | 
					            playing: false,
 | 
				
			||||||
            command_sender: None,
 | 
					            command_sender: None,
 | 
				
			||||||
            remote_server_as_song_file_source: None,
 | 
					            remote_server_as_song_file_source: None,
 | 
				
			||||||
 | 
					            client_is_init: false,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn load_database(path: PathBuf) -> Result<Self, std::io::Error> {
 | 
					    pub fn load_database(path: PathBuf, lib_directory: PathBuf) -> Result<Self, std::io::Error> {
 | 
				
			||||||
        let mut file = BufReader::new(File::open(&path)?);
 | 
					        let mut file = BufReader::new(File::open(&path)?);
 | 
				
			||||||
        eprintln!("[info] loading library from {file:?}");
 | 
					        eprintln!("[info] loading library from {file:?}");
 | 
				
			||||||
        let lib_directory = ToFromBytes::from_bytes(&mut file)?;
 | 
					 | 
				
			||||||
        eprintln!("[info] library directory is {lib_directory:?}");
 | 
					 | 
				
			||||||
        Ok(Self {
 | 
					        Ok(Self {
 | 
				
			||||||
            db_file: path,
 | 
					            db_file: path,
 | 
				
			||||||
            lib_directory,
 | 
					            lib_directory,
 | 
				
			||||||
@ -406,6 +411,7 @@ impl Database {
 | 
				
			|||||||
            playing: false,
 | 
					            playing: false,
 | 
				
			||||||
            command_sender: None,
 | 
					            command_sender: None,
 | 
				
			||||||
            remote_server_as_song_file_source: None,
 | 
					            remote_server_as_song_file_source: None,
 | 
				
			||||||
 | 
					            client_is_init: false,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// saves the database's contents. save path can be overridden
 | 
					    /// saves the database's contents. save path can be overridden
 | 
				
			||||||
@ -425,7 +431,6 @@ impl Database {
 | 
				
			|||||||
            .truncate(true)
 | 
					            .truncate(true)
 | 
				
			||||||
            .create(true)
 | 
					            .create(true)
 | 
				
			||||||
            .open(&path)?;
 | 
					            .open(&path)?;
 | 
				
			||||||
        self.lib_directory.to_bytes(&mut file)?;
 | 
					 | 
				
			||||||
        self.artists.to_bytes(&mut file)?;
 | 
					        self.artists.to_bytes(&mut file)?;
 | 
				
			||||||
        self.albums.to_bytes(&mut file)?;
 | 
					        self.albums.to_bytes(&mut file)?;
 | 
				
			||||||
        self.songs.to_bytes(&mut file)?;
 | 
					        self.songs.to_bytes(&mut file)?;
 | 
				
			||||||
@ -433,6 +438,10 @@ impl Database {
 | 
				
			|||||||
        Ok(path)
 | 
					        Ok(path)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn broadcast_update(&mut self, update: &Command) {
 | 
					    pub fn broadcast_update(&mut self, update: &Command) {
 | 
				
			||||||
 | 
					        match update {
 | 
				
			||||||
 | 
					            Command::InitComplete => return,
 | 
				
			||||||
 | 
					            _ => {}
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        let mut remove = vec![];
 | 
					        let mut remove = vec![];
 | 
				
			||||||
        let mut bytes = None;
 | 
					        let mut bytes = None;
 | 
				
			||||||
        let mut arc = None;
 | 
					        let mut arc = None;
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,6 @@ use std::{
 | 
				
			|||||||
    eprintln,
 | 
					    eprintln,
 | 
				
			||||||
    io::{BufRead, BufReader, Read, Write},
 | 
					    io::{BufRead, BufReader, Read, Write},
 | 
				
			||||||
    net::{SocketAddr, TcpListener},
 | 
					    net::{SocketAddr, TcpListener},
 | 
				
			||||||
    path::PathBuf,
 | 
					 | 
				
			||||||
    sync::{mpsc, Arc, Mutex},
 | 
					    sync::{mpsc, Arc, Mutex},
 | 
				
			||||||
    thread,
 | 
					    thread,
 | 
				
			||||||
    time::Duration,
 | 
					    time::Duration,
 | 
				
			||||||
@ -51,7 +50,7 @@ pub enum Command {
 | 
				
			|||||||
    RemoveAlbum(AlbumId),
 | 
					    RemoveAlbum(AlbumId),
 | 
				
			||||||
    RemoveArtist(ArtistId),
 | 
					    RemoveArtist(ArtistId),
 | 
				
			||||||
    ModifyArtist(Artist),
 | 
					    ModifyArtist(Artist),
 | 
				
			||||||
    SetLibraryDirectory(PathBuf),
 | 
					    InitComplete,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
impl Command {
 | 
					impl Command {
 | 
				
			||||||
    pub fn send_to_server(self, db: &Database) -> Result<(), Self> {
 | 
					    pub fn send_to_server(self, db: &Database) -> Result<(), Self> {
 | 
				
			||||||
@ -277,9 +276,8 @@ impl ToFromBytes for Command {
 | 
				
			|||||||
                s.write_all(&[0b11011100])?;
 | 
					                s.write_all(&[0b11011100])?;
 | 
				
			||||||
                artist.to_bytes(s)?;
 | 
					                artist.to_bytes(s)?;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Self::SetLibraryDirectory(path) => {
 | 
					            Self::InitComplete => {
 | 
				
			||||||
                s.write_all(&[0b00110001])?;
 | 
					                s.write_all(&[0b00110001])?;
 | 
				
			||||||
                path.to_bytes(s)?;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
@ -325,7 +323,7 @@ impl ToFromBytes for Command {
 | 
				
			|||||||
            0b11010011 => Self::RemoveAlbum(ToFromBytes::from_bytes(s)?),
 | 
					            0b11010011 => Self::RemoveAlbum(ToFromBytes::from_bytes(s)?),
 | 
				
			||||||
            0b11011100 => Self::RemoveArtist(ToFromBytes::from_bytes(s)?),
 | 
					            0b11011100 => Self::RemoveArtist(ToFromBytes::from_bytes(s)?),
 | 
				
			||||||
            0b01011101 => Self::AddCover(ToFromBytes::from_bytes(s)?),
 | 
					            0b01011101 => Self::AddCover(ToFromBytes::from_bytes(s)?),
 | 
				
			||||||
            0b00110001 => Self::SetLibraryDirectory(ToFromBytes::from_bytes(s)?),
 | 
					            0b00110001 => Self::InitComplete,
 | 
				
			||||||
            _ => {
 | 
					            _ => {
 | 
				
			||||||
                eprintln!("unexpected byte when reading command; stopping playback.");
 | 
					                eprintln!("unexpected byte when reading command; stopping playback.");
 | 
				
			||||||
                Self::Stop
 | 
					                Self::Stop
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@ edition = "2021"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
axum = { version = "0.6.19", features = ["headers"] }
 | 
					axum = { version = "0.6.19", features = ["headers"] }
 | 
				
			||||||
 | 
					clap = { version = "4.4.6", features = ["derive"] }
 | 
				
			||||||
futures = "0.3.28"
 | 
					futures = "0.3.28"
 | 
				
			||||||
headers = "0.3.8"
 | 
					headers = "0.3.8"
 | 
				
			||||||
musicdb-lib = { version = "0.1.0", path = "../musicdb-lib" }
 | 
					musicdb-lib = { version = "0.1.0", path = "../musicdb-lib" }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,166 +1,68 @@
 | 
				
			|||||||
mod web;
 | 
					mod web;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
 | 
					    net::SocketAddr,
 | 
				
			||||||
    path::PathBuf,
 | 
					    path::PathBuf,
 | 
				
			||||||
    process::exit,
 | 
					    process::exit,
 | 
				
			||||||
    sync::{Arc, Mutex},
 | 
					    sync::{Arc, Mutex},
 | 
				
			||||||
    thread,
 | 
					    thread,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use clap::Parser;
 | 
				
			||||||
use musicdb_lib::server::run_server;
 | 
					use musicdb_lib::server::run_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use musicdb_lib::data::database::Database;
 | 
					use musicdb_lib::data::database::Database;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					#[derive(Parser, Debug)]
 | 
				
			||||||
 | 
					struct Args {
 | 
				
			||||||
# Exit codes
 | 
					    /// The file which contains information about the songs in your library
 | 
				
			||||||
 | 
					    #[arg()]
 | 
				
			||||||
0 => exited as requested by the user
 | 
					    dbfile: PathBuf,
 | 
				
			||||||
1 => exit after printing help message
 | 
					    /// The path containing your actual library.
 | 
				
			||||||
3 => error parsing cli arguments
 | 
					    #[arg()]
 | 
				
			||||||
10 => tried to start with a path that caused some io::Error
 | 
					    lib_dir: PathBuf,
 | 
				
			||||||
11 => tried to start with a path that does not exist (--init prevents this)
 | 
					    /// skip reading the `dbfile` (because it doesn't exist yet)
 | 
				
			||||||
 | 
					    #[arg(long)]
 | 
				
			||||||
*/
 | 
					    init: bool,
 | 
				
			||||||
 | 
					    /// optional address for tcp connections to the server
 | 
				
			||||||
 | 
					    #[arg(long)]
 | 
				
			||||||
 | 
					    tcp: Option<SocketAddr>,
 | 
				
			||||||
 | 
					    /// optional address on which to start a website which can be used on devices without `musicdb-client` to control playback.
 | 
				
			||||||
 | 
					    /// requires the `assets/` folder to be present!
 | 
				
			||||||
 | 
					    #[arg(long)]
 | 
				
			||||||
 | 
					    web: Option<SocketAddr>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[tokio::main]
 | 
					#[tokio::main]
 | 
				
			||||||
async fn main() {
 | 
					async fn main() {
 | 
				
			||||||
    // parse args
 | 
					    // parse args
 | 
				
			||||||
    let mut args = std::env::args().skip(1);
 | 
					    let args = Args::parse();
 | 
				
			||||||
    let mut tcp_addr = None;
 | 
					    let database = if args.init {
 | 
				
			||||||
    let mut web_addr = None;
 | 
					        Database::new_empty(args.dbfile, args.lib_dir)
 | 
				
			||||||
    let mut lib_dir_for_init = None;
 | 
					 | 
				
			||||||
    let database = if let Some(path_s) = args.next() {
 | 
					 | 
				
			||||||
        loop {
 | 
					 | 
				
			||||||
            if let Some(arg) = args.next() {
 | 
					 | 
				
			||||||
                if arg.starts_with("--") {
 | 
					 | 
				
			||||||
                    match &arg[2..] {
 | 
					 | 
				
			||||||
                        "init" => {
 | 
					 | 
				
			||||||
                            if let Some(lib_dir) = args.next() {
 | 
					 | 
				
			||||||
                                lib_dir_for_init = Some(lib_dir);
 | 
					 | 
				
			||||||
                            } else {
 | 
					 | 
				
			||||||
                                eprintln!(
 | 
					 | 
				
			||||||
                                    "[EXIT]
 | 
					 | 
				
			||||||
missing argument: --init <lib path>"
 | 
					 | 
				
			||||||
                                );
 | 
					 | 
				
			||||||
                                exit(3);
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        "tcp" => {
 | 
					 | 
				
			||||||
                            if let Some(addr) = args.next() {
 | 
					 | 
				
			||||||
                                if let Ok(addr) = addr.parse() {
 | 
					 | 
				
			||||||
                                    tcp_addr = Some(addr)
 | 
					 | 
				
			||||||
                                } else {
 | 
					 | 
				
			||||||
                                    eprintln!(
 | 
					 | 
				
			||||||
                                        "[EXIT]
 | 
					 | 
				
			||||||
bad argument: --tcp <addr:port>: couldn't parse <addr:port>"
 | 
					 | 
				
			||||||
                                    );
 | 
					 | 
				
			||||||
                                    exit(3);
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            } else {
 | 
					 | 
				
			||||||
                                eprintln!(
 | 
					 | 
				
			||||||
                                    "[EXIT]
 | 
					 | 
				
			||||||
missing argument: --tcp <addr:port>"
 | 
					 | 
				
			||||||
                                );
 | 
					 | 
				
			||||||
                                exit(3);
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        "web" => {
 | 
					 | 
				
			||||||
                            if let Some(addr) = args.next() {
 | 
					 | 
				
			||||||
                                if let Ok(addr) = addr.parse() {
 | 
					 | 
				
			||||||
                                    web_addr = Some(addr)
 | 
					 | 
				
			||||||
                                } else {
 | 
					 | 
				
			||||||
                                    eprintln!(
 | 
					 | 
				
			||||||
                                        "[EXIT]
 | 
					 | 
				
			||||||
bad argument: --web <addr:port>: couldn't parse <addr:port>"
 | 
					 | 
				
			||||||
                                    );
 | 
					 | 
				
			||||||
                                    exit(3);
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            } else {
 | 
					 | 
				
			||||||
                                eprintln!(
 | 
					 | 
				
			||||||
                                    "[EXIT]
 | 
					 | 
				
			||||||
missing argument: --web <addr:port>"
 | 
					 | 
				
			||||||
                                );
 | 
					 | 
				
			||||||
                                exit(3);
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        o => {
 | 
					 | 
				
			||||||
                            eprintln!(
 | 
					 | 
				
			||||||
                                "[EXIT]
 | 
					 | 
				
			||||||
Unknown long argument --{o}"
 | 
					 | 
				
			||||||
                            );
 | 
					 | 
				
			||||||
                            exit(3);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                } else if arg.starts_with("-") {
 | 
					 | 
				
			||||||
                    match &arg[1..] {
 | 
					 | 
				
			||||||
                        o => {
 | 
					 | 
				
			||||||
                            eprintln!(
 | 
					 | 
				
			||||||
                                "[EXIT]
 | 
					 | 
				
			||||||
Unknown short argument -{o}"
 | 
					 | 
				
			||||||
                            );
 | 
					 | 
				
			||||||
                            exit(3);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    eprintln!(
 | 
					 | 
				
			||||||
                        "[EXIT]
 | 
					 | 
				
			||||||
Argument didn't start with - or -- ({arg})."
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                    exit(3);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        let path = PathBuf::from(&path_s);
 | 
					 | 
				
			||||||
        match path.try_exists() {
 | 
					 | 
				
			||||||
            Ok(exists) => {
 | 
					 | 
				
			||||||
                if let Some(lib_directory) = lib_dir_for_init {
 | 
					 | 
				
			||||||
                    Database::new_empty(path, lib_directory.into())
 | 
					 | 
				
			||||||
                } else if exists {
 | 
					 | 
				
			||||||
                    Database::load_database(path).unwrap()
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    eprintln!(
 | 
					 | 
				
			||||||
                        "[EXIT]
 | 
					 | 
				
			||||||
The provided path does not exist."
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                    exit(11);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Err(e) => {
 | 
					 | 
				
			||||||
                eprintln!(
 | 
					 | 
				
			||||||
                    "[EXIT]
 | 
					 | 
				
			||||||
Error getting information about the provided path '{path_s}': {e}"
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                exit(10);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        eprintln!(
 | 
					        match Database::load_database(args.dbfile.clone(), args.lib_dir.clone()) {
 | 
				
			||||||
            "[EXIT]
 | 
					            Ok(db) => db,
 | 
				
			||||||
musicdb-server - help
 | 
					            Err(e) => {
 | 
				
			||||||
musicdb-server <path to database file> <options> <options> <...>
 | 
					                eprintln!("Couldn't load database!");
 | 
				
			||||||
options:
 | 
					                eprintln!("  dbfile: {:?}", args.dbfile);
 | 
				
			||||||
  --init <lib directory>
 | 
					                eprintln!("  libdir: {:?}", args.lib_dir);
 | 
				
			||||||
  --tcp <addr:port>
 | 
					                eprintln!("  err: {}", e);
 | 
				
			||||||
  --web <addr:port>
 | 
					                exit(1);
 | 
				
			||||||
this help was shown because no arguments were provided."
 | 
					            }
 | 
				
			||||||
        );
 | 
					        }
 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    // database can be shared by multiple threads using Arc<Mutex<_>>
 | 
					    // database can be shared by multiple threads using Arc<Mutex<_>>
 | 
				
			||||||
    let database = Arc::new(Mutex::new(database));
 | 
					    let database = Arc::new(Mutex::new(database));
 | 
				
			||||||
    if tcp_addr.is_some() || web_addr.is_some() {
 | 
					    if args.tcp.is_some() || args.web.is_some() {
 | 
				
			||||||
        if let Some(addr) = web_addr {
 | 
					        if let Some(addr) = &args.web {
 | 
				
			||||||
            let (s, mut r) = tokio::sync::mpsc::channel(2);
 | 
					            let (s, mut r) = tokio::sync::mpsc::channel(2);
 | 
				
			||||||
            let db = Arc::clone(&database);
 | 
					            let db = Arc::clone(&database);
 | 
				
			||||||
            thread::spawn(move || run_server(database, tcp_addr, Some(s)));
 | 
					            thread::spawn(move || run_server(database, args.tcp, Some(s)));
 | 
				
			||||||
            if let Some(sender) = r.recv().await {
 | 
					            if let Some(sender) = r.recv().await {
 | 
				
			||||||
                web::main(db, sender, addr).await;
 | 
					                web::main(db, sender, *addr).await;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            run_server(database, tcp_addr, None);
 | 
					            run_server(database, args.tcp, None);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        eprintln!("nothing to do, not starting the server.");
 | 
					        eprintln!("nothing to do, not starting the server.");
 | 
				
			||||||
 | 
				
			|||||||
@ -438,7 +438,7 @@ async fn sse_handler(
 | 
				
			|||||||
                            .collect::<String>(),
 | 
					                            .collect::<String>(),
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                Command::Save | Command::SetLibraryDirectory(_) => return Poll::Pending,
 | 
					                Command::Save | Command::InitComplete => return Poll::Pending,
 | 
				
			||||||
            }))
 | 
					            }))
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            return Poll::Pending;
 | 
					            return Poll::Pending;
 | 
				
			||||||
@ -673,17 +673,15 @@ fn build_queue_content_build(
 | 
				
			|||||||
                        HtmlPart::Plain(v) => html.push_str(v),
 | 
					                        HtmlPart::Plain(v) => html.push_str(v),
 | 
				
			||||||
                        HtmlPart::Insert(key) => match key.as_str() {
 | 
					                        HtmlPart::Insert(key) => match key.as_str() {
 | 
				
			||||||
                            "path" => html.push_str(&path),
 | 
					                            "path" => html.push_str(&path),
 | 
				
			||||||
                            "content" => {
 | 
					                            "content" => build_queue_content_build(
 | 
				
			||||||
                                    build_queue_content_build(
 | 
					                                db,
 | 
				
			||||||
                                        db,
 | 
					                                state,
 | 
				
			||||||
                                        state,
 | 
					                                html,
 | 
				
			||||||
                                        html,
 | 
					                                &inner,
 | 
				
			||||||
                                        &inner,
 | 
					                                format!("{path}-0"),
 | 
				
			||||||
                                        format!("{path}-0"),
 | 
					                                current,
 | 
				
			||||||
                                        current,
 | 
					                                true,
 | 
				
			||||||
                                        true,
 | 
					                            ),
 | 
				
			||||||
                                    )
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            _ => {}
 | 
					                            _ => {}
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user