aboutsummaryrefslogtreecommitdiffstats
path: root/src/videos
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-10-14 14:56:29 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-10-14 14:56:29 +0200
commit6c9286857ef8b314962b67f4a16a66e8c35531bc (patch)
tree9ced4485ec38b39f82cba258c06321a21c40000a /src/videos
parentbuild(Cargo.toml): Add further lints (diff)
downloadyt-6c9286857ef8b314962b67f4a16a66e8c35531bc.zip
refactor(treewide): Combine the separate crates in one workspace
Diffstat (limited to 'src/videos')
-rw-r--r--src/videos/display/format_video.rs166
-rw-r--r--src/videos/display/mod.rs314
-rw-r--r--src/videos/mod.rs66
3 files changed, 0 insertions, 546 deletions
diff --git a/src/videos/display/format_video.rs b/src/videos/display/format_video.rs
deleted file mode 100644
index 50646a1..0000000
--- a/src/videos/display/format_video.rs
+++ /dev/null
@@ -1,166 +0,0 @@
-// yt - A fully featured command line YouTube client
-//
-// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-// This file is part of Yt.
-//
-// 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;
-
-pub trait FormatVideo {
- type Output;
-
- 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;
-
- 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 string = format!(
- "\
-{title} ({extractor_hash})
-| -> {cache_path}
-| -> {duration}
-| -> {parent_subscription_name}
-| -> priority: {priority}
-| -> {publish_date}
-| -> status: {status} since {last_status_change}
-| -> {status_change}
-| -> {thumbnail_url}
-| -> {url}
-| -> options: {}
-{description}\n",
- video_options.to_string().trim()
- );
- string
- }
-
- fn to_line_display(&self) -> String
- where
- Self::Output: Display,
- {
- let f = format!(
- "{} {} {} {} {} {}",
- self.status(),
- self.extractor_hash(),
- self.title(),
- self.publish_date(),
- self.parent_subscription_name(),
- self.duration()
- );
-
- f
- }
-
- fn to_select_file_display(&self) -> String
- where
- Self::Output: Display,
- {
- 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(),
- '\n'
- );
-
- f
- }
-}
diff --git a/src/videos/display/mod.rs b/src/videos/display/mod.rs
deleted file mode 100644
index d919dd2..0000000
--- a/src/videos/display/mod.rs
+++ /dev/null
@@ -1,314 +0,0 @@
-// yt - A fully featured command line YouTube client
-//
-// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-// This file is part of Yt.
-//
-// 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::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::{getters::get_video_opts, Video},
-};
-
-use anyhow::{Context, Result};
-
-pub mod format_video;
-
-macro_rules! get {
- ($value:expr, $key:ident, $name:expr, $code:tt) => {
- if let Some(value) = &$value.$key {
- $code(value)
- } else {
- concat!("[No ", $name, "]").to_owned()
- }
- };
-}
-
-/// This is identical to a [`FormattedVideo`], but has colorized fields.
-pub struct ColorizedFormattedVideo(FormattedVideo);
-
-impl FormattedVideo {
- pub fn colorize(self) -> ColorizedFormattedVideo {
- 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(),
- })
- }
-}
-
-/// 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,
-}
-
-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!(
- self,
- cache_path,
- "Cache Path",
- (|value: &PathBuf| value.to_string_lossy().to_string())
- );
- let description = get!(
- self,
- description,
- "Description",
- (|value: &str| value.to_owned())
- );
- let duration = Duration::from(self.duration);
- let extractor_hash = self
- .extractor_hash
- .into_short_hash(app)
- .await
- .with_context(|| {
- format!(
- "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
- }
-
- fn thumbnail_url(&self) -> Self::Output {
- &self.thumbnail_url
- }
-
- fn title(&self) -> Self::Output {
- &self.title
- }
-
- fn url(&self) -> Self::Output {
- &self.url
- }
-
- fn video_options(&self) -> Self::Output {
- &self.video_options
- }
-}
-impl<'a> FormatVideo for &'a ColorizedFormattedVideo {
- type Output = &'a str;
-
- fn cache_path(&self) -> Self::Output {
- &self.0.cache_path
- }
-
- fn description(&self) -> Self::Output {
- &self.0.description
- }
-
- fn duration(&self) -> Self::Output {
- &self.0.duration
- }
-
- fn extractor_hash(&self) -> Self::Output {
- &self.0.extractor_hash
- }
-
- fn last_status_change(&self) -> Self::Output {
- &self.0.last_status_change
- }
-
- fn parent_subscription_name(&self) -> Self::Output {
- &self.0.parent_subscription_name
- }
-
- fn priority(&self) -> Self::Output {
- &self.0.priority
- }
-
- fn publish_date(&self) -> Self::Output {
- &self.0.publish_date
- }
-
- fn status(&self) -> Self::Output {
- &self.0.status
- }
-
- fn status_change(&self) -> Self::Output {
- &self.0.status_change
- }
-
- fn thumbnail_url(&self) -> Self::Output {
- &self.0.thumbnail_url
- }
-
- fn title(&self) -> Self::Output {
- &self.0.title
- }
-
- fn url(&self) -> Self::Output {
- &self.0.url
- }
-
- fn video_options(&self) -> Self::Output {
- &self.0.video_options
- }
-}
diff --git a/src/videos/mod.rs b/src/videos/mod.rs
deleted file mode 100644
index 59baa8c..0000000
--- a/src/videos/mod.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-// yt - A fully featured command line YouTube client
-//
-// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-// This file is part of Yt.
-//
-// 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 anyhow::Result;
-use display::{format_video::FormatVideo, FormattedVideo};
-use futures::{stream::FuturesUnordered, TryStreamExt};
-use nucleo_matcher::{
- pattern::{CaseMatching, Normalization, Pattern},
- Matcher,
-};
-
-pub mod display;
-
-use crate::{
- app::App,
- storage::video_database::{getters::get_videos, VideoStatus},
-};
-
-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?;
- }
-
- let limit = limit.unwrap_or(all_videos.len());
-
- let all_video_strings: Vec<String> = all_videos
- .into_iter()
- .take(limit)
- .map(|vid| vid.to_formatted_video_owned(app))
- .collect::<FuturesUnordered<_>>()
- .try_collect::<Vec<FormattedVideo>>()
- .await?
- .into_iter()
- .map(|vid| (&vid.colorize()).to_line_display())
- .collect();
-
- if let Some(query) = search_query {
- let mut matcher = Matcher::new(nucleo_matcher::Config::DEFAULT.match_paths());
-
- let matches = Pattern::parse(
- &query.replace(' ', "\\ "),
- CaseMatching::Ignore,
- Normalization::Smart,
- )
- .match_list(all_video_strings, &mut matcher);
-
- matches
- .iter()
- .rev()
- .for_each(|(val, key)| println!("{} ({})", val, key));
- } else {
- println!("{}", all_video_strings.join("\n"))
- }
-
- Ok(())
-}