Better error handling + general cleanup (#182)

* chore: cleanup .gitignore

- remove unused /typings, not using typescript
- remove .next as this is not using next.js
+ add editors to ignore file
+ add exceptions for more .env files, .env.local, etc.
+ seperate lockfiles and add yarn lockfile

* feat(package.json): add dev command

* feat: better error handling 1/4

+ add status codes to all of the errors.

? I understand this is similar to robtop so I didn't change any of the very cryptic responses, i.e. -1, -2, -3.

* feat: cleanup unused params & add status codes

* chore(servers.json): remove weird space in json

* feat: final status codes

* fix(leaderboard): fix comment for private server

* fix(merge): merge on 7da5632

* revert: revert icon.js
This commit is contained in:
Matt 2021-12-07 11:06:33 -08:00 committed by GitHub
parent 4d1ea03115
commit a37125ed59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 472 additions and 372 deletions

12
.gitignore vendored
View file

@ -1,6 +1,9 @@
# Ew # Ew
extra extra
# Package manager lockfiles
package-lock.json package-lock.json
yarn.lock
# Logs # Logs
logs logs
@ -40,9 +43,6 @@ build/Release
node_modules/ node_modules/
jspm_packages/ jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory # Optional npm cache directory
.npm .npm
@ -60,6 +60,8 @@ typings/
# dotenv environment variables file # dotenv environment variables file
.env .env
.env.*
# next.js build output # Editors
.next .idea
.vscode

View file

@ -21,14 +21,14 @@ module.exports = async (app, req, res, level) => {
const raw_data = level.data; const raw_data = level.data;
const response_data = analyze_level(level, raw_data); const response_data = analyze_level(level, raw_data);
return res.send(response_data); return res.status(200).send(response_data);
} else { } else {
zlib.unzip(levelString, (err, buffer) => { zlib.unzip(levelString, (err, buffer) => {
if (err) { return res.send("-2"); } if (err) { return res.status(500).send("-2"); }
const raw_data = buffer.toString(); const raw_data = buffer.toString();
const response_data = analyze_level(level, raw_data); const response_data = analyze_level(level, raw_data);
return res.send(response_data); return res.status(200).send(response_data);
}); });
} }
} }

View file

@ -1,6 +1,6 @@
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
if (req.offline) return res.send("-1") if (req.offline) return res.status(500).send("-1")
let count = +req.query.count || 10 let count = +req.query.count || 10
if (count > 1000) count = 1000 if (count > 1000) count = 1000
@ -20,14 +20,14 @@ module.exports = async (app, req, res) => {
req.gdRequest(path, req.gdParams(params), function(err, resp, body) { req.gdRequest(path, req.gdParams(params), function(err, resp, body) {
if (err) return res.send("-1") if (err) return res.status(500).send("-1")
comments = body.split('|') comments = body.split('|')
comments = comments.map(x => x.split(':')) comments = comments.map(x => x.split(':'))
comments = comments.map(x => x.map(x => app.parseResponse(x, "~"))) comments = comments.map(x => x.map(x => app.parseResponse(x, "~")))
if (req.query.type == "profile") comments.filter(x => x[0][2]) if (req.query.type == "profile") comments.filter(x => x[0][2])
else comments = comments.filter(x => x[0] && x[0][2]) else comments = comments.filter(x => x[0] && x[0][2])
if (!comments.length) return res.send("-1") if (!comments.length) return res.status(204).send("-1")
let pages = body.split('#')[1].split(":") let pages = body.split('#')[1].split(":")
let lastPage = +Math.ceil(+pages[0] / +pages[2]); let lastPage = +Math.ceil(+pages[0] / +pages[2]);
@ -79,7 +79,7 @@ module.exports = async (app, req, res) => {
}) })
return res.send(commentArray) return res.status(200).send(commentArray)
}) })
} }

View file

