Browse and listen to thousands of radio stations across the globe right from your terminal 🌎 📻 🎵✨
radio
rust
tokio
web-radio
command-line-tool
tui
1use anyhow::Error;
2use app::CurrentDisplayMode;
3use clap::{arg, Command};
4
5mod app;
6mod browse;
7mod cfg;
8mod decoder;
9mod extract;
10mod input;
11mod music;
12mod play;
13mod player;
14mod provider;
15mod search;
16mod server;
17mod service;
18mod tags;
19mod tui;
20mod types;
21mod visualization;
22
23fn cli() -> Command<'static> {
24 const VESRION: &str = env!("CARGO_PKG_VERSION");
25 Command::new("tunein")
26 .version(VESRION)
27 .author("Tsiry Sandratraina <tsiry.sndr@fluentci.io>")
28 .about(
29 r#"
30 ______ ____ _______ ____
31 /_ __/_ _____ ___ / _/__ / ___/ / / _/
32 / / / // / _ \/ -_)/ // _ \ / /__/ /___/ /
33 /_/ \_,_/_//_/\__/___/_//_/ \___/____/___/
34
35A simple CLI to listen to radio stations"#,
36 )
37 .arg(
38 arg!(-p --provider "The radio provider to use, can be 'tunein' or 'radiobrowser'. Default is 'tunein'").default_value("tunein")
39 )
40 .subcommand_required(true)
41 .subcommand(
42 Command::new("search")
43 .about("Search for a radio station")
44 .arg(arg!(<query> "The query to search for")),
45 )
46 .subcommand(
47 Command::new("play")
48 .about("Play a radio station")
49 .arg(arg!(<station> "The station to play"))
50 .arg(arg!(--volume "Set the initial volume (as a percent)").default_value("100"))
51 .arg(clap::Arg::new("display-mode").long("display-mode").help("Set the display mode to start with").default_value("Spectroscope")),
52 )
53 .subcommand(
54 Command::new("browse")
55 .about("Browse radio stations")
56 .arg(arg!([category] "The category (category name or id) to browse"))
57 .arg(arg!(--offset "The offset to start from").default_value("0"))
58 .arg(arg!(--limit "The number of results to show").default_value("100")),
59 )
60 .subcommand(
61 Command::new("server")
62 .about("Start the server")
63 .arg(arg!([port] "The port to listen on").default_value("8090")),
64 )
65 .subcommand(
66 Command::new("service")
67 .about("Manage systemd service for tunein-cli server")
68 .subcommand(
69 Command::new("install")
70 .about("Install systemd service for tunein-cli server")
71 )
72 .subcommand(
73 Command::new("uninstall")
74 .about("Uninstall systemd service for tunein-cli server")
75 )
76 .subcommand(
77 Command::new("status")
78 .about("Check status of tunein-cli systemd service")
79 )
80 )
81}
82
83#[tokio::main]
84async fn main() -> Result<(), Error> {
85 let matches = cli().get_matches();
86
87 match matches.subcommand() {
88 Some(("search", args)) => {
89 let query = args.value_of("query").unwrap();
90 let provider = matches.value_of("provider").unwrap();
91 search::exec(query, provider).await?;
92 }
93 Some(("play", args)) => {
94 let station = args.value_of("station").unwrap();
95 let provider = matches.value_of("provider").unwrap();
96 let volume = args.value_of("volume").unwrap().parse::<f32>().unwrap();
97 let display_mode = args
98 .value_of("display-mode")
99 .unwrap()
100 .parse::<CurrentDisplayMode>()
101 .unwrap();
102 play::exec(station, provider, volume, display_mode).await?;
103 }
104 Some(("browse", args)) => {
105 let category = args.value_of("category");
106 let offset = args.value_of("offset").unwrap();
107 let limit = args.value_of("limit").unwrap();
108 let provider = matches.value_of("provider").unwrap();
109 browse::exec(
110 category,
111 offset.parse::<u32>()?,
112 limit.parse::<u32>()?,
113 provider,
114 )
115 .await?;
116 }
117 Some(("server", args)) => {
118 let port = args.value_of("port").unwrap();
119 let port = port.parse::<u16>().unwrap();
120 server::exec(port).await?;
121 }
122 Some(("service", sub_m)) => match sub_m.subcommand() {
123 Some(("install", _)) => service::install()?,
124 Some(("uninstall", _)) => service::uninstall()?,
125 Some(("status", _)) => service::status()?,
126 _ => {
127 println!("Invalid subcommand. Use `tunein service --help` for more information");
128 std::process::exit(1);
129 }
130 },
131 _ => unreachable!(),
132 }
133
134 Ok(())
135}