Skip to content
Extraits de code Groupes Projets
Vérifiée Valider 7c2f3d4e rédigé par Kubat's avatar Kubat
Parcourir les fichiers

AMADEUS: Add things to the amadeus-next workspace

- Add more things in the common crate
- Fix cargo files + can now convert from a &str to a LektorUri
- Begin to parse arguments
parent 50a8400d
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
Affichage de avec 299 ajouts et 6 suppressions
...@@ -6,6 +6,8 @@ authors.workspace = true ...@@ -6,6 +6,8 @@ authors.workspace = true
license.workspace = true license.workspace = true
[dependencies] [dependencies]
log.workspace = true
serde.workspace = true serde.workspace = true
tokio.workspace = true tokio.workspace = true
commons = { path = "../commons" }
amalib = { path = "../amalib" }
...@@ -6,7 +6,6 @@ authors.workspace = true ...@@ -6,7 +6,6 @@ authors.workspace = true
license.workspace = true license.workspace = true
[dependencies] [dependencies]
log.workspace = true
serde.workspace = true serde.workspace = true
tokio.workspace = true tokio.workspace = true
......
...@@ -13,8 +13,7 @@ pub use query::*; ...@@ -13,8 +13,7 @@ pub use query::*;
pub use response::*; pub use response::*;
pub use uri::*; pub use uri::*;
pub(crate) use commons::*; pub(crate) use commons::{log::*, *};
pub(crate) use log::*;
pub(crate) use std::str::FromStr; pub(crate) use std::str::FromStr;
/// The playback state of the lektord server. /// The playback state of the lektord server.
......
//! Build lektord queries. //! Build lektord queries.
use crate::*; use crate::*;
use std::str::FromStr;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum LektorUri { pub enum LektorUri {
...@@ -34,3 +35,26 @@ impl std::fmt::Display for LektorUri { ...@@ -34,3 +35,26 @@ impl std::fmt::Display for LektorUri {
f.write_str(&ret_str) f.write_str(&ret_str)
} }
} }
impl TryFrom<&str> for LektorUri {
type Error = String;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value.trim().split_once("://") {
Some(("id", id)) => {
Ok(Self::Id(i32::from_str(id).map_err(|e| {
format!("the string `{id}` is not an i32: {e}")
})?))
}
Some(("author", author)) => Ok(Self::Author(author.to_string())),
Some(("playlist", plt)) => Ok(Self::Playlist(plt.to_string())),
Some(("query", query)) => Ok(Self::Query(
query.split(' ').map(String::from).collect::<Vec<_>>(),
)),
Some((identifier, _)) => Err(format!(
"the identifier `{identifier}` is not a valid uri identifier"
)),
None => Err(format!("the string `{value}` is not a valid uri")),
}
}
}
#[macro_export]
macro_rules! fatal {
(target: $target: expr, $($arg:tt)+) => {{
$crate::log::log!(target: $target, $crate::log::Level::Error, $($arg)+);
std::process::exit(1);
}};
($($arg:tt)+) => {{
$crate::log::log!($crate::log::Level::Error, $($arg)+);
std::process::exit(1);
}};
}
/// Test that something was [`Err`] and return the content of the
/// [`Result::Err`] variant. Panic on [`Ok`].
#[macro_export]
macro_rules! assert_err {
($x: expr) => {
match $x {
Ok(e) => panic!("'{}' was successfull and got '{e:?}'", stringify!($x)),
Err(e) => e,
}
};
}
/// Test that something was [`Ok`] and return the content of the [`Result::Ok`]
/// variant. Panic on [`Err`].
#[macro_export]
macro_rules! assert_ok {
($x: expr) => {
match $x {
Ok(x) => x,
Err(e) => panic!("failed '{}' with '{e:?}'", stringify!($x)),
}
};
}
mod asserts;
mod error; mod error;
mod macros; mod macros;
pub mod log;
pub use error::*; pub use error::*;
pub use log::{debug, error, info, log, trace, warn, Level};
...@@ -6,5 +6,16 @@ authors.workspace = true ...@@ -6,5 +6,16 @@ authors.workspace = true
license.workspace = true license.workspace = true
[dependencies] [dependencies]
log.workspace = true
serde.workspace = true serde.workspace = true
commons = { path = "../commons" }
amalib = { path = "../amalib" }
clap = { version = "^4", default-features = false, features = [
"usage",
"help",
"std",
"suggestions",
"error-context",
"derive",
] }
use crate::types::*;
use clap::{Parser, Subcommand};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Args {
#[command(subcommand)]
action: SubCommand,
}
#[derive(Subcommand, Debug)]
pub enum SubCommand {
// Status commands
#[command(
about = "Prints informations about the currently playing kara. Can be used to display the current kara in a status bar like xmobar or in the i3 panel."
)]
Current,
#[command(
about = "Prints information about the state of lektor and the currently playing kara."
)]
Status,
// Playback commands
#[command(
about = "Toggle play/pause state. If the playback is stopped, start at a possibly specified index."
)]
Play { index: Option<usize> },
#[command(about = "For lektord to be paused, don't do anything is lektord is already paused.")]
Pause,
#[command(
about = "Unpause lektord, starts at the begening of the queue if lektord was stopped."
)]
UnPause,
#[command(about = "Stop the playback and reading the queue, the state is now stopped.")]
Stop,
#[command(about = "Play next kara in the queue.")]
Next,
#[command(about = "Play the previous kara in the queue.")]
Previous,
#[command(
about = "Shuffle the queue. If lektord was paused it will unpause but if it was stopped it won't start. If it exists, the current kara will be placed in the first place in the queue. You can also pass a level to shuffle up to."
)]
Shuffle {
#[arg(
default_value_t = PriorityLevel::Add,
)]
level: PriorityLevel,
},
// Playlist commands
#[command(alias = "plt", short_flag = 'P')]
Playlist {
#[arg(
value_parser = clap::builder::NonEmptyStringValueParser::new(),
exclusive = true,
short = 'c',
help = "Create a new playlist with a specific name.",
)]
create: Option<String>,
#[arg(
value_parser = clap::builder::NonEmptyStringValueParser::new(),
exclusive = true,
short = 'd',
help = "Delete a playlist with all its content, do nothing if the playlist didn't exists.",
)]
destroy: Option<String>,
#[arg(
short = 'l',
exclusive = true,
help = "List the content of the playlist named if a name is passed. If missing returns a list of all the available playlists."
)]
list: Option<Option<String>>,
#[arg(
action = clap::ArgAction::Append,
exclusive = true,
num_args = 2..,
short = 'r',
help = "Deletes karas from a playlist with a valid query. The first element is the name of the playlist."
)]
remove: Option<Vec<String>>,
#[arg(
action = clap::ArgAction::Append,
exclusive = true,
num_args = 2..,
short = 'a',
help = "Add karas to a playlist with a valid query. The first element is the name of the playlist."
)]
add: Option<Vec<String>>,
},
// Queue commands
#[command(short_flag = 'Q')]
Queue {},
// Search commands
#[command(short_flag = 'S')]
Search {},
// Admin commands
#[command(alias = "adm", short_flag = 'A')]
Admin {},
}
fn main() {} mod args;
mod parsers;
mod types;
fn main() {
let args = <args::Args as clap::Parser>::parse();
println!("{args:#?}");
}
use clap::{builder::TypedValueParser, error::ErrorKind, Arg, Command, Error};
/// A parser for the [crate::types::FilterPlaylist] structure
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub struct FilterPlaylistParser {}
impl FilterPlaylistParser {
/// Parse non-empty string values
pub fn new() -> Self {
Self {}
}
}
impl TypedValueParser for FilterPlaylistParser {
type Value = (String, String);
fn parse_ref(
&self,
cmd: &Command,
arg: Option<&Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, Error> {
let arg = arg
.map(ToString::to_string)
.unwrap_or_else(|| "...".to_owned());
let value = value.to_str().ok_or_else(|| {
Error::raw(
ErrorKind::InvalidUtf8,
format!("not a valid utf8 string: {}", value.to_string_lossy()),
)
})?;
match value.split_once(' ') {
Some((head, tail)) => Ok((head.to_string(), tail.to_string())),
_ => Err(Error::raw(
ErrorKind::InvalidValue,
format!(
"in `{} {arg}`, the value should be of the form: [PLAYLIST] [QUERY]",
cmd.get_name()
),
)),
}
}
}
impl Default for FilterPlaylistParser {
fn default() -> Self {
Self::new()
}
}
use commons::fatal;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PriorityLevel {
Add = 1,
Suggest = 2,
Insert = 3,
Pick = 4,
Enforce = 5,
}
impl From<&str> for PriorityLevel {
fn from(value: &str) -> Self {
use PriorityLevel::*;
match value {
"add" | "1" => Add,
"suggest" | "2" => Suggest,
"insert" | "3" => Insert,
"pick" | "4" => Pick,
"enforce" | "5" => Enforce,
_ => fatal!("unknown priority level: {value}"),
}
}
}
impl Default for PriorityLevel {
fn default() -> Self {
PriorityLevel::Add
}
}
impl std::fmt::Display for PriorityLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
PriorityLevel::Add => "add",
PriorityLevel::Suggest => "suggest",
PriorityLevel::Insert => "insert",
PriorityLevel::Pick => "pick",
PriorityLevel::Enforce => "enforce",
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FilterPlaylist {
playlist: String,
query: String,
}
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter