diff --git a/Cargo.lock b/Cargo.lock index 202ebf4..a7c10a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1527,6 +1527,7 @@ dependencies = [ "base64", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2 0.4.7", diff --git a/Cargo.toml b/Cargo.toml index 95fdd5d..8f8fb7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] bytes = "1.9.0" favicon-scraper = "0.3.1" -reqwest = { version = "0.12.12", features = ["stream"] } +reqwest = { version = "0.12.12", features = ["stream", "blocking"] } rocket = { version = "0.5.1", features = ["json"] } semver = "1.0.24" serde = { version = "1.0.217", features = ["derive"] } diff --git a/src/api/mod.rs b/src/api/mod.rs index 5faff5a..6417434 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,11 +1,17 @@ use rocket::Route; pub mod instance_info; +pub mod nekomata_avatars; pub mod proxy; +pub fn init() { + nekomata_avatars::init(); +} + pub fn get_routes() -> Vec { routes![ instance_info::instance_info, + nekomata_avatars::nekomata_avatars, // Proxy is temporarily disabled as it's not needed // proxy::proxy ] diff --git a/src/api/nekomata_avatars.rs b/src/api/nekomata_avatars.rs new file mode 100644 index 0000000..6dfb8f7 --- /dev/null +++ b/src/api/nekomata_avatars.rs @@ -0,0 +1,49 @@ +use reqwest::blocking::Client; +use rocket::serde::json::Json; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use std::sync::OnceLock; + +#[derive(Debug, Serialize)] +pub struct Avatars { + charlotte: Option, + kio: Option, +} + +#[derive(Deserialize)] +struct MisskeyUser { + #[serde(rename = "avatarUrl")] + avatar_url: String, +} + +fn get_avatar(client: &Client, origin: &str, user_id: &str) -> Option { + let body = json!({ + "userId": user_id + }) + .to_string(); + println!("{body}"); + let user: MisskeyUser = client + .post(format!("https://{origin}/api/users/show")) + .header("content-type", "application/json") + .body(body) + .send() + .ok()? + .json() + .ok()?; + Some(user.avatar_url) +} + +pub static AVATARS: OnceLock = OnceLock::new(); + +pub fn init() { + let client = Client::new(); + let charlotte = get_avatar(&client, "eepy.moe", "9xt2s326nxev039h"); + let kio = get_avatar(&client, "kitsunes.club", "9810gvfne3"); + AVATARS.set(Avatars { charlotte, kio }).unwrap(); +} + +/// Gets (relatively) up-to-date Nekomata avatars +#[get("/nekomata_avatars")] +pub async fn nekomata_avatars() -> Json<&'static Avatars> { + Json(AVATARS.get().unwrap()) +} diff --git a/src/main.rs b/src/main.rs index c12ec48..734b6d5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,8 @@ fn route_for_unknown_instance_software(instance: &str, route: PathBuf) -> (Conte #[launch] fn rocket() -> _ { + api::init(); + rocket::build() .mount("/static", FileServer::from("static").rank(0)) .mount("/api", api::get_routes()) diff --git a/static/about.mts b/static/about.mts index 709e958..741170c 100644 --- a/static/about.mts +++ b/static/about.mts @@ -1,17 +1,11 @@ import { findImageOrFail } from "./dom.mjs"; -async function populateUser(selector: string, origin: string, userId: string) { - const avatarImage = findImageOrFail(document.body, selector); - const userData = await fetch(`https://${origin}/api/users/show`, { - method: "POST", - body: JSON.stringify({ - userId, - }) - }).then(r => r.json()); - if (userData.avatarUrl) { - avatarImage.src = userData.avatarUrl; - } +async function populateUsers(charlotteSelector: string, kioSelector: string) { + const charlotteImage = findImageOrFail(document.body, charlotteSelector); + const kioImage = findImageOrFail(document.body, kioSelector); + const { charlotte, kio } = await fetch("/api/nekomata_avatars").then(r => r.json()); + if (charlotte) charlotteImage.src = charlotte; + if (kio) kioImage.src = kio; } -populateUser("#charlotteAvatar", "eepy.moe", "9xt2s326nxev039h"); -populateUser("#kioAvatar", "kitsunes.club", "9810gvfne3"); +populateUsers("#charlotteAvatar", "#kioAvatar");