[no description]
Diffstat (limited to 'src/tenor.rs')
-rw-r--r--src/tenor.rs171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/tenor.rs b/src/tenor.rs
new file mode 100644
index 0000000..0cf79af
--- /dev/null
+++ b/src/tenor.rs
@@ -0,0 +1,171 @@
+use std::collections::HashMap;
+
+use anyhow::Context;
+use reqwest::get;
+use scraper::{Html, Selector};
+use serde::Deserialize;
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Tracks {
+ pub app_config: AppConfig,
+ pub config: AppConfig,
+ pub tags: AppConfig,
+ pub gifs: Gifs,
+ pub stickers: Memes,
+ pub memes: Memes,
+ pub universal: Universal,
+ pub packs: Collections,
+ pub collections: Collections,
+ pub exploreterms: AppConfig,
+ pub search_suggestions: AppConfig,
+ pub profiles: AppConfig,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+pub struct AppConfig {}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Collections {
+ pub by_id: AppConfig,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Gifs {
+ pub by_id: HashMap<u64, Item>,
+ pub search_by_username: AppConfig,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+pub struct Item {
+ pub results: Vec<PurpleResult>,
+ pub promise: AppConfig,
+ pub loaded: bool,
+ pub pending: bool,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+pub struct PurpleResult {
+ pub id: String,
+ pub legacy_info: LegacyInfo,
+ pub title: String,
+ // media_formats: HashMap<String, MediaFormat>,
+ pub media_formats: MediaFormats,
+ pub bg_color: String,
+ pub created: f64,
+ pub content_description: String,
+ pub h1_title: String,
+ pub long_title: String,
+ pub embed: String,
+ pub itemurl: String,
+ pub url: String,
+ pub tags: Vec<String>,
+ pub flags: Vec<Option<serde_json::Value>>,
+ pub user: PurpleUser,
+ pub hasaudio: bool,
+ pub source_id: String,
+ pub shares: i64,
+ pub policy_status: PolicyStatus,
+ pub index: i64,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+pub struct LegacyInfo {
+ pub post_id: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+pub struct MediaFormat {
+ pub url: String,
+ pub duration: f64,
+ pub preview: String,
+ pub dims: [i64; 2],
+ pub size: i64,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+pub enum PolicyStatus {
+ #[serde(rename = "POLICY_STATUS_UNSPECIFIED")]
+ PolicyStatusUnspecified,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+pub struct PurpleUser {
+ pub username: String,
+ pub partnername: String,
+ pub url: String,
+ pub tagline: String,
+ pub userid: String,
+ pub profile_id: String,
+ pub avatars: AppConfig,
+ pub usertype: Usertype,
+ pub partnerbanner: AppConfig,
+ pub partnercategories: Vec<Option<serde_json::Value>>,
+ pub partnerlinks: Vec<Option<serde_json::Value>>,
+ pub flags: Vec<Option<serde_json::Value>>,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+#[serde(rename_all = "snake_case")]
+pub enum Usertype {
+ User,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+pub struct MediaFormats {
+ pub gif: MediaFormat,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Memes {
+ search_by_username: AppConfig,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+pub struct Universal {
+ search: AppConfig,
+}
+
+pub async fn download_url(
+ url: &str,
+) -> anyhow::Result<(
+ PurpleResult,
+ impl FnOnce() -> impl Future<Output = anyhow::Result<Vec<u8>>>,
+)> {
+ let response = get(dbg!(url)).await.context("h")?;
+ let html_content = response.text().await.context("ah")?;
+ let document = Html::parse_document(&html_content);
+ let selector = Selector::parse("#store-cache").unwrap();
+ let element = document
+ .select(&selector)
+ .next()
+ .ok_or_else(|| anyhow::anyhow!("!#store-cache"))?;
+
+ let json_str = element.inner_html();
+ let data = serde_json::from_str::<Tracks>(&json_str).context("alas")?;
+ let id = url.rsplit('-').next().unwrap_or("");
+ let result = data
+ .gifs
+ .by_id
+ .get(&id.parse().unwrap())
+ .ok_or_else(|| anyhow::anyhow!("failure to find {}", id))?
+ .results
+ .get(0)
+ .ok_or_else(|| anyhow::anyhow!("not in data"))?
+ .clone();
+
+ let gif_url = result.media_formats.gif.url.clone();
+ Ok((result, move || async move {
+ Ok(get(gif_url)
+ .await
+ .context("no gif")?
+ .bytes()
+ .await
+ .context("no gif")?
+ .to_vec())
+ }))
+}