aboutsummaryrefslogtreecommitdiffstats
path: root/crates/yt_dlp/src/post_processors
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-16 13:58:55 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-16 13:58:55 +0200
commitab61a4e47a955dd4a5dabeef3ade1b85f6576b84 (patch)
tree4076a7f96ef2a6b6b359eff83bb9b8c8357a03e5 /crates/yt_dlp/src/post_processors
parentrefactor(yt_dlp/lib): De-duplicate the info json sanitize code (diff)
downloadyt-ab61a4e47a955dd4a5dabeef3ade1b85f6576b84.zip
feat(yt_dlp): Support a DeArrow post processor
Diffstat (limited to 'crates/yt_dlp/src/post_processors')
-rw-r--r--crates/yt_dlp/src/post_processors/dearrow.rs108
-rw-r--r--crates/yt_dlp/src/post_processors/mod.rs20
2 files changed, 128 insertions, 0 deletions
diff --git a/crates/yt_dlp/src/post_processors/dearrow.rs b/crates/yt_dlp/src/post_processors/dearrow.rs
new file mode 100644
index 0000000..110beeb
--- /dev/null
+++ b/crates/yt_dlp/src/post_processors/dearrow.rs
@@ -0,0 +1,108 @@
+use log::{info, warn};
+use serde::{Deserialize, Serialize};
+
+use crate::{InfoJson, json_get};
+
+use super::PostProcessor;
+
+#[derive(Debug, Clone, Copy)]
+pub struct DeArrowPP;
+
+impl PostProcessor for DeArrowPP {
+ fn extractors(&self) -> &'static [&'static str] {
+ &["Youtube"]
+ }
+
+ fn process(&self, mut info: InfoJson) -> Result<InfoJson, super::Error> {
+ let mut output: DeArrowApi = reqwest::blocking::get(format!(
+ "https://sponsor.ajay.app/api/branding?videoID={}",
+ json_get!(info, "id", as_str)
+ ))?
+ .json()?;
+
+ output.titles.reverse();
+
+ let title_len = output.titles.len();
+ loop {
+ let Some(title) = output.titles.pop() else {
+ break;
+ };
+
+ if (title.locked || title.votes < 1) && title_len > 1 {
+ info!(
+ "Skipping title {:#?}, as it is not good enough",
+ title.value
+ );
+ // Skip titles that are not “good” enough.
+ continue;
+ }
+
+ if let Some(old_title) = info.insert(
+ "title".to_owned(),
+ serde_json::Value::String(title.value.clone()),
+ ) {
+ warn!("Updating title from {:#?} to {:#?}", old_title, title.value);
+ info.insert("original_title".to_owned(), old_title);
+ } else {
+ warn!("Setting title to {:#?}", title.value);
+ }
+
+ break;
+ }
+
+ Ok(info)
+ }
+}
+
+#[derive(Serialize, Deserialize)]
+/// See: <https://wiki.sponsor.ajay.app/w/API_Docs/DeArrow>
+struct DeArrowApi {
+ titles: Vec<Title>,
+ thumbnails: Vec<Thumbnail>,
+
+ #[serde(alias = "randomTime")]
+ random_time: Option<f64>,
+
+ #[serde(alias = "videoDuration")]
+ video_duration: Option<f64>,
+
+ #[serde(alias = "casualVotes")]
+ casual_votes: Vec<String>,
+}
+
+#[derive(Serialize, Deserialize)]
+struct Title {
+ /// Note: Titles will sometimes contain > before a word.
+ /// This tells the auto-formatter to not format a word.
+ /// If you have no auto-formatter, you can ignore this and replace it with an empty string
+ #[serde(alias = "title")]
+ value: String,
+
+ original: bool,
+ votes: u64,
+ locked: bool,
+
+ #[serde(alias = "UUID")]
+ uuid: String,
+
+ /// only present if requested
+ #[serde(alias = "userID")]
+ user_id: Option<String>,
+}
+
+#[derive(Serialize, Deserialize)]
+struct Thumbnail {
+ // null if original is true
+ timestamp: Option<f64>,
+
+ original: bool,
+ votes: u64,
+ locked: bool,
+
+ #[serde(alias = "UUID")]
+ uuid: String,
+
+ /// only present if requested
+ #[serde(alias = "userID")]
+ user_id: Option<String>,
+}
diff --git a/crates/yt_dlp/src/post_processors/mod.rs b/crates/yt_dlp/src/post_processors/mod.rs
new file mode 100644
index 0000000..6067c7a
--- /dev/null
+++ b/crates/yt_dlp/src/post_processors/mod.rs
@@ -0,0 +1,20 @@
+use crate::InfoJson;
+
+pub mod dearrow;
+
+pub trait PostProcessor: std::fmt::Debug + Send {
+ /// Process a [`InfoJson`] object and return the updated one.
+ ///
+ /// # Errors
+ /// If the processing steps failed.
+ fn process(&self, info: InfoJson) -> Result<InfoJson, Error>;
+
+ /// The supported extractors for this post processor
+ fn extractors(&self) -> &'static [&'static str];
+}
+
+#[derive(thiserror::Error, Debug)]
+pub enum Error {
+ #[error("Failed to access a api: {0}")]
+ Get(#[from] reqwest::Error),
+}