From f99001be9ff18fe664aec07d7e1ac60c68cd3dbc Mon Sep 17 00:00:00 2001 From: red binder Date: Sun, 12 Apr 2026 14:52:28 +0200 Subject: [PATCH] Preliminary support for miis route --- src/nnid/miis.rs | 120 +++++++++++++++++++++++++++++++++++++++++++++++ src/nnid/mod.rs | 1 + 2 files changed, 121 insertions(+) create mode 100644 src/nnid/miis.rs diff --git a/src/nnid/miis.rs b/src/nnid/miis.rs new file mode 100644 index 0000000..020f1a3 --- /dev/null +++ b/src/nnid/miis.rs @@ -0,0 +1,120 @@ +use rocket::{get, State}; +use crate::Pool; +use crate::xml::{Xml, YesNoVal}; +use crate::error::Errors; +use crate::mii_util::get_mii_img_url; +use serde::Serialize; +use gxhash::gxhash32; + +#[derive(Serialize)] +pub struct MiiImage { + pub cached_url: String, + pub id: u32, + pub url: String, + #[serde(rename = "type")] + pub image_type: String, +} + +#[derive(Serialize)] +pub struct MiiImages { + pub image: Vec, +} + +#[derive(Serialize)] +pub struct MiiEntry { + pub data: String, + pub id: u32, + pub images: MiiImages, + pub name: String, + pub pid: i32, + pub primary: YesNoVal, + pub user_id: String, +} + +#[derive(Serialize)] +#[serde(rename = "miis")] +pub struct MiisResponse { + #[serde(rename = "mii")] + pub miis: Vec, +} + +#[get("/v1/api/miis?")] +pub async fn get_miis( + database: &State, + pids: Option, +) -> Result, Option>> { + let db = database.inner(); + + let input = pids.filter(|s| !s.is_empty()).ok_or(None)?; + + let pid_list: Vec = input + .split(',') + .filter_map(|s| s.parse::().ok()) + .collect(); + + if pid_list.is_empty() { + return Err(None); + } + + let rows = sqlx::query!( + "SELECT pid, username, mii_data FROM users WHERE pid = ANY($1)", + &pid_list + ) + .fetch_all(db) + .await + .map_err(|_| None)?; + + if rows.is_empty() { + return Err(None); + } + + let mut miis = Vec::new(); + + for row in rows { + let clean_mii_data = row.mii_data + .replace(['\r', '\n', '\t', ' '], ""); + + let mii_id = gxhash32(clean_mii_data.as_bytes(), 0); + + let expression_types = [ + ("normal_face.png", "standard"), + ("frustrated.png", "frustrated_face"), + ("smile_open_mouth.png", "happy_face"), + ("wink_left.png", "like_face"), + ("normal_face.png", "normal_face"), // pretendo had this duplicated, and i'm not taking any chances + ("sorrow.png", "puzzled_face"), + ("surprised_open_mouth.png", "surprised_face"), + ("body.png", "whole_body"), + ]; + + let images = MiiImages { + image: expression_types + .iter() + .map(|(file, img_type)| { + // dummy URL for now + let url = format!("https://dummy.url.com/mii/{}/{}", row.pid, file); + MiiImage { + cached_url: url.clone(), + id: mii_id, + url, + image_type: img_type.to_string(), + } + }) + .collect(), + }; + + miis.push(MiiEntry { + data: clean_mii_data, + id: mii_id, + images, + name: mii::MiiData::read(&row.mii_data) + .map(|v| v.name) + .unwrap_or_else(|| "Mii".to_string()), + pid: row.pid, + primary: YesNoVal(true), //assuming true here + user_id: row.username, + }); + } + + Ok(Xml(MiisResponse { miis })) +} \ No newline at end of file diff --git a/src/nnid/mod.rs b/src/nnid/mod.rs index a86c6f7..7fa3e4d 100644 --- a/src/nnid/mod.rs +++ b/src/nnid/mod.rs @@ -8,3 +8,4 @@ pub mod people; pub mod provider; pub mod mapped_ids; pub mod support; +pub mod miis;