commit 44fd2dfbe476a8f13b067f8fbd583a39d777863a
parent 47bb2484a81e610a81ac977cbb4a19ba5c081871
Author: Alex Balgavy <alex@balgavy.eu>
Date: Sat, 4 Jun 2022 22:33:36 +0200
Submenus!
Diffstat:
M | config.toml | | | 88 | ++++++++++++++++++------------------------------------------------------------- |
M | src/config.rs | | | 3 | ++- |
M | src/main.rs | | | 49 | +++++++++++++++++++++++++++++++++++++++---------- |
M | src/screen.rs | | | 58 | +++++++++++++++++++++++++++++++++++++++++++--------------- |
4 files changed, 104 insertions(+), 94 deletions(-)
diff --git a/config.toml b/config.toml
@@ -56,73 +56,25 @@ url = "https://streaming.live365.com/a37043"
mpc_load_option = "ADD"
[[config.radios]]
-name = "SOMA - Groove Salad ambient/downtempo"
+name = "SOMA..."
website = "https://somafm.com/"
-url = "https://somafm.com/groovesalad256.pls"
-mpc_load_option = "LOAD"
-
-[[config.radios]]
-name = "SOMA - Mission Control ambient space"
-website = "https://somafm.com/"
-url = "https://somafm.com/missioncontrol.pls"
-mpc_load_option = "LOAD"
-
-[[config.radios]]
-name = "SOMA - The Trip prog house/trance"
-website = "https://somafm.com/"
-url = "https://somafm.com/thetrip.pls"
-mpc_load_option = "LOAD"
-
-[[config.radios]]
-name = "SOMA - Beat Blender deep house downtempo"
-website = "https://somafm.com/"
-url = "https://somafm.com/beatblender.pls"
-mpc_load_option = "LOAD"
-
-[[config.radios]]
-name = "SOMA - Dub Step"
-website = "https://somafm.com/"
-url = "https://somafm.com/dubstep256.pls"
-mpc_load_option = "LOAD"
-
-[[config.radios]]
-name = "SOMA - Defcon"
-website = "https://somafm.com/"
-url = "https://somafm.com/defcon256.pls"
-mpc_load_option = "LOAD"
-
-[[config.radios]]
-name = "SOMA - Deep Space deep ambient electro/experimental"
-website = "https://somafm.com/"
-url = "https://somafm.com/deepspaceone.pls"
-mpc_load_option = "LOAD"
-
-[[config.radios]]
-name = "SOMA - Thistle Radio Celtic"
-website = "https://somafm.com/"
-url = "https://somafm.com/thistle.pls"
-mpc_load_option = "LOAD"
-
-[[config.radios]]
-name = "SOMA - Fluid instr. hip hop liquid trap"
-website = "https://somafm.com/"
-url = "https://somafm.com/fluid.pls"
-mpc_load_option = "LOAD"
-
-[[config.radios]]
-name = "Bluemars"
-website = "http://echoesofbluemars.org/"
-url = "http://streams.echoesofbluemars.org:8000/bluemars.m3u"
-mpc_load_option = "LOAD"
-
-[[config.radios]]
-name = "Cryosleep"
+radios = [
+ {name = "Groove Salad ambient/downtempo", website = "https://somafm.com/", url = "https://somafm.com/groovesalad256.pls", mpc_load_option = "LOAD"},
+ {name = "Mission Control ambient space", website = "https://somafm.com/", url = "https://somafm.com/missioncontrol.pls", mpc_load_option = "LOAD"},
+ {name = "The Trip prog house/trance", website = "https://somafm.com/", url = "https://somafm.com/thetrip.pls", mpc_load_option = "LOAD"},
+ {name = "Beat Blender deep house downtempo", website = "https://somafm.com/", url = "https://somafm.com/beatblender.pls", mpc_load_option = "LOAD"},
+ {name = "Dub Step", website = "https://somafm.com/", url = "https://somafm.com/dubstep256.pls", mpc_load_option = "LOAD"},
+ {name = "Defcon", website = "https://somafm.com/", url = "https://somafm.com/defcon256.pls", mpc_load_option = "LOAD"},
+ {name = "Deep Space deep ambient electro/experimental", website = "https://somafm.com/", url = "https://somafm.com/deepspaceone.pls", mpc_load_option = "LOAD"},
+ {name = "Thistle Radio Celtic", website = "https://somafm.com/", url = "https://somafm.com/thistle.pls", mpc_load_option = "LOAD"},
+ {name = "Fluid instr. hip hop liquid trap", website = "https://somafm.com/", url = "https://somafm.com/fluid.pls", mpc_load_option = "LOAD"},
+]
+
+[[config.radios]]
+name = "Echoes of Blue Mars..."
website = "http://echoesofbluemars.org/"
-url = "http://streams.echoesofbluemars.org:8000/cryosleep.m3u"
-mpc_load_option = "LOAD"
-
-[[config.radios]]
-name = "Voices From Within"
-website = "http://echoesofbluemars.org/"
-url = "http://streams.echoesofbluemars.org:8000/voicesfromwithin.m3u"
-mpc_load_option = "LOAD"
+radios = [
+ {name = "Bluemars", website = "http://echoesofbluemars.org/", url = "http://streams.echoesofbluemars.org:8000/bluemars.m3u", mpc_load_option = "LOAD"},
+ {name = "Cryosleep", website = "http://echoesofbluemars.org/", url = "http://streams.echoesofbluemars.org:8000/cryosleep.m3u", mpc_load_option = "LOAD"},
+ {name = "Voices From Within", website = "http://echoesofbluemars.org/", url = "http://streams.echoesofbluemars.org:8000/voicesfromwithin.m3u", mpc_load_option = "LOAD"}
+]
diff --git a/src/config.rs b/src/config.rs
@@ -17,8 +17,9 @@ pub struct Config {
pub struct Item {
pub name: String,
pub website: String,
- pub url: String,
+ pub url: Option<String>,
pub mpc_load_option: Option<MpcLoadOptions>,
+ pub radios: Option<Vec<Item>>
}
pub fn read_config() -> ConfigData {
diff --git a/src/main.rs b/src/main.rs
@@ -1,21 +1,50 @@
+mod config;
mod radio;
mod screen;
mod tunein;
-mod config;
use radio::*;
use std::process::exit;
use tunein::*;
+use config::*;
+fn choose_radio(radios: &Vec<Item>) -> &Item {
+ loop {
+ let choices: Vec<String> = radios
+ .iter()
+ .map(|x| format!("{} ({})", x.name, x.website))
+ .collect();
+
+ let (choice_i, _) = match screen::list_menu(&*choices) {
+ Some((i, s)) => (i, s),
+ None => continue
+ };
+ let chosen_radio = match radios[choice_i].url {
+ Some(_) => &radios[choice_i],
+ None => {
+ let choices: Vec<String> = radios[choice_i].radios.as_ref().unwrap()
+ .iter()
+ .map(|x| format!("{} ({})", x.name, x.website))
+ .collect();
+ let (choice_i, _) = match screen::list_menu(&*choices) {
+ Some((i, s)) => (i, s),
+ None => continue
+ };
+ &radios[choice_i]
+ }
+ };
+ return chosen_radio;
+ }
+}
fn main() {
let data = config::read_config();
- let choices: Vec<String> = data
- .config
- .radios
- .iter()
- .map(|x| format!("{} ({})", x.name, x.website))
- .collect();
- let (choice_i, _) = screen::list_menu(&choices[..]);
- let chosen_radio = &data.config.radios[choice_i];
- let radio = baseradio::BaseRadio::new(&chosen_radio.url);
+ assert!(data
+ .config
+ .radios
+ .iter()
+ .all(|x| (x.url.is_some() && x.mpc_load_option.is_some()) || (x.radios.is_some())));
+
+ let top_radios = &data.config.radios;
+ let chosen_radio = choose_radio(top_radios);
+ let radio = baseradio::BaseRadio::new(chosen_radio.url.as_ref().unwrap());
let opts = RadioOptions {
method: data.config.player,
load_options: chosen_radio.mpc_load_option,
diff --git a/src/screen.rs b/src/screen.rs
@@ -4,19 +4,13 @@ pub fn clear() {
println!("\x1B[H\x1B[2J");
}
-pub fn list_menu(list: &[String]) -> (usize, String) {
- let mut message = None;
+fn prompt(prompt: &str) -> String {
+ let mut message: Option<&str> = None;
loop {
- clear();
- println!("== Internet Radio Player ==");
- for (i, val) in list.iter().enumerate() {
- println!("{} {}", i + 1, val);
- }
if message.is_some() {
println!("Error: {}", message.unwrap());
}
-
- print!("Enter number or press ^C to go back> ");
+ print!("{}", prompt);
let _ = stdout().flush();
let mut input_text = String::new();
@@ -24,16 +18,50 @@ pub fn list_menu(list: &[String]) -> (usize, String) {
message = Some("did not input text.");
continue;
}
- let trimmed = input_text.trim();
+ return input_text.trim().to_string();
+ }
+}
+
+
+pub fn list_menu(list: &[String]) -> Option<(usize, String)> {
+ let mut message = None;
+ loop {
+ clear();
+ println!("== Internet Radio Player ==");
+ for (i, val) in list.iter().enumerate() {
+ println!("{} {}", i + 1, val);
+ }
+ println!("Type 'q' or 'quit' to go back, press ^C to exit.");
+ if message.is_some() {
+ println!("Error: {}", message.unwrap());
+ }
- let index = match trimmed.parse::<usize>() {
- Ok(n) if n > 0 && n <= list.len() => n - 1,
+ // can't use just prompt(..), because match goes on &str, and prompt returns String.
+ // can't use prompt(..).as_str(), because temporary value dropped while borrowed.
+ // - i could use a new variable here, but it's clutter.
+ // So, I reborrow with &*.
+ let trimmed = &*prompt("Enter number> ");
+
+ let n = match trimmed.parse::<usize>() {
+ Ok(n) => n,
_ => {
- message = Some("choice out of range");
- continue;
+ match trimmed {
+ "q" | "quit" => {
+ return None;
+ }
+ _ => {
+ message = Some("Not a number!");
+ continue;
+ }
+ }
}
};
+ if n == 0 || n > list.len() {
+ message = Some("choice out of range");
+ continue;
+ }
+ let index = n - 1;
- return (index, list[index].to_string());
+ return Some((index, list[index].to_string()));
}
}