use crate::json::Json;
use crate::options::{
string_list, KeywordOptions, ModeOption, ParseOptions, Requested, Resolved, SplitAnd,
SplitAndMode,
};
use crate::types::Mode;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(default, rename_all = "camelCase"))]
#[non_exhaustive]
pub struct TracklistOptions {
pub mode: ModeOption,
pub known_artists: Vec<String>,
pub split_and: SplitAnd,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub keywords: Option<KeywordOptions>,
#[cfg_attr(
feature = "serde",
serde(
skip_serializing_if = "Option::is_none",
serialize_with = "crate::serde_support::opt_seconds"
)
)]
pub audio_seconds: Option<f64>,
pub marker_words: Vec<String>,
}
impl Default for TracklistOptions {
fn default() -> Self {
TracklistOptions {
mode: ModeOption::Tracklist,
known_artists: Vec::new(),
split_and: SplitAnd::Auto,
keywords: None,
audio_seconds: None,
marker_words: Vec::new(),
}
}
}
impl TracklistOptions {
pub fn new() -> Self {
Self::default()
}
pub fn mode(mut self, mode: ModeOption) -> Self {
self.mode = mode;
self
}
pub fn known_artists<I, S>(mut self, names: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.known_artists = names.into_iter().map(Into::into).collect();
self
}
pub fn split_and(mut self, split_and: SplitAnd) -> Self {
self.split_and = split_and;
self
}
pub fn keywords(mut self, keywords: KeywordOptions) -> Self {
self.keywords = Some(keywords);
self
}
pub fn audio_seconds(mut self, seconds: f64) -> Self {
self.audio_seconds = Some(seconds);
self
}
pub fn marker_words<I, S>(mut self, words: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.marker_words = words.into_iter().map(Into::into).collect();
self
}
}
pub(crate) struct ResolvedOptions {
pub parse: Resolved,
pub audio_seconds: Option<f64>,
pub marker_words: Vec<String>,
}
pub(crate) fn js_number(value: Option<&Json>) -> Option<f64> {
match value {
Some(Json::Num(n)) => Some(*n),
_ => None,
}
}
fn audio(seconds: Option<f64>) -> Option<f64> {
seconds.filter(|a| a.is_finite() && *a >= 0.0)
}
pub(crate) fn resolve_json(options: &Json) -> ResolvedOptions {
let mut parse = Resolved::from_json(options);
parse.uploader = None;
parse.mode = match options.get("mode").and_then(Json::as_str) {
Some("auto") => Requested::Auto,
Some(name) => {
Mode::from_name(name).map_or(Requested::Mode(Mode::Tracklist), Requested::Mode)
}
None => Requested::Mode(Mode::Tracklist),
};
parse.split_and = match options.get("splitAnd").and_then(Json::as_str) {
Some("always") => SplitAndMode::Always,
Some("never") => SplitAndMode::Never,
_ => SplitAndMode::Auto,
};
ResolvedOptions {
parse,
audio_seconds: audio(js_number(options.get("audioSeconds"))),
marker_words: string_list(options.get("markerWords")),
}
}
pub(crate) fn resolve_typed(options: &TracklistOptions) -> ResolvedOptions {
let parse = ParseOptions {
mode: options.mode,
uploader: None,
known_artists: options.known_artists.clone(),
split_and: options.split_and,
keywords: options.keywords.clone(),
};
ResolvedOptions {
parse: Resolved::from_typed(&parse),
audio_seconds: audio(options.audio_seconds),
marker_words: options.marker_words.clone(),
}
}