[no description]
Diffstat (limited to 'src/tenor.rs')
| -rw-r--r-- | src/tenor.rs | 171 |
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()) + })) +} |