mirror of
https://github.com/TheFunny/TelegramTwitterMediaBot.git
synced 2026-09-23 23:32:05 +00:00
style: cargo fmt across the workspace
Apply rustfmt to the 11 files that had drifted (86 hunks): x-media site modules (bsky/pixiv/twitter) and xmedia-bot (config/main/ photo/send). Formatting only - no semantic changes; full test suite still green.
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use serde_json::{json, Value};
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::site::FetchError;
|
||||
|
||||
@@ -40,8 +40,7 @@ static AUTH_TOKEN: LazyLock<Option<String>> = LazyLock::new(|| {
|
||||
});
|
||||
|
||||
/// Public "logged in" client token used by the x.com web app.
|
||||
const LOGGED_IN_BEARER: &str =
|
||||
"Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA";
|
||||
const LOGGED_IN_BEARER: &str = "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA";
|
||||
|
||||
/// `TweetDetail` query id (from nazurin; still valid as of 2026-08,
|
||||
/// corroborated by the current FxEmbed build — see module caveats).
|
||||
@@ -103,9 +102,7 @@ pub fn enabled() -> bool {
|
||||
/// Fetches a tweet as the logged-in user via the private GraphQL API.
|
||||
/// Returns the syndication-shaped [`Tweet`] (media included for NSFW posts).
|
||||
pub async fn fetch(id: &str) -> Result<Tweet, FetchError> {
|
||||
let token = AUTH_TOKEN
|
||||
.as_deref()
|
||||
.ok_or(FetchError::Sensitive)?;
|
||||
let token = AUTH_TOKEN.as_deref().ok_or(FetchError::Sensitive)?;
|
||||
// 16 random bytes as 32 hex chars: X rejects ct0 values of any other
|
||||
// length with 403 code 353 ("matching csrf cookie and header").
|
||||
let ct0: String = (0..16)
|
||||
@@ -136,11 +133,12 @@ pub async fn fetch(id: &str) -> Result<Tweet, FetchError> {
|
||||
let text = response.text().await?;
|
||||
let json: Value = serde_json::from_str(&text)?;
|
||||
let result = parse_tweet_result(&json, id)?;
|
||||
let syndication_shape = to_syndication_shape(&result)
|
||||
.ok_or_else(|| FetchError::Json(serde_json::Error::io(std::io::Error::new(
|
||||
let syndication_shape = to_syndication_shape(&result).ok_or_else(|| {
|
||||
FetchError::Json(serde_json::Error::io(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"missing tweet fields in GraphQL response",
|
||||
))))?;
|
||||
)))
|
||||
})?;
|
||||
Tweet::from_syndication_json(&syndication_shape.to_string()).map_err(FetchError::Json)
|
||||
}
|
||||
|
||||
@@ -317,7 +315,10 @@ mod tests {
|
||||
}
|
||||
other => panic!("expected video, got {other:?}"),
|
||||
}
|
||||
assert_eq!(fetched.source_url, "https://x.com/nsfw_author/status/2083868672721039569");
|
||||
assert_eq!(
|
||||
fetched.source_url,
|
||||
"https://x.com/nsfw_author/status/2083868672721039569"
|
||||
);
|
||||
// The appended media short link (no URL-entity mapping) is stripped.
|
||||
assert_eq!(fetched.title, "nsfw content");
|
||||
}
|
||||
@@ -330,7 +331,10 @@ mod tests {
|
||||
let json = conversation(rt);
|
||||
let result = parse_tweet_result(&json, "2083868672721039569").unwrap();
|
||||
assert!(result.pointer("/legacy/retweeted_status_result").is_none());
|
||||
assert_eq!(result.pointer("/legacy/id_str").unwrap(), "2083868672721039569");
|
||||
assert_eq!(
|
||||
result.pointer("/legacy/id_str").unwrap(),
|
||||
"2083868672721039569"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -35,9 +35,7 @@ pub async fn fetch_from_url(url: &str) -> Result<Fetched, FetchError> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::info!(
|
||||
"tweet {id} is sensitive; set TWITTER_AUTH_TOKEN to fetch NSFW media"
|
||||
);
|
||||
log::info!("tweet {id} is sensitive; set TWITTER_AUTH_TOKEN to fetch NSFW media");
|
||||
Ok(empty_fetched(url))
|
||||
}
|
||||
}
|
||||
@@ -228,25 +226,22 @@ fn expand_links(text: &str, urls: &[model::SyndicationEntityUrl]) -> String {
|
||||
/// Internal x.com page links (reply / quote plumbing) expand to
|
||||
/// `x.com/i/web/status/<id>`; FxEmbed drops them — the tweet's own content
|
||||
/// already carries the information.
|
||||
static WEB_STATUS_URL: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(r"^https://(?:x\.com|twitter\.com)/i/web/status/\w+").unwrap()
|
||||
});
|
||||
static WEB_STATUS_URL: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r"^https://(?:x\.com|twitter\.com)/i/web/status/\w+").unwrap());
|
||||
|
||||
/// A t.co short link, optionally preceded by a space. Any leftover
|
||||
/// occurrence (unmapped — e.g. the appended media link) is removed,
|
||||
/// mirroring FxEmbed. Real short-link codes are 10 alphanumerics; the
|
||||
/// length-agnostic class keeps fixtures and hypothetical odd lengths safe.
|
||||
static TCO_LINK: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(r" ?https?://t\.co/[A-Za-z0-9]+").unwrap()
|
||||
});
|
||||
static TCO_LINK: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r" ?https?://t\.co/[A-Za-z0-9]+").unwrap());
|
||||
|
||||
/// pbs.twimg.com serves a reduced default size without size params; `name=orig`
|
||||
/// returns the original file (fxtwitter used to hand out the original
|
||||
/// directly, the syndication API does not). Non-twimg URLs pass through
|
||||
/// unchanged.
|
||||
fn original_twimg_url(url: &str) -> String {
|
||||
if url.starts_with("https://pbs.twimg.com/")
|
||||
&& (url.ends_with(".jpg") || url.ends_with(".png"))
|
||||
if url.starts_with("https://pbs.twimg.com/") && (url.ends_with(".jpg") || url.ends_with(".png"))
|
||||
{
|
||||
format!("{url}?name=orig")
|
||||
} else {
|
||||
@@ -361,24 +356,23 @@ mod tests {
|
||||
match &fetched.media[0] {
|
||||
Media::Illustration { url, .. } => {
|
||||
// Photo URL is rewritten to request the original file.
|
||||
assert_eq!(
|
||||
url,
|
||||
"https://pbs.twimg.com/media/photo.jpg?name=orig"
|
||||
);
|
||||
assert_eq!(url, "https://pbs.twimg.com/media/photo.jpg?name=orig");
|
||||
}
|
||||
other => panic!("expected illustration, got {other:?}"),
|
||||
}
|
||||
match &fetched.media[1] {
|
||||
Media::Video { url, thumbnail_url, .. } => {
|
||||
Media::Video {
|
||||
url, thumbnail_url, ..
|
||||
} => {
|
||||
assert_eq!(url, "https://video.twimg.com/v.mp4");
|
||||
assert_eq!(thumbnail_url, "https://pbs.twimg.com/thumb.jpg");
|
||||
}
|
||||
other => panic!("expected video, got {other:?}"),
|
||||
}
|
||||
assert!(
|
||||
fetched
|
||||
.caption
|
||||
.contains("<a href=\"https://x.com/author_handle\">Display Name</a>: a & b <c>"),
|
||||
fetched.caption.contains(
|
||||
"<a href=\"https://x.com/author_handle\">Display Name</a>: a & b <c>"
|
||||
),
|
||||
"caption: {}",
|
||||
fetched.caption
|
||||
);
|
||||
@@ -587,6 +581,9 @@ mod tests {
|
||||
async fn live_fetch_deleted_tweet_is_not_found() {
|
||||
// Deleted tweet: the syndication endpoint answers with errors.
|
||||
let result = fetch("0").await;
|
||||
assert!(matches!(result, Err(FetchError::NotFound)), "got {result:?}");
|
||||
assert!(
|
||||
matches!(result, Err(FetchError::NotFound)),
|
||||
"got {result:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user