@ -6,7 +6,7 @@ module.exports = async (app, req, res, api, ID, analyze) => {
function rejectLevel() { function rejectLevel() {
if (!api) return res.redirect('search/' + req.params.id) if (!api) return res.redirect('search/' + req.params.id)
else return res.send("-1") else return res.status(500).send("-1")
} }
if (req.offline) { if (req.offline) {
@ -22,7 +22,7 @@ module.exports = async (app, req, res, api, ID, analyze) => {
req.gdRequest('downloadGJLevel22', { levelID }, function (err, resp, body) { req.gdRequest('downloadGJLevel22', { levelID }, function (err, resp, body) {
if (err) { if (err) {
if (analyze && api && req.server.downloadsDisabled) return res.send("-3") if (analyze && api && req.server.downloadsDisabled) return res.status(403).send("-3")
else if (!api && levelID < 0) return res.redirect(`/?daily=${levelID * -1}`) else if (!api && levelID < 0) return res.redirect(`/?daily=${levelID * -1}`)
else return rejectLevel() else return rejectLevel()
} }
@ -69,7 +69,7 @@ module.exports = async (app, req, res, api, ID, analyze) => {
if (analyze) return app.run.analyze(app, req, res, level) if (analyze) return app.run.analyze(app, req, res, level)
function sendLevel() { function sendLevel() {
if (api) return res.send(level) if (api) return res.status(200).send(level)
else return fs.readFile('./html/level.html', 'utf8', function (err, data) { else return fs.readFile('./html/level.html', 'utf8', function (err, data) {
let html = data; let html = data;
@ -78,7 +78,7 @@ module.exports = async (app, req, res, api, ID, analyze) => {
let regex = new RegExp(`\\[\\[${x.toUpperCase()}\\]\\]`, "g") let regex = new RegExp(`\\[\\[${x.toUpperCase()}\\]\\]`, "g")
html = html.replace(regex, app.clean(level[x])) html = html.replace(regex, app.clean(level[x]))
}) })
return res.send(html) return res.status(200).send(html)
}) })
} }

View file

@ -3,19 +3,19 @@ let gauntletNames = ["Fire", "Ice", "Poison", "Shadow", "Lava", "Bonus", "Chaos"
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
if (req.offline) return res.send("-1") if (req.offline) return res.status(500).send("-1")
let cached = cache[req.id] let cached = cache[req.id]
if (app.config.cacheGauntlets && cached && cached.data && cached.indexed + 2000000 > Date.now()) return res.send(cached.data) // half hour cache if (app.config.cacheGauntlets && cached && cached.data && cached.indexed + 2000000 > Date.now()) return res.status(200).send(cached.data) // half hour cache
req.gdRequest('getGJGauntlets21', {}, function (err, resp, body) { req.gdRequest('getGJGauntlets21', {}, function (err, resp, body) {
if (err) return res.send("-1") if (err) return res.status(500).send("-1")
let gauntlets = body.split('#')[0].split('|').map(x => app.parseResponse(x)).filter(x => x[3]) let gauntlets = body.split('#')[0].split('|').map(x => app.parseResponse(x)).filter(x => x[3])
let gauntletList = gauntlets.map(x => ({ id: +x[1], name: gauntletNames[+x[1] - 1] || "Unknown", levels: x[3].split(",") })) let gauntletList = gauntlets.map(x => ({ id: +x[1], name: gauntletNames[+x[1] - 1] || "Unknown", levels: x[3].split(",") }))
if (app.config.cacheGauntlets) cache[req.id] = {data: gauntletList, indexed: Date.now()} if (app.config.cacheGauntlets) cache[req.id] = {data: gauntletList, indexed: Date.now()}
res.send(gauntletList) res.status(200).send(gauntletList)
}) })

View file

@ -1,311 +1,389 @@
const sharp = require('sharp'); // this file is a potential candidate for worst code on github
const Canvas = require('canvas') // i advise you to turn back now
const psd = require('ag-psd') // seriously, it's not too late
const Jimp = require('jimp');
const fs = require('fs'); const fs = require('fs');
const mainPath = `../icons/` const icons = require('../icons/gameSheet.json');
const icons = require('../misc/icons/gameSheet.json'); const colors = require('../icons/colors.json');
const colors = require('../misc/icons/colors.json'); const forms = require('../icons/forms.json')
const forms = require('../misc/icons/forms.json') const offsets = require('../icons/offsets.json');
const offsets = require('../misc/icons/offsets.json')
const legOffsets = require('../misc/icons/legOffsets.json')
let canvasSize = 300
let halfCanvas = canvasSize/2
let TRANSPARENT = {r: 0, g: 0, b: 0, alpha: 0}
let cache = {}
let partNames = {
"1": "Primary",
"2": "Secondary",
"3": "UFO Dome",
"glow": "Glow",
"extra": "White",
}
// convert hex to RGB
let hexRegex = /^[A-Fa-f0-9]{6}$/ let hexRegex = /^[A-Fa-f0-9]{6}$/
function hexConvert(hex) { hex = hex.replace('#', ''); return {val: hex, r: '0x' + hex[0] + hex[1] | 0, g: '0x' + hex[2] + hex[3] | 0, b: '0x' + hex[4] + hex[5] | 0}; } function hexConvert(hex) { hex = hex.replace('#', ''); return {r: '0x' + hex[0] + hex[1] | 0, g: '0x' + hex[2] + hex[3] | 0, b: '0x' + hex[4] + hex[5] | 0}; }
function recolor(img, col) {
// get path name from icon form and ID return img.scan(0, 0, img.bitmap.width, img.bitmap.height, function (x, y, idx) {
function getIconPath(icon, formName) { if (img.bitmap.data.slice(idx, idx+3).every(function(val) {return val >= 20 && val <= 255})) { // If it's not "black, i.e. we want to recolor it"
return `${mainPath}${formName}_${icon < 10 ? "0" : ""}${icon}` this.bitmap.data[idx] = colors[col].r / (255 / this.bitmap.data[idx]);
this.bitmap.data[idx + 1] = colors[col].g / (255 / this.bitmap.data[idx + 1]);
this.bitmap.data[idx + 2] = colors[col].b / (255 / this.bitmap.data[idx + 2]);
}
})
} }
// get color from param input /* Caveat of genFileName is that if there are any falsey values in the arguments they are ignored.
function getColor(colInput, defaultCol) { This is usually a good thing though - avoid issues by not putting something like 0 instead of '0' */
colInput = String(colInput) function genFileName(...args) { return args.filter(function(val) {return val}).join('_') +'_001.png' }
let foundColor = colors[colInput] function fromIcons(filename) { return `./icons/${filename}` }
if (foundColor) { let cache = {};
foundColor.val = colInput
return foundColor
}
else if (colInput.match(hexRegex)) { // custom hex code
let hexCol = hexConvert(colInput)
colors[colInput.toLowerCase()] = hexCol
return hexCol
}
else if (!foundColor && defaultCol) {
let def = colors[defaultCol]
def.val = defaultCol
return def
}
}
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
async function buildIcon(account=[], userCode) { function buildIcon(account=[], usercode) {
let form = forms[req.query.form] || forms["icon"] let { form, ind } = forms[req.query.form] || {};
form = form || 'player';
ind = ind || 21;
let iconID = req.query.icon || account[form.index] || 1; let iconID = req.query.icon || account[ind] || 1;
let col1 = getColor(req.query.col1 || account[10], "0") let col1 = req.query.col1 || account[10] || 0;
let col2 = getColor(req.query.col2 || account[11], "3") let col2 = req.query.col2 || account[11] || 3;
let colG = getColor(req.query.colG || req.query.colg) let colG = req.query.colG || req.query.colg
let colW = getColor(req.query.colW || req.query.colw || req.query.col3) let colW = req.query.colW || req.query.colw || req.query.col3
let outline = req.query.glow || account[28] || "0";
let useGlow = req.query.glow || account[28] || false; let topless = form == "bird" && req.query.topless
if (useGlow && ["false", "0"].includes(useGlow)) useGlow = false let drawLegs = !(req.query.noLegs > 0)
if (col1.r == 0 && col1.g == 0 && col1.b == 0 ) useGlow = true let autoSize = req.query.size == "auto"
let sizeParam = autoSize || (req.query.size && !isNaN(req.query.size))
if (outline == "0" || outline == "false") outline = false;
// bit of a hacky solution for glow color but whatev if (iconID && iconID.toString().length == 1) iconID = "0" + iconID;
let glowColor = colG || col2
if (glowColor.r == 0 && glowColor.g == 0 && glowColor.b == 0) glowColor = col1
if (glowColor.r == 0 && glowColor.g == 0 && glowColor.b == 0) glowColor = {r: 255, g: 255, b: 255}
let psdExport = req.query.psd || false function genImageName(...args) { return genFileName(form, iconID, ...args) }
let topless = form.name == "UFO" ? req.query.topless || false : false
let customSize = req.query.size == "auto" ? "auto" : +req.query.size || null let icon, glow, extra;
function setBaseIcons() {
let iconPath = getIconPath(iconID, form.form) icon = genImageName(isSpecial && '01');
glow = genImageName(isSpecial && '01', '2');
let iconCode = `${form.name}-${iconID}-${col1.val}-${col2.val}-${colG ? colG.val : "x"}-${colW ? colW.val : "x"}-${useGlow ? 1 : 0}` extra = genImageName(isSpecial && '01', 'extra');
let cachable = !topless && !customSize && !psdExport
if (cachable && cache[iconCode]) return res.end(cache[iconCode].buffer)
// default to 1 if icon ID does not exist
if (!fs.existsSync(getPartName(1).slice(1))) { // slice 1 from filename since fs reads paths differently
iconID = 1
iconPath = getIconPath(1, form.form)
}
// get path of icon 'part' (1: primary, 2: secondary, 3: ufo top, extra: white, glow: glow, )
function getPartName(part, robotPart) {
let path = iconPath
if (form.legs) path += `_0${robotPart || 1}`
if (!part || part == "1") return `${path}_001.png`
else return `${path}_${part}_001.png`
}
// recolor white parts of icon to specified color
async function recolor(img, col) {
let rawData = await img.raw().toBuffer({resolveWithObject: true})
for (let i=0; i<rawData.data.length; i += 4) { // [R, G, B, A]
if (rawData.data[i + 3] > 0) {
rawData.data[i] = col.r / (255 / rawData.data[i]);
rawData.data[i + 1] = col.g / (255 / rawData.data[i + 1]);
rawData.data[i + 2] = col.b / (255 / rawData.data[i + 2]);
}
} }
return sharp(rawData.data, {raw: {width: rawData.info.width, height: rawData.info.height, channels: 4, background: TRANSPARENT}}).png() let isSpecial = ['robot', 'spider'].includes(form);
} setBaseIcons();
// color icon part and add to layer list if (!fs.existsSync(fromIcons(icon)) || (isSpecial && !fs.existsSync(fromIcons(genImageName('02'))))) {
async function addLayer(part, color, legSection) { iconID = '01';
setBaseIcons();
let leg = legSection ? legSection.leg : null
let partName = getPartName(part, leg)
let offsetData = icons[partName.slice(mainPath.length)]
let { spriteSize, spriteOffset } = offsetData
let builtPart = sharp(partName.slice(1)) // slice 1 from filename since sharp also reads paths differently
if (color) builtPart = await recolor(builtPart, color)
let left = halfCanvas - Math.floor(spriteSize[0] / 2) + spriteOffset[0]
let top = halfCanvas - Math.floor(spriteSize[1] / 2) - spriteOffset[1]
if (legSection) {
left += Math.floor(legSection.xPos)
top -= Math.floor(legSection.yPos)
// if (legSection.darken) builtPart.tint({r: 100, g: 100, b: 100})
if (legSection.rotation) {
builtPart.rotate(legSection.rotation, {background: TRANSPARENT})
if (part == "glow") { left--; top--; }
}
if (legSection.yScale) builtPart.resize({width: spriteSize[0], height: Math.floor(spriteSize[1] * legSection.yScale), fit: "fill"})
if (legSection.xFlip) builtPart.flop()
} }
let layerData = { let ex = fromIcons(extra)
partName, spriteOffset, spriteSize, leg, let hasExtra = fs.existsSync(ex)
layerName: partNames[part],
behind: legSection && legSection.darken,
isGlow: part == "glow",
input: await builtPart.toBuffer(),
left, top
}
if (legSection) { let cols = [col1, col2, colG, colW]
if (!legLayers[legSection.leg]) legLayers[legSection.leg] = [layerData] cols.forEach(col => {
else legLayers[legSection.leg].push(layerData) if (!col) return
} col = col.toString()
if (col.match(hexRegex)) colors[col.toLowerCase()] = hexConvert(col)
else layers.push(layerData)
}
// build all layers of icon segment (col1, col2, glow, extra)
async function buildFullLayer(legSection) {
let hasExtra = fs.existsSync(getPartName("extra", legSection ? legSection.leg : null).slice(1))
if (form.form == "bird" && !topless) await addLayer(3, null, legSection) // ufo top
await addLayer(2, col2, legSection) // secondary color
if (useGlow) await addLayer("glow", glowColor, legSection) // glow
await addLayer(1, col1, legSection) // primary color
if (hasExtra) await addLayer("extra", colW, legSection) // extra
// if (legSection) {
// let foundLeg = legLayers[legSection.leg]
// foundLeg.forEach(x => layers.push(x))
// }
}
let layers = []
let legLayers = []
let legData = form.legs ? legOffsets[form.form] || [] : []
let parentSize = icons[getPartName(1).slice(mainPath.length)].spriteSize
let canvas = sharp({create: {width: canvasSize, height: canvasSize, channels: 4, background: TRANSPARENT}})
// if (legData.length) {
// for (let i=0; i<legData.length; i++) {
// await buildFullLayer(legData[i])
// }
// }
await buildFullLayer()
// if (legData.length) layers = legLayers.flat().filter(x => x).sort((a, b) => !!b.behind - !!a.behind).sort((a, b) => !!b.isGlow - !!a.isGlow)
canvas.composite(layers)
let rawData = await canvas.toBuffer({resolveWithObject: true})
let minX = canvasSize; let maxX = 0;
let minY = canvasSize; let maxY = 0;
for (let i=0; i<rawData.data.length; i += 4) { // [R, G, B, A]
let pixelIndex = i/4
let x = pixelIndex % canvasSize;
let y = Math.floor(pixelIndex / canvasSize);
let alpha = rawData.data[i + 3];
if (alpha > 0) {
if (x < minX) minX = x
if (x > maxX) maxX = x
if (y < minY) minY = y
if (y > maxY) maxY = y
}
}
// need to make a new sharp instance so everything is merged. bit hacky but it works
let dimensions = [maxX - minX, maxY - minY]
if (!psdExport) {
let finalIcon = sharp(rawData.data, {raw: {width: canvasSize, height: canvasSize, channels: 4}})
.extract({left: minX, top: minY, width: dimensions[0], height: dimensions[1]})
if (customSize) {
let isThicc = dimensions[0] > dimensions[1]
let squareSize = req.query.size == "auto" ? (isThicc ? dimensions[0] : dimensions[1]) : Math.floor(req.query.size)
if (squareSize < 32) squareSize = 32
if (squareSize > 256) squareSize = 256
// use longest side to make square
if (isThicc) finalIcon.resize({
width: dimensions[isThicc ? 0 : 1],
height: dimensions[isThicc ? 0 : 1],
fit: "contain",
background: TRANSPARENT
})
finalIcon.resize({width: squareSize, height: squareSize, fit: "contain", background: TRANSPARENT})
}
finalIcon.png().toBuffer().then(x => {
res.end(x) // send file
if (cachable) { // cache for a bit
cache[iconCode] = { buffer: x, timeoutID: setTimeout(function() {delete cache[iconCode]}, 10000000) } // cache file for 3 hours
if (userCode) cache[userCode] = { buffer: x, timeoutID: setTimeout(function() {delete cache[userCode]}, 300000) } // 5 min cache for player icons
}
})
}
else {
let psdLayers = layers.map(x => {
let Image = Canvas.Image
let canvas = Canvas.createCanvas(...dimensions)
let ctx = canvas.getContext('2d');
const img = new Image()
img.onload = () => {
ctx.drawImage(img, 0 + x.left - minX, 0 + x.top - minY)
}
img.onerror = err => { throw err }
img.src = x.input
return {name: x.layerName, canvas, leg: x.leg}
}) })
if (form.legs) { if (!colors[col1] || isNaN(colors[col1].r)) col1 = colors[+col1] ? +col1 : 0
let legLayers = [] if (!colors[col2] || isNaN(colors[col2].r)) col2 = colors[+col2] ? +col2 : 3
for (let i=1; i<=form.legs + 1; i++) legLayers.push({name: i == 1 ? "Base" : `Leg ${i}`, opened: true, children: []}) if (!colors[colG] || isNaN(colors[colG].r)) colG = colors[+colG] ? +colG : null
psdLayers.forEach(x => { if (!colors[colW] || isNaN(colors[colW].r)) colW = colors[+colW] ? +colW : null
legLayers[x.leg-1].children.push(x) if (colW && (!hasExtra || colW == 12)) colW = null
})
psdLayers = legLayers.reverse() if (col1 == 15 || col1 === "000000") outline = true;
let iconCode = `${req.query.form == "cursed" ? "cursed" : form}${topless ? "top" : ""}-${iconID}-${col1}-${col2}-${colG || "x"}-${colW || "x"}-${outline ? 1 : 0}`
if (!sizeParam && (!isSpecial || drawLegs) && cache[iconCode]) return res.end(cache[iconCode].value)
let useExtra = false
let originalOffset = icons[icon].spriteOffset;
let minusOrigOffset = function(x, y) { return x - originalOffset[y] }
let offset = icons[glow].spriteOffset.map(minusOrigOffset);
let robotLeg1, robotLeg2, robotLeg3, robotLeg3b, robotLeg2b, robotLeg1b, robotLeg1c;
let robotOffset1, robotOffset2, robotOffset3, robotOffset1b, robotOffset2b, robotOffset3b;
let robotGlow1, robotGlow2, robotGlow3, glowOffset
let ufoTop, ufoOffset, ufoCoords, ufoSprite
let extrabit, offset2, size2;
if (isSpecial) {
const legs = [1,2,3].map(function(val) {return genImageName(`0${val+1}`)});
const glows = [1,2,3].map(function(val) {return genImageName(`0${val+1}`, '2')});
robotOffset1 = icons[legs[0]].spriteOffset.map(minusOrigOffset).concat(icons[legs[0]].spriteSize);
robotOffset2 = icons[legs[1]].spriteOffset.map(minusOrigOffset).concat(icons[legs[1]].spriteSize);
robotOffset3 = icons[legs[2]].spriteOffset.map(minusOrigOffset).concat(icons[legs[2]].spriteSize);
robotOffset1b = icons[glows[0]].spriteOffset.map(minusOrigOffset).concat(icons[glows[0]].spriteSize);
robotOffset2b = icons[glows[1]].spriteOffset.map(minusOrigOffset).concat(icons[glows[1]].spriteSize);
robotOffset3b = icons[glows[2]].spriteOffset.map(minusOrigOffset).concat(icons[glows[2]].spriteSize);
robotLeg1 = new Jimp(fromIcons(legs[0])); robotGlow1 = new Jimp(fromIcons(glows[0]))
robotLeg2 = new Jimp(fromIcons(legs[1])); robotGlow2 = new Jimp(fromIcons(glows[1]))
robotLeg3 = new Jimp(fromIcons(legs[2])); robotGlow3 = new Jimp(fromIcons(glows[2]))
glowOffset = offsets[form][+iconID] || []
} }
const photoshop = { Jimp.read(fromIcons(glow)).then(async function (image) {
width: dimensions[0],
height: dimensions[1], let size = [image.bitmap.width, image.bitmap.height]
children: psdLayers let glow = recolor(image, col2)
}; let imgOff = isSpecial ? 100 : 0
const buffer = psd.writePsdBuffer(photoshop); let eb = fromIcons(extra)
return res.end(buffer) if (fs.existsSync(eb)) {
extrabit = icons[extra]
offset2 = extrabit.spriteOffset.map(minusOrigOffset);
size2 = extrabit.spriteSize;
extra = new Jimp(eb);
if (colW) await Jimp.read(eb).then(e => { extra = recolor(e, colW) })
useExtra = true
}
Jimp.read(fromIcons(icon)).then(async function (ic) {
let iconSize = [ic.bitmap.width, ic.bitmap.height]
recolor(ic, col1)
ic.composite(glow, (iconSize[0] / 2) - (size[0] / 2) + offset[0], (iconSize[1] / 2) - (size[1] / 2) - offset[1], { mode: Jimp.BLEND_DESTINATION_OVER })
if (form == "bird" && !topless) {
ufoTop = genImageName('3')
ufoOffset = icons[ufoTop].spriteOffset.map(minusOrigOffset).concat(icons[ufoTop].spriteSize);
ufoCoords = [imgOff + (iconSize[0] / 2) - (ufoOffset[2] / 2) + ufoOffset[0], (iconSize[1] / 2) - (ufoOffset[3] / 2) - ufoOffset[1] + 300 - iconSize[1]]
ufoSprite = fromIcons(ufoTop)
ic.contain(iconSize[0], 300, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_BOTTOM)
// Only add dome if there's no glow, otherwise the dome will be outlined as well
if (!outline) ic.composite(await Jimp.read(ufoSprite), ufoCoords[0], ufoCoords[1], {mode: Jimp.BLEND_DESTINATION_OVER})
}
if (drawLegs && (form == "robot" || req.query.form == "cursed")) {
ic.contain(iconSize[0], 300, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_TOP)
ic.contain(iconSize[0] + 200, 300, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_TOP)
await Jimp.read(new Jimp(robotGlow1)).then(rob => {
rob.rotate(-45)
robotGlow1 = recolor(rob, col2)
})
await Jimp.read(new Jimp(robotGlow2)).then(rob => {
rob.rotate(45)
robotGlow2 = recolor(rob, col2)
})
await Jimp.read(new Jimp(robotGlow3)).then(rob => {
robotGlow3 = recolor(rob, col2)
})
await Jimp.read(new Jimp(robotLeg1)).then(rob => {
rob.rotate(-45)
recolor(rob, col1)
rob.composite(robotGlow1, (robotOffset1[2] - robotOffset1b[2]) + (glowOffset[0] || 1), ((robotOffset1[3] - robotOffset1b[3]) / 2) + (glowOffset[1] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
robotLeg1 = rob
})
await Jimp.read(new Jimp(robotLeg2)).then(rob => {
rob.rotate(45)
recolor(rob, col1)
rob.composite(robotGlow2, ((robotOffset2[2] - robotOffset2b[2]) / 4) + (glowOffset[4] || 0), ((robotOffset2[3] - robotOffset2b[3]) / 2) + (glowOffset[5] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
robotLeg2 = rob
})
await Jimp.read(new Jimp(robotLeg2)).then(rob => {
robotLeg2b = rob.color([{ apply: 'darken', params: [20] }]).rotate(-5)
})
await Jimp.read(new Jimp(robotLeg3)).then(rob => {
recolor(rob, col1)
rob.composite(robotGlow3, ((robotOffset3[2] - robotOffset3b[2]) / 2) + (glowOffset[2] || 0), ((robotOffset3[3] - robotOffset3b[3]) / 2) + (glowOffset[3] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
robotLeg3 = rob
})
await Jimp.read(new Jimp(robotLeg3)).then(rob => {
robotLeg3b = rob.color([{ apply: 'darken', params: [10] }])
})
ic.composite(robotLeg2b, 100 + (iconSize[0] / 2) - (robotOffset2[2]) + robotOffset2[0] - 31, (iconSize[1] / 2) - (robotOffset2[3]) - robotOffset2[1] + 73)
ic.composite(robotLeg3b, 100 + (iconSize[0] / 2) - (robotOffset3[2]) + robotOffset3[0] + 20, (iconSize[1] / 2) - (robotOffset3[3]) - robotOffset3[1] + 78)
ic.composite(robotLeg2, 100 + (iconSize[0] / 2) - (robotOffset2[2]) + robotOffset2[0] - 20, (iconSize[1] / 2) - (robotOffset2[3]) - robotOffset2[1] + 73)
ic.composite(robotLeg3, 100 + (iconSize[0] / 2) - (robotOffset3[2]) + robotOffset3[0] + 40, (iconSize[1] / 2) - (robotOffset3[3]) - robotOffset3[1] + 78)
ic.composite(robotLeg1, 100 + (iconSize[0] / 2) - (robotOffset1[2]) + robotOffset1[0] - 20, (iconSize[1] / 2) - (robotOffset1[3]) - robotOffset1[1] + 50)
}
else if (drawLegs && form == "spider") {
let spiderBody;
ic.contain(iconSize[0], 300, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_TOP)
ic.contain(iconSize[0] + 200, 300, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_TOP)
if (iconID == "07") {
robotOffset2[2] -= 10
robotOffset2[1] += 12
robotOffset1b[3] -= 105
robotOffset2b[3] -= 150
robotOffset2b[2] -= 60
}
if (iconID == "16") {
robotOffset1b[3] -= 100
robotOffset2b[3] -= 200
robotOffset2b[2] -= 30
}
await Jimp.read(new Jimp(robotGlow1)).then(rob => {
if (robotGlow1.bitmap.width < 10) robotGlow1.opacity(0)
else robotGlow1 = recolor(rob, col2)
})
await Jimp.read(new Jimp(robotGlow2)).then(rob => {
robotGlow2 = recolor(rob, col2)
})
await Jimp.read(new Jimp(robotGlow3)).then(rob => {
robotGlow3 = recolor(rob, col2)
})
await Jimp.read(new Jimp(robotLeg1)).then(rob => {
recolor(rob, col1)
rob.composite(robotGlow1, ((robotOffset1[2] - robotOffset1b[2]) / 2) + (glowOffset[2] || 0), ((robotOffset1[3] - robotOffset1b[3]) / 4) + (glowOffset[3] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
robotLeg1 = rob
})
await Jimp.read(new Jimp(robotLeg2)).then(rob => {
recolor(rob, col1)
rob.composite(robotGlow2, ((robotOffset2[2] - robotOffset2b[2]) / 6) + (glowOffset[0] || 0), ((robotOffset2[3] - robotOffset2b[3]) / 6) + (glowOffset[1] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
rob.rotate(-40)
robotLeg2 = rob
})
await Jimp.read(new Jimp(robotLeg1)).then(rob => {
robotLeg1b = rob.color([{ apply: 'darken', params: [20] }])
})
await Jimp.read(new Jimp(robotLeg1b)).then(rob => {
robotLeg1c = rob.mirror(true, false)
})
await Jimp.read(new Jimp(robotLeg3)).then(rob => {
recolor(rob, col1)
rob.composite(robotGlow3, ((robotOffset3[2] - robotOffset3b[2]) / 2) + (glowOffset[4] || 0), ((robotOffset3[3] - robotOffset3b[3]) / 2) + (glowOffset[5] || 0), { mode: Jimp.BLEND_DESTINATION_OVER })
robotLeg3 = rob
})
await Jimp.read(new Jimp(ic)).then(rob => {
spiderBody = rob
})
ic.composite(robotLeg3, 100 + (iconSize[0] / 2) - (robotOffset3[2]) + (robotOffset3[0]), (iconSize[1] / 2) - (robotOffset2[3]) - robotOffset2[1] + 77)
ic.composite(robotLeg1b, 100 + (iconSize[0] / 2) - (robotOffset1[2]) + robotOffset1[0] + 35, (iconSize[1] / 2) - (robotOffset1[3]) - robotOffset1[1] + 70)
ic.composite(robotLeg1c, 100 + (iconSize[0] / 2) - (robotOffset1[2]) + robotOffset1[0] + 75, (iconSize[1] / 2) - (robotOffset1[3]) - robotOffset1[1] + 70)
// ^ BELOW
ic.composite(spiderBody, 0, 0)
// v ABOVE
ic.composite(robotLeg2, 100 + (iconSize[0] / 2) - (robotOffset2[2]) + robotOffset2[0] - 60, (iconSize[1] / 2) - (robotOffset2[3]) - robotOffset2[1] + 75)
ic.composite(robotLeg1, 100 + (iconSize[0] / 2) - (robotOffset1[2]) + robotOffset1[0] + 7, (iconSize[1] / 2) - (robotOffset1[3]) - robotOffset1[1] + 70)
}
// every now and then jimp does a fucky wucky uwu and this line errors. seems to be an issue with the lib itself :v
try { if (useExtra) ic.composite(extra, imgOff + (iconSize[0] / 2) - (size2[0] / 2) + offset2[0], (iconSize[1] / 2) - (size2[1] / 2) - offset2[1] + (form == "bird" && !req.query.topless ? 300 - iconSize[1] : 0)) }
catch(e) {}
let finalSize = [ic.bitmap.width, ic.bitmap.height]
function finish(img) {
img.autocrop(0.01, false)
if (form == "swing") img.resize(120, 111)
if (img.bitmap.height == 300) ic.autocrop(1, false)
if (sizeParam) {
let thicc = img.bitmap.width > img.bitmap.height
let imgSize = req.query.size == "auto" ? (thicc ? img.bitmap.width : img.bitmap.height) : Math.round(req.query.size)
if (imgSize < 32) imgSize = 32
if (imgSize > 512) imgSize = 512
if (thicc) img.contain(img.bitmap.width, img.bitmap.width, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE)
else img.contain(img.bitmap.height, img.bitmap.height, Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE)
img.resize(imgSize, Jimp.AUTO)
}
img.getBuffer(Jimp.AUTO, (err, buffer) => {
if (!sizeParam && drawLegs) {
cache[iconCode] = { value: buffer, timeoutID: setTimeout(function() {delete cache[iconCode]}, 10000000) } // 3 hour cache
if (usercode) cache[usercode] = { value: buffer, timeoutID: setTimeout(function() {delete cache[usercode]}, 300000) } // 5 min cache for player icons
}
return res.end(buffer, 'base64')
})
}
if (!outline) return finish(ic)
else {
ic.getBuffer(Jimp.AUTO, function (err, buff) {
const Canvas = require('canvas')
, Image = Canvas.Image
, canvas = Canvas.createCanvas(finalSize[0] + 10, finalSize[1] + 10)
, ctx = canvas.getContext('2d');
if (!colG) colG = (col2 == 15 || col2 == "000000" ? col1 : col2)
if (colG == 15 || colG == "000000") colG = 12
const img = new Image()
img.onload = () => {
var dArr = [-1, -1, 0, -1, 1, -1, -1, 0, 1, 0, -1, 1, 0, 1, 1, 1], // offset array
s = 2, i = 0, x = canvas.width / 2 - finalSize[0] / 2, y = canvas.height / 2 - finalSize[1] / 2;
for (; i < dArr.length; i += 2) ctx.drawImage(img, x + dArr[i] * s, y + dArr[i + 1] * s);
ctx.globalCompositeOperation = "source-in";
ctx.fillStyle = `rgba(${colors[colG].r}, ${colors[colG].g}, ${colors[colG].b}, 1})`;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "source-over";
ctx.imageSmoothingEnabled = false;
// Add UFO top last so it doesn't get glow'd
if (form == "bird" && !topless) {
const dome = new Image()
dome.src = ufoSprite
ctx.drawImage(dome, ufoCoords[0]+5, ufoCoords[1]+5)
}
ctx.drawImage(img, x, y)
}
img.onerror = err => { throw err }
img.src = buff
Jimp.read(canvas.toBuffer()).then(b => {
return finish(b)
})
})
}
})
})
} }
}
let username = req.params.text
let userCode;
res.contentType('image/png');
// ==================================== // if (req.offline || req.query.hasOwnProperty("noUser") || req.query.hasOwnProperty("nouser") || username == "icon") return buildIcon()
// OLD CODE IS BEING USED FOR ROBOTS AND SPIDERS else if (app.config.cachePlayerIcons && !Object.keys(req.query).filter(x => !["form", "forceGD"].includes(x)).length) {
let formCheck = forms[req.query.form] userCode = `${req.id}u-${username.toLowerCase()}-${forms[req.query.form] ? req.query.form : 'cube'}`
if (formCheck && formCheck.legs) return app.run.icon_old(app, req, res) if (cache[userCode]) return res.end(cache[userCode].value)
}
let username = req.params.text let accountMode = !req.query.hasOwnProperty("player") && Number(req.params.id)
let userCode; let foundID = app.userCache(req.id, username)
res.contentType('image/png'); let skipRequest = accountMode || foundID
let forceGD = req.query.hasOwnProperty("forceGD")
if (req.offline || req.query.hasOwnProperty("noUser") || req.query.hasOwnProperty("nouser") || username == "icon") return buildIcon() // skip request by causing fake error lmao
req.gdRequest(skipRequest ? "" : 'getGJUsers20', skipRequest ? {} : req.gdParams({ str: username, forceGD }, !forceGD), function (err1, res1, body1) {
else if (app.config.cachePlayerIcons && !Object.keys(req.query).filter(x => !["form", "forceGD"].includes(x)).length) { let result = foundID ? foundID[0] : (accountMode || err1) ? username : app.parseResponse(body1)[16];
userCode = `${req.id}u-${username.toLowerCase()}-${forms[req.query.form] ? req.query.form : 'cube'}`
if (cache[userCode]) return res.end(cache[userCode].value)
}
let accountMode = !req.query.hasOwnProperty("player") && Number(req.params.id) req.gdRequest('getGJUserInfo20', req.gdParams({ targetAccountID: result, forceGD }, !forceGD), function (err2, res2, body2) {
let foundID = app.userCache(req.id, username)
let skipRequest = accountMode || foundID
let forceGD = req.query.hasOwnProperty("forceGD")
// skip request by causing fake error lmao if (err2) return buildIcon();
req.gdRequest(skipRequest ? "" : 'getGJUsers20', skipRequest ? {} : req.gdParams({ str: username, forceGD }, !forceGD), function (err1, res1, body1) { let iconData = app.parseResponse(body2)
if (!foundID && !forceGD) app.userCache(req.id, iconData[16], iconData[2], iconData[1])
return buildIcon(iconData, userCode);
let result = foundID ? foundID[0] : (accountMode || err1) ? username : app.parseResponse(body1)[16]; })
});
req.gdRequest('getGJUserInfo20', req.gdParams({ targetAccountID: result, forceGD }, !forceGD), function (err2, res2, body2) {
if (err2) return buildIcon();
let iconData = app.parseResponse(body2)
if (!foundID && !forceGD) app.userCache(req.id, iconData[16], iconData[2], iconData[1])
return buildIcon(iconData, userCode);
})
});
} }

View file

@ -9,8 +9,9 @@ let caches = [{"stars": null, "coins": null, "demons": null, "diamonds": null},
module.exports = async (app, req, res, post) => { module.exports = async (app, req, res, post) => {
if (req.isGDPS) return res.send("-2") // Accurate leaderboard returns 418 because private servers do not use.
if (!app.sheetsKey) return res.send([]) if (req.isGDPS) return res.status(418).send("-2")
if (!app.sheetsKey) return res.status(500).send([])
let gdMode = post || req.query.hasOwnProperty("gd") let gdMode = post || req.query.hasOwnProperty("gd")
let modMode = !gdMode && req.query.hasOwnProperty("mod") let modMode = !gdMode && req.query.hasOwnProperty("mod")
let cache = caches[gdMode ? 2 : modMode ? 1 : 0] let cache = caches[gdMode ? 2 : modMode ? 1 : 0]
@ -18,7 +19,7 @@ module.exports = async (app, req, res, post) => {
let type = req.query.type ? req.query.type.toLowerCase() : 'stars' let type = req.query.type ? req.query.type.toLowerCase() : 'stars'
if (type == "usercoins") type = "coins" if (type == "usercoins") type = "coins"
if (!indexes.includes(type)) type = "stars" if (!indexes.includes(type)) type = "stars"
if (lastIndex[modMode ? 1 : 0][type] + 600000 > Date.now() && cache[type]) return res.send(gdMode ? cache[type] : JSON.parse(cache[type])) // 10 min cache if (lastIndex[modMode ? 1 : 0][type] + 600000 > Date.now() && cache[type]) return res.status(200).send(gdMode ? cache[type] : JSON.parse(cache[type])) // 10 min cache
sheet.useApiKey(app.sheetsKey) sheet.useApiKey(app.sheetsKey)
sheet.loadInfo().then(async () => { sheet.loadInfo().then(async () => {
@ -29,7 +30,7 @@ module.exports = async (app, req, res, post) => {
if (modMode) cellIndex += indexes.length if (modMode) cellIndex += indexes.length
let cell = tab.getCell(1, cellIndex).value let cell = tab.getCell(1, cellIndex).value
if (!cell || typeof cell != "string" || cell.startsWith("GoogleSpreadsheetFormulaError")) { console.log("Spreadsheet Error:"); console.log(cell); return res.send("-1") } if (!cell || typeof cell != "string" || cell.startsWith("GoogleSpreadsheetFormulaError")) { console.log("Spreadsheet Error:"); console.log(cell); return res.status(500).send("-1") }
let leaderboard = JSON.parse(cell.replace(/~( |$)/g, "")) let leaderboard = JSON.parse(cell.replace(/~( |$)/g, ""))
let gdFormatting = "" let gdFormatting = ""
@ -40,7 +41,7 @@ module.exports = async (app, req, res, post) => {
caches[modMode ? 1 : 0][type] = JSON.stringify(leaderboard) caches[modMode ? 1 : 0][type] = JSON.stringify(leaderboard)
caches[2][type] = gdFormatting caches[2][type] = gdFormatting
lastIndex[modMode ? 1 : 0][type] = Date.now() lastIndex[modMode ? 1 : 0][type] = Date.now()
return res.send(gdMode ? gdFormatting : leaderboard) return res.status(200).send(gdMode ? gdFormatting : leaderboard)
}) })
} }

View file

@ -2,12 +2,13 @@ const request = require('request')
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
if (req.isGDPS) return res.send("0") // Accurate leaderboard returns 418 because Private servers do not use.
if (req.isGDPS) return res.status(418).send("0")
request.post('http://robtopgames.com/Boomlings/get_scores.php', { request.post('http://robtopgames.com/Boomlings/get_scores.php', {
form : { secret: app.config.params.secret || "Wmfd2893gb7", name: "Player" } }, function(err, resp, body) { form : { secret: app.config.params.secret || "Wmfd2893gb7", name: "Player" } }, function(err, resp, body) {
if (err || !body || body == 0) return res.send("0") if (err || !body || body == 0) return res.status(500).send("0")
let info = body.split(" ").filter(x => x.includes(";")) let info = body.split(" ").filter(x => x.includes(";"))
let users = [] let users = []
@ -36,7 +37,7 @@ module.exports = async (app, req, res) => {
users.push(user) users.push(user)
}) })
return res.send(users) return res.status(200).send(users)
}) })
} }

View file

@ -1,6 +1,6 @@
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
if (req.offline) return res.send("-1") if (req.offline) return res.status(500).send("-1")
let amount = 100; let amount = 100;
let count = req.query.count ? parseInt(req.query.count) : null let count = req.query.count ? parseInt(req.query.count) : null
@ -18,9 +18,9 @@ module.exports = async (app, req, res) => {
req.gdRequest('getGJLevelScores211', params, function(err, resp, body) { req.gdRequest('getGJLevelScores211', params, function(err, resp, body) {
if (err) return res.send({error: true, lastWorked: app.timeSince(req.id)}) if (err) return res.status(500).send({error: true, lastWorked: app.timeSince(req.id)})
scores = body.split('|').map(x => app.parseResponse(x)).filter(x => x[1]) scores = body.split('|').map(x => app.parseResponse(x)).filter(x => x[1])
if (!scores.length) return res.send([]) if (!scores.length) return res.status(500).send([])
else app.trackSuccess(req.id) else app.trackSuccess(req.id)
scores.forEach(x => { scores.forEach(x => {
@ -43,7 +43,7 @@ module.exports = async (app, req, res) => {
app.userCache(req.id, x.accountID, x.playerID, x.username) app.userCache(req.id, x.accountID, x.playerID, x.username)
}) })
return res.send(scores.slice(0, amount)) return res.status(200).send(scores.slice(0, amount))
}) })
} }

View file

@ -1,6 +1,6 @@
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
if (req.offline) return res.send("-1") if (req.offline) return res.status(500).send("-1")
let amount = 100; let amount = 100;
let count = req.query.count ? parseInt(req.query.count) : null let count = req.query.count ? parseInt(req.query.count) : null
@ -16,9 +16,9 @@ module.exports = async (app, req, res) => {
req.gdRequest('getGJScores20', params, function(err, resp, body) { req.gdRequest('getGJScores20', params, function(err, resp, body) {
if (err) return res.send("-1") if (err) return res.status(500).send("-1")
scores = body.split('|').map(x => app.parseResponse(x)).filter(x => x[1]) scores = body.split('|').map(x => app.parseResponse(x)).filter(x => x[1])
if (!scores.length) return res.send("-1") if (!scores.length) return res.status(500).send("-1")
scores.forEach(x => { scores.forEach(x => {
let keys = Object.keys(x) let keys = Object.keys(x)
@ -42,6 +42,6 @@ module.exports = async (app, req, res) => {
keys.forEach(k => delete x[k]) keys.forEach(k => delete x[k])
app.userCache(req.id, x.accountID, x.playerID, x.username) app.userCache(req.id, x.accountID, x.playerID, x.username)
}) })
return res.send(scores) return res.status(200).send(scores)
}) })
} }

View file

@ -6,7 +6,7 @@ module.exports = async (app, req, res, api, analyze) => {
function rejectLevel() { function rejectLevel() {
if (!api) return res.redirect('search/' + req.params.id) if (!api) return res.redirect('search/' + req.params.id)
else return res.send("-1") else return res.status(500).send("-1")
} }
if (req.offline) return rejectLevel() if (req.offline) return rejectLevel()
@ -37,7 +37,7 @@ module.exports = async (app, req, res, api, analyze) => {
function sendLevel() { function sendLevel() {
if (api) return res.send(level) if (api) return res.status(200).send(level)
else return fs.readFile('./html/level.html', 'utf8', function (err, data) { else return fs.readFile('./html/level.html', 'utf8', function (err, data) {
let html = data; let html = data;
@ -50,7 +50,7 @@ module.exports = async (app, req, res, api, analyze) => {
}) })
if (req.server.downloadsDisabled) html = html.replace('id="additional" class="', 'id="additional" class="downloadDisabled ') if (req.server.downloadsDisabled) html = html.replace('id="additional" class="', 'id="additional" class="downloadDisabled ')
.replace('analyzeBtn"', 'analyzeBtn" style="filter: opacity(30%)"') .replace('analyzeBtn"', 'analyzeBtn" style="filter: opacity(30%)"')
return res.send(html) return res.status(200).send(html)
}) })
} }

View file

@ -3,17 +3,17 @@ let cache = {}
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
if (req.offline) return res.send("-1") if (req.offline) return res.status(500).send("-1")
let cached = cache[req.id] let cached = cache[req.id]
if (app.config.cacheMapPacks && cached && cached.data && cached.indexed + 5000000 > Date.now()) return res.send(cached.data) // 1.5 hour cache if (app.config.cacheMapPacks && cached && cached.data && cached.indexed + 5000000 > Date.now()) return res.status(200).send(cached.data) // 1.5 hour cache
let params = { count: 250, page: 0 } let params = { count: 250, page: 0 }
let packs = [] let packs = []
function mapPackLoop() { function mapPackLoop() {
req.gdRequest('getGJMapPacks21', params, function (err, resp, body) { req.gdRequest('getGJMapPacks21', params, function (err, resp, body) {
if (err) return res.send("-1") if (err) return res.status(500).send("-1")
let newPacks = body.split('#')[0].split('|').map(x => app.parseResponse(x)).filter(x => x[2]) let newPacks = body.split('#')[0].split('|').map(x => app.parseResponse(x)).filter(x => x[2])
packs = packs.concat(newPacks) packs = packs.concat(newPacks)
@ -36,7 +36,7 @@ module.exports = async (app, req, res) => {
})) }))
if (app.config.cacheMapPacks) cache[req.id] = {data: mappacks, indexed: Date.now()} if (app.config.cacheMapPacks) cache[req.id] = {data: mappacks, indexed: Date.now()}
return res.send(mappacks) return res.status(200).send(mappacks)
}) })
} }
mapPackLoop() mapPackLoop()

View file

@ -1,5 +1,7 @@
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
if (!req.body.accountID) return res.status(400).send("No account ID provided!") if (!req.body.accountID) return res.status(400).send("No account ID provided!")
if (!req.body.password) return res.status(400).send("No password provided!") if (!req.body.password) return res.status(400).send("No password provided!")

View file

@ -1,4 +1,6 @@
module.exports = async (app, req, res, api) => { module.exports = async (app, req, res) => {
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
if (!req.body.accountID) return res.status(400).send("No account ID provided!") if (!req.body.accountID) return res.status(400).send("No account ID provided!")
if (!req.body.password) return res.status(400).send("No password provided!") if (!req.body.password) return res.status(400).send("No password provided!")

View file

@ -1,4 +1,6 @@
module.exports = async (app, req, res, api) => { module.exports = async (app, req, res) => {
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
if (!req.body.accountID) return res.status(400).send("No account ID provided!") if (!req.body.accountID) return res.status(400).send("No account ID provided!")
if (!req.body.password) return res.status(400).send("No password provided!") if (!req.body.password) return res.status(400).send("No password provided!")

View file

@ -1,4 +1,6 @@
module.exports = async (app, req, res, api) => { module.exports = async (app, req, res) => {
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
if (req.body.count) return app.run.countMessages(app, req, res) if (req.body.count) return app.run.countMessages(app, req, res)
if (!req.body.accountID) return res.status(400).send("No account ID provided!") if (!req.body.accountID) return res.status(400).send("No account ID provided!")

View file

@ -1,4 +1,6 @@
module.exports = async (app, req, res, api) => { module.exports = async (app, req, res) => {
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
if (!req.body.targetID) return res.status(400).send("No target ID provided!") if (!req.body.targetID) return res.status(400).send("No target ID provided!")
if (!req.body.message) return res.status(400).send("No message provided!") if (!req.body.message) return res.status(400).send("No message provided!")

View file

@ -3,6 +3,8 @@ function sha1(data) { return crypto.createHash("sha1").update(data, "binary").di
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
if (!req.body.ID) return res.status(400).send("No ID provided!") if (!req.body.ID) return res.status(400).send("No ID provided!")
if (!req.body.accountID) return res.status(400).send("No account ID provided!") if (!req.body.accountID) return res.status(400).send("No account ID provided!")
if (!req.body.password) return res.status(400).send("No password provided!") if (!req.body.password) return res.status(400).send("No password provided!")

View file

@ -11,6 +11,8 @@ function getTime(time) {
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
if (!req.body.comment) return res.status(400).send("No comment provided!") if (!req.body.comment) return res.status(400).send("No comment provided!")
if (!req.body.username) return res.status(400).send("No username provided!") if (!req.body.username) return res.status(400).send("No username provided!")
if (!req.body.levelID) return res.status(400).send("No level ID provided!") if (!req.body.levelID) return res.status(400).send("No level ID provided!")

View file

@ -3,6 +3,8 @@ function sha1(data) { return crypto.createHash("sha1").update(data, "binary").di
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
if (!req.body.comment) return res.status(400).send("No comment provided!") if (!req.body.comment) return res.status(400).send("No comment provided!")
if (!req.body.username) return res.status(400).send("No username provided!") if (!req.body.username) return res.status(400).send("No username provided!")
if (!req.body.accountID) return res.status(400).send("No account ID provided!") if (!req.body.accountID) return res.status(400).send("No account ID provided!")

View file

@ -4,7 +4,7 @@ module.exports = async (app, req, res, api, getLevels) => {
if (req.offline) { if (req.offline) {
if (!api) return res.redirect('/search/' + req.params.id) if (!api) return res.redirect('/search/' + req.params.id)
else return res.send("-1") else return res.status(500).send("-1")
} }
let username = getLevels || req.params.id let username = getLevels || req.params.id
@ -42,7 +42,7 @@ module.exports = async (app, req, res, api, getLevels) => {
if (err2 || dumbGDPSError) { if (err2 || dumbGDPSError) {
if (!api) return res.redirect('/search/' + req.params.id) if (!api) return res.redirect('/search/' + req.params.id)
else return res.send("-1") else return res.status(500).send("-1")
} }
if (!foundID) app.userCache(req.id, account[16], account[2], account[1]) if (!foundID) app.userCache(req.id, account[16], account[2], account[1])
@ -78,7 +78,7 @@ module.exports = async (app, req, res, api, getLevels) => {
glow: account[28] == "1", glow: account[28] == "1",
} }
if (api) return res.send(userData) if (api) return res.status(200).send(userData)
else fs.readFile('./html/profile.html', 'utf8', function(err, data) { else fs.readFile('./html/profile.html', 'utf8', function(err, data) {
let html = data; let html = data;
@ -87,7 +87,7 @@ module.exports = async (app, req, res, api, getLevels) => {
let regex = new RegExp(`\\[\\[${x.toUpperCase()}\\]\\]`, "g") let regex = new RegExp(`\\[\\[${x.toUpperCase()}\\]\\]`, "g")
html = html.replace(regex, app.clean(userData[x])) html = html.replace(regex, app.clean(userData[x]))
}) })
return res.send(html) return res.status(200).send(html)
}) })
}) })

View file

@ -5,17 +5,17 @@ let demonList = {}
module.exports = async (app, req, res) => { module.exports = async (app, req, res) => {
if (req.offline) return res.send(req.query.hasOwnProperty("err") ? "err" : "-1") if (req.offline) return res.status(500).send(req.query.hasOwnProperty("err") ? "err" : "-1")
let demonMode = req.query.hasOwnProperty("demonlist") || req.query.hasOwnProperty("demonList") || req.query.type == "demonlist" || req.query.type == "demonList" let demonMode = req.query.hasOwnProperty("demonlist") || req.query.hasOwnProperty("demonList") || req.query.type == "demonlist" || req.query.type == "demonList"
if (demonMode) { if (demonMode) {
if (!req.server.demonList) return res.send('-1') if (!req.server.demonList) return res.status(400).send('-1')
let dList = demonList[req.id] let dList = demonList[req.id]
if (!dList || !dList.list.length || dList.lastUpdated + 600000 < Date.now()) { // 10 minute cache if (!dList || !dList.list.length || dList.lastUpdated + 600000 < Date.now()) { // 10 minute cache
return request.get(req.server.demonList + 'api/v2/demons/listed/?limit=100', function (err1, resp1, list1) { return request.get(req.server.demonList + 'api/v2/demons/listed/?limit=100', function (err1, resp1, list1) {
if (err1) return res.send("-1") if (err1) return res.status(500).send("-1")
else return request.get(req.server.demonList + 'api/v2/demons/listed/?limit=100&after=100', function (err2, resp2, list2) { else return request.get(req.server.demonList + 'api/v2/demons/listed/?limit=100&after=100', function (err2, resp2, list2) {
if (err2) return res.send("-1") if (err2) return res.status(500).send("-1")
demonList[req.id] = {list: JSON.parse(list1).concat(JSON.parse(list2)).map(x => String(x.level_id)), lastUpdated: Date.now()} demonList[req.id] = {list: JSON.parse(list1).concat(JSON.parse(list2)).map(x => String(x.level_id)), lastUpdated: Date.now()}
return app.run.search(app, req, res) return app.run.search(app, req, res)
}) })
@ -85,7 +85,7 @@ module.exports = async (app, req, res) => {
filters.str = demonMode ? demonList[req.id].list : filters.str.split(",") filters.str = demonMode ? demonList[req.id].list : filters.str.split(",")
listSize = filters.str.length listSize = filters.str.length
filters.str = filters.str.slice(filters.page*amount, filters.page*amount + amount) filters.str = filters.str.slice(filters.page*amount, filters.page*amount + amount)
if (!filters.str.length) return res.send("-1") if (!filters.str.length) return res.status(400).send("-1")
filters.str = filters.str.map(x => String(Number(x) + (+req.query.l || 0))).join() filters.str = filters.str.map(x => String(Number(x) + (+req.query.l || 0))).join()
filters.page = 0 filters.page = 0
} }
@ -95,7 +95,7 @@ module.exports = async (app, req, res) => {
req.gdRequest('getGJLevels21', req.gdParams(filters), function(err, resp, body) { req.gdRequest('getGJLevels21', req.gdParams(filters), function(err, resp, body) {
if (err) return res.send("-1") if (err) return res.status(500).send("-1")
let splitBody = body.split('#') let splitBody = body.split('#')
let preRes = splitBody[0].split('|') let preRes = splitBody[0].split('|')
let authorList = {} let authorList = {}
@ -154,7 +154,7 @@ module.exports = async (app, req, res) => {
}) })
if (filters.type == 10) parsedLevels = parsedLevels.slice((+filters.page) * amount, (+filters.page + 1) * amount) if (filters.type == 10) parsedLevels = parsedLevels.slice((+filters.page) * amount, (+filters.page + 1) * amount)
return res.send(parsedLevels) return res.status(200).send(parsedLevels)
}) })
} }

View file

@ -4,14 +4,15 @@ module.exports = async (app, req, res) => {
// temporary solution until song api is re-enabled // temporary solution until song api is re-enabled
if (req.offline) return res.send('-1') if (req.offline) return res.status(500).send('-1')
let songID = req.params.song let songID = req.params.song
req.gdRequest('getGJSongInfo', {songID: songID}, function(err, resp, body) { req.gdRequest('getGJSongInfo', {songID: songID}, function(err, resp, body) {
if (err) return res.send('-1') if (err) return res.status(400).send('-1')
else if (body < 0) return res.send(false) else if (body < 0) return res.send(false)
request.get('https://www.newgrounds.com/audio/listen/' + songID, function(err2, resp2, song) { request.get('https://www.newgrounds.com/audio/listen/' + songID, function(err2, resp2, song) {
return res.send(resp2.statusCode == 200) console.log(resp2.statusCode)
return res.status(200).send(resp2.statusCode == 200)
}) })
}) })
} }

View file

@ -184,8 +184,8 @@ app.clean = function(text) {if (!text || typeof text != "string") return text; e
app.use('/assets', express.static(__dirname + '/assets', {maxAge: "7d"})); app.use('/assets', express.static(__dirname + '/assets', {maxAge: "7d"}));
app.use('/assets/css', express.static(__dirname + '/assets/css')); // override maxAge app.use('/assets/css', express.static(__dirname + '/assets/css')); // override maxAge
app.get("/sizecheck.js", function(req, res) { res.sendFile(__dirname + "/misc/sizecheck.js") }) app.get("/sizecheck.js", function(req, res) { res.status(200).sendFile(__dirname + "/misc/sizecheck.js") })
app.get("/dragscroll.js", function(req, res) { res.sendFile(__dirname + "/misc/dragscroll.js") }) app.get("/dragscroll.js", function(req, res) { res.status(200).sendFile(__dirname + "/misc/dragscroll.js") })
app.get("/assets/:dir*?", function(req, res) { app.get("/assets/:dir*?", function(req, res) {
let main = (req.params.dir || "").toLowerCase() let main = (req.params.dir || "").toLowerCase()
@ -193,10 +193,10 @@ app.get("/assets/:dir*?", function(req, res) {
if (dir.includes('.') || !req.path.endsWith("/")) { if (dir.includes('.') || !req.path.endsWith("/")) {
if (!req.params[0]) main = "" if (!req.params[0]) main = ""
if (req.params.dir == "deatheffects" || req.params.dir == "trails") return res.sendFile(__dirname + "/assets/deatheffects/0.png") if (req.params.dir == "deatheffects" || req.params.dir == "trails") return res.status(200).sendFile(__dirname + "/assets/deatheffects/0.png")
else if (req.params.dir == "gdps" && req.params[0].endsWith("_icon.png")) return res.sendFile(__dirname + "/assets/gdps/unknown_icon.png") else if (req.params.dir == "gdps" && req.params[0].endsWith("_icon.png")) return res.status(200).sendFile(__dirname + "/assets/gdps/unknown_icon.png")
else if (req.params.dir == "gdps" && req.params[0].endsWith("_logo.png")) return res.sendFile(__dirname + "/assets/gdps/unknown_logo.png") else if (req.params.dir == "gdps" && req.params[0].endsWith("_logo.png")) return res.status(200).sendFile(__dirname + "/assets/gdps/unknown_logo.png")
return res.send(`<p style="font-size: 20px; font-family: aller, helvetica, arial">Looks like this file doesn't exist ¯\\_(ツ)_/¯<br><a href='/assets/${main}'>View directory listing for <b>/assets/${main}</b></a></p>`) return res.status(404).send(`<p style="font-size: 20px; font-family: aller, helvetica, arial">Looks like this file doesn't exist ¯\\_(ツ)_/¯<br><a href='/assets/${main}'>View directory listing for <b>/assets/${main}</b></a></p>`)
} }
let path = `./assets/${dir}` let path = `./assets/${dir}`
@ -205,7 +205,7 @@ app.get("/assets/:dir*?", function(req, res) {
assetPage = fs.readFileSync('./html/assets.html', 'utf8') assetPage = fs.readFileSync('./html/assets.html', 'utf8')
let assetData = JSON.stringify({files: files.filter(x => x.includes('.')), directories: files.filter(x => !x.includes('.'))}) let assetData = JSON.stringify({files: files.filter(x => x.includes('.')), directories: files.filter(x => !x.includes('.'))})
res.send(assetPage.replace('{NAME}', dir || "assets").replace('{DATA}', assetData)) res.status(200).send(assetPage.replace('{NAME}', dir || "assets").replace('{DATA}', assetData))
}) })
@ -230,7 +230,7 @@ let downloadDisabled = ['daily', 'weekly']
let gdpsHide = ['achievements', 'messages'] let gdpsHide = ['achievements', 'messages']
app.get("/", function(req, res) { app.get("/", function(req, res) {
if (req.query.hasOwnProperty("offline") || (req.offline && !req.query.hasOwnProperty("home"))) res.sendFile(__dirname + "/html/offline.html") if (req.query.hasOwnProperty("offline") || (req.offline && !req.query.hasOwnProperty("home"))) res.status(200).sendFile(__dirname + "/html/offline.html")
else { else {
fs.readFile('./html/home.html', 'utf8', function (err, data) { fs.readFile('./html/home.html', 'utf8', function (err, data) {
let html = data; let html = data;
@ -249,26 +249,26 @@ app.get("/", function(req, res) {
html = html.replace('id="dl" style="display: none', 'style="display: block') html = html.replace('id="dl" style="display: none', 'style="display: block')
.replace('No active <span id="noLevel">daily</span> level!', '[Blocked by RobTop]') .replace('No active <span id="noLevel">daily</span> level!', '[Blocked by RobTop]')
} }
return res.send(html) return res.status(200).send(html)
}) })
} }
}) })
app.get("/achievements", function(req, res) { res.sendFile(__dirname + "/html/achievements.html") }) app.get("/achievements", function(req, res) { res.status(200).sendFile(__dirname + "/html/achievements.html") })
app.get("/analyze/:id", function(req, res) { res.sendFile(__dirname + "/html/analyze.html") }) app.get("/analyze/:id", function(req, res) { res.status(200).sendFile(__dirname + "/html/analyze.html") })
app.get("/api", function(req, res) { res.sendFile(__dirname + "/html/api.html") }) app.get("/api", function(req, res) { res.status(200).sendFile(__dirname + "/html/api.html") })
app.get("/boomlings", function(req, res) { res.sendFile(__dirname + "/html/boomlings.html") }) app.get("/boomlings", function(req, res) { res.status(200).sendFile(__dirname + "/html/boomlings.html") })
app.get("/comments/:id", function(req, res) { res.sendFile(__dirname + "/html/comments.html") }) app.get("/comments/:id", function(req, res) { res.status(200).sendFile(__dirname + "/html/comments.html") })
app.get("/demon/:id", function(req, res) { res.sendFile(__dirname + "/html/demon.html") }) app.get("/demon/:id", function(req, res) { res.status(200).sendFile(__dirname + "/html/demon.html") })
app.get("/gauntlets", function(req, res) { res.sendFile(__dirname + "/html/gauntlets.html") }) app.get("/gauntlets", function(req, res) { res.status(200).sendFile(__dirname + "/html/gauntlets.html") })
app.get("/gdps", function(req, res) { res.sendFile(__dirname + "/html/gdps.html") }) app.get("/gdps", function(req, res) { res.status(200).sendFile(__dirname + "/html/gdps.html") })
app.get("/iconkit", function(req, res) { res.sendFile(__dirname + "/html/iconkit.html") }) app.get("/iconkit", function(req, res) { res.status(200).sendFile(__dirname + "/html/iconkit.html") })
app.get("/leaderboard", function(req, res) { res.sendFile(__dirname + "/html/leaderboard.html") }) app.get("/leaderboard", function(req, res) { res.status(200).sendFile(__dirname + "/html/leaderboard.html") })
app.get("/leaderboard/:text", function(req, res) { res.sendFile(__dirname + "/html/levelboard.html") }) app.get("/leaderboard/:text", function(req, res) { res.status(200).sendFile(__dirname + "/html/levelboard.html") })
app.get("/mappacks", function(req, res) { res.sendFile(__dirname + "/html/mappacks.html") }) app.get("/mappacks", function(req, res) { res.status(200).sendFile(__dirname + "/html/mappacks.html") })
app.get("/messages", function(req, res) { res.sendFile(__dirname + "/html/messages.html") }) app.get("/messages", function(req, res) { res.status(200).sendFile(__dirname + "/html/messages.html") })
app.get("/search", function(req, res) { res.sendFile(__dirname + "/html/filters.html") }) app.get("/search", function(req, res) { res.status(200).sendFile(__dirname + "/html/filters.html") })
app.get("/search/:text", function(req, res) { res.sendFile(__dirname + "/html/search.html") }) app.get("/search/:text", function(req, res) { res.status(200).sendFile(__dirname + "/html/search.html") })
// API // API
@ -276,7 +276,7 @@ app.get("/search/:text", function(req, res) { res.sendFile(__dirname + "/html/se
app.get("/api/analyze/:id", RL, function(req, res) { app.run.level(app, req, res, true, true) }) app.get("/api/analyze/:id", RL, function(req, res) { app.run.level(app, req, res, true, true) })
app.get("/api/boomlings", function(req, res) { app.run.boomlings(app, req, res) }) app.get("/api/boomlings", function(req, res) { app.run.boomlings(app, req, res) })
app.get("/api/comments/:id", RL2, function(req, res) { app.run.comments(app, req, res) }) app.get("/api/comments/:id", RL2, function(req, res) { app.run.comments(app, req, res) })
app.get("/api/credits", function(req, res) { res.send(require('./misc/credits.json')) }) app.get("/api/credits", function(req, res) { res.status(200).send(require('./misc/credits.json')) })
app.get("/api/gauntlets", function(req, res) { app.run.gauntlets(app, req, res) }) app.get("/api/gauntlets", function(req, res) { app.run.gauntlets(app, req, res) })
app.get("/api/leaderboard", function(req, res) { app.run[req.query.hasOwnProperty("accurate") ? "accurate" : "scores"](app, req, res) }) app.get("/api/leaderboard", function(req, res) { app.run[req.query.hasOwnProperty("accurate") ? "accurate" : "scores"](app, req, res) })
app.get("/api/leaderboardLevel/:id", RL2, function(req, res) { app.run.leaderboardLevel(app, req, res) }) app.get("/api/leaderboardLevel/:id", RL2, function(req, res) { app.run.leaderboardLevel(app, req, res) })
@ -310,24 +310,23 @@ app.get("/:id", function(req, res) { app.run.level(app, req, res) })
// MISC // MISC
app.get("/icon/:text", function(req, res) { app.run.icon(app, req, res) }) app.get("/icon/:text", function(req, res) { app.run.icon(app, req, res) })
app.get("/api/userCache", function(req, res) { res.send(app.accountCache) }) app.get("/api/userCache", function(req, res) { res.status(200).send(app.accountCache) })
app.get("/api/achievements", function(req, res) { res.send({achievements, types: achievementTypes, shopIcons, colors: colorList }) }) app.get("/api/achievements", function(req, res) { res.status(200).send({achievements, types: achievementTypes, shopIcons, colors: colorList }) })
app.get("/api/music", function(req, res) { res.send(music) }) app.get("/api/music", function(req, res) { res.status(200).send(music) })
app.get("/api/gdps", function(req, res) {res.send(req.query.hasOwnProperty("current") ? app.safeServers.find(x => req.server.id == x.id) : app.safeServers) }) app.get("/api/gdps", function(req, res) {res.status(200).send(req.query.hasOwnProperty("current") ? app.safeServers.find(x => req.server.id == x.id) : app.safeServers) })
app.get('/api/icons', function(req, res) { app.get('/api/icons', function(req, res) {
let sample = [JSON.stringify(sampleIcons[Math.floor(Math.random() * sampleIcons.length)].slice(1))] let sample = [JSON.stringify(sampleIcons[Math.floor(Math.random() * sampleIcons.length)].slice(1))]
let iconserver = req.isGDPS ? req.server.name : undefined let iconserver = req.isGDPS ? req.server.name : undefined
res.send({icons: gdIcons, colors: colorList, colorOrder, whiteIcons, server: iconserver, noCopy: req.onePointNine || req.offline, sample}); res.status(200).send({icons: gdIcons, colors: colorList, colorOrder, whiteIcons, server: iconserver, noCopy: req.onePointNine || req.offline, sample});
}); });
app.get('*', function(req, res) { app.get('*', function(req, res) {
if (req.path.startsWith('/api')) res.send('-1') if (req.path.startsWith('/api')) res.status(404).send('-1')
else res.redirect('/search/404%20') else res.redirect('/search/404%20')
}); });
app.use(function (err, req, res, next) { app.use(function (err, req, res, next) {
if (err && err.message == "Response timeout") res.status(500).send('Internal server error! (Timed out)') if (err && err.message == "Response timeout") res.status(504).send('Internal server error! (Timed out)')
else if (err) console.log(err)
}) })
process.on('uncaughtException', (e) => { console.log(e) }); process.on('uncaughtException', (e) => { console.log(e) });

View file

@ -4,6 +4,9 @@
"main": "index.js", "main": "index.js",
"license": "MIT", "license": "MIT",
"private": true, "private": true,
"scripts": {
"dev": "node ./index.js"
},
"dependencies": { "dependencies": {
"ag-psd": "^14.3.2", "ag-psd": "^14.3.2",
"canvas": "^2.8.0", "canvas": "^2.8.0",

View file

@ -26,7 +26,6 @@
"targetAccountID": "targetBddpvouKE" "targetAccountID": "targetBddpvouKE"
} }
}, },
{ {
"name": "1.9 GDPS", "name": "1.9 GDPS",
"link": "https://absolllute.com/gdps/", "link": "https://absolllute.com/gdps/",