mirror of
https://github.com/azures04/crafatar.git
synced 2026-03-22 07:51:17 +01:00
add support for helmets (?helm), closes #2. changed '/:uuid/123' to '/:uuid?size=123', closes #10. Bugfixes
This commit is contained in:
parent
a61ac9b6a4
commit
1606fac89b
@ -1,10 +1,11 @@
|
|||||||
var config = {
|
var config = {
|
||||||
min_size: 0, // < 0 will (obviously) cause crash
|
min_size: 0, // < 0 will (obviously) cause crash
|
||||||
max_size: 512, // too big values might lead to slow response time or DoS
|
max_size: 512, // too big values might lead to slow response time or DoS
|
||||||
default_size: 180, // size to be used when no size given
|
default_size: 180, // size to be used when no size given
|
||||||
browser_cache_time: 3600,// seconds until browser will request image again
|
browser_cache_time: 3600, // seconds until browser will request image again
|
||||||
http_timeout: 1000, // ms until connection to mojang is dropped
|
http_timeout: 1000, // ms until connection to mojang is dropped
|
||||||
skins_dir: 'skins/' // directory where skins are kept. should have trailing '/'
|
faces_dir: 'skins/faces/', // directory where faces are kept. should have trailing '/'
|
||||||
|
helms_dir: 'skins/helms/' // directory where helms are kept. should have trailing '/'
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
@ -8,7 +8,7 @@ var valid_uuid = /^[0-9a-f]{32}$/;
|
|||||||
var exp = {};
|
var exp = {};
|
||||||
|
|
||||||
// exracts the skin url of a +profile+ object
|
// exracts the skin url of a +profile+ object
|
||||||
// returns null when no url found
|
// returns null when no url found (user has no skin)
|
||||||
exp.skin_url = function(profile) {
|
exp.skin_url = function(profile) {
|
||||||
var url = null;
|
var url = null;
|
||||||
if (profile && profile.properties) {
|
if (profile && profile.properties) {
|
||||||
@ -16,7 +16,7 @@ exp.skin_url = function(profile) {
|
|||||||
if (prop.name == 'textures') {
|
if (prop.name == 'textures') {
|
||||||
var json = Buffer(prop.value, 'base64').toString();
|
var json = Buffer(prop.value, 'base64').toString();
|
||||||
var props = JSON.parse(json);
|
var props = JSON.parse(json);
|
||||||
url = props && props.textures && props.textures.SKIN && props.textures.SKIN.url;
|
url = props && props.textures && props.textures.SKIN && props.textures.SKIN.url || null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -31,22 +31,27 @@ exp.uuid_valid = function(uuid) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// handles requests for +uuid+ images with +size+
|
// handles requests for +uuid+ images with +size+
|
||||||
//
|
|
||||||
// callback is a function with 3 parameters:
|
// callback is a function with 3 parameters:
|
||||||
// error, status, image buffer
|
// error, status, image buffer
|
||||||
|
// image is the user's face+helm when helm is true, or the face otherwise
|
||||||
//
|
//
|
||||||
// the status gives information about how the image was received
|
// the status gives information about how the image was received
|
||||||
// -1: error
|
// -1: error
|
||||||
// 1: found on disk
|
// 1: found on disk
|
||||||
// 2: profile requested/found, skin downloaded from mojang servers
|
// 2: profile requested/found, skin downloaded from mojang servers
|
||||||
// 3: profile requested/found, but it has no skin
|
// 3: profile requested/found, but it has no skin
|
||||||
exp.get_avatar = function(uuid, size, callback) {
|
exp.get_avatar = function(uuid, helm, size, callback) {
|
||||||
var filepath = config.skins_dir + uuid + ".png";
|
var facepath = config.faces_dir + uuid + ".png";
|
||||||
|
var helmpath = config.helms_dir + uuid + ".png";
|
||||||
|
var filepath = helm ? helmpath : facepath;
|
||||||
|
|
||||||
if (fs.existsSync(filepath)) {
|
if (fs.existsSync(filepath)) {
|
||||||
|
// file found on disk
|
||||||
skins.resize_img(filepath, size, function(err, result) {
|
skins.resize_img(filepath, size, function(err, result) {
|
||||||
callback(err, 1, result);
|
callback(err, 1, result);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// download skin
|
||||||
networking.get_profile(uuid, function(err, profile) {
|
networking.get_profile(uuid, function(err, profile) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err, -1, profile);
|
callback(err, -1, profile);
|
||||||
@ -55,7 +60,7 @@ exp.get_avatar = function(uuid, size, callback) {
|
|||||||
var skinurl = exp.skin_url(profile);
|
var skinurl = exp.skin_url(profile);
|
||||||
|
|
||||||
if (skinurl) {
|
if (skinurl) {
|
||||||
networking.skin_file(skinurl, filepath, function(err) {
|
networking.skin_file(skinurl, facepath, helmpath, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err, -1, null);
|
callback(err, -1, null);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -6,12 +6,15 @@ var session_url = "https://sessionserver.mojang.com/session/minecraft/profile/";
|
|||||||
|
|
||||||
var exp = {};
|
var exp = {};
|
||||||
|
|
||||||
|
// download the Mojang profile for +uuid+
|
||||||
|
// callback contains error, profile object
|
||||||
exp.get_profile = function(uuid, callback) {
|
exp.get_profile = function(uuid, callback) {
|
||||||
request.get({
|
request.get({
|
||||||
url: session_url + uuid,
|
url: session_url + uuid,
|
||||||
timeout: config.http_timeout // ms
|
timeout: config.http_timeout // ms
|
||||||
}, function (error, response, body) {
|
}, function (error, response, body) {
|
||||||
if (!error && response.statusCode == 200) {
|
if (!error && response.statusCode == 200) {
|
||||||
|
// profile downloaded successfully
|
||||||
callback(null, JSON.parse(body));
|
callback(null, JSON.parse(body));
|
||||||
} else {
|
} else {
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -33,15 +36,26 @@ exp.get_profile = function(uuid, callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
exp.skin_file = function(url, outname, callback) {
|
// downloads skin file from +url+
|
||||||
|
// stores face image as +facename+
|
||||||
|
// stores helm image as +helmname+
|
||||||
|
// callback is forwarded from skins/extract_face or skins/extract_helm
|
||||||
|
exp.skin_file = function(url, facename, helmname, callback) {
|
||||||
request.get({
|
request.get({
|
||||||
url: url,
|
url: url,
|
||||||
encoding: null, // encoding must be null so we get a buffer
|
encoding: null, // encoding must be null so we get a buffer
|
||||||
timeout: config.http_timeout // ms
|
timeout: config.http_timeout // ms
|
||||||
}, function (error, response, body) {
|
}, function (error, response, body) {
|
||||||
if (!error && response.statusCode == 200) {
|
if (!error && response.statusCode == 200) {
|
||||||
skins.extract_face(body, outname, function(err) {
|
// skin downloaded successfully
|
||||||
callback(err);
|
skins.extract_face(body, facename, function(err) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
skins.extract_helm(facename, body, helmname, function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|||||||
@ -3,15 +3,15 @@ var lwip = require('lwip');
|
|||||||
var exp = {};
|
var exp = {};
|
||||||
|
|
||||||
// extracts the face from an image +buffer+
|
// extracts the face from an image +buffer+
|
||||||
// save it to a file called +outname+
|
// result is saved to a file called +outname+
|
||||||
// callback has an error parameter which can be null
|
// +callback+ contains error
|
||||||
exp.extract_face = function(buffer, outname, callback) {
|
exp.extract_face = function(buffer, outname, callback) {
|
||||||
lwip.open(buffer, "png", function(err, image) {
|
lwip.open(buffer, "png", function(err, image) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
} else {
|
} else {
|
||||||
image.batch()
|
image.batch()
|
||||||
.crop(8, 8, 15, 15)
|
.crop(8, 8, 15, 15) // face
|
||||||
.writeFile(outname, function(err) {
|
.writeFile(outname, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
@ -23,8 +23,47 @@ exp.extract_face = function(buffer, outname, callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// extracts the helm from an image +buffer+ and lays it over a +facefile+
|
||||||
|
// +facefile+ is the filename of an image produced by extract_face
|
||||||
|
// result is saved to a file called +outname+
|
||||||
|
// +callback+ contains error
|
||||||
|
exp.extract_helm = function(facefile, buffer, outname, callback) {
|
||||||
|
lwip.open(buffer, "png", function(err, skin) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
lwip.open(facefile, function(err, face_img) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
skin.crop(42, 8, 49, 15, function(err, helm_img) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
face_img.paste(0, 0, helm_img, function(err, face_helm_img) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
face_helm_img.writeFile(outname, function(err) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
callback(null);
|
||||||
|
// JavaScript callback hell <3
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// resizes the image file +inname+ to +size+ by +size+ pixels
|
// resizes the image file +inname+ to +size+ by +size+ pixels
|
||||||
// +callback+ is a buffer of the resized image
|
// +callback+ contains error, image buffer
|
||||||
exp.resize_img = function(inname, size, callback) {
|
exp.resize_img = function(inname, size, callback) {
|
||||||
lwip.open(inname, function(err, image) {
|
lwip.open(inname, function(err, image) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@ -6,10 +6,11 @@ var skins = require('../modules/skins');
|
|||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|
||||||
/* GET avatar request. */
|
/* GET avatar request. */
|
||||||
router.get('/:uuid/:size?', function(req, res) {
|
router.get('/:uuid', function(req, res) {
|
||||||
var uuid = req.param('uuid');
|
var uuid = req.params.uuid;
|
||||||
var size = req.param('size') || config.default_size;
|
var size = req.query.size || config.default_size;
|
||||||
var def = req.query.default;
|
var def = req.query.default;
|
||||||
|
var helm = req.query.hasOwnProperty('helm');
|
||||||
var start = new Date();
|
var start = new Date();
|
||||||
|
|
||||||
// Prevent app from crashing/freezing
|
// Prevent app from crashing/freezing
|
||||||
@ -24,13 +25,12 @@ router.get('/:uuid/:size?', function(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
helpers.get_avatar(uuid, size, function(err, status, image) {
|
helpers.get_avatar(uuid, helm, size, function(err, status, image) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
handle_404(def);
|
handle_404(def);
|
||||||
} else if (status == 1 || status == 2) {
|
} else if (status == 1 || status == 2) {
|
||||||
var time = new Date() - start;
|
sendimage(200, image);
|
||||||
sendimage(200, time, image);
|
|
||||||
} else if (status == 3) {
|
} else if (status == 3) {
|
||||||
handle_404(def);
|
handle_404(def);
|
||||||
}
|
}
|
||||||
@ -44,19 +44,18 @@ router.get('/:uuid/:size?', function(req, res) {
|
|||||||
function handle_404(def) {
|
function handle_404(def) {
|
||||||
if (def == "alex" || def == "steve") {
|
if (def == "alex" || def == "steve") {
|
||||||
skins.resize_img("public/images/" + def + ".png", size, function(image) {
|
skins.resize_img("public/images/" + def + ".png", size, function(image) {
|
||||||
var time = new Date() - start;
|
sendimage(404, image);
|
||||||
sendimage(404, time, image);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(404).send('404 Not found');
|
res.status(404).send('404 Not found');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendimage(status, time, image) {
|
function sendimage(status, image) {
|
||||||
res.writeHead(status, {
|
res.writeHead(status, {
|
||||||
'Content-Type': 'image/png',
|
'Content-Type': 'image/png',
|
||||||
'Cache-Control': 'max-age=' + config.browser_cache_time + ', public',
|
'Cache-Control': 'max-age=' + config.browser_cache_time + ', public',
|
||||||
'Response-Time': time,
|
'Response-Time': new Date() - start,
|
||||||
'X-Storage-Type': 'local'
|
'X-Storage-Type': 'local'
|
||||||
});
|
});
|
||||||
res.end(image);
|
res.end(image);
|
||||||
|
|||||||
0
skins/helms/.gitkeep
Normal file
0
skins/helms/.gitkeep
Normal file
@ -32,8 +32,8 @@ block content
|
|||||||
p(style="margin-top: 10px;") By default, a 404 text is returned when the avatar was not found. You can change that to the avatar of steve or alex:
|
p(style="margin-top: 10px;") By default, a 404 text is returned when the avatar was not found. You can change that to the avatar of steve or alex:
|
||||||
.well <img src="#{domain}/avatars/ae795aa86327408e92ab25c8a59f3ba1/250?default=alex">
|
.well <img src="#{domain}/avatars/ae795aa86327408e92ab25c8a59f3ba1/250?default=alex">
|
||||||
.col-md-2
|
.col-md-2
|
||||||
img(src="/avatars/2d5aa9cdaeb049189930461fc9b91cc5?default=steve", title="Jake0oo0")
|
img(src="/avatars/2d5aa9cdaeb049189930461fc9b91cc5?default=alex&helm", title="Jake0oo0")
|
||||||
img(src="/avatars/ae795aa86327408e92ab25c8a59f3ba1?default=steve", title="redstone_sheep")
|
img(src="/avatars/ae795aa86327408e92ab25c8a59f3ba1?default=alex&helm", title="redstone_sheep")
|
||||||
img(src="/avatars/069a79f444e94726a5befca90e38aaf5?default=steve", title="Notch")
|
img(src="/avatars/069a79f444e94726a5befca90e38aaf5?default=alex&helm", title="Notch")
|
||||||
img(src="/avatars/0ea8eca3dbf647cc9d1ac64551ca975c?default=steve", title="sk89q")
|
img(src="/avatars/0ea8eca3dbf647cc9d1ac64551ca975c?default=alex&helm", title="sk89q")
|
||||||
img(src="/avatars/af74a02d19cb445bb07f6866a861f783?default=steve", title="md_5")
|
img(src="/avatars/af74a02d19cb445bb07f6866a861f783?default=alex&helm", title="md_5")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user