A lot of refactoring, and etc #232
9 changed files with 231 additions and 233 deletions
214
api/analyze.js
214
api/analyze.js
|
@ -17,18 +17,18 @@ module.exports = async (app, req, res, level) => {
|
|||
let levelString = unencrypted ? level.data : Buffer.from(level.data, 'base64')
|
||||
|
||||
if (unencrypted) {
|
||||
const raw_data = level.data;
|
||||
|
||||
const response_data = analyze_level(level, raw_data);
|
||||
return res.send(response_data);
|
||||
} else {
|
||||
const raw_data = level.data
|
||||
const response_data = analyze_level(level, raw_data)
|
||||
return res.send(response_data)
|
||||
}
|
||||
else {
|
||||
zlib.unzip(levelString, (err, buffer) => {
|
||||
if (err) { return res.status(500).send("-2"); }
|
||||
if (err) return res.status(500).send("-2")
|
||||
|
||||
const raw_data = buffer.toString();
|
||||
const response_data = analyze_level(level, raw_data);
|
||||
return res.send(response_data);
|
||||
});
|
||||
const raw_data = buffer.toString()
|
||||
const response_data = analyze_level(level, raw_data)
|
||||
return res.send(response_data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,22 +40,22 @@ function sortObj(obj, sortBy) {
|
|||
}
|
||||
|
||||
function parse_obj(obj, splitter, name_arr, valid_only) {
|
||||
const s_obj = obj.split(splitter);
|
||||
let robtop_obj = {};
|
||||
const s_obj = obj.split(splitter)
|
||||
let robtop_obj = {}
|
||||
|
||||
// semi-useless optimization depending on where at node js you're at
|
||||
for (let i = 0, obj_l = s_obj.length; i < obj_l; i += 2) {
|
||||
let k_name = s_obj[i];
|
||||
let k_name = s_obj[i]
|
||||
if (s_obj[i] in name_arr) {
|
||||
if (!valid_only) k_name = name_arr[s_obj[i]];
|
||||
robtop_obj[k_name] = s_obj[i + 1];
|
||||
if (!valid_only) k_name = name_arr[s_obj[i]]
|
||||
robtop_obj[k_name] = s_obj[i + 1]
|
||||
}
|
||||
}
|
||||
return robtop_obj;
|
||||
return robtop_obj
|
||||
}
|
||||
|
||||
function analyze_level(level, rawData) {
|
||||
let response = {};
|
||||
let response = {}
|
||||
|
||||
let blockCounts = {}
|
||||
let miscCounts = {}
|
||||
|
@ -63,62 +63,58 @@ function analyze_level(level, rawData) {
|
|||
let highDetail = 0
|
||||
let alphaTriggers = []
|
||||
|
||||
let misc_objects = {};
|
||||
let block_ids = {};
|
||||
let misc_objects = {}
|
||||
let block_ids = {}
|
||||
|
||||
for (const [name, object_ids] of Object.entries(ids.misc)) {
|
||||
const copied_ids = object_ids.slice(1);
|
||||
const copied_ids = object_ids.slice(1)
|
||||
// funny enough, shift effects the original id list
|
||||
copied_ids.forEach((object_id) => {
|
||||
misc_objects[object_id] = name;
|
||||
});
|
||||
copied_ids.forEach(object_id => { misc_objects[object_id] = name })
|
||||
}
|
||||
|
||||
for (const [name, object_ids] of Object.entries(blocks)) {
|
||||
object_ids.forEach((object_id) => {
|
||||
block_ids[object_id] = name;
|
||||
});
|
||||
object_ids.forEach(object_id => { block_ids[object_id] = name })
|
||||
}
|
||||
|
||||
const data = rawData.split(";");
|
||||
const header = data.shift();
|
||||
const data = rawData.split(";")
|
||||
const header = data.shift()
|
||||
|
||||
let level_portals = [];
|
||||
let level_coins = [];
|
||||
let level_text = [];
|
||||
let level_portals = []
|
||||
let level_coins = []
|
||||
let level_text = []
|
||||
|
||||
let orb_array = {};
|
||||
let trigger_array = {};
|
||||
let orb_array = {}
|
||||
let trigger_array = {}
|
||||
|
||||
let last = 0
|
||||
|
||||
const obj_length = data.length;
|
||||
const obj_length = data.length
|
||||
for (let i = 0; i < obj_length; ++i) {
|
||||
obj = parse_obj(data[i], ',', properties);
|
||||
obj = parse_obj(data[i], ',', properties)
|
||||
|
||||
let id = obj.id
|
||||
|
||||
if (id in ids.portals) {
|
||||
obj.portal = ids.portals[id];
|
||||
level_portals.push(obj);
|
||||
obj.portal = ids.portals[id]
|
||||
level_portals.push(obj)
|
||||
} else if (id in ids.coins) {
|
||||
obj.coin = ids.coins[id];
|
||||
level_coins.push(obj);
|
||||
obj.coin = ids.coins[id]
|
||||
level_coins.push(obj)
|
||||
} else if (id in ids.orbs) {
|
||||
obj.orb = ids.orbs[id];
|
||||
obj.orb = ids.orbs[id]
|
||||
|
||||
if (obj.orb in orb_array) {
|
||||
orb_array[obj.orb]++;
|
||||
orb_array[obj.orb]++
|
||||
} else {
|
||||
orb_array[obj.orb] = 1;
|
||||
orb_array[obj.orb] = 1
|
||||
}
|
||||
} else if (id in ids.triggers) {
|
||||
obj.trigger = ids.triggers[id];
|
||||
obj.trigger = ids.triggers[id]
|
||||
|
||||
if (obj.trigger in trigger_array) {
|
||||
trigger_array[obj.trigger]++;
|
||||
trigger_array[obj.trigger]++
|
||||
} else {
|
||||
trigger_array[obj.trigger] = 1;
|
||||
trigger_array[obj.trigger] = 1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,32 +126,30 @@ function analyze_level(level, rawData) {
|
|||
if (obj.highDetail == 1) highDetail++
|
||||
|
||||
if (id in misc_objects) {
|
||||
const name = misc_objects[id];
|
||||
const name = misc_objects[id]
|
||||
if (name in miscCounts) {
|
||||
miscCounts[name][0] += 1;
|
||||
miscCounts[name][0] += 1
|
||||
} else {
|
||||
miscCounts[name] = [1, ids.misc[name][0]];
|
||||
miscCounts[name] = [1, ids.misc[name][0]]
|
||||
}
|
||||
}
|
||||
|
||||
if (id in block_ids) {
|
||||
const name = block_ids[id];
|
||||
const name = block_ids[id]
|
||||
if (name in blockCounts) {
|
||||
blockCounts[name] += 1;
|
||||
blockCounts[name]++
|
||||
} else {
|
||||
blockCounts[name] = 1;
|
||||
blockCounts[name] = 1
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.x) { // sometimes the field doesn't exist
|
||||
last = Math.max(last, obj.x);
|
||||
}
|
||||
// sometimes the field doesn't exist
|
||||
if (obj.x) last = Math.max(last, obj.x)
|
||||
|
||||
if (obj.trigger == "Alpha") { // invisible triggers
|
||||
alphaTriggers.push(obj)
|
||||
}
|
||||
// invisible triggers
|
||||
if (obj.trigger == "Alpha") alphaTriggers.push(obj)
|
||||
|
||||
data[i] = obj;
|
||||
data[i] = obj
|
||||
}
|
||||
|
||||
let invisTriggers = []
|
||||
|
@ -166,7 +160,7 @@ function analyze_level(level, rawData) {
|
|||
&& tr.opacity == 0 && tr.duration == 0
|
||||
&& alphaTriggers.filter(x => x.targetGroupID == tr.targetGroupID).length == 1
|
||||
)
|
||||
invisTriggers.push(Number(tr.targetGroupID));
|
||||
invisTriggers.push(Number(tr.targetGroupID))
|
||||
})
|
||||
|
||||
response.level = {};
|
||||
|
@ -176,15 +170,18 @@ function analyze_level(level, rawData) {
|
|||
response.highDetail = highDetail
|
||||
response.settings = {}
|
||||
|
||||
response.portals = level_portals.sort(function (a, b) {return parseInt(a.x) - parseInt(b.x)}).map(x => x.portal + " " + Math.floor(x.x / (Math.max(last, 529.0) + 340.0) * 100) + "%").join(", ")
|
||||
response.coins = level_coins.sort(function (a, b) {return parseInt(a.x) - parseInt(b.x)}).map(x => Math.floor(x.x / (Math.max(last, 529.0) + 340.0) * 100))
|
||||
// I have no idea what to name this lmao
|
||||
let WTF = x => Math.floor(x.x / (Math.max(last, 529) + 340) * 100)
|
||||
response.portals = level_portals.sort((a, b) => parseInt(a.x) - parseInt(b.x)).map(x => x.portal + " " + WTF(x) + "%").join(", ")
|
||||
response.coins = level_coins.sort((a, b) => parseInt(a.x) - parseInt(b.x)).map(WTF)
|
||||
response.coinsVerified = level.verifiedCoins
|
||||
|
||||
let sum = arr => arr.reduce((a, x) => a + x, 0)
|
||||
response.orbs = orb_array
|
||||
response.orbs.total = Object.values(orb_array).reduce((a, x) => a + x, 0); // we already have an array of objects, use it
|
||||
response.orbs.total = sum(Object.values(orb_array)) // we already have an array of objects, use it
|
||||
|
||||
response.triggers = trigger_array
|
||||
response.triggers.total = Object.values(trigger_array).reduce((a, x) => a + x, 0);
|
||||
response.triggers.total = sum(Object.values(trigger_array))
|
||||
|
||||
response.triggerGroups = {}
|
||||
response.blocks = sortObj(blockCounts)
|
||||
|
@ -203,24 +200,24 @@ function analyze_level(level, rawData) {
|
|||
// find alpha group with the most objects
|
||||
response.invisibleGroup = triggerKeys.find(x => invisTriggers.includes(x))
|
||||
|
||||
response.text = level_text.sort(function (a, b) {return parseInt(a.x) - parseInt(b.x)}).map(x => [Buffer.from(x.message, 'base64').toString(), Math.round(x.x / last * 99) + "%"])
|
||||
response.text = level_text.sort((a, b) => parseInt(a.x) - parseInt(b.x)).map(x => [Buffer.from(x.message, 'base64').toString(), Math.round(x.x / last * 99) + "%"])
|
||||
|
||||
const header_response = parse_header(header);
|
||||
response.settings = header_response.settings;
|
||||
response.colors = header_response.colors;
|
||||
const header_response = parse_header(header)
|
||||
response.settings = header_response.settings
|
||||
response.colors = header_response.colors
|
||||
|
||||
response.dataLength = rawData.length
|
||||
response.data = rawData
|
||||
|
||||
return response;
|
||||
return response
|
||||
}
|
||||
|
||||
function parse_header(header) {
|
||||
let response = {};
|
||||
response.settings = {};
|
||||
response.colors = [];
|
||||
let response = {}
|
||||
response.settings = {}
|
||||
response.colors = []
|
||||
|
||||
const header_keyed = parse_obj(header, ',', init.values, true);
|
||||
const header_keyed = parse_obj(header, ',', init.values, true)
|
||||
|
||||
Object.keys(header_keyed).forEach(x => {
|
||||
let val = init.values[x]
|
||||
|
@ -229,41 +226,38 @@ function parse_header(header) {
|
|||
switch (val[1]) {
|
||||
case 'list':
|
||||
val = init[(val[0] + "s")][property];
|
||||
break;
|
||||
break
|
||||
case 'number':
|
||||
val = Number(property);
|
||||
break;
|
||||
break
|
||||
case 'bump':
|
||||
val = Number(property) + 1;
|
||||
break;
|
||||
break
|
||||
case 'bool':
|
||||
val = property != "0";
|
||||
break;
|
||||
break
|
||||
case 'extra-legacy-color': { // scope?
|
||||
// you can only imagine my fear when i discovered this was a thing
|
||||
// these literally are keys set the value, and to convert this to the color list we have to do this fun messy thing that shouldn't exist
|
||||
// since i wrote the 1.9 color before this, a lot of explaination will be there instead
|
||||
const colorInfo = name.split('-');
|
||||
const color = colorInfo[2]; // r,g,b
|
||||
const channel = colorInfo[1];
|
||||
const colorInfo = name.split('-')
|
||||
const color = colorInfo[2] // r,g,b
|
||||
const channel = colorInfo[1]
|
||||
|
||||
// first we create the color object
|
||||
if (color == 'r') response.colors.push({"channel": channel, "opacity": 1})
|
||||
|
||||
if (color == 'r') {
|
||||
// first we create the color object
|
||||
response.colors.push({"channel": channel, "opacity": 1});
|
||||
}
|
||||
// from here we touch the color object
|
||||
let currentChannel = response.colors.find(k => k.channel == channel);
|
||||
if (color == 'blend') {
|
||||
currentChannel.blending = true; // only one color has blending though lol
|
||||
} else if (color == 'pcol' && property != 0) {
|
||||
currentChannel.pColor = property;
|
||||
}
|
||||
currentChannel[color] = property;
|
||||
break;
|
||||
let currentChannel = response.colors.find(k => k.channel == channel)
|
||||
if (color == 'blend') currentChannel.blending = true // only one color has blending though lol
|
||||
else if (color == 'pcol' && property != 0) currentChannel.pColor = property
|
||||
|
||||
currentChannel[color] = property
|
||||
break
|
||||
}
|
||||
case 'legacy-color': {
|
||||
// if a level has a legacy color, we can assume that it does not have a kS38 at all
|
||||
const color = parse_obj(property, "_", colorStuff.properties);
|
||||
const color = parse_obj(property, "_", colorStuff.properties)
|
||||
|
||||
let colorObj = color
|
||||
|
||||
|
@ -275,15 +269,15 @@ function parse_header(header) {
|
|||
colorObj.channel = colorVal
|
||||
|
||||
// from here stuff can continue as normal, ish
|
||||
if (colorObj.pColor == "-1" || colorObj.pColor == "0") delete colorObj.pColor;
|
||||
colorObj.opacity = 1; // 1.9 colors don't have this!
|
||||
if (colorObj.blending && colorObj.blending == '1') colorObj.blending = true; // 1.9 colors manage to always think they're blending - they're not
|
||||
else delete colorObj.blending;
|
||||
if (colorObj.pColor == "-1" || colorObj.pColor == "0") delete colorObj.pColor
|
||||
colorObj.opacity = 1 // 1.9 colors don't have this!
|
||||
if (colorObj.blending && colorObj.blending == '1') colorObj.blending = true // 1.9 colors manage to always think they're blending - they're not
|
||||
else delete colorObj.blending
|
||||
|
||||
if (colorVal == '3DL') { response.colors.splice(4, 0, colorObj); } // hardcode the position of 3DL, it typically goes at the end due to how RobTop make the headers
|
||||
else if (colorVal == 'Line') { colorObj.blending = true; response.colors.push(colorObj); } // in line with 2.1 behavior
|
||||
else { response.colors.push(colorObj); } // bruh whatever was done to make the color list originally was long
|
||||
break;
|
||||
if (colorVal == '3DL') response.colors.splice(4, 0, colorObj) // hardcode the position of 3DL, it typically goes at the end due to how RobTop make the headers
|
||||
else if (colorVal == 'Line') { colorObj.blending = true; response.colors.push(colorObj) } // in line with 2.1 behavior
|
||||
else response.colors.push(colorObj) // bruh whatever was done to make the color list originally was long
|
||||
break
|
||||
}
|
||||
case 'colors': {
|
||||
let colorList = property.split("|")
|
||||
|
@ -293,9 +287,9 @@ function parse_header(header) {
|
|||
if (!color.channel) return colorList = colorList.filter((h, i) => y != i)
|
||||
|
||||
if (colorStuff.channels[colorObj.channel]) colorObj.channel = colorStuff.channels[colorObj.channel]
|
||||
if (colorObj.channel > 1000) return;
|
||||
if (colorObj.channel > 1000) return
|
||||
if (colorStuff.channels[colorObj.copiedChannel]) colorObj.copiedChannel = colorStuff.channels[colorObj.copiedChannel]
|
||||
if (colorObj.copiedChannel > 1000) delete colorObj.copiedChannel;
|
||||
if (colorObj.copiedChannel > 1000) delete colorObj.copiedChannel
|
||||
if (colorObj.pColor == "-1") delete colorObj.pColor
|
||||
if (colorObj.blending) colorObj.blending = true
|
||||
if (colorObj.copiedHSV) {
|
||||
|
@ -308,16 +302,16 @@ function parse_header(header) {
|
|||
}
|
||||
colorObj.opacity = +Number(colorObj.opacity).toFixed(2)
|
||||
colorList[y] = colorObj
|
||||
});
|
||||
})
|
||||
// we assume this is only going to be run once so... some stuff can go here
|
||||
colorList = colorList.filter(x => typeof x == "object")
|
||||
if (!colorList.find(x => x.channel == "Obj")) colorList.push({"r": "255", "g": "255", "b": "255", "channel": "Obj", "opacity": "1"})
|
||||
|
||||
const specialSort = ["BG", "G", "G2", "Line", "Obj", "3DL"]
|
||||
let specialColors = colorList.filter(x => isNaN(x.channel)).sort(function (a, b) {return specialSort.indexOf( a.channel ) > specialSort.indexOf( b.channel ) } )
|
||||
let regularColors = colorList.filter(x => !isNaN(x.channel)).sort(function(a, b) {return (+a.channel) - (+b.channel) } );
|
||||
let specialColors = colorList.filter(x => isNaN(x.channel)).sort((a, b) => specialSort.indexOf(a.channel) > specialSort.indexOf(b.channel))
|
||||
let regularColors = colorList.filter(x => !isNaN(x.channel)).sort((a, b) => +a.channel - +b.channel)
|
||||
response.colors = specialColors.concat(regularColors)
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
response.settings[name] = val
|
||||
|
@ -332,9 +326,9 @@ function parse_header(header) {
|
|||
|
||||
Object.keys(response.settings).filter(k => {
|
||||
// this should be parsed into color list instead
|
||||
if (k.includes('legacy')) delete response.settings[k];
|
||||
});
|
||||
if (k.includes('legacy')) delete response.settings[k]
|
||||
})
|
||||
|
||||
delete response.settings['colors'];
|
||||
return response;
|
||||
delete response.settings['colors']
|
||||
return response
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"use strict";
|
||||
const Player = require('../classes/Player.js')
|
||||
|
||||
module.exports = async (app, req, res) => {
|
||||
|
@ -8,8 +9,8 @@ module.exports = async (app, req, res) => {
|
|||
if (count > 1000) count = 1000
|
||||
|
||||
let params = {
|
||||
userID : req.params.id,
|
||||
accountID : req.params.id,
|
||||
userID : req.params.id,
|
||||
accountID : req.params.id,
|
||||
levelID: req.params.id,
|
||||
page: +req.query.page || 0,
|
||||
count,
|
||||
|
@ -20,7 +21,7 @@ module.exports = async (app, req, res) => {
|
|||
if (req.query.type == "commentHistory") { path = "getGJCommentHistory"; delete params.levelID }
|
||||
else if (req.query.type == "profile") path = "getGJAccountComments20"
|
||||
|
||||
req.gdRequest(path, req.gdParams(params), function(err, resp, body) {
|
||||
req.gdRequest(path, req.gdParams(params), function(err, resp, body) {
|
||||
|
||||
if (err) return res.sendError()
|
||||
|
||||
|
@ -32,7 +33,7 @@ module.exports = async (app, req, res) => {
|
|||
if (!comments.length) return res.status(204).send([])
|
||||
|
||||
let pages = body.split('#')[1].split(":")
|
||||
let lastPage = +Math.ceil(+pages[0] / +pages[2]);
|
||||
let lastPage = +Math.ceil(+pages[0] / +pages[2])
|
||||
|
||||
let commentArray = []
|
||||
|
||||
|
@ -41,7 +42,7 @@ module.exports = async (app, req, res) => {
|
|||
var x = c[0] //comment info
|
||||
var y = c[1] //account info
|
||||
|
||||
if (!x[2]) return;
|
||||
if (!x[2]) return
|
||||
|
||||
let comment = {}
|
||||
comment.content = Buffer.from(x[2], 'base64').toString();
|
||||
|
@ -50,9 +51,9 @@ module.exports = async (app, req, res) => {
|
|||
comment.date = (x[9] || "?") + req.timestampSuffix
|
||||
if (comment.content.endsWith("⍟") || comment.content.endsWith("☆")) {
|
||||
comment.content = comment.content.slice(0, -1)
|
||||
comment.browserColor = true
|
||||
comment.browserColor = true
|
||||
}
|
||||
|
||||
|
||||
if (req.query.type != "profile") {
|
||||
let commentUser = new Player(y)
|
||||
Object.keys(commentUser).forEach(k => {
|
||||
|
@ -74,7 +75,7 @@ module.exports = async (app, req, res) => {
|
|||
|
||||
commentArray.push(comment)
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
return res.send(commentArray)
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"use strict";
|
||||
const request = require('request')
|
||||
const fs = require('fs')
|
||||
const Level = require('../classes/Level.js')
|
||||
|
@ -5,27 +6,27 @@ const Level = require('../classes/Level.js')
|
|||
module.exports = async (app, req, res, api, ID, analyze) => {
|
||||
|
||||
function rejectLevel() {
|
||||
if (!api) return res.redirect('search/' + req.params.id)
|
||||
else return res.sendError()
|
||||
return !api ? res.redirect('search/' + req.params.id) : res.sendError()
|
||||
}
|
||||
|
||||
if (req.offline) {
|
||||
if (!api && levelID < 0) return res.redirect('/')
|
||||
return rejectLevel()
|
||||
return !api && levelID < 0 ? res.redirect('/') : rejectLevel()
|
||||
}
|
||||
|
||||
let levelID = ID || req.params.id
|
||||
if (levelID == "daily") levelID = -1
|
||||
else if (levelID == "weekly") levelID = -2
|
||||
else levelID = levelID.replace(/[^0-9]/g, "")
|
||||
levelID = (
|
||||
levelID == "daily" ? -1 :
|
||||
levelID == "weekly" ? -2 :
|
||||
levelID.replace(/\D/g, "")
|
||||
)
|
||||
|
||||
req.gdRequest('downloadGJLevel22', { levelID }, function (err, resp, body) {
|
||||
|
||||
if (err) {
|
||||
if (analyze && api && req.server.downloadsDisabled) return res.status(403).send("-3")
|
||||
else if (!api && levelID < 0) return res.redirect(`/?daily=${levelID * -1}`)
|
||||
else return rejectLevel()
|
||||
}
|
||||
if (err) return (
|
||||
analyze && api && req.server.downloadsDisabled ? res.status(403).send("-3")
|
||||
: !api && levelID < 0 ? res.redirect(`/?daily=${levelID * -1}`)
|
||||
: rejectLevel()
|
||||
)
|
||||
|
||||
let authorData = body.split("#")[3] // daily/weekly only, most likely
|
||||
|
||||
|
@ -72,7 +73,7 @@ module.exports = async (app, req, res, api, ID, analyze) => {
|
|||
if (api) return res.send(level)
|
||||
|
||||
else return fs.readFile('./html/level.html', 'utf8', function (err, data) {
|
||||
let html = data;
|
||||
let html = data
|
||||
let variables = Object.keys(level)
|
||||
variables.forEach(x => {
|
||||
let regex = new RegExp(`\\[\\[${x.toUpperCase()}\\]\\]`, "g")
|
||||
|
@ -89,7 +90,7 @@ module.exports = async (app, req, res, api, ID, analyze) => {
|
|||
level.nextDaily = +dailyTime
|
||||
level.nextDailyTimestamp = Math.round((Date.now() + (+dailyTime * 1000)) / 100000) * 100000
|
||||
return sendLevel()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
else if (req.server.demonList && level.difficulty == "Extreme Demon") {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"use strict";
|
||||
let cache = {}
|
||||
let gauntletNames = ["Fire", "Ice", "Poison", "Shadow", "Lava", "Bonus", "Chaos", "Demon", "Time", "Crystal", "Magic", "Spike", "Monster", "Doom", "Death"]
|
||||
|
||||
|
@ -6,7 +7,8 @@ module.exports = async (app, req, res) => {
|
|||
if (req.offline) return res.sendError()
|
||||
|
||||
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.send(cached.data) // half hour cache
|
||||
|
||||
req.gdRequest('getGJGauntlets21', {}, function (err, resp, body) {
|
||||
|
||||
|
@ -14,9 +16,10 @@ module.exports = async (app, req, res) => {
|
|||
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(",") }))
|
||||
|
||||
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)
|
||||
|
||||
})
|
||||
|
||||
|
||||
}
|
19
api/level.js
19
api/level.js
|
@ -1,3 +1,4 @@
|
|||
"use strict";
|
||||
const request = require('request')
|
||||
const fs = require('fs')
|
||||
const Level = require('../classes/Level.js')
|
||||
|
@ -5,17 +6,14 @@ const Level = require('../classes/Level.js')
|
|||
module.exports = async (app, req, res, api, analyze) => {
|
||||
|
||||
function rejectLevel() {
|
||||
if (!api) return res.redirect('search/' + req.params.id)
|
||||
else return res.sendError()
|
||||
return !api ? res.redirect('search/' + req.params.id) : res.sendError()
|
||||
}
|
||||
|
||||
if (req.offline) return rejectLevel()
|
||||
|
||||
let levelID = req.params.id
|
||||
if (levelID == "daily") return app.run.download(app, req, res, api, 'daily', analyze)
|
||||
else if (levelID == "weekly") return app.run.download(app, req, res, api, 'weekly', analyze)
|
||||
else if (levelID.match(/[^0-9]/)) return rejectLevel()
|
||||
else levelID = levelID.replace(/[^0-9]/g, "")
|
||||
if (levelID == "daily" || levelID == "weekly") return app.run.download(app, req, res, api, levelID, analyze)
|
||||
else if (/\D/.test(levelID)) return rejectLevel()
|
||||
|
||||
if (analyze || req.query.hasOwnProperty("download")) return app.run.download(app, req, res, api, levelID, analyze)
|
||||
|
||||
|
@ -23,9 +21,10 @@ module.exports = async (app, req, res, api, analyze) => {
|
|||
|
||||
if (err || body.startsWith("##")) return rejectLevel()
|
||||
|
||||
let preRes = body.split('#')[0].split('|', 10)
|
||||
let author = body.split('#')[1].split('|')[0].split(':')
|
||||
let song = '~' + body.split('#')[2];
|
||||
const bodySplit = body.split('#') // IDK how to name it lol -Rudxain
|
||||
let preRes = bodySplit[0].split('|', 10)
|
||||
let author = bodySplit[1].split('|')[0].split(':')
|
||||
let song = '~' + bodySplit[2]
|
||||
song = app.parseResponse(song, '~|~')
|
||||
|
||||
let levelInfo = app.parseResponse(preRes.find(x => x.startsWith(`1:${levelID}`)) || preRes[0])
|
||||
|
@ -40,7 +39,7 @@ module.exports = async (app, req, res, api, analyze) => {
|
|||
if (api) return res.send(level)
|
||||
|
||||
else return fs.readFile('./html/level.html', 'utf8', function (err, data) {
|
||||
let html = data;
|
||||
let html = data
|
||||
let filteredSong = level.songName.replace(/[^ -~]/g, "") // strip off unsupported characters
|
||||
level.songName = filteredSong || level.songName
|
||||
let variables = Object.keys(level)
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
"use strict";
|
||||
let difficulties = ["auto", "easy", "normal", "hard", "harder", "insane", "demon", "demon-easy", "demon-medium", "demon-insane", "demon-extreme"]
|
||||
let cache = {}
|
||||
|
||||
module.exports = async (app, req, res) => {
|
||||
|
||||
if (req.offline) return res.sendError()
|
||||
|
||||
|
||||
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.send(cached.data) // 1.5 hour cache
|
||||
let params = { count: 250, page: 0 }
|
||||
let packs = []
|
||||
|
||||
|
@ -23,7 +25,7 @@ module.exports = async (app, req, res) => {
|
|||
params.page++
|
||||
return mapPackLoop()
|
||||
}
|
||||
|
||||
|
||||
let mappacks = packs.map(x => ({ // "packs.map()" laugh now please
|
||||
id: +x[1],
|
||||
name: x[2],
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
"use strict";
|
||||
const fs = require('fs')
|
||||
const Player = require('../classes/Player.js')
|
||||
|
||||
module.exports = async (app, req, res, api, getLevels) => {
|
||||
|
||||
if (req.offline) {
|
||||
if (!api) return res.redirect('/search/' + req.params.id)
|
||||
else return res.sendError()
|
||||
function rejectLevel() {
|
||||
// this variant has an extra "/"
|
||||
return !api ? res.redirect('/search/' + req.params.id) : res.sendError()
|
||||
}
|
||||
|
||||
|
||||
if (req.offline) return rejectLevel()
|
||||
|
||||
let username = getLevels || req.params.id
|
||||
let probablyID
|
||||
if (username.endsWith(".") && req.isGDPS) {
|
||||
|
@ -20,7 +22,7 @@ module.exports = async (app, req, res, api, getLevels) => {
|
|||
let searchResult;
|
||||
|
||||
// if you're searching by account id, an intentional error is caused to skip the first request to the gd servers. see i pulled a sneaky on ya. (fuck callbacks man)
|
||||
req.gdRequest(skipRequest ? "" : 'getGJUsers20', skipRequest ? {} : { str: username, page: 0 }, function (err1, res1, b1) {
|
||||
req.gdRequest(skipRequest ? "" : 'getGJUsers20', skipRequest ? {} : { str: username, page: 0 }, function (err1, res1, b1) {
|
||||
|
||||
if (foundID) searchResult = foundID[0]
|
||||
else if (accountMode || err1 || b1 == '-1' || b1.startsWith("<") || !b1) searchResult = probablyID ? username : req.params.id
|
||||
|
@ -28,7 +30,7 @@ module.exports = async (app, req, res, api, getLevels) => {
|
|||
else { // GDPS's return multiple users, GD no longer does this
|
||||
let userResults = b1.split("|").map(x => app.parseResponse(x))
|
||||
searchResult = userResults.find(x => x[1].toLowerCase() == username.toLowerCase() || x[2] == username) || ""
|
||||
if (searchResult) searchResult = searchResult[16]
|
||||
searchResult &&= searchResult[16]
|
||||
}
|
||||
|
||||
if (getLevels) {
|
||||
|
@ -40,20 +42,17 @@ module.exports = async (app, req, res, api, getLevels) => {
|
|||
|
||||
let account = app.parseResponse(body || "")
|
||||
let dumbGDPSError = req.isGDPS && (!account[16] || account[1].toLowerCase() == "undefined")
|
||||
|
||||
if (err2 || dumbGDPSError) {
|
||||
if (!api) return res.redirect('/search/' + req.params.id)
|
||||
else return res.sendError()
|
||||
}
|
||||
|
||||
|
||||
if (err2 || dumbGDPSError) return rejectLevel()
|
||||
|
||||
if (!foundID) app.userCache(req.id, account[16], account[2], account[1])
|
||||
|
||||
let userData = new Player(account)
|
||||
|
||||
|
||||
let userData = new Player(account)
|
||||
|
||||
if (api) return res.send(userData)
|
||||
|
||||
else fs.readFile('./html/profile.html', 'utf8', function(err, data) {
|
||||
let html = data;
|
||||
let html = data
|
||||
let variables = Object.keys(userData)
|
||||
variables.forEach(x => {
|
||||
let regex = new RegExp(`\\[\\[${x.toUpperCase()}\\]\\]`, "g")
|
||||
|
@ -61,7 +60,6 @@ module.exports = async (app, req, res, api, getLevels) => {
|
|||
})
|
||||
return res.send(html)
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
124
api/search.js
124
api/search.js
|
@ -1,94 +1,92 @@
|
|||
"use strict";
|
||||
const request = require('request')
|
||||
const music = require('../misc/music.json')
|
||||
const Level = require('../classes/Level.js')
|
||||
let demonList = {}
|
||||
|
||||
module.exports = async (app, req, res) => {
|
||||
const {query} = req
|
||||
if (req.offline) return res.status(500).send(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 = query.hasOwnProperty("demonlist") || query.hasOwnProperty("demonList") || query.type == "demonlist" || query.type == "demonList"
|
||||
if (demonMode) {
|
||||
if (!req.server.demonList) return res.sendError(400)
|
||||
let dList = demonList[req.id]
|
||||
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) {
|
||||
let demonStr = req.server.demonList + 'api/v2/demons/listed/?limit=100'
|
||||
return request.get(demonStr, function (err1, resp1, list1) {
|
||||
if (err1) return res.sendError()
|
||||
else return request.get(req.server.demonList + 'api/v2/demons/listed/?limit=100&after=100', function (err2, resp2, list2) {
|
||||
else return request.get(demonStr + '&after=100', function (err2, resp2, list2) {
|
||||
if (err2) return res.sendError()
|
||||
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)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let amount = 10;
|
||||
let count = req.isGDPS ? 10 : +req.query.count
|
||||
if (count && count > 0) {
|
||||
if (count > 500) amount = 500
|
||||
else amount = count;
|
||||
}
|
||||
|
||||
let amount = 10
|
||||
let count = req.isGDPS ? 10 : +query.count
|
||||
if (count && count > 0) amount = Math.min(count, 500)
|
||||
|
||||
let filters = {
|
||||
str: req.params.text,
|
||||
|
||||
diff: req.query.diff,
|
||||
demonFilter: req.query.demonFilter,
|
||||
page: req.query.page || 0,
|
||||
gauntlet: req.query.gauntlet || 0,
|
||||
len: req.query.length,
|
||||
song: req.query.songID,
|
||||
followed: req.query.creators,
|
||||
diff: query.diff,
|
||||
demonFilter: query.demonFilter,
|
||||
page: query.page || 0,
|
||||
gauntlet: query.gauntlet || 0,
|
||||
len: query.length,
|
||||
song: query.songID,
|
||||
followed: query.creators,
|
||||
|
||||
featured: req.query.hasOwnProperty("featured") ? 1 : 0,
|
||||
originalOnly: req.query.hasOwnProperty("original") ? 1 : 0,
|
||||
twoPlayer: req.query.hasOwnProperty("twoPlayer") ? 1 : 0,
|
||||
coins: req.query.hasOwnProperty("coins") ? 1 : 0,
|
||||
epic: req.query.hasOwnProperty("epic") ? 1 : 0,
|
||||
star: req.query.hasOwnProperty("starred") ? 1 : 0,
|
||||
noStar: req.query.hasOwnProperty("noStar") ? 1 : 0,
|
||||
customSong: req.query.hasOwnProperty("customSong") ? 1 : 0,
|
||||
featured: query.hasOwnProperty("featured") ? 1 : 0,
|
||||
originalOnly: query.hasOwnProperty("original") ? 1 : 0,
|
||||
twoPlayer: query.hasOwnProperty("twoPlayer") ? 1 : 0,
|
||||
coins: query.hasOwnProperty("coins") ? 1 : 0,
|
||||
epic: query.hasOwnProperty("epic") ? 1 : 0,
|
||||
star: query.hasOwnProperty("starred") ? 1 : 0,
|
||||
noStar: query.hasOwnProperty("noStar") ? 1 : 0,
|
||||
customSong: query.hasOwnProperty("customSong") ? 1 : 0,
|
||||
|
||||
type: req.query.type || 0,
|
||||
type: query.type || 0,
|
||||
count: amount
|
||||
}
|
||||
|
||||
if (req.query.type) {
|
||||
let filterCheck = req.query.type.toLowerCase()
|
||||
switch(filterCheck) {
|
||||
case 'mostdownloaded': filters.type = 1; break;
|
||||
case 'mostliked': filters.type = 2; break;
|
||||
case 'trending': filters.type = 3; break;
|
||||
case 'recent': filters.type = 4; break;
|
||||
case 'featured': filters.type = 6; break;
|
||||
case 'magic': filters.type = 7; break;
|
||||
case 'awarded': filters.type = 11; break;
|
||||
case 'starred': filters.type = 11; break;
|
||||
case 'halloffame': filters.type = 16; break;
|
||||
case 'hof': filters.type = 16; break;
|
||||
case 'gdw': filters.type = 17; break;
|
||||
case 'gdworld': filters.type = 17; break;
|
||||
if (query.type) {
|
||||
let filterCheck = query.type.toLowerCase()
|
||||
let typeMap = {
|
||||
'mostdownloaded': 1, 'mostliked': 2,
|
||||
'trending': 3, 'recent': 4,
|
||||
'featured': 6, 'magic': 7,
|
||||
'awarded': 11, 'starred': 11,
|
||||
'halloffame': 16, 'hof': 16,
|
||||
'gdw': 17, 'gdworld': 17
|
||||
}
|
||||
if (typeMap.hasOwnProperty(filterCheck)) // JIC there's no match
|
||||
filters.type = typeMap[filterCheck]
|
||||
}
|
||||
|
||||
if (req.query.hasOwnProperty("user")) {
|
||||
if (query.hasOwnProperty("user")) {
|
||||
let accountCheck = app.userCache(req.id, filters.str)
|
||||
filters.type = 5
|
||||
if (accountCheck) filters.str = accountCheck[1]
|
||||
else if (!filters.str.match(/^[0-9]*$/)) return app.run.profile(app, req, res, null, req.params.text)
|
||||
}
|
||||
else if ( !(/^\d*$/).test(filters.str) ) return app.run.profile(app, req, res, null, req.params.text)
|
||||
}
|
||||
|
||||
if (req.query.hasOwnProperty("creators")) filters.type = 12
|
||||
if (query.hasOwnProperty("creators")) filters.type = 12
|
||||
|
||||
let listSize = 10
|
||||
if (demonMode || req.query.gauntlet || req.query.type == "saved" || ["mappack", "list", "saved"].some(x => req.query.hasOwnProperty(x))) {
|
||||
if (demonMode || query.gauntlet || query.type == "saved" || ["mappack", "list", "saved"].some(x => query.hasOwnProperty(x))) {
|
||||
filters.type = 10
|
||||
filters.str = demonMode ? demonList[req.id].list : filters.str.split(",")
|
||||
listSize = filters.str.length
|
||||
filters.str = filters.str.slice(filters.page*amount, filters.page*amount + amount)
|
||||
if (!filters.str.length) return res.sendError(400)
|
||||
filters.str = filters.str.map(x => String(Number(x) + (+req.query.l || 0))).join()
|
||||
filters.str = filters.str.map(x => String(Number(x) + (+query.l || 0))).join()
|
||||
filters.page = 0
|
||||
}
|
||||
|
||||
|
@ -103,25 +101,25 @@ module.exports = async (app, req, res) => {
|
|||
let authorList = {}
|
||||
let songList = {}
|
||||
let authors = splitBody[1].split('|')
|
||||
let songs = splitBody[2]; songs = songs.split('~:~').map(x => app.parseResponse(`~${x}~`, '~|~'))
|
||||
let songs = splitBody[2].split('~:~').map(x => app.parseResponse(`~${x}~`, '~|~'))
|
||||
songs.forEach(x => {songList[x['~1']] = x['2']})
|
||||
|
||||
authors.forEach(x => {
|
||||
if (x.startsWith('~')) return
|
||||
let arr = x.split(':')
|
||||
authorList[arr[0]] = [arr[1], arr[2]]})
|
||||
if (x.startsWith('~')) return
|
||||
let arr = x.split(':')
|
||||
authorList[arr[0]] = [arr[1], arr[2]]
|
||||
})
|
||||
|
||||
let levelArray = preRes.map(x => app.parseResponse(x)).filter(x => x[1])
|
||||
let parsedLevels = []
|
||||
|
||||
levelArray.forEach((x, y) => {
|
||||
|
||||
let songSearch = songs.find(y => y['~1'] == x[35]) || []
|
||||
|
||||
let level = new Level(x, req.server).getSongInfo(songSearch)
|
||||
if (!level.id) return
|
||||
level.author = authorList[x[6]] ? authorList[x[6]][0] : "-";
|
||||
level.accountID = authorList[x[6]] ? authorList[x[6]][1] : "0";
|
||||
level.author = authorList[x[6]] ? authorList[x[6]][0] : "-"
|
||||
level.accountID = authorList[x[6]] ? authorList[x[6]][1] : "0"
|
||||
|
||||
if (demonMode) {
|
||||
if (!y) level.demonList = req.server.demonList
|
||||
|
@ -133,21 +131,21 @@ module.exports = async (app, req, res) => {
|
|||
|
||||
//this is broken if you're not on page 0, blame robtop
|
||||
if (filters.page == 0 && y == 0 && splitBody[3]) {
|
||||
let pages = splitBody[3].split(":");
|
||||
let pages = splitBody[3].split(":")
|
||||
|
||||
if (filters.gauntlet) { // gauntlet page stuff
|
||||
level.results = levelArray.length
|
||||
level.results = levelArray.length
|
||||
level.pages = 1
|
||||
}
|
||||
|
||||
else if (filters.type == 10) { // custom page stuff
|
||||
level.results = listSize
|
||||
level.pages = +Math.ceil(listSize / (amount || 10))
|
||||
level.pages = Math.ceil(listSize / (amount || 10))
|
||||
}
|
||||
|
||||
else { // normal page stuff
|
||||
level.results = +pages[0];
|
||||
level.pages = +pages[0] == 9999 ? 1000 : +Math.ceil(pages[0] / amount);
|
||||
level.results = +pages[0]
|
||||
level.pages = +pages[0] == 9999 ? 1000 : Math.ceil(pages[0] / amount)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
"use strict";
|
||||
module.exports = async (app, req, res) => {
|
||||
|
||||
if (req.offline) return res.sendError()
|
||||
|
||||
let songID = req.params.song
|
||||
req.gdRequest('getGJSongInfo', {songID: songID}, function(err, resp, body) {
|
||||
if (err) return res.sendError(400)
|
||||
return res.send(!body.startsWith("-") && body.length > 10)
|
||||
return err ?
|
||||
res.sendError(400) :
|
||||
res.send(!body.startsWith("-") && body.length > 10)
|
||||
})
|
||||
}
|
Loading…
Add table
Reference in a new issue