aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornea <romangraef@gmail.com>2022-11-26 19:08:14 +0100
committernea <romangraef@gmail.com>2022-11-26 19:08:14 +0100
commit10f3ac6b18cbfcf74b41019ba2071b402310b245 (patch)
treec3244e1479875246d5cc32ab0130d5024b221825
parent0ed508b4ae5ba79d12cff1314438e79f322df9de (diff)
downloaddiscordavatarproxy-10f3ac6b18cbfcf74b41019ba2071b402310b245.tar.gz
discordavatarproxy-10f3ac6b18cbfcf74b41019ba2071b402310b245.tar.bz2
discordavatarproxy-10f3ac6b18cbfcf74b41019ba2071b402310b245.zip
Introducing .json and .png extensions as well as default avatars
-rw-r--r--README3
-rw-r--r--src/main.rs64
2 files changed, 56 insertions, 11 deletions
diff --git a/README b/README
index 1dfc278..fefcd66 100644
--- a/README
+++ b/README
@@ -8,7 +8,8 @@ Run:
Listens to localhost:<port>
-Requests to localhost:<port>/avatar/<userid> instead reply with a png of the users avatar.
+Requests to localhost:<port>/avatar/<userid>.png reply with a png of the users avatar.
+Requests to localhost:<port>/avatar/<userid>.json reply with a json of the users data.
A publicly hosted version is available at https://dp.nea.moe/avatar/310702108997320705
diff --git a/src/main.rs b/src/main.rs
index b30447e..ce2150d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,7 +7,7 @@ use hyper::client::{Client, HttpConnector};
use hyper::service::{make_service_fn, service_fn};
use hyper_tls::HttpsConnector;
-async fn get_avatar_url(client: &Client<HttpsConnector<HttpConnector>>, token: &str, user_id: u64) -> anyhow::Result<String> {
+async fn get_user_data(client: &Client<HttpsConnector<HttpConnector>>, token: &str, user_id: u64) -> anyhow::Result<serde_json::Value> {
let request = Request::builder()
.method(Method::GET)
.uri(format!("https://discord.com/api/v10/users/{}", user_id))
@@ -18,20 +18,29 @@ async fn get_avatar_url(client: &Client<HttpsConnector<HttpConnector>>, token: &
let body = hyper::body::to_bytes(x.body_mut()).await?;
let json_data = String::from_utf8(Vec::from(body))?;
let json: serde_json::Value = serde_json::from_str(&json_data)?;
- let avatar = json["avatar"].as_str().ok_or(anyhow::anyhow!("Missing avatar"))?;
+ Ok(json)
+}
+
+async fn get_avatar_url(client: &Client<HttpsConnector<HttpConnector>>, token: &str, user_id: u64) -> anyhow::Result<String> {
+ let json = get_user_data(client, token, user_id).await?;
let id = json["id"].as_str().ok_or(anyhow::anyhow!("Missing avatar"))?;
- let avatar_url = format!("https://cdn.discordapp.com/avatars/{}/{}.png", id, avatar);
- println!("Served request for {}: {}#{}", id, json["username"], json["discriminator"]);
+ let discrim = json["discriminator"].as_str().ok_or(anyhow::anyhow!("Missing discriminator"))?;
+ println!("Served request for {}: {}#{}", id, json["username"], discrim);
+ let avatar_url = match json["avatar"].as_str() {
+ None => default_avatar_url(discrim)?,
+ Some(avatar_hash) => format!("https://cdn.discordapp.com/avatars/{}/{}.png", id, avatar_hash)
+ };
Ok(avatar_url)
}
+fn make_err(err: u16, text: &str) -> anyhow::Result<Response<Body>> {
+ return Ok(Response::builder()
+ .status(err)
+ .body(format!("{} {}", err, text).into())?);
+}
+
async fn resp(arc: Arc<Ctx>, req: Request<Body>) -> anyhow::Result<Response<Body>> {
- fn make_err(err: u16, text: &str) -> anyhow::Result<Response<Body>> {
- return Ok(Response::builder()
- .status(err)
- .body(format!("{} {}", err, text).into())?);
- }
let x = req.uri().path();
if x == "/" {
return Ok(Response::builder()
@@ -43,7 +52,41 @@ async fn resp(arc: Arc<Ctx>, req: Request<Body>) -> anyhow::Result<Response<Body
None => return make_err(404, "Not found"),
Some(request) => request,
};
- let num_id = match request.parse::<u64>() {
+ if let Some(userid) = request.strip_suffix(".png") {
+ return respond_with_image(arc, userid).await;
+ }
+ if let Some(userid) = request.strip_suffix(".json") {
+ return respond_with_json(arc, userid).await;
+ }
+ return make_err(404, "Invalid format");
+}
+
+fn default_avatar_url(discrim: &str) -> anyhow::Result<String> {
+ let d = discrim.parse::<u16>()?;
+ let bare = d % 5;
+ Ok(format!("https://cdn.discordapp.com/embed/avatars/{}.png", bare))
+}
+
+struct ResponseUserFormat {
+ username: String,
+ discriminator: String,
+ avatar: String,
+ banner: Option<String>,
+}
+
+async fn respond_with_json(arc: Arc<Ctx>, userid: &str) -> anyhow::Result<Response<Body>> {
+ let num_id = match userid.parse::<u64>() {
+ Err(_) => return make_err(404, "Not found"),
+ Ok(num) => num,
+ };
+ Ok(Response::builder()
+ .status(200)
+ .header("content-type", "application/json")
+ .body(serde_json::to_string("{\"todo\": true}")?.into())?)
+}
+
+async fn respond_with_image(arc: Arc<Ctx>, userid: &str) -> anyhow::Result<Response<Body>> {
+ let num_id = match userid.parse::<u64>() {
Err(_) => return make_err(404, "Not found"),
Ok(num) => num,
};
@@ -61,6 +104,7 @@ async fn resp(arc: Arc<Ctx>, req: Request<Body>) -> anyhow::Result<Response<Body
.body(resp.into_body())?)
}
+
struct Ctx {
client: Client<HttpsConnector<HttpConnector>>,
token: String,