mirror of
https://github.com/TheFunny/TelegramTwitterMediaBot.git
synced 2026-09-23 23:32:05 +00:00
refactor(site): carry site_id on Fetched; unify cache-key site lookup
This commit is contained in:
@@ -299,6 +299,7 @@ impl From<Post> for Fetched {
|
|||||||
title: post.text.clone(),
|
title: post.text.clone(),
|
||||||
media: post.media,
|
media: post.media,
|
||||||
sensitive: post.sensitive,
|
sensitive: post.sensitive,
|
||||||
|
site_id: "bsky",
|
||||||
render_data,
|
render_data,
|
||||||
_keep_alive: None,
|
_keep_alive: None,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ pub struct Fetched {
|
|||||||
pub media: Vec<crate::media::Media>,
|
pub media: Vec<crate::media::Media>,
|
||||||
/// Spoiler flag for all media of this post.
|
/// Spoiler flag for all media of this post.
|
||||||
pub sensitive: bool,
|
pub sensitive: bool,
|
||||||
|
/// Site id (`"twitter"` / `"bsky"` / `"pixiv"`): the single source of
|
||||||
|
/// truth for site identity — caption-format lookup, cache-key prefix and
|
||||||
|
/// the SetFormat whitelist all derive from it. Set by the producing site.
|
||||||
|
pub site_id: &'static str,
|
||||||
/// Raw values (pre-escaped) for user-customizable caption formats.
|
/// Raw values (pre-escaped) for user-customizable caption formats.
|
||||||
pub(crate) render_data: Option<RenderData>,
|
pub(crate) render_data: Option<RenderData>,
|
||||||
/// Keeps temp files (e.g. an encoded ugoira MP4) alive until the caller
|
/// Keeps temp files (e.g. an encoded ugoira MP4) alive until the caller
|
||||||
@@ -50,16 +54,10 @@ pub(crate) struct RenderData {
|
|||||||
|
|
||||||
impl Fetched {
|
impl Fetched {
|
||||||
/// The site this post came from (used for per-site format overrides).
|
/// The site this post came from (used for per-site format overrides).
|
||||||
|
/// A thin alias over [`Fetched::site_id`] kept for callers that read the
|
||||||
|
/// site off a fetched post.
|
||||||
pub fn site_name(&self) -> &'static str {
|
pub fn site_name(&self) -> &'static str {
|
||||||
if self.source_url.contains("x.com") || self.source_url.contains("twitter.com") {
|
self.site_id
|
||||||
"twitter"
|
|
||||||
} else if self.source_url.contains("bsky.app") {
|
|
||||||
"bsky"
|
|
||||||
} else if self.source_url.contains("pixiv.net") {
|
|
||||||
"pixiv"
|
|
||||||
} else {
|
|
||||||
"unknown"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders a user-supplied caption format. The format string is
|
/// Renders a user-supplied caption format. The format string is
|
||||||
@@ -177,6 +175,25 @@ pub fn cache_key(url: &str) -> Option<String> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The site id carried by a cache key (`"twitter:123"` → `"twitter"`).
|
||||||
|
/// Unknown prefixes fall back to `"unknown"`. The bot uses this on the
|
||||||
|
/// link-cache hit path, where no [`Fetched`] is available — the same value
|
||||||
|
/// a fresh fetch would read from [`Fetched::site_id`].
|
||||||
|
pub fn site_id_from_key(key: &str) -> &'static str {
|
||||||
|
match key.split(':').next() {
|
||||||
|
Some("twitter") => "twitter",
|
||||||
|
Some("pixiv") => "pixiv",
|
||||||
|
Some("bsky") => "bsky",
|
||||||
|
_ => "unknown",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Every supported site id, in dispatch order. The bot's SetFormat whitelist
|
||||||
|
/// and per-site caption-format lookup derive from this list.
|
||||||
|
pub fn site_ids() -> Vec<&'static str> {
|
||||||
|
vec!["twitter", "bsky", "pixiv"]
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FetchError {
|
pub enum FetchError {
|
||||||
Http(reqwest::Error),
|
Http(reqwest::Error),
|
||||||
@@ -476,6 +493,15 @@ mod tests {
|
|||||||
assert_eq!(cache_key("https://example.com/not-a-post"), None);
|
assert_eq!(cache_key("https://example.com/not-a-post"), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn site_id_from_key_parses_prefix() {
|
||||||
|
assert_eq!(site_id_from_key("twitter:123"), "twitter");
|
||||||
|
assert_eq!(site_id_from_key("pixiv:123"), "pixiv");
|
||||||
|
assert_eq!(site_id_from_key("bsky:handle.example/3lorem"), "bsky");
|
||||||
|
assert_eq!(site_id_from_key("unknown:1"), "unknown");
|
||||||
|
assert_eq!(site_id_from_key("no-colon"), "unknown");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fetch_error_retryability_classification() {
|
fn fetch_error_retryability_classification() {
|
||||||
// Transient: network errors, explicit transient, pixiv 429/5xx.
|
// Transient: network errors, explicit transient, pixiv 429/5xx.
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ impl From<Illustration> for Fetched {
|
|||||||
title: illustration.title.clone(),
|
title: illustration.title.clone(),
|
||||||
media: illustration.media,
|
media: illustration.media,
|
||||||
sensitive: illustration.nsfw,
|
sensitive: illustration.nsfw,
|
||||||
|
site_id: "pixiv",
|
||||||
render_data,
|
render_data,
|
||||||
_keep_alive: illustration._keep_alive,
|
_keep_alive: illustration._keep_alive,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ fn empty_fetched(url: &str) -> Fetched {
|
|||||||
title: String::new(),
|
title: String::new(),
|
||||||
media: vec![],
|
media: vec![],
|
||||||
sensitive: true,
|
sensitive: true,
|
||||||
|
site_id: "twitter",
|
||||||
render_data: None,
|
render_data: None,
|
||||||
_keep_alive: None,
|
_keep_alive: None,
|
||||||
}
|
}
|
||||||
@@ -301,6 +302,7 @@ impl From<Tweet> for Fetched {
|
|||||||
title: tweet.text.clone(),
|
title: tweet.text.clone(),
|
||||||
media: tweet.media,
|
media: tweet.media,
|
||||||
sensitive: tweet.sensitive,
|
sensitive: tweet.sensitive,
|
||||||
|
site_id: "twitter",
|
||||||
render_data,
|
render_data,
|
||||||
_keep_alive: None,
|
_keep_alive: None,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -402,7 +402,7 @@ async fn execute_command(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if !["twitter", "bsky", "pixiv"].contains(&site) {
|
if !x_media::site::site_ids().contains(&site) {
|
||||||
reply(
|
reply(
|
||||||
bot.clone(),
|
bot.clone(),
|
||||||
message.clone(),
|
message.clone(),
|
||||||
@@ -636,7 +636,9 @@ async fn url_media(bot: Bot, message: &Message, url: &str) {
|
|||||||
{
|
{
|
||||||
log::debug!("link cache hit for {key}");
|
log::debug!("link cache hit for {key}");
|
||||||
let chat_data = CHAT_STORE.get(chat_id).await;
|
let chat_data = CHAT_STORE.get(chat_id).await;
|
||||||
let site = key.split(':').next().unwrap_or("unknown");
|
// Cache keys are prefixed with the site id ("twitter:…"), matching
|
||||||
|
// the value a fresh fetch would read from Fetched::site_id.
|
||||||
|
let site = x_media::site::site_id_from_key(&key);
|
||||||
let format = chat_data
|
let format = chat_data
|
||||||
.message_format
|
.message_format
|
||||||
.get(site)
|
.get(site)
|
||||||
|
|||||||
Reference in New Issue
Block a user