Skip to content
Clone
main
81 lines 2.6 KB Rust
use crate::http;
#[derive(Debug, Clone, Default)]
pub struct OEmbed {
pub oembed_type: Option<String>,
pub title: Option<String>,
pub description: Option<String>,
pub provider_name: Option<String>,
pub provider_url: Option<String>,
pub author_name: Option<String>,
pub author_url: Option<String>,
pub thumbnail_url: Option<String>,
pub url: Option<String>,
pub html: Option<String>,
pub width: Option<u32>,
pub height: Option<u32>,
}
pub async fn fetch(endpoint: &str, max_bytes: usize) -> Option<OEmbed> {
let fetched = http::fetch(endpoint, "application/json", max_bytes)
.await
.ok()?;
if !(200..300).contains(&fetched.status) {
return None;
}
parse(&fetched.body)
}
pub fn parse(body: &str) -> Option<OEmbed> {
let value: serde_json::Value = serde_json::from_str(body).ok()?;
if !value.is_object() {
return None;
}
let oembed = OEmbed {
oembed_type: string_field(&value, "type"),
title: string_field(&value, "title"),
description: string_field(&value, "description"),
provider_name: string_field(&value, "provider_name"),
provider_url: string_field(&value, "provider_url"),
author_name: string_field(&value, "author_name"),
author_url: string_field(&value, "author_url"),
thumbnail_url: string_field(&value, "thumbnail_url"),
url: string_field(&value, "url"),
html: string_field(&value, "html"),
width: number_field(&value, "width"),
height: number_field(&value, "height"),
};
(oembed.title.is_some()
|| oembed.description.is_some()
|| oembed.thumbnail_url.is_some()
|| oembed.html.is_some())
.then_some(oembed)
}
fn string_field(value: &serde_json::Value, key: &str) -> Option<String> {
let text = value.get(key)?.as_str()?.trim();
(!text.is_empty()).then(|| text.to_owned())
}
fn number_field(value: &serde_json::Value, key: &str) -> Option<u32> {
let node = value.get(key)?;
node.as_u64()
.and_then(|value| u32::try_from(value).ok())
.or_else(|| node.as_str().and_then(|value| value.trim().parse().ok()))
}
pub fn iframe_src(html: &str) -> Option<String> {
let lower = html.to_ascii_lowercase();
let start = lower.find("<iframe")?;
let tail = &html[start..];
let index = tail.to_ascii_lowercase().find("src=")? + 4;
let after = tail[index..].trim_start();
let quote = after.chars().next()?;
if quote != '"' && quote != '\'' {
return None;
}
let rest = &after[1..];
let end = rest.find(quote)?;
let src = rest[..end].trim();
(!src.is_empty()).then(|| src.to_owned())
}