A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1use std::{env, ffi::OsString};
2
3use anyhow::Error;
4use clap::{arg, Command};
5use owo_colors::OwoColorize;
6
7use cmd::{
8 clear::*, community::*, login::*, repl::*, run::*, scan::*, service, start::*, webui::*,
9 whoami::*,
10};
11
12pub mod cmd;
13
14fn cli() -> Command {
15 let banner = format!(
16 "{}\nA fork of the original Rockbox project, with a focus on modernization and more features.",
17 r#"
18 __________ __ ___.
19 Open \______ \ ____ ____ | | _\_ |__ _______ ___
20 Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
21 Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
22 Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
23 \/ \/ \/ \/ \/
24 "#
25 .yellow()
26 );
27 const VERSION: &str = match option_env!("TAG") {
28 Some(tag) => tag,
29 None => env!("CARGO_PKG_VERSION"),
30 };
31 Command::new("rockbox")
32 .version(VERSION)
33 .about(&banner)
34 .arg(arg!(--rebuild -r "Rebuild index after scan"))
35 .subcommand(
36 Command::new("scan")
37 .arg(arg!(--directory -d [PATH] "path to your music library").required(false))
38 .arg(arg!(--rebuild -r "Rebuild index after scan"))
39 .about("Scan your music library for new media files"),
40 )
41 .subcommand(
42 Command::new("community").about("Join our community on Discord to chat with us!"),
43 )
44 .subcommand(
45 Command::new("start")
46 .about("Start Rockbox server")
47 .arg(arg!(--rebuild -r "Rebuild index after scan")),
48 )
49 .subcommand(Command::new("tui").about("Start Rockbox TUI"))
50 .subcommand(
51 Command::new("webui")
52 .about("Open the Rockbox web UI in your browser")
53 .visible_alias("web"),
54 )
55 .subcommand(
56 Command::new("repl")
57 .about("Start the Rockbox REPL")
58 .visible_alias("shell"),
59 )
60 .subcommand(
61 Command::new("run")
62 .arg(arg!(<FILE> "JavaScript or TypeScript file to run"))
63 .about("Run a JavaScript or TypeScript program")
64 .visible_alias("x"),
65 )
66 .subcommand(
67 Command::new("service")
68 .about("Manage systemd service for Rockbox")
69 .subcommand(Command::new("install").about("Install systemd service for Rockbox"))
70 .subcommand(
71 Command::new("uninstall").about("Uninstall systemd service for Rockbox"),
72 )
73 .subcommand(
74 Command::new("status").about("Check status of systemd service for Rockbox"),
75 ),
76 )
77 .subcommand(
78 Command::new("login")
79 .arg(arg!(<handle> "Your BlueSky handle"))
80 .about("Login to your Rocksky account")
81 .visible_alias("auth"),
82 )
83 .subcommand(
84 Command::new("whoami")
85 .about("Display information about the currently logged in user")
86 .visible_alias("me"),
87 )
88 .subcommand(Command::new("clear").about("Clear current playlist"))
89}
90
91#[tokio::main]
92async fn main() -> Result<(), Error> {
93 let args = std::env::args().collect::<Vec<String>>();
94 if args.len() > 1 && args[1] == "run" {
95 let _args = args
96 .into_iter()
97 .map(|s| match s.as_str() {
98 "rockbox" => "deno".into(),
99 _ => s.into(),
100 })
101 .collect::<Vec<OsString>>();
102
103 run(_args);
104 return Ok(());
105 }
106
107 let matches = cli().get_matches();
108
109 match matches.subcommand() {
110 Some(("scan", args)) => {
111 let directory = args.get_one::<String>("directory").map(|d| d.to_string());
112 let rebuild_index = match args.get_flag("rebuild") {
113 true => Some(true),
114 false => None,
115 };
116 scan(directory, rebuild_index).await?;
117 }
118 Some(("community", _)) => {
119 community();
120 }
121 Some(("start", _)) => {
122 start(true)?;
123 }
124 Some(("webui", _)) => {
125 webui()?;
126 }
127 Some(("repl", _)) => {
128 repl();
129 }
130 Some(("tui", _)) => {
131 rmpc::main_tui()?;
132 }
133 Some(("service", sub_m)) => match sub_m.subcommand() {
134 Some(("install", _)) => {
135 service::install()?;
136 }
137 Some(("uninstall", _)) => {
138 service::uninstall()?;
139 }
140 Some(("status", _)) => {
141 service::status()?;
142 }
143 _ => {
144 println!("Invalid subcommand. Use `rockbox service --help` for more information.");
145 }
146 },
147 Some(("login", args)) => {
148 let handle = args.get_one::<String>("handle").unwrap();
149 login(handle).await?;
150 }
151 Some(("whoami", _)) => {
152 whoami().await?;
153 }
154 Some(("clear", _)) => {
155 match clear() {
156 Ok(_) => {}
157 Err(e) => {}
158 };
159 println!("✅ Rockbox Playlist Cleared");
160 }
161 Some((_, args)) => {
162 if args.get_flag("rebuild") {
163 env::set_var("ROCKBOX_UPDATE_LIBRARY", "1");
164 }
165 start(true)?;
166 }
167 None => start(true)?,
168 }
169 Ok(())
170}