embeds: match status metadata shape

This commit is contained in:
4cuck committed 2026-06-11 22:32:47 -04:00
1 parent f8d391aed3
commit b75d379642
3 files changed
+75 -27

No files matched your search

+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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)