diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-02-17 19:34:33 +0100 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-02-17 19:34:33 +0100 |
commit | 27fae0bcd380fdf7396c33678f4aa3fa2df192cf (patch) | |
tree | 70784d5b1aa231997faaf50773363bd38bdd1d23 | |
parent | fix(yt): Remove most of the references to the zero version `Video` struct (diff) | |
download | yt-27fae0bcd380fdf7396c33678f4aa3fa2df192cf.zip |
refactor(yt/videos/display): Streamline video formatting
The previous approach with a trait and two newtype wrappers was just too complicated and really not worth it. Simply implementing the functions directly makes the code more readable and simplifies the implementation.
-rw-r--r-- | yt/src/main.rs | 7 | ||||
-rw-r--r-- | yt/src/select/cmds/add.rs | 6 | ||||
-rw-r--r-- | yt/src/select/mod.rs | 42 | ||||
-rw-r--r-- | yt/src/update/mod.rs | 7 | ||||
-rw-r--r-- | yt/src/videos/display/format_video.rs | 175 | ||||
-rw-r--r-- | yt/src/videos/display/mod.rs | 375 | ||||
-rw-r--r-- | yt/src/videos/mod.rs | 18 |
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()); |