INSANE optimizations (+ more rate limit stuff for rob)
WAY less requests should be made to the servers now: - Account IDs are now cached to save a request - getgjusers is skipped if Account ID is provided - User icons are cached for 5 minutes
This commit is contained in:
parent
72ffcc4947
commit
f9f2cbf06b
12 changed files with 121 additions and 114 deletions
|
@ -11,9 +11,7 @@ Just make sure to give credit, obviously. Via the bottom of the homepage, the cr
|
|||
|
||||
Obviously, GDBrowser isn't perfect when it comes to GD private servers, since both requests and responses might be a bit different. Or a LOT, as I learned.
|
||||
|
||||
You can tweak the endpoint (e.g. boomlings.com) in index.js
|
||||
|
||||
You can also check out `gdpsConfig.js` to tweak some additional GDPS settings such as whether to decrypt level descriptions or if timestamps should end with "ago"
|
||||
You can also check out `settings.js` to tweak some additional settings (mainly GDPS related) such as whether to cache things or if timestamps should end with "ago"
|
||||
|
||||
GDPS compatibility is still a HUGE work in progress, so pull requests would be greatly appreciated if you manage to make any improvements!
|
||||
|
||||
|
@ -89,12 +87,12 @@ colors.json - The colors for generating icons
|
|||
|
||||
credits.json - Credits! (shown on the homepage)
|
||||
|
||||
gdpsConfig.js - Tweak small settings for GDPS'es here, such as whether to decrypt level descriptions or if timestamps should end with "ago"
|
||||
|
||||
level.json - An array of the official GD tracks, and also difficulty face stuff for level searching
|
||||
|
||||
secretStuff.json - GJP goes here, needed for level leaderboards. Not included in the repo for obvious reasons
|
||||
|
||||
settings.js - Tweak small settings here, mainly for local use or GDPS'es
|
||||
|
||||
sizecheck.js - Excecuted on most pages, used for the 'page isn't wide enough' message, back button, and a few other things
|
||||
|
||||
---
|
||||
|
|
57
api/icon.js
57
api/icon.js
|
@ -1,7 +1,6 @@
|
|||
const request = require('request')
|
||||
const Jimp = require('jimp');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const icons = require('../icons/gameSheet.json');
|
||||
const colors = require('../misc/colors.json');
|
||||
const forms = require('../icons/forms.json')
|
||||
|
@ -25,9 +24,7 @@ let cache = {};
|
|||
|
||||
module.exports = async (app, req, res) => {
|
||||
|
||||
function buildIcon(account) {
|
||||
|
||||
if (!account) account = []
|
||||
function buildIcon(account=[], usercode) {
|
||||
|
||||
let { form, ind } = forms[req.query.form] || {};
|
||||
form = form || 'player';
|
||||
|
@ -38,10 +35,6 @@ module.exports = async (app, req, res) => {
|
|||
let col2 = req.query.col2 || account[11] || 3;
|
||||
let outline = req.query.glow || account[28] || "0";
|
||||
|
||||
// meant for debugging robot/spider offsets, but i'll leave it in anyways
|
||||
let glowOffset = (req.query.off || "").split(",").map(x => Number(x))
|
||||
if (!glowOffset.some(x => x != 0)) glowOffset = []
|
||||
|
||||
let topless = form == "bird" && req.query.topless
|
||||
let autoSize = req.query.size == "auto"
|
||||
let sizeParam = autoSize || (req.query.size && !isNaN(req.query.size))
|
||||
|
@ -65,8 +58,6 @@ module.exports = async (app, req, res) => {
|
|||
if (!fs.existsSync(fromIcons(icon)) || (isSpecial && !fs.existsSync(fromIcons(genImageName('02'))))) {
|
||||
iconID = '01';
|
||||
setBaseIcons();
|
||||
// Condition on next line should never be satisfied but you never know!
|
||||
if (!fs.existsSync(fromIcons(icon))) return res.sendFile(path.join(__dirname, '../assets/unknownIcon.png'))
|
||||
}
|
||||
|
||||
let ex = fromIcons(extra)
|
||||
|
@ -80,11 +71,7 @@ module.exports = async (app, req, res) => {
|
|||
|
||||
let iconCode = `${req.query.form == "cursed" ? "cursed" : form}${topless ? "top" : ""}-${iconID}-${col1}-${col2}-${col3 || "x"}-${outline ? 1 : 0}`
|
||||
|
||||
if (!sizeParam && !glowOffset.length && cache[iconCode]) {
|
||||
clearTimeout(cache[iconCode].timeoutID);
|
||||
cache[iconCode].timeoutID = setTimeout(function() {delete cache[iconCode]}, 1800000);
|
||||
return res.end(cache[iconCode].value);
|
||||
}
|
||||
if (!sizeParam && cache[iconCode]) return res.end(cache[iconCode].value)
|
||||
|
||||
let useExtra = false
|
||||
|
||||
|
@ -93,7 +80,7 @@ module.exports = async (app, req, res) => {
|
|||
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
|
||||
let robotGlow1, robotGlow2, robotGlow3, glowOffset
|
||||
let ufoTop, ufoOffset, ufoCoords, ufoSprite
|
||||
let extrabit, offset2, size2;
|
||||
|
||||
|
@ -112,7 +99,7 @@ module.exports = async (app, req, res) => {
|
|||
robotLeg2 = new Jimp(fromIcons(legs[1])); robotGlow2 = new Jimp(fromIcons(glows[1]))
|
||||
robotLeg3 = new Jimp(fromIcons(legs[2])); robotGlow3 = new Jimp(fromIcons(glows[2]))
|
||||
|
||||
if (!glowOffset.length) glowOffset = offsets[form][+iconID] || []
|
||||
glowOffset = offsets[form][+iconID] || []
|
||||
}
|
||||
|
||||
Jimp.read(fromIcons(glow)).then(async function (image) {
|
||||
|
@ -294,11 +281,9 @@ module.exports = async (app, req, res) => {
|
|||
img.resize(imgSize, Jimp.AUTO)
|
||||
}
|
||||
img.getBuffer(Jimp.AUTO, (err, buffer) => {
|
||||
if (!sizeParam && !glowOffset.length) {
|
||||
cache[iconCode] = {
|
||||
value: buffer,
|
||||
timeoutID: setTimeout(function() {delete cache[iconCode]}, 1800000)
|
||||
}
|
||||
if (!sizeParam) {
|
||||
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')
|
||||
})
|
||||
|
@ -355,19 +340,31 @@ module.exports = async (app, req, res) => {
|
|||
}
|
||||
|
||||
let username = req.params.text
|
||||
let result = []
|
||||
let userCode;
|
||||
|
||||
if (app.offline || req.query.hasOwnProperty("noUser") || req.query.hasOwnProperty("nouser") || username == "icon") return buildIcon()
|
||||
res.contentType('image/png');
|
||||
if (app.offline || req.query.hasOwnProperty("noUser") || req.query.hasOwnProperty("nouser") || username == "icon") return buildIcon()
|
||||
|
||||
else if (app.config.cachePlayerIcons && !Object.keys(req.query).length || Object.keys(req.query).length == 1 && req.query.form) {
|
||||
userCode = `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)
|
||||
let foundID = app.accountCache[username.toLowerCase()]
|
||||
let skipRequest = accountMode || foundID
|
||||
|
||||
request.post(app.endpoint + 'getGJUsers20.php', req.gdParams({ str: username }), function (err1, res1, body1) {
|
||||
if (err1 || !body1 || body1 == "-1") return buildIcon()
|
||||
else result = app.parseResponse(body1);
|
||||
// skip request by causing fake error lmao
|
||||
request.post(skipRequest ? "" : app.endpoint + 'getGJUsers20.php', skipRequest ? {} : req.gdParams({ str: username }), function (err1, res1, body1) {
|
||||
|
||||
let result = foundID ? foundID[0] : (accountMode || err1 || !body1 || body1 == "-1" || body1.startsWith("<!")) ? username : app.parseResponse(body1)[16];
|
||||
|
||||
request.post(app.endpoint + 'getGJUserInfo20.php', req.gdParams({ targetAccountID: result[16] }), function (err2, res2, body2) {
|
||||
request.post(app.endpoint + 'getGJUserInfo20.php', req.gdParams({ targetAccountID: result }), function (err2, res2, body2) {
|
||||
|
||||
if (!err2 && body2 && body2 != '-1') return buildIcon(app.parseResponse(body2));
|
||||
else return buildIcon()
|
||||
if (err2 || !body2 || body2 == '-1' || body2.startsWith("<!")) return buildIcon();
|
||||
let iconData = app.parseResponse(body2)
|
||||
if (!foundID && app.config.cacheAccountIDs) app.accountCache[username.toLowerCase()] = [iconData[16], iconData[2]]
|
||||
return buildIcon(iconData, userCode);
|
||||
|
||||
})
|
||||
});
|
||||
|
|
|
@ -4,10 +4,20 @@ const fs = require('fs')
|
|||
module.exports = async (app, req, res, api, getLevels) => {
|
||||
|
||||
if (app.offline) return res.send("-1")
|
||||
let username = getLevels || req.params.id
|
||||
let accountMode = !req.query.hasOwnProperty("player") && Number(req.params.id)
|
||||
let foundID = app.accountCache[username.toLowerCase()]
|
||||
let skipRequest = accountMode || foundID
|
||||
|
||||
request.post(app.endpoint + 'getGJUsers20.php', req.gdParams({ str: getLevels || req.params.id }), function (err1, res1, b1) {
|
||||
// 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)
|
||||
request.post(skipRequest ? "" : app.endpoint + 'getGJUsers20.php', skipRequest ? {} : req.gdParams({ str: username }), function (err1, res1, b1) {
|
||||
|
||||
let searchResult = foundID ? foundID[0] : (accountMode || err1 || b1 == '-1' || b1.startsWith("<!") || !b1) ? req.params.id : app.parseResponse(b1)[16]
|
||||
|
||||
let searchResult = ((!req.query.hasOwnProperty("player") && Number(req.params.id)) || err1 || b1 == '-1' || b1.startsWith("<!") || !b1) ? req.params.id : app.parseResponse(b1)[16]
|
||||
if (getLevels) {
|
||||
req.params.text = foundID ? foundID[1] : app.parseResponse(b1)[2]
|
||||
return app.run.search(app, req, res)
|
||||
}
|
||||
|
||||
request.post(app.endpoint + 'getGJUserInfo20.php', req.gdParams({ targetAccountID: searchResult }), function (err2, res2, body) {
|
||||
|
||||
|
@ -17,46 +27,44 @@ module.exports = async (app, req, res, api, getLevels) => {
|
|||
}
|
||||
|
||||
let account = app.parseResponse(body)
|
||||
|
||||
if (!foundID && app.config.cacheAccountIDs) app.accountCache[username.toLowerCase()] = [account[16], account[2]]
|
||||
else console.log(app.accountCache)
|
||||
|
||||
let userData = {
|
||||
username: account[1],
|
||||
playerID: account[2],
|
||||
accountID: account[16],
|
||||
rank: +account[30],
|
||||
stars: +account[3],
|
||||
diamonds: +account[46],
|
||||
coins: +account[13],
|
||||
userCoins: +account[17],
|
||||
demons: +account[4],
|
||||
cp: +account[8],
|
||||
friendRequests: account[19] == "0",
|
||||
messages: account[18] == "0" ? "all" : account[18] == "1" ? "friends" : "off",
|
||||
commentHistory: account[50] == "0" ? "all" : account[50] == "1" ? "friends" : "off",
|
||||
moderator: +account[49],
|
||||
youtube: account[20] || null,
|
||||
twitter: account[44] || null,
|
||||
twitch: account[45] || null,
|
||||
icon: +account[21],
|
||||
ship: +account[22],
|
||||
ball: +account[23],
|
||||
ufo: +account[24],
|
||||
wave: +account[25],
|
||||
robot: +account[26],
|
||||
spider: +account[43],
|
||||
col1: +account[10],
|
||||
col2: +account[11],
|
||||
deathEffect: +account[48],
|
||||
glow: account[28] == "1",
|
||||
}
|
||||
|
||||
if (getLevels) {
|
||||
req.params.text = account[2]
|
||||
return app.run.search(app, req, res)
|
||||
let userData = {
|
||||
username: account[1],
|
||||
playerID: account[2],
|
||||
accountID: account[16],
|
||||
rank: +account[30],
|
||||
stars: +account[3],
|
||||
diamonds: +account[46],
|
||||
coins: +account[13],
|
||||
userCoins: +account[17],
|
||||
demons: +account[4],
|
||||
cp: +account[8],
|
||||
friendRequests: account[19] == "0",
|
||||
messages: account[18] == "0" ? "all" : account[18] == "1" ? "friends" : "off",
|
||||
commentHistory: account[50] == "0" ? "all" : account[50] == "1" ? "friends" : "off",
|
||||
moderator: +account[49],
|
||||
youtube: account[20] || null,
|
||||
twitter: account[44] || null,
|
||||
twitch: account[45] || null,
|
||||
icon: +account[21],
|
||||
ship: +account[22],
|
||||
ball: +account[23],
|
||||
ufo: +account[24],
|
||||
wave: +account[25],
|
||||
robot: +account[26],
|
||||
spider: +account[43],
|
||||
col1: +account[10],
|
||||
col2: +account[11],
|
||||
deathEffect: +account[48],
|
||||
glow: account[28] == "1",
|
||||
}
|
||||
|
||||
if (api) return res.send(userData)
|
||||
|
||||
else if (api) return res.send(userData)
|
||||
|
||||
else return fs.readFile('./html/profile.html', 'utf8', function(err, data) {
|
||||
else fs.readFile('./html/profile.html', 'utf8', function(err, data) {
|
||||
let html = data;
|
||||
let variables = Object.keys(userData)
|
||||
variables.forEach(x => {
|
||||
|
|
|
@ -9,7 +9,7 @@ module.exports = async (app, req, res) => {
|
|||
let amount = 10;
|
||||
let count = +req.query.count
|
||||
if (count && count > 0) {
|
||||
if (count > 100) amount = 100
|
||||
if (count > 500) amount = 500
|
||||
else amount = count;
|
||||
}
|
||||
|
||||
|
@ -56,8 +56,10 @@ module.exports = async (app, req, res) => {
|
|||
}
|
||||
|
||||
if (req.query.hasOwnProperty("user")) {
|
||||
let accountCheck = app.accountCache[filters.str.toLowerCase()]
|
||||
filters.type = 5
|
||||
if (!req.params.text.match(/^[0-9]*$/)) return app.run.profile(app, req, res, null, req.params.text)
|
||||
if (accountCheck) filters.str = accountCheck[1]
|
||||
else if (!filters.str.match(/^[0-9]*$/)) return app.run.profile(app, req, res, null, req.params.text)
|
||||
}
|
||||
|
||||
if (req.query.hasOwnProperty("creators")) filters.type = 12
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
|
@ -1,5 +1,5 @@
|
|||
const XOR = require(__dirname + "/../classes/XOR");
|
||||
const config = require(__dirname + "/../gdpsConfig");
|
||||
const config = require(__dirname + "/../settings");
|
||||
|
||||
let orbs = [0, 0, 50, 75, 125, 175, 225, 275, 350, 425, 500]
|
||||
let length = ['Tiny', 'Short', 'Medium', 'Long', 'XL']
|
||||
|
|
|
@ -250,7 +250,7 @@
|
|||
|
||||
<br>
|
||||
<p><b>Params that require a number</b> (e.g. ?page=1)</p>
|
||||
<p>count: The amount of levels to list (default and max is 10)</p>
|
||||
<p>count: The amount of levels to list (default is 10, max is 500)</p>
|
||||
<p>diff: The number of the difficulty to search for, see <u>difficulty IDs</u> below</p>
|
||||
<p>demonFilter: If searching for demon levels, what difficulty to search for (1 is easy, 5 is extreme)</p>
|
||||
<p>page: The page of the search</p>
|
||||
|
@ -767,7 +767,7 @@
|
|||
<p style="font-size:15px; margin-top:-7px">This one isn't really part of the API, but dammit, my website my rules</p>
|
||||
|
||||
<br>
|
||||
<p class="reveal" onclick="$('#params-icons').slideToggle(100)"><b>Parameters (9)</b></p>
|
||||
<p class="reveal" onclick="$('#params-icons').slideToggle(100)"><b>Parameters (10)</b></p>
|
||||
<div class="subdiv" id="params-icons">
|
||||
<p><b>Parameters can be used to modify parts of a fetched user's icon</b></p>
|
||||
<p>IDs generally correspond to their order of appearance in GD</p>
|
||||
|
@ -779,6 +779,7 @@
|
|||
<p>glow: If the icon should have a glow/outline (0 = off, anything else = on)</p>
|
||||
<p>size: The size in pixels that the icon should be (always square), in case you don't want the default. "Auto" also works.</p>
|
||||
<p>topless: Removes the glass 'dome' from generated UFOs (legacy)</p>
|
||||
<p>player: Forces the player ID to be used for fetching (normally Account ID is tried first)</p>
|
||||
<p>noUser: Disables fetching the icon from the GD servers. Slightly faster, but comes at the cost of having to build icons from the ground up using the parameters listed above. It completely ignores the entered username and always returns the default icon</p>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -228,7 +228,7 @@ $(document).keydown(function(k) {
|
|||
});
|
||||
|
||||
$('#pageSize').on('input blur', function (event) {
|
||||
var x = +$(this).val(); var max = 100; var min = 1
|
||||
var x = +$(this).val(); var max = 250; var min = 1
|
||||
if (event.type == "input") { if (x > max || x < min) $(this).addClass('red'); else $(this).removeClass('red')}
|
||||
else {
|
||||
$(this).val(Math.max(Math.min(Math.floor(x), max), min));
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
</tr>
|
||||
</table>
|
||||
|
||||
<p>Website created by GD Colon.<br>Pretty much everything other than that belongs to RobTopGames.</p>
|
||||
<p>Website created by <a class="menuLink" href="https://gdcolon.com">GD Colon</a>.<br>Pretty much everything other than that belongs to <a class="menuLink" href="http://robtopgames.com">RobTopGames</a>.</p>
|
||||
<p style="margin-top: -0.5%"><a class="menuLink" href="https://gdcolon.com/tools">GD Tools</a>
|
||||
|
||||
<a class="menuLink" href="./api">API</a>
|
||||
|
|
30
index.js
30
index.js
|
@ -3,22 +3,34 @@ const fs = require("fs")
|
|||
const compression = require('compression');
|
||||
const timeout = require('connect-timeout')
|
||||
const rateLimit = require("express-rate-limit");
|
||||
|
||||
const app = express();
|
||||
|
||||
app.offline = false // set to true to go into "offline" mode (in case of ip ban from rob)
|
||||
app.secret = "Wmfd2893gb7" // lol
|
||||
|
||||
app.config = require('./gdpsConfig') // tweak settings in this file if you're using a GDPS
|
||||
app.config = require('./settings') // tweak settings in this file if you're using a GDPS
|
||||
app.endpoint = app.config.endpoint // default is boomlings.com/database/
|
||||
app.accountCache = {} // account IDs are cached here to shave off requests to getgjusers
|
||||
|
||||
let rlMessage = "Rate limited ¯\\_(ツ)_/¯<br><br>Please do not spam my servers with a crazy amount of requests. It slows things down on my end and stresses RobTop's servers just as much." +
|
||||
" If you really want to send a zillion requests for whatever reason, please download the GDBrowser repository locally - or even just send the request directly to the GD servers.<br><br>" +
|
||||
"This kind of spam usually leads to GDBrowser getting IP banned by RobTop, and every time that happens I have to start making the rate limit even stricter. Please don't be the reason for that.<br><br>" +
|
||||
"(also, keep in mind that most endpoints have a ?count parameter that let you fetch a LOT more stuff in just one request)"
|
||||
|
||||
const RL = rateLimit({
|
||||
windowMs: app.config.rateLimiting ? 5 * 60 * 1000 : 0,
|
||||
max: app.config.rateLimiting ? 100 : 0, // max requests per 5 minutes
|
||||
message: "Rate limited ¯\\_(ツ)_/¯",
|
||||
keyGenerator: function(req) { return req.headers['x-real-ip'] },
|
||||
message: rlMessage,
|
||||
keyGenerator: function(req) { return req.headers['x-real-ip'] || req.headers['x-forwarded-for'] },
|
||||
skip: function(req) { return ((req.url.includes("api/level") && !req.query.hasOwnProperty("download")) ? true : false) }
|
||||
})
|
||||
|
||||
const RL2 = rateLimit({
|
||||
windowMs: app.config.rateLimiting ? 2 * 60 * 1000 : 0,
|
||||
max: app.config.rateLimiting ? 200 : 0, // max requests per 1 minute
|
||||
message: rlMessage,
|
||||
keyGenerator: function(req) { return req.headers['x-real-ip'] || req.headers['x-forwarded-for'] }
|
||||
})
|
||||
|
||||
let api = true;
|
||||
let gdIcons = fs.readdirSync('./icons/iconkit')
|
||||
let sampleIcons = require('./misc/sampleIcons.json')
|
||||
|
@ -126,14 +138,14 @@ app.get("/search/:text", function(req, res) { res.sendFile(__dirname + "/html/se
|
|||
// API
|
||||
|
||||
app.get("/api/analyze/:id", RL, async function(req, res) { app.run.level(app, req, res, api, true) })
|
||||
app.get("/api/comments/:id", 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/leaderboard", function(req, res) { app.run[req.query.hasOwnProperty("accurate") ? "accurate" : "scores"](app, req, res) })
|
||||
app.get("/api/leaderboardLevel/:id", RL, function(req, res) { app.run.leaderboardLevel(app, req, res) })
|
||||
app.get("/api/leaderboardLevel/:id", RL2, function(req, res) { app.run.leaderboardLevel(app, req, res) })
|
||||
app.get("/api/level/:id", RL, async function(req, res) { app.run.level(app, req, res, api) })
|
||||
app.get("/api/mappacks", async function(req, res) { app.run.mappack(app, req, res) })
|
||||
app.get("/api/profile/:id", function(req, res) { app.run.profile(app, req, res, api) })
|
||||
app.get("/api/search/:text", function(req, res) { app.run.search(app, req, res) })
|
||||
app.get("/api/profile/:id", RL2, function(req, res) { app.run.profile(app, req, res, api) })
|
||||
app.get("/api/search/:text", RL2, function(req, res) { app.run.search(app, req, res) })
|
||||
|
||||
|
||||
// REDIRECTS
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
{
|
||||
"header": "Demon List",
|
||||
"name": "stadust1971",
|
||||
"name": "stadust",
|
||||
"ign": "stardust1971",
|
||||
"youtube": ["https://youtube.com/user/stardust19710", "youtube"],
|
||||
"twitter": ["https://twitter.com/stadust1971", "twitter"],
|
||||
|
@ -35,7 +35,8 @@
|
|||
|
||||
{
|
||||
"header": "API Help",
|
||||
"name": "SMJSGaming",
|
||||
"name": "SMJS",
|
||||
"ign": "SMJSGaming",
|
||||
"youtube": ["https://youtube.com/channel/UCwEsWDs9kGN2vvoiNTJKdaQ", "youtube"],
|
||||
"twitter": ["https://instagram.com/smjs_gaming", "instagram"],
|
||||
"github": ["https://github.com/SMJSGaming", "github"]
|
||||
|
@ -55,7 +56,7 @@
|
|||
"name": "RobTop",
|
||||
"youtube": ["https://youtube.com/channel/UCz_yk8mDSAnxJq0ar66L4sw", "youtube"],
|
||||
"twitter": ["https://twitter.com/RobTopGames", "twitter"],
|
||||
"github": ["https://www.facebook.com/geometrydash", "facebook"]
|
||||
"github": ["https://twitch.tv/RobTopGames", "twitch"]
|
||||
}
|
||||
],
|
||||
|
||||
|
@ -67,6 +68,7 @@
|
|||
"Ucrash",
|
||||
"zmxmx",
|
||||
"101arrowz",
|
||||
"Figment/FigmentBoy"
|
||||
"Figment/FigmentBoy",
|
||||
"Wylie/TheWylieMaster"
|
||||
]
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
// In case you wanna use a fork of GDBrowser for a GDPS or something, here are some settings you can tweak to save you some precious time
|
||||
// Main endpoint (e.g. boomlings.com) should be edited in index.js
|
||||
// In case you wanna use a fork of GDBrowser locally or for a GDPS or something, here are some settings you can tweak to save you some precious time
|
||||
// This isn't a JSON because you can't leave comments on them, ew
|
||||
|
||||
module.exports = {
|
||||
|
@ -12,27 +11,15 @@ module.exports = {
|
|||
binaryVersion: '35',
|
||||
},
|
||||
|
||||
cacheMapPacks: true, // Caches map packs to speed up loading. Useful if they're rarely updated.
|
||||
cacheAccountIDs: true, // Caches account IDs in order to shave off an extra request to the servers.
|
||||
cachePlayerIcons: true, // Caches player icons to speed up loading. Changing your icon in-game may take time to update on the site.
|
||||
rateLimiting: true, // Enables rate limiting to avoid api spam, feel free to disable for private use.
|
||||
ipForwarding: true, // Forwards 'x-real-ip' to the servers. (requested by robtop)
|
||||
|
||||
// GDPS Related (feel free to drop a PR if you're able to make gdbrowser work better with gdps'es <3)
|
||||
base64descriptions: true, // Are level descriptions encoded in Base64?
|
||||
xorPasswords: true, // Are level passwords XOR encrypted?
|
||||
cacheMapPacks: true, // Caches map packs to speed up loading. Useful if they're rarely updated.
|
||||
timestampSuffix: " ago", // Suffix to add after timestamps, if any.
|
||||
|
||||
// more settings soon
|
||||
// feel free to drop a PR if you're able to make gdbrowser work better with gdps'es <3
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
STUFF THAT'S BROKEN
|
||||
- Comments, because of how profiles are handled
|
||||
- Leaderboards
|
||||
- Level descriptions, if a mix of Base64 and plain text is used
|
||||
- Map packs and gauntlets
|
||||
|
||||
|
||||
STUFF THAT I HAVEN'T TESTED
|
||||
- Level leaderboards
|
||||
- All POST requests (commenting, liking, etc)
|
||||
*/
|
||||
}
|
Loading…
Reference in a new issue