helpers.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. var networking = require('./networking');
  2. var config = require('./config');
  3. var cache = require('./cache');
  4. var skins = require('./skins');
  5. var valid_uuid = /^([0-9a-f]{32}|[a-zA-Z0-9_]{1,16})$/; // uuid|username
  6. var hash_pattern = /([^\/]+)(?=\.\w{0,16}$)|((?:[a-z][a-z]*[0-9]+[a-z0-9]*))/;
  7. function get_hash(url) {
  8. return hash_pattern.exec(url)[0].toLowerCase();
  9. }
  10. // requests skin for +uuid+ and extracts face/helm if image hash in +details+ changed
  11. // callback contains error, image hash
  12. function store_images(uuid, details, callback) {
  13. // get profile for +uuid+
  14. networking.get_profile(uuid, function(err, profile) {
  15. if (err === 0) {
  16. // uuid does not exist
  17. cache.save_hash(uuid, null);
  18. callback(null, null);
  19. } else if (err) {
  20. callback(err, null);
  21. } else {
  22. var skinurl = null;
  23. // Username handling
  24. if (uuid.length <= 16) {
  25. skinurl = "https://skins.minecraft.net/MinecraftSkins/" + uuid + ".png"
  26. console.log('is username')
  27. } else {
  28. skinurl = skin_url(profile);
  29. }
  30. if (skinurl) {
  31. console.log(uuid + " " + skinurl);
  32. // set file paths
  33. var hash = get_hash(skinurl);
  34. if (details && details.hash == hash) {
  35. // hash hasn't changed
  36. console.log(uuid + " hash has not changed");
  37. cache.update_timestamp(uuid, hash);
  38. callback(null, hash);
  39. } else {
  40. // hash has changed
  41. console.log(uuid + "new hash: " + hash);
  42. var facepath = __dirname + '/../' + config.faces_dir + hash + ".png";
  43. var helmpath = __dirname + '/../' + config.helms_dir + hash + ".png";
  44. // download skin, extract face/helm
  45. networking.skin_file(skinurl, facepath, helmpath, function(err) {
  46. if (err) {
  47. if (uuid.length <= 16) {
  48. cache.save_hash(uuid, null);
  49. }
  50. callback(err, null);
  51. } else {
  52. cache.save_hash(uuid, hash);
  53. callback(null, hash);
  54. }
  55. });
  56. }
  57. } else {
  58. // profile found, but has no skin
  59. cache.save_hash(uuid, null);
  60. callback(null, null);
  61. }
  62. }
  63. });
  64. }
  65. // exracts the skin url of a +profile+ object
  66. // returns null when no url found (user has no skin)
  67. function skin_url(profile) {
  68. var url = null;
  69. if (profile && profile.properties) {
  70. profile.properties.forEach(function(prop) {
  71. if (prop.name == 'textures') {
  72. var json = Buffer(prop.value, 'base64').toString();
  73. var props = JSON.parse(json);
  74. url = props && props.textures && props.textures.SKIN && props.textures.SKIN.url || null;
  75. }
  76. });
  77. }
  78. return url;
  79. }
  80. // decides whether to get an image from disk or to download it
  81. // callback contains error, status, hash
  82. // the status gives information about how the image was received
  83. // -1: error
  84. // 0: cached as null
  85. // 1: found on disk
  86. // 2: profile requested/found, skin downloaded from mojang servers
  87. // 3: profile requested/found, but it has not changed or no skin
  88. function get_image_hash(uuid, callback) {
  89. cache.get_details(uuid, function(err, details) {
  90. if (err) {
  91. callback(err, -1, null);
  92. } else {
  93. if (details && details.time + config.local_cache_time * 1000 >= new Date().getTime()) {
  94. // uuid known + recently updated
  95. console.log(uuid + " uuid known & recently updated");
  96. callback(null, (details.hash ? 1 : 0), details.hash);
  97. } else {
  98. console.log(uuid + " uuid not known or too old");
  99. store_images(uuid, details, function(err, hash) {
  100. if (err) {
  101. callback(err, -1, details && details.hash);
  102. } else {
  103. console.log(uuid + " hash: " + hash);
  104. callback(null, (hash != (details && details.hash) ? 2 : 3), hash);
  105. }
  106. });
  107. }
  108. }
  109. });
  110. }
  111. var exp = {};
  112. // returns true if the +uuid+ is a valid uuid or username
  113. // the uuid may be not exist, however
  114. exp.uuid_valid = function(uuid) {
  115. return valid_uuid.test(uuid);
  116. };
  117. // handles requests for +uuid+ images with +size+
  118. // callback contains error, status, image buffer
  119. // image is the user's face+helm when helm is true, or the face otherwise
  120. // for status, see get_image_hash
  121. exp.get_avatar = function(uuid, helm, size, callback) {
  122. console.log("\nrequest: " + uuid);
  123. get_image_hash(uuid, function(err, status, hash) {
  124. if (hash) {
  125. var filepath = __dirname + '/../' + (helm ? config.helms_dir : config.faces_dir) + hash + ".png";
  126. skins.resize_img(filepath, size, function(img_err, result) {
  127. if (img_err) {
  128. callback(img_err, -1, null);
  129. } else {
  130. // we might have a hash although an error occured
  131. // (e.g. Mojang servers not reachable, using outdated hash)
  132. callback(err, (err ? -1 : status), result);
  133. }
  134. });
  135. } else {
  136. // hash is null when uuid has no skin
  137. callback(err, status, null);
  138. }
  139. });
  140. };
  141. module.exports = exp;