aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--yt/src/main.rs7
-rw-r--r--yt/src/select/cmds/add.rs6
-rw-r--r--yt/src/select/mod.rs42
-rw-r--r--yt/src/update/mod.rs7
-rw-r--r--yt/src/videos/display/format_video.rs175
-rw-r--r--yt/src/videos/display/mod.rs375
-rw-r--r--yt/src/videos/mod.rs18
7 files changed, 222 insertions, 408 deletions
diff --git a/yt/src/main.rs b/yt/src/main.rs
index acc6c7d..0178488 100644
--- a/yt/src/main.rs
+++ b/yt/src/main.rs
@@ -30,7 +30,6 @@ use tokio::{
task::JoinHandle,
};
use url::Url;
-use videos::display::format_video::FormatVideo;
use yt_dlp::wrapper::info_json::InfoJson;
use crate::{cli::Command, storage::subscriptions};
@@ -147,12 +146,10 @@ async fn main() -> Result<()> {
print!(
"{}",
- (&video
- .to_formatted_video(&app)
+ &video
+ .to_info_display(&app)
.await
.context("Failed to format video")?
- .colorize(&app))
- .to_info_display()
);
}
},
diff --git a/yt/src/select/cmds/add.rs b/yt/src/select/cmds/add.rs
index 89d50c0..1e14995 100644
--- a/yt/src/select/cmds/add.rs
+++ b/yt/src/select/cmds/add.rs
@@ -6,7 +6,6 @@ use crate::{
},
unreachable::Unreachable,
update::video_entry_to_video,
- videos::display::format_video::FormatVideo,
};
use anyhow::{Context, Result, bail};
@@ -76,10 +75,7 @@ pub(super) async fn add(
let video = video_entry_to_video(entry, None)?;
add_video(app, video.clone()).await?;
- println!(
- "{}",
- (&video.to_formatted_video(app).await?.colorize(app)).to_line_display()
- );
+ println!("{}", &video.to_line_display(app).await?);
Ok(())
}
diff --git a/yt/src/select/mod.rs b/yt/src/select/mod.rs
index e7eb460..34262af 100644
--- a/yt/src/select/mod.rs
+++ b/yt/src/select/mod.rs
@@ -19,15 +19,14 @@ use crate::{
app::App,
cli::CliArgs,
constants::HELP_STR,
- storage::video_database::{VideoStatus, getters::get_videos},
+ storage::video_database::{Video, VideoStatus, getters::get_videos},
unreachable::Unreachable,
- videos::display::format_video::FormatVideo,
};
use anyhow::{Context, Result, bail};
use clap::Parser;
use cmds::handle_select_cmd;
-use futures::future::join_all;
+use futures::{TryStreamExt, stream::FuturesOrdered};
use selection_file::process_line;
use tempfile::Builder;
use tokio::process::Command;
@@ -35,6 +34,10 @@ use tokio::process::Command;
pub mod cmds;
pub mod selection_file;
+async fn to_select_file_display_owned(video: Video, app: &App) -> Result<String> {
+ (&video).to_select_file_display(&app).await
+}
+
pub async fn select(app: &App, done: bool, use_last_selection: bool) -> Result<()> {
let temp_file = Builder::new()
.prefix("yt_video_select-")
@@ -65,28 +68,25 @@ pub async fn select(app: &App, done: bool, use_last_selection: bool) -> Result<(
// Warmup the cache for the display rendering of the videos.
// Otherwise the futures would all try to warm it up at the same time.
if let Some(vid) = matching_videos.first() {
- drop(vid.to_formatted_video(app).await?);
+ drop(vid.to_line_display(app).await?);
}
let mut edit_file = BufWriter::new(&temp_file);
- join_all(
- matching_videos
- .into_iter()
- .map(|vid| async { vid.to_formatted_video_owned(app).await })
- .collect::<Vec<_>>(),
- )
- .await
- .into_iter()
- .try_for_each(|line| -> Result<()> {
- let formatted_line = (&line?).to_select_file_display();
-
- edit_file
- .write_all(formatted_line.as_bytes())
- .context("Failed to write to `edit_file`")?;
+ matching_videos
+ .into_iter()
+ .map(|vid| to_select_file_display_owned(vid, app))
+ .collect::<FuturesOrdered<_>>()
+ .try_collect::<Vec<String>>()
+ .await?
+ .into_iter()
+ .try_for_each(|line| -> Result<()> {
+ edit_file
+ .write_all(line.as_bytes())
+ .context("Failed to write to `edit_file`")?;
- Ok(())
- })?;
+ Ok(())
+ })?;
edit_file.write_all(HELP_STR.as_bytes())?;
edit_file.flush().context("Failed to flush edit file")?;
@@ -153,7 +153,7 @@ pub async fn select(app: &App, done: bool, use_last_selection: bool) -> Result<(
}
// // FIXME: There should be no reason why we need to re-run yt, just to get the help string. But I've
-// // yet to find a way to do it with out the extra exec <2024-08-20>
+// // yet to find a way to do it without the extra exec <2024-08-20>
// async fn get_help() -> Result<String> {
// let binary_name = current_exe()?;
// let cmd = Command::new(binary_name)
diff --git a/yt/src/update/mod.rs b/yt/src/update/mod.rs
index 7bd37b6..da19bae 100644
--- a/yt/src/update/mod.rs
+++ b/yt/src/update/mod.rs
@@ -25,7 +25,6 @@ use crate::{
setters::add_video,
},
},
- videos::display::format_video::FormatVideo,
};
mod updater;
@@ -188,12 +187,10 @@ async fn process_subscription(app: &App, sub: &Subscription, entry: InfoJson) ->
.with_context(|| format!("Failed to add video to database: '{}'", video.title))?;
println!(
"{}",
- (&video
- .to_formatted_video(app)
+ &video
+ .to_line_display(app)
.await
.with_context(|| format!("Failed to format video: '{}'", video.title))?
- .colorize(app))
- .to_line_display()
);
Ok(())
}
diff --git a/yt/src/videos/display/format_video.rs b/yt/src/videos/display/format_video.rs
index 26f0f5b..f9c50af 100644
--- a/yt/src/videos/display/format_video.rs
+++ b/yt/src/videos/display/format_video.rs
@@ -8,119 +8,48 @@
// You should have received a copy of the License along with this program.
// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-use std::fmt::Display;
+use anyhow::Result;
-use crate::comments::output::format_text;
+use crate::{app::App, comments::output::format_text, storage::video_database::Video};
-pub trait FormatVideo {
- type Output;
+impl Video {
+ pub async fn to_info_display(&self, app: &App) -> Result<String> {
+ let cache_path = self.cache_path_fmt(app);
+ let description = self.description_fmt();
+ let duration = self.duration_fmt(app);
+ let extractor_hash = self.extractor_hash_fmt(app).await?;
+ let in_playlist = self.in_playlist_fmt(app);
+ let last_status_change = self.last_status_change_fmt(app);
+ let parent_subscription_name = self.parent_subscription_name_fmt(app);
+ let priority = self.priority_fmt();
+ let publish_date = self.publish_date_fmt(app);
+ let status = self.status_fmt(app);
+ let thumbnail_url = self.thumbnail_url_fmt();
+ let title = self.title_fmt(app);
+ let url = self.url_fmt(app);
+ let watch_progress = self.watch_progress_fmt(app);
+ let video_options = self.video_options_fmt(app).await?;
- fn cache_path(&self) -> Self::Output;
- fn description(&self) -> Self::Output;
- fn duration(&self) -> Self::Output;
- fn extractor_hash(&self) -> Self::Output;
- fn last_status_change(&self) -> Self::Output;
- fn parent_subscription_name(&self) -> Self::Output;
- fn priority(&self) -> Self::Output;
- fn publish_date(&self) -> Self::Output;
- fn status(&self) -> Self::Output;
- fn status_change(&self) -> Self::Output;
- fn thumbnail_url(&self) -> Self::Output;
- fn title(&self) -> Self::Output;
- fn url(&self) -> Self::Output;
- fn video_options(&self) -> Self::Output;
-
- #[allow(clippy::type_complexity)]
- fn to_parts(
- &self,
- ) -> (
- Self::Output,
- Self::Output,
- Self::Output,
- Self::Output,
- Self::Output,
- Self::Output,
- Self::Output,
- Self::Output,
- Self::Output,
- Self::Output,
- Self::Output,
- Self::Output,
- Self::Output,
- Self::Output,
- ) {
- let cache_path = self.cache_path();
- let description = self.description();
- let duration = self.duration();
- let extractor_hash = self.extractor_hash();
- let last_status_change = self.last_status_change();
- let parent_subscription_name = self.parent_subscription_name();
- let priority = self.priority();
- let publish_date = self.publish_date();
- let status = self.status();
- let status_change = self.status_change();
- let thumbnail_url = self.thumbnail_url();
- let title = self.title();
- let url = self.url();
- let video_options = self.video_options();
-
- (
- cache_path,
- description,
- duration,
- extractor_hash,
- last_status_change,
- parent_subscription_name,
- priority,
- publish_date,
- status,
- status_change,
- thumbnail_url,
- title,
- url,
- video_options,
- )
- }
-
- fn to_info_display(&self) -> String
- where
- <Self as FormatVideo>::Output: Display,
- {
- let (
- cache_path,
- description,
- duration,
- extractor_hash,
- last_status_change,
- parent_subscription_name,
- priority,
- publish_date,
- status,
- status_change,
- thumbnail_url,
- title,
- url,
- video_options,
- ) = self.to_parts();
-
- let status_change = if status_change.to_string().as_str() == "false" {
- "currently not changing"
- } else if status_change.to_string().as_str() == "true" {
- "currently changing"
- } else {
- unreachable!("This is an formatted boolean");
+ let watched_percentage_fmt = {
+ if let Some(duration) = self.duration {
+ format!(
+ " (watched: {:0.1}%)",
+ f64::from(self.watch_progress) / duration
+ )
+ } else {
+ format!(" {watch_progress}")
+ }
};
let string = format!(
"\
{title} ({extractor_hash})
| -> {cache_path}
-| -> {duration}
+| -> {duration}{watched_percentage_fmt}
| -> {parent_subscription_name}
| -> priority: {priority}
| -> {publish_date}
-| -> status: {status} since {last_status_change}
-| -> {status_change}
+| -> status: {status} since {last_status_change} ({in_playlist})
| -> {thumbnail_url}
| -> {url}
| -> options: {}
@@ -128,43 +57,37 @@ pub trait FormatVideo {
video_options.to_string().trim(),
format_text(description.to_string().as_str())
);
- string
+ Ok(string)
}
- fn to_line_display(&self) -> String
- where
- Self::Output: Display,
- {
+ pub async fn to_line_display(&self, app: &App) -> Result<String> {
let f = format!(
"{} {} {} {} {} {}",
- self.status(),
- self.extractor_hash(),
- self.title(),
- self.publish_date(),
- self.parent_subscription_name(),
- self.duration()
+ self.status_fmt(app),
+ self.extractor_hash_fmt(app).await?,
+ self.title_fmt(app),
+ self.publish_date_fmt(app),
+ self.parent_subscription_name_fmt(app),
+ self.duration_fmt(app)
);
- f
+ Ok(f)
}
- fn to_select_file_display(&self) -> String
- where
- Self::Output: Display,
- {
+ pub async fn to_select_file_display(&self, app: &App) -> Result<String> {
let f = format!(
r#"{}{} {} "{}" "{}" "{}" "{}" "{}"{}"#,
- self.status(),
- self.video_options(),
- self.extractor_hash(),
- self.title(),
- self.publish_date(),
- self.parent_subscription_name(),
- self.duration(),
- self.url(),
+ self.status_fmt_no_color(),
+ self.video_options_fmt_no_color(app).await?,
+ self.extractor_hash_fmt_no_color(app).await?,
+ self.title_fmt_no_color(),
+ self.publish_date_fmt_no_color(),
+ self.parent_subscription_name_fmt_no_color(),
+ self.duration_fmt_no_color(),
+ self.url_fmt_no_color(),
'\n'
);
- f
+ Ok(f)
}
}
diff --git a/yt/src/videos/display/mod.rs b/yt/src/videos/display/mod.rs
index 3f03ec0..21ab1d4 100644
--- a/yt/src/videos/display/mod.rs
+++ b/yt/src/videos/display/mod.rs
@@ -11,14 +11,13 @@
use std::path::PathBuf;
use chrono::DateTime;
-use format_video::FormatVideo;
use owo_colors::OwoColorize;
use url::Url;
use crate::{
app::App,
select::selection_file::duration::Duration,
- storage::video_database::{Video, getters::get_video_opts},
+ storage::video_database::{InPlaylist, Video, getters::get_video_opts},
};
use anyhow::{Context, Result};
@@ -35,105 +34,62 @@ macro_rules! get {
};
}
-/// This is identical to a [`FormattedVideo`], but has colorized fields.
-#[derive(Debug)]
-pub struct ColorizedFormattedVideo(FormattedVideo);
-
-impl FormattedVideo {
- #[must_use]
- pub fn colorize(self, app: &App) -> ColorizedFormattedVideo {
- if app.config.global.display_colors {
- let Self {
- cache_path,
- description,
- duration,
- extractor_hash,
- last_status_change,
- parent_subscription_name,
- priority,
- publish_date,
- status,
- status_change,
- thumbnail_url,
- title,
- url,
- video_options,
- } = self;
-
- ColorizedFormattedVideo(Self {
- cache_path: cache_path.blue().bold().to_string(),
- description,
- duration: duration.cyan().bold().to_string(),
- extractor_hash: extractor_hash.bright_purple().italic().to_string(),
- last_status_change: last_status_change.bright_cyan().to_string(),
- parent_subscription_name: parent_subscription_name.bright_magenta().to_string(),
- priority,
- publish_date: publish_date.bright_white().bold().to_string(),
- status: status.red().bold().to_string(),
- status_change,
- thumbnail_url,
- title: title.green().bold().to_string(),
- url: url.italic().to_string(),
- video_options: video_options.bright_green().to_string(),
- })
- } else {
- ColorizedFormattedVideo(self)
- }
- }
+fn date_from_stamp(stamp: i64) -> String {
+ DateTime::from_timestamp(stamp, 0)
+ .expect("The timestamps should always be valid")
+ .format("%Y-%m-%d")
+ .to_string()
}
-
-/// This is a version of [`Video`] that has all the fields of the original [`Video`] structure
-/// turned to [`String`]s to facilitate displaying it.
-///
-/// This structure provides a way to display a [`Video`] in a coherent way, as it enforces to
-/// always use the same colors for one field.
-#[derive(Debug)]
-pub struct FormattedVideo {
- cache_path: String,
- description: String,
- duration: String,
- extractor_hash: String,
- last_status_change: String,
- parent_subscription_name: String,
- priority: String,
- publish_date: String,
- status: String,
- status_change: String,
- thumbnail_url: String,
- title: String,
- url: String,
- /// This string contains the video options (speed, `subtitle_languages`, etc.).
- /// It already starts with an extra whitespace, when these are not empty.
- video_options: String,
+fn maybe_add_color<F>(app: &App, input: String, mut color_fn: F) -> String
+where
+ F: FnMut(String) -> String,
+{
+ if app.config.global.display_colors {
+ color_fn(input)
+ } else {
+ input
+ }
}
-
impl Video {
- pub async fn to_formatted_video_owned(self, app: &App) -> Result<FormattedVideo> {
- Self::to_formatted_video(&self, app).await
- }
-
- pub async fn to_formatted_video(&self, app: &App) -> Result<FormattedVideo> {
- fn date_from_stamp(stamp: i64) -> String {
- DateTime::from_timestamp(stamp, 0)
- .expect("The timestamps should always be valid")
- .format("%Y-%m-%d")
- .to_string()
- }
-
- let cache_path: String = get!(
+ #[must_use]
+ pub fn cache_path_fmt(&self, app: &App) -> String {
+ let cache_path = get!(
self,
cache_path,
"Cache Path",
(|value: &PathBuf| value.to_string_lossy().to_string())
);
- let description = get!(
+ maybe_add_color(app, cache_path, |v| v.blue().bold().to_string())
+ }
+
+ #[must_use]
+ pub fn description_fmt(&self) -> String {
+ get!(
self,
description,
"Description",
(|value: &str| value.to_owned())
- );
- let duration = Duration::from(self.duration);
- let extractor_hash = self
+ )
+ }
+
+ #[must_use]
+ pub fn duration_fmt_no_color(&self) -> String {
+ Duration::from(self.duration).to_string()
+ }
+ #[must_use]
+ pub fn duration_fmt(&self, app: &App) -> String {
+ let duration = self.duration_fmt_no_color();
+ maybe_add_color(app, duration, |v| v.cyan().bold().to_string())
+ }
+
+ #[must_use]
+ pub fn watch_progress_fmt(&self, app: &App) -> String {
+ let progress = Duration::from(Some(f64::from(self.watch_progress))).to_string();
+ maybe_add_color(app, progress, |v| v.cyan().bold().to_string())
+ }
+
+ pub async fn extractor_hash_fmt_no_color(&self, app: &App) -> Result<String> {
+ let hash = self
.extractor_hash
.into_short_hash(app)
.await
@@ -142,179 +98,124 @@ impl Video {
"Failed to format extractor hash, whilst formatting video: '{}'",
self.title
)
- })?;
- let last_status_change = date_from_stamp(self.last_status_change);
- let parent_subscription_name = get!(
- self,
- parent_subscription_name,
- "author",
- (|sub: &str| sub.replace('"', "'"))
- );
- let priority = self.priority;
- let publish_date = get!(
- self,
- publish_date,
- "release date",
- (|date: &i64| date_from_stamp(*date))
- );
- // TODO: We might support `.trim()`ing that, as the extra whitespace could be bad in the
- // selection file. <2024-10-07>
- let status = self.status.as_command();
- let status_change = self.status_change;
- let thumbnail_url = get!(
- self,
- thumbnail_url,
- "thumbnail URL",
- (|url: &Url| url.to_string())
- );
- let title = self.title.replace(['"', '„', '”', '“'], "'");
- let url = self.url.as_str().replace('"', "\\\"");
-
- let video_options = {
- let opts = get_video_opts(app, &self.extractor_hash)
- .await
- .with_context(|| {
- format!("Failed to get video options for video: '{}'", self.title)
- })?
- .to_cli_flags(app);
- let opts_white = if opts.is_empty() { "" } else { " " };
- format!("{opts_white}{opts}")
- };
-
- Ok(FormattedVideo {
- cache_path,
- description,
- duration: duration.to_string(),
- extractor_hash: extractor_hash.to_string(),
- last_status_change,
- parent_subscription_name,
- priority: priority.to_string(),
- publish_date,
- status: status.to_string(),
- status_change: status_change.to_string(),
- thumbnail_url,
- title,
- url,
- video_options,
- })
- }
-}
-
-impl<'a> FormatVideo for &'a FormattedVideo {
- type Output = &'a str;
-
- fn cache_path(&self) -> Self::Output {
- &self.cache_path
- }
-
- fn description(&self) -> Self::Output {
- &self.description
- }
-
- fn duration(&self) -> Self::Output {
- &self.duration
- }
-
- fn extractor_hash(&self) -> Self::Output {
- &self.extractor_hash
- }
-
- fn last_status_change(&self) -> Self::Output {
- &self.last_status_change
- }
-
- fn parent_subscription_name(&self) -> Self::Output {
- &self.parent_subscription_name
- }
-
- fn priority(&self) -> Self::Output {
- &self.priority
- }
-
- fn publish_date(&self) -> Self::Output {
- &self.publish_date
- }
-
- fn status(&self) -> Self::Output {
- &self.status
- }
-
- fn status_change(&self) -> Self::Output {
- &self.status_change
+ })?
+ .to_string();
+ Ok(hash)
}
-
- fn thumbnail_url(&self) -> Self::Output {
- &self.thumbnail_url
- }
-
- fn title(&self) -> Self::Output {
- &self.title
+ pub async fn extractor_hash_fmt(&self, app: &App) -> Result<String> {
+ let hash = self.extractor_hash_fmt_no_color(app).await?;
+ Ok(maybe_add_color(app, hash, |v| {
+ v.bright_purple().italic().to_string()
+ }))
}
- fn url(&self) -> Self::Output {
- &self.url
+ #[must_use]
+ pub fn in_playlist_fmt(&self, app: &App) -> String {
+ let output = match self.in_playlist {
+ InPlaylist::Excluded => "Not in the playlist",
+ InPlaylist::Hidden => "In the playlist",
+ InPlaylist::Focused => "In the playlist and focused",
+ };
+ maybe_add_color(app, output.to_owned(), |v| v.yellow().italic().to_string())
}
-
- fn video_options(&self) -> Self::Output {
- &self.video_options
+ #[must_use]
+ pub fn last_status_change_fmt(&self, app: &App) -> String {
+ let lsc = date_from_stamp(self.last_status_change);
+ maybe_add_color(app, lsc, |v| v.bright_cyan().to_string())
}
-}
-impl<'a> FormatVideo for &'a ColorizedFormattedVideo {
- type Output = &'a str;
- fn cache_path(&self) -> Self::Output {
- &self.0.cache_path
+ #[must_use]
+ pub fn parent_subscription_name_fmt_no_color(&self) -> String {
+ get!(
+ self,
+ parent_subscription_name,
+ "author",
+ (|sub: &str| sub.replace('"', "'"))
+ )
}
-
- fn description(&self) -> Self::Output {
- &self.0.description
+ #[must_use]
+ pub fn parent_subscription_name_fmt(&self, app: &App) -> String {
+ let psn = self.parent_subscription_name_fmt_no_color();
+ maybe_add_color(app, psn, |v| v.bright_magenta().to_string())
}
- fn duration(&self) -> Self::Output {
- &self.0.duration
+ #[must_use]
+ pub fn priority_fmt(&self) -> String {
+ self.priority.to_string()
}
- fn extractor_hash(&self) -> Self::Output {
- &self.0.extractor_hash
+ #[must_use]
+ pub fn publish_date_fmt_no_color(&self) -> String {
+ get!(
+ self,
+ publish_date,
+ "release date",
+ (|date: &i64| date_from_stamp(*date))
+ )
}
-
- fn last_status_change(&self) -> Self::Output {
- &self.0.last_status_change
+ #[must_use]
+ pub fn publish_date_fmt(&self, app: &App) -> String {
+ let date = self.publish_date_fmt_no_color();
+ maybe_add_color(app, date, |v| v.bright_white().bold().to_string())
}
- fn parent_subscription_name(&self) -> Self::Output {
- &self.0.parent_subscription_name
+ #[must_use]
+ pub fn status_fmt_no_color(&self) -> String {
+ // TODO: We might support `.trim()`ing that, as the extra whitespace could be bad in the
+ // selection file. <2024-10-07>
+ self.status.as_command().to_string()
}
-
- fn priority(&self) -> Self::Output {
- &self.0.priority
+ #[must_use]
+ pub fn status_fmt(&self, app: &App) -> String {
+ let status = self.status_fmt_no_color();
+ maybe_add_color(app, status, |v| v.red().bold().to_string())
}
- fn publish_date(&self) -> Self::Output {
- &self.0.publish_date
+ #[must_use]
+ pub fn thumbnail_url_fmt(&self) -> String {
+ get!(
+ self,
+ thumbnail_url,
+ "thumbnail URL",
+ (|url: &Url| url.to_string())
+ )
}
- fn status(&self) -> Self::Output {
- &self.0.status
+ #[must_use]
+ pub fn title_fmt_no_color(&self) -> String {
+ self.title.replace(['"', '„', '”', '“'], "'")
}
-
- fn status_change(&self) -> Self::Output {
- &self.0.status_change
+ #[must_use]
+ pub fn title_fmt(&self, app: &App) -> String {
+ let title = self.title_fmt_no_color();
+ maybe_add_color(app, title, |v| v.green().bold().to_string())
}
- fn thumbnail_url(&self) -> Self::Output {
- &self.0.thumbnail_url
+ #[must_use]
+ pub fn url_fmt_no_color(&self) -> String {
+ self.url.as_str().replace('"', "\\\"")
}
-
- fn title(&self) -> Self::Output {
- &self.0.title
+ #[must_use]
+ pub fn url_fmt(&self, app: &App) -> String {
+ let url = self.url_fmt_no_color();
+ maybe_add_color(app, url, |v| v.italic().to_string())
}
- fn url(&self) -> Self::Output {
- &self.0.url
+ pub async fn video_options_fmt_no_color(&self, app: &App) -> Result<String> {
+ let video_options = {
+ let opts = get_video_opts(app, &self.extractor_hash)
+ .await
+ .with_context(|| {
+ format!("Failed to get video options for video: '{}'", self.title)
+ })?
+ .to_cli_flags(app);
+ let opts_white = if opts.is_empty() { "" } else { " " };
+ format!("{opts_white}{opts}")
+ };
+ Ok(video_options)
}
-
- fn video_options(&self) -> Self::Output {
- &self.0.video_options
+ pub async fn video_options_fmt(&self, app: &App) -> Result<String> {
+ let opts = self.video_options_fmt_no_color(app).await?;
+ Ok(maybe_add_color(app, opts, |v| v.bright_green().to_string()))
}
}
diff --git a/yt/src/videos/mod.rs b/yt/src/videos/mod.rs
index 23613f7..2f9d8af 100644
--- a/yt/src/videos/mod.rs
+++ b/yt/src/videos/mod.rs
@@ -9,7 +9,6 @@
// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
use anyhow::Result;
-use display::{FormattedVideo, format_video::FormatVideo};
use futures::{TryStreamExt, stream::FuturesUnordered};
use nucleo_matcher::{
Matcher,
@@ -20,15 +19,19 @@ pub mod display;
use crate::{
app::App,
- storage::video_database::{VideoStatus, getters::get_videos},
+ storage::video_database::{Video, VideoStatus, getters::get_videos},
};
+async fn to_line_display_owned(video: Video, app: &App) -> Result<String> {
+ (&video).to_line_display(&app).await
+}
+
pub async fn query(app: &App, limit: Option<usize>, search_query: Option<String>) -> Result<()> {
let all_videos = get_videos(app, VideoStatus::ALL, None).await?;
// turn one video to a color display, to pre-warm the hash shrinking cache
if let Some(val) = all_videos.first() {
- val.to_formatted_video(app).await?;
+ val.to_line_display(app).await?;
}
let limit = limit.unwrap_or(all_videos.len());
@@ -36,13 +39,10 @@ pub async fn query(app: &App, limit: Option<usize>, search_query: Option<String>
let all_video_strings: Vec<String> = all_videos
.into_iter()
.take(limit)
- .map(|vid| vid.to_formatted_video_owned(app))
+ .map(|vid| to_line_display_owned(vid, app))
.collect::<FuturesUnordered<_>>()
- .try_collect::<Vec<FormattedVideo>>()
- .await?
- .into_iter()
- .map(|vid| (&vid.colorize(app)).to_line_display())
- .collect();
+ .try_collect::<Vec<String>>()
+ .await?;
if let Some(query) = search_query {
let mut matcher = Matcher::new(nucleo_matcher::Config::DEFAULT.match_paths());