mirror of
https://github.com/4cuck/teapawt.git
synced 2026-10-27 04:01:55 +00:00
embeds: match status metadata shape
This commit is contained in:
1 parent
f8d391aed3
commit
b75d379642
3 files changed
+75
-27
No files matched your search
+1
-1
@@ -172,7 +172,7 @@ async fn oembed(
|
||||
author_url,
|
||||
provider_name: state.config.server.title.clone(),
|
||||
provider_url: state.config.url_prefix().to_owned(),
|
||||
title: "Post",
|
||||
title: "Embed",
|
||||
kind: "rich",
|
||||
version: "1.0",
|
||||
};
|
||||
|
||||
+45
-9
@@ -684,16 +684,14 @@ pub fn render_status_page(
|
||||
let avatar_url = formatters::get_pic_url(&tweet.user.user_pic, config.config.base64_media);
|
||||
|
||||
let head_extra = html! {
|
||||
// Theme color for Discord embed accent
|
||||
meta name="theme-color" content="#1F1F1F";
|
||||
|
||||
// Profile pic as author icon in Discord embeds
|
||||
link rel="canonical" href=(canonical);
|
||||
meta property="og:url" content=(canonical);
|
||||
meta property="twitter:site" content=(format!("@{}", tweet.user.username));
|
||||
meta property="twitter:creator" content=(format!("@{}", tweet.user.username));
|
||||
meta property="theme-color" content="#1F1F1F";
|
||||
meta property="twitter:title" content=(og_title);
|
||||
link rel="apple-touch-icon" href=(format!("{url_prefix}{avatar_url}"));
|
||||
|
||||
// Override OG title/description with tweet-specific values
|
||||
meta property="og:title" content=(og_title);
|
||||
meta property="og:description" content=(description);
|
||||
|
||||
// Publish time for Discord footer timestamp
|
||||
@if let Some(ts) = tweet.time {
|
||||
@let iso = ts.format(&Rfc3339).unwrap_or_default();
|
||||
@@ -703,6 +701,11 @@ pub fn render_status_page(
|
||||
// Media-specific OG/twitter tags
|
||||
(render_media_meta_tags(tweet, config, url_prefix))
|
||||
|
||||
meta property="og:title" content=(og_title);
|
||||
meta property="og:description" content=(description);
|
||||
meta property="og:site_name" content=(config.server.title);
|
||||
meta property="og:locale" content="en_US";
|
||||
|
||||
// ActivityPub discovery link
|
||||
link rel="alternate"
|
||||
href=(format!("{url_prefix}/users/{username}/statuses/{id}"))
|
||||
@@ -711,7 +714,8 @@ pub fn render_status_page(
|
||||
// oEmbed link for engagement metrics
|
||||
link rel="alternate"
|
||||
href=(oembed_url)
|
||||
type="application/json+oembed";
|
||||
type="application/json+oembed"
|
||||
title=(tweet.user.fullname);
|
||||
};
|
||||
|
||||
let rss_url = format!("/{username}/status/{id}/rss");
|
||||
@@ -723,6 +727,7 @@ pub fn render_status_page(
|
||||
.canonical(&canonical)
|
||||
.referer(&referer)
|
||||
.head_extra(&head_extra)
|
||||
.custom_open_graph()
|
||||
.render()
|
||||
}
|
||||
|
||||
@@ -902,6 +907,37 @@ mod tests {
|
||||
assert_eq!(attachment.description.as_deref(), Some("alt text"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn status_page_uses_author_first_embed_metadata() {
|
||||
let tweet = tweet(400, "G2CSGO", "Trying hard to win/lose/something");
|
||||
let html = render_status_page(
|
||||
&tweet,
|
||||
&html! {},
|
||||
&Prefs::default(),
|
||||
&test_config(),
|
||||
"G2CSGO",
|
||||
"400",
|
||||
)
|
||||
.into_string();
|
||||
|
||||
assert!(!html.contains(
|
||||
r#"property="og:title" content="G2CSGO (@G2CSGO): "Trying hard to win/lose/something"""#
|
||||
));
|
||||
assert!(html.contains(r#"property="twitter:title" content="G2CSGO (@G2CSGO)""#));
|
||||
assert!(html.contains(r#"property="og:title" content="G2CSGO (@G2CSGO)""#));
|
||||
assert!(
|
||||
html.contains(r#"property="og:description" content="Trying hard to win/lose/something""#)
|
||||
);
|
||||
assert!(html.contains(r#"property="twitter:site" content="@G2CSGO""#));
|
||||
assert!(html.contains(r#"property="og:url" content="https://x.com/G2CSGO/status/400""#));
|
||||
assert!(html.contains(r#"link rel="apple-touch-icon" href="https://teapot.test/pic/enc/"#));
|
||||
assert!(
|
||||
!html.contains(
|
||||
r#"link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png""#
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn best_dimensions_parse_non_widescreen_video_url() {
|
||||
assert_eq!(video().best_dimensions(), (720, 1280));
|
||||
|
||||
+29
-17
@@ -33,6 +33,7 @@ pub struct PageLayout<'a> {
|
||||
og_image: &'a str,
|
||||
og_type: &'a str,
|
||||
head_extra: Option<&'a Markup>,
|
||||
custom_og: bool,
|
||||
}
|
||||
|
||||
impl<'a> PageLayout<'a> {
|
||||
@@ -49,6 +50,7 @@ impl<'a> PageLayout<'a> {
|
||||
og_image: "",
|
||||
og_type: "article",
|
||||
head_extra: None,
|
||||
custom_og: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +96,12 @@ impl<'a> PageLayout<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Let `head_extra` provide the complete OpenGraph/Twitter card block.
|
||||
pub const fn custom_open_graph(mut self) -> Self {
|
||||
self.custom_og = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn render(self) -> Markup {
|
||||
let (infinite_scroll, theme, sticky_nav, use_twemoji, font_size) =
|
||||
self.prefs.map_or((false, None, true, true, ""), |prefs| {
|
||||
@@ -133,7 +141,9 @@ impl<'a> PageLayout<'a> {
|
||||
meta name="theme-color" content="#1F1F1F";
|
||||
|
||||
// Favicon and manifest links
|
||||
link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png";
|
||||
@if !self.custom_og {
|
||||
link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png";
|
||||
}
|
||||
link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png";
|
||||
link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png";
|
||||
link rel="manifest" href="/site.webmanifest";
|
||||
@@ -171,22 +181,24 @@ impl<'a> PageLayout<'a> {
|
||||
}
|
||||
|
||||
// OpenGraph meta tags
|
||||
meta property="og:site_name" content=(self.config.server.title);
|
||||
meta property="og:locale" content="en_US";
|
||||
meta property="og:title" content=(self.title);
|
||||
meta property="og:description" content=(strip_html(self.description));
|
||||
// head_extra provides its own og:type and twitter:card
|
||||
// when present (e.g. video/player for GIF embeds).
|
||||
// Discord takes the first occurrence, so suppress defaults.
|
||||
@if self.head_extra.is_none() {
|
||||
meta property="og:type" content=(self.og_type);
|
||||
}
|
||||
@if !self.og_image.is_empty() {
|
||||
meta property="og:image" content=(self.og_image);
|
||||
meta property="twitter:image:src" content=(self.og_image);
|
||||
}
|
||||
@if self.head_extra.is_none() && !self.rss.is_empty() {
|
||||
meta name="twitter:card" content="summary";
|
||||
@if !self.custom_og {
|
||||
meta property="og:site_name" content=(self.config.server.title);
|
||||
meta property="og:locale" content="en_US";
|
||||
meta property="og:title" content=(self.title);
|
||||
meta property="og:description" content=(strip_html(self.description));
|
||||
// head_extra provides its own og:type and twitter:card
|
||||
// when present (e.g. video/player for GIF embeds).
|
||||
// Discord takes the first occurrence, so suppress defaults.
|
||||
@if self.head_extra.is_none() {
|
||||
meta property="og:type" content=(self.og_type);
|
||||
}
|
||||
@if !self.og_image.is_empty() {
|
||||
meta property="og:image" content=(self.og_image);
|
||||
meta property="twitter:image:src" content=(self.og_image);
|
||||
}
|
||||
@if self.head_extra.is_none() && !self.rss.is_empty() {
|
||||
meta name="twitter:card" content="summary";
|
||||
}
|
||||
}
|
||||
|
||||
// Custom head content (OG overrides, oEmbed, ActivityPub)
|
||||
|
||||
Reference in new issue
Block a user