|
@@ -1,15 +1,63 @@
|
|
|
use clap::{Arg, ArgMatches};
|
|
|
-use ffsend_api::action::params::{
|
|
|
- PARAMS_DOWNLOAD_MAX as DOWNLOAD_MAX, PARAMS_DOWNLOAD_MIN as DOWNLOAD_MIN,
|
|
|
-};
|
|
|
+use ffsend_api::api::Version as ApiVersion;
|
|
|
+use ffsend_api::config::downloads_max;
|
|
|
|
|
|
use super::{CmdArg, CmdArgFlag, CmdArgOption};
|
|
|
+use crate::cmd::matcher::MainMatcher;
|
|
|
+use crate::util::{highlight, prompt_yes};
|
|
|
|
|
|
-use crate::util::{quit_error_msg, ErrorHintsBuilder};
|
|
|
+use crate::util::{quit, ErrorHintsBuilder};
|
|
|
|
|
|
/// The download limit argument.
|
|
|
pub struct ArgDownloadLimit {}
|
|
|
|
|
|
+impl ArgDownloadLimit {
|
|
|
+ pub fn value_checked<'a>(
|
|
|
+ matches: &ArgMatches<'a>,
|
|
|
+ main_matcher: &MainMatcher,
|
|
|
+ api_version: ApiVersion,
|
|
|
+ auth: bool,
|
|
|
+ ) -> Option<usize> {
|
|
|
+ // Get the download value
|
|
|
+ let mut downloads = Self::value(matches)?;
|
|
|
+
|
|
|
+ // Get number of allowed downloads, return if allowed
|
|
|
+ let allowed = downloads_max(api_version, auth);
|
|
|
+ if allowed.contains(&downloads) {
|
|
|
+ return Some(downloads);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Prompt the user the specified downloads limit is invalid
|
|
|
+ let allowed_str = allowed
|
|
|
+ .iter()
|
|
|
+ .map(|value| format!("{}", value))
|
|
|
+ .collect::<Vec<_>>()
|
|
|
+ .join(", ");
|
|
|
+ eprintln!("The downloads limit must be one of: {}", allowed_str,);
|
|
|
+ if auth {
|
|
|
+ eprintln!("Use '{}' to force", highlight("--force"));
|
|
|
+ } else {
|
|
|
+ eprintln!(
|
|
|
+ "Use '{}' to force, authenticate for higher limits",
|
|
|
+ highlight("--force")
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Ask to use closest limit, quit if user cancelled
|
|
|
+ let closest = closest(allowed, downloads);
|
|
|
+ if !prompt_yes(
|
|
|
+ &format!("Would you like to limit downloads to {} instead?", closest),
|
|
|
+ None,
|
|
|
+ main_matcher,
|
|
|
+ ) {
|
|
|
+ quit();
|
|
|
+ }
|
|
|
+ downloads = closest;
|
|
|
+
|
|
|
+ Some(downloads)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
impl CmdArg for ArgDownloadLimit {
|
|
|
fn name() -> &'static str {
|
|
|
"download-limit"
|
|
@@ -29,30 +77,26 @@ impl CmdArg for ArgDownloadLimit {
|
|
|
impl CmdArgFlag for ArgDownloadLimit {}
|
|
|
|
|
|
impl<'a> CmdArgOption<'a> for ArgDownloadLimit {
|
|
|
- type Value = Option<u8>;
|
|
|
+ type Value = Option<usize>;
|
|
|
|
|
|
fn value<'b: 'a>(matches: &'a ArgMatches<'b>) -> Self::Value {
|
|
|
// TODO: do not unwrap, report an error
|
|
|
- Self::value_raw(matches)
|
|
|
- .map(|d| d.parse::<u8>().expect("invalid download limit"))
|
|
|
- .and_then(|d| {
|
|
|
- // Check the download limit bounds
|
|
|
- // TODO: somehow allow to force a different number here
|
|
|
- if d < DOWNLOAD_MIN || d > DOWNLOAD_MAX {
|
|
|
- quit_error_msg(
|
|
|
- format!(
|
|
|
- "invalid download limit, must be between {} and {}",
|
|
|
- DOWNLOAD_MIN, DOWNLOAD_MAX,
|
|
|
- ),
|
|
|
- ErrorHintsBuilder::default()
|
|
|
- .force(false)
|
|
|
- .verbose(false)
|
|
|
- .build()
|
|
|
- .unwrap(),
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- Some(d)
|
|
|
- })
|
|
|
+ Self::value_raw(matches).map(|d| d.parse::<usize>().expect("invalid download limit"))
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/// Find the closest value to `current` in the given `values` range.
|
|
|
+fn closest(values: &[usize], current: usize) -> usize {
|
|
|
+ // Own the values, sort and reverse, start with biggest first
|
|
|
+ let mut values = values.to_vec();
|
|
|
+ values.sort_unstable();
|
|
|
+
|
|
|
+ // Find the closest value, return it
|
|
|
+ *values
|
|
|
+ .iter()
|
|
|
+ .rev()
|
|
|
+ .map(|value| (value, (current as i64 - *value as i64).abs()))
|
|
|
+ .min_by_key(|value| value.1)
|
|
|
+ .expect("failed to find closest value, none given")
|
|
|
+ .0
|
|
|
+}
|