mirror of
https://github.com/azures04/crafatar.git
synced 2026-03-21 23:41:18 +01:00
Implement Skeleton for Returning Capes (Currently returns skins)
Align capes.js codestyle to the rest of the project get_cape_hash helper (not working - wip) clean up capes.js
This commit is contained in:
parent
5929461df8
commit
dd7e46f377
63
app.js
Normal file
63
app.js
Normal file
@ -0,0 +1,63 @@
|
||||
var express = require("express");
|
||||
var path = require("path");
|
||||
var logger = require("morgan");
|
||||
var cookieParser = require("cookie-parser");
|
||||
var bodyParser = require("body-parser");
|
||||
|
||||
var routes = require("./routes/index");
|
||||
var avatars = require("./routes/avatars");
|
||||
var skins = require("./routes/skins");
|
||||
var renders = require('./routes/renders');
|
||||
var capes = require("./routes/capes");
|
||||
|
||||
var app = express();
|
||||
|
||||
// view engine setup
|
||||
app.set("views", path.join(__dirname, "views"));
|
||||
app.set("view engine", "jade");
|
||||
|
||||
app.use(logger("dev"));
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({ extended: false }));
|
||||
app.use(cookieParser());
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
|
||||
app.use('/', routes);
|
||||
app.use('/avatars', avatars);
|
||||
app.use('/skins', skins);
|
||||
app.use('/renders', renders);
|
||||
app.use("/capes", capes);
|
||||
|
||||
|
||||
// catch 404 and forward to error handler
|
||||
app.use(function(req, res, next) {
|
||||
var err = new Error("Not Found");
|
||||
err.status = 404;
|
||||
next(err);
|
||||
});
|
||||
|
||||
// error handlers
|
||||
|
||||
// development error handler
|
||||
// will print stacktrace
|
||||
if (app.get("env") === "development") {
|
||||
app.use(function(err, req, res, next) {
|
||||
res.status(err.status || 500);
|
||||
res.render("error", {
|
||||
message: err.message,
|
||||
error: err
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// production error handler
|
||||
// no stacktraces leaked to user
|
||||
app.use(function(err, req, res, next) {
|
||||
res.status(err.status || 500);
|
||||
res.render("error", {
|
||||
message: err.message,
|
||||
error: {}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = app;
|
||||
@ -13,6 +13,7 @@ var config = {
|
||||
helms_dir: "images/helms/", // directory where helms are kept. should have trailing "/"
|
||||
skins_dir: "images/skins/", // directory where skins are kept. should have trailing "/"
|
||||
renders_dir: "images/renders/",// Directory where rendered skins are kept. should have trailing "/"
|
||||
capes_dir: "images/capes/", // directory where capes are kept. should have trailing "/"
|
||||
debug_enabled: false, // enables logging.debug
|
||||
min_scale: 1, // for renders
|
||||
max_scale: 10, // for renders; too big values might lead to slow response time or DoS
|
||||
|
||||
@ -75,6 +75,45 @@ function store_images(uuid, details, callback) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
networking.get_cape_url(uuid, function(err, cape_url) {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
} else {
|
||||
if (cape_url) {
|
||||
logging.log(uuid + " " + cape_url);
|
||||
// set file paths
|
||||
var hash = get_hash(cape_url);
|
||||
if (details && details.hash == hash) {
|
||||
// hash hasn't changed
|
||||
logging.log(uuid + " hash has not changed");
|
||||
cache.update_timestamp(uuid, hash);
|
||||
callback(null, hash);
|
||||
} else {
|
||||
// hash has changed
|
||||
logging.log(uuid + " new hash: " + hash);
|
||||
var capepath = __dirname + "/../" + config.capes_dir + hash + ".png";
|
||||
|
||||
if (fs.existsSync(capepath)) {
|
||||
logging.log(uuid + " Cape already exists, not downloading");
|
||||
cache.save_hash(uuid, hash);
|
||||
callback(null, hash);
|
||||
} else {
|
||||
// download cape
|
||||
networking.get_cape(cape_url, function(err, img) {
|
||||
if (err || !img) {
|
||||
callback(err, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// profile found, but has no cape
|
||||
cache.save_hash(uuid, null);
|
||||
callback(null, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -127,6 +166,19 @@ exp.get_image_hash = function(uuid, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
exp.get_cape_hash = function(uuid, callback) {
|
||||
cache.get_details(uuid, function(err, details) {
|
||||
if (err) {
|
||||
callback(err, -1, null);
|
||||
} else {
|
||||
if (details && details.time + config.local_cache_time * 1000 >= new Date().getTime()) {
|
||||
logging.log(uuid + " uuid cached & recently updated");
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
// handles requests for +uuid+ avatars with +size+
|
||||
// callback contains error, status, image buffer, hash
|
||||
@ -224,4 +276,23 @@ exp.get_render = function(uuid, scale, helm, body, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
exp.get_cape = function(uuid, callback) {
|
||||
logging.log(uuid + " cape request");
|
||||
exp.get_image_hash(uuid, function(err, status, hash) {
|
||||
if (hash) {
|
||||
var capeurl = "http://textures.minecraft.net/texture/" + hash;
|
||||
networking.get_cape(capeurl, function(err, img) {
|
||||
if (err) {
|
||||
logging.error("error while downloading cape");
|
||||
callback(err, hash, null);
|
||||
} else {
|
||||
callback(null, hash, img);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback(err, null, null);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = exp;
|
||||
@ -6,6 +6,7 @@ var fs = require("fs");
|
||||
|
||||
var session_url = "https://sessionserver.mojang.com/session/minecraft/profile/";
|
||||
var skins_url = "https://skins.minecraft.net/MinecraftSkins/";
|
||||
var capes_url = "https://skins.minecraft.net/MinecraftCloaks/";
|
||||
|
||||
// exracts the skin url of a +profile+ object
|
||||
// returns null when no url found (user has no skin)
|
||||
@ -23,6 +24,20 @@ function extract_skin_url(profile) {
|
||||
return url;
|
||||
}
|
||||
|
||||
function extract_cape_url(profile) {
|
||||
var url = null;
|
||||
if (profile && profile.properties) {
|
||||
profile.properties.forEach(function(prop) {
|
||||
if (prop.name == "textures") {
|
||||
var json = Buffer(prop.value, "base64").toString();
|
||||
var props = JSON.parse(json);
|
||||
url = props && props.textures && props.textures.CAPE && props.textures.CAPE.url || null;
|
||||
}
|
||||
});
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
// make a request to skins.miencraft.net
|
||||
// the skin url is taken from the HTTP redirect
|
||||
var get_username_url = function(name, callback) {
|
||||
@ -104,6 +119,18 @@ exp.get_skin_url = function(uuid, callback) {
|
||||
}
|
||||
};
|
||||
|
||||
exp.get_cape_url = function(uuid, callback) {
|
||||
if (uuid.length <= 16) {
|
||||
get_username_url(uuid, function(err, url) {
|
||||
callback(err, url);
|
||||
});
|
||||
} else {
|
||||
get_uuid_url(uuid, function(err, url) {
|
||||
callback(err, url);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// downloads skin file from +url+
|
||||
// callback contains error, image
|
||||
exp.get_skin = function(url, uuid, callback) {
|
||||
@ -162,4 +189,37 @@ exp.save_skin = function(uuid, hash, outpath, callback) {
|
||||
}
|
||||
};
|
||||
|
||||
exp.get_cape = function(url, callback) {
|
||||
request.get({
|
||||
url: url,
|
||||
headers: {
|
||||
"User-Agent": "https://crafatar.com"
|
||||
},
|
||||
encoding: null, // encoding must be null so we get a buffer
|
||||
timeout: config.http_timeout // ms
|
||||
}, function (error, response, body) {
|
||||
if (!error && response.statusCode == 200) {
|
||||
// cape downloaded successfully
|
||||
logging.log("downloaded cape");
|
||||
logging.debug(url);
|
||||
callback(null, body);
|
||||
} else {
|
||||
if (error) {
|
||||
logging.error("Error downloading '" + url + "': " + error);
|
||||
} else if (response.statusCode == 404) {
|
||||
logging.warn("texture not found (404): " + url);
|
||||
} else if (response.statusCode == 429) {
|
||||
logging.warn("too many requests for " + url);
|
||||
logging.warn(body);
|
||||
} else {
|
||||
logging.error("unknown error for " + url);
|
||||
logging.error(response);
|
||||
logging.error(body);
|
||||
error = "unknown error"; // Error needs to be set, otherwise null in callback
|
||||
}
|
||||
callback(error, null);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = exp;
|
||||
66
routes/capes.js
Normal file
66
routes/capes.js
Normal file
@ -0,0 +1,66 @@
|
||||
var logging = require("../modules/logging");
|
||||
var helpers = require("../modules/helpers");
|
||||
var config = require("../modules/config");
|
||||
var router = require("express").Router();
|
||||
var lwip = require("lwip");
|
||||
|
||||
/* GET skin request. */
|
||||
router.get("/:uuid.:ext?", function (req, res) {
|
||||
var uuid = (req.params.uuid || "");
|
||||
var def = req.query.default;
|
||||
var start = new Date();
|
||||
var etag = null;
|
||||
|
||||
if (!helpers.uuid_valid(uuid)) {
|
||||
res.status(422).send("422 Invalid UUID");
|
||||
return;
|
||||
}
|
||||
|
||||
// strip dashes
|
||||
uuid = uuid.replace(/-/g, "");
|
||||
|
||||
try {
|
||||
helpers.get_cape(uuid, function (err, hash, image) {
|
||||
logging.log(uuid);
|
||||
if (err) {
|
||||
logging.error(err);
|
||||
}
|
||||
etag = hash && hash.substr(0, 32) || "none";
|
||||
var matches = req.get("If-None-Match") == "\"" + etag + "\"";
|
||||
if (image) {
|
||||
var http_status = 200;
|
||||
if (matches) {
|
||||
http_status = 304;
|
||||
} else if (err) {
|
||||
http_status = 503;
|
||||
}
|
||||
logging.debug("Etag: " + req.get("If-None-Match"));
|
||||
logging.debug("matches: " + matches);
|
||||
logging.log("status: " + http_status);
|
||||
sendimage(http_status, image);
|
||||
} else {
|
||||
res.status(404).send("404 not found");
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
logging.error("Error!");
|
||||
logging.error(e);
|
||||
res.status(500).send("500 error while retrieving cape");
|
||||
}
|
||||
|
||||
|
||||
function sendimage(http_status, image) {
|
||||
res.writeHead(http_status, {
|
||||
"Content-Type": "image/png",
|
||||
"Cache-Control": "max-age=" + config.browser_cache_time + ", public",
|
||||
"Response-Time": new Date() - start,
|
||||
"X-Storage-Type": "downloaded",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Etag": "\"" + etag + "\""
|
||||
});
|
||||
res.end(http_status == 304 ? null : image);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
||||
0
skins/capes/.gitkeep
Normal file
0
skins/capes/.gitkeep
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 907 B |
Binary file not shown.
|
After Width: | Height: | Size: 610 B |
Loading…
x
Reference in New Issue
Block a user