From 45a8ab134bde4efa741c65bdcba30c3628fa5cae Mon Sep 17 00:00:00 2001 From: GDColon Date: Fri, 15 Jan 2021 10:29:46 -0500 Subject: [PATCH] More GDPS improvements + Better gauntlets --- api/download.js | 1 + api/gauntlets.js | 21 +++++ api/leaderboards/accurate.js | 3 +- api/leaderboards/leaderboardLevel.js | 4 +- api/level.js | 4 +- api/{mappack.js => mappacks.js} | 2 +- api/post/postProfileComment.js | 4 + api/profile.js | 6 +- api/search.js | 113 ++++++++++++++------------- api/song.js | 2 +- classes/Level.js | 2 + html/api.html | 19 ++--- html/gauntlets.html | 19 ++--- html/leaderboard.html | 11 ++- html/level.html | 13 +-- html/profile.html | 2 +- index.js | 12 ++- 17 files changed, 144 insertions(+), 94 deletions(-) create mode 100644 api/gauntlets.js rename api/{mappack.js => mappacks.js} (100%) diff --git a/api/download.js b/api/download.js index c99903a..540a3da 100644 --- a/api/download.js +++ b/api/download.js @@ -71,6 +71,7 @@ module.exports = async (app, req, res, api, ID, analyze) => { level.data = levelInfo[4] if (analyze) return app.run.analyze(app, req, res, level) + if (app.isGDPS) level.gdps = true function sendLevel() { if (api) return res.send(level) diff --git a/api/gauntlets.js b/api/gauntlets.js new file mode 100644 index 0000000..9842960 --- /dev/null +++ b/api/gauntlets.js @@ -0,0 +1,21 @@ +const request = require('request') + +let cache = {data: null, indexed: 0} + +module.exports = async (app, req, res) => { + + if (app.offline) return res.send("-1") + else if (app.config.cacheGauntlets && cache.data != null && cache.indexed + 2000000 > Date.now()) return res.send(cache.data) // half hour cache + + request.post(app.endpoint + 'getGJGauntlets21.php', req.gdParams({}), function (err, resp, body) { + + if (err || !body || body == '-1' || body.startsWith(" app.parseResponse(x)) + let gauntletList = gauntlets.map(x => ({ id: +x[1], levels: x[3].split(",") })) + + if (app.config.cacheGauntlets) cache = {data: gauntletList, indexed: Date.now()} + res.send(gauntletList) + + }) + +} \ No newline at end of file diff --git a/api/leaderboards/accurate.js b/api/leaderboards/accurate.js index a7169f0..37fff73 100644 --- a/api/leaderboards/accurate.js +++ b/api/leaderboards/accurate.js @@ -7,7 +7,8 @@ let caches = [{"stars": null, "coins": null, "demons": null}, {"stars": null, "c module.exports = async (app, req, res, post) => { - if (!app.sheetsKey || app.endpoint != "http://boomlings.com/database/") return res.send([]) + if (app.isGDPS) return res.send("-2") + if (!app.sheetsKey) return res.send([]) let gdMode = post || req.query.hasOwnProperty("gd") let modMode = !gdMode && req.query.hasOwnProperty("mod") let cache = caches[gdMode ? 2 : modMode ? 1 : 0] diff --git a/api/leaderboards/leaderboardLevel.js b/api/leaderboards/leaderboardLevel.js index 716cf8b..c55eaa3 100644 --- a/api/leaderboards/leaderboardLevel.js +++ b/api/leaderboards/leaderboardLevel.js @@ -21,8 +21,8 @@ module.exports = async (app, req, res) => { request.post(app.endpoint + 'getGJLevelScores211.php', params, async function(err, resp, body) { if (err || body == -1 || !body) return res.send("-1") - scores = body.split('|').map(x => app.parseResponse(x)) - if (!(scores.filter(x => x[1]).length)) return res.send("-1") + scores = body.split('|').map(x => app.parseResponse(x)).filter(x => x[1]) + if (!scores.length) return res.send("-1") else app.trackSuccess() scores.forEach(x => { diff --git a/api/level.js b/api/level.js index 2b3e66b..9af5bad 100644 --- a/api/level.js +++ b/api/level.js @@ -24,7 +24,7 @@ module.exports = async (app, req, res, api, analyze) => { request.post(app.endpoint + 'getGJLevels21.php', req.gdParams({ str: levelID, type: 0 }), async function (err, resp, body) { - if (err || !body || body == '-1' || body.startsWith(" { level.songID = "Level " + [parseInt(levelInfo[12]) + 1] } + if (app.isGDPS) level.gdps = true + function sendLevel() { if (api) return res.send(level) diff --git a/api/mappack.js b/api/mappacks.js similarity index 100% rename from api/mappack.js rename to api/mappacks.js index d8fdf4c..2c3ecce 100644 --- a/api/mappack.js +++ b/api/mappacks.js @@ -16,8 +16,8 @@ module.exports = async (app, req, res) => { let mappacks = packs.map(x => ({ // "packs.map()" laugh now please id: +x[1], - name: x[2], levels: x[3].split(","), + name: x[2], stars: +x[4], coins: +x[5], difficulty: difficulties[+x[6]], diff --git a/api/post/postProfileComment.js b/api/post/postProfileComment.js index 0aa404b..b478626 100644 --- a/api/post/postProfileComment.js +++ b/api/post/postProfileComment.js @@ -28,6 +28,10 @@ module.exports = async (app, req, res) => { request.post(app.endpoint + 'uploadGJAccComment20.php', req.gdParams(params), function (err, resp, body) { if (err) return res.status(400).send("The Geometry Dash servers returned an error! Perhaps they're down for maintenance") else if (!body || body == "-1") return res.status(400).send(`The Geometry Dash servers rejected your profile post! Try again later, or make sure your username and password are entered correctly. Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince()} ago.`) + if (body.startsWith("temp")) { + let banStuff = body.split("_") + return res.status(400).send(`You have been banned from commenting for ${(parseInt(banStuff[1]) / 86400).toFixed(0)} days. Reason: ${banStuff[2] || "None"}`) + } else app.trackSuccess() res.status(200).send(`Comment posted to ${params.userName} with ID ${body}`) }) diff --git a/api/profile.js b/api/profile.js index f90777f..7faea29 100644 --- a/api/profile.js +++ b/api/profile.js @@ -11,7 +11,6 @@ module.exports = async (app, req, res, api, getLevels) => { // 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, page: 0 }), function (err1, res1, b1) { - let searchResult = foundID ? foundID[0] : (accountMode || err1 || b1 == '-1' || b1.startsWith(" { } request.post(app.endpoint + 'getGJUserInfo20.php', req.gdParams({ targetAccountID: searchResult }), function (err2, res2, body) { - if (err2 || body == '-1' || !body) { if (!api) return res.redirect('/search/' + req.params.id) else return res.send("-1") @@ -60,6 +58,10 @@ module.exports = async (app, req, res, api, getLevels) => { deathEffect: +account[48] || 1, glow: account[28] == "1", } + + if (app.isGDPS) { + if (userData.icon == 0 && !userData.accountID && userData.username.toLowerCase() == "undefined") userData.username = "[MISSINGNO.]" + } if (api) return res.send(userData) diff --git a/api/search.js b/api/search.js index a0535a4..bc1725c 100644 --- a/api/search.js +++ b/api/search.js @@ -9,6 +9,7 @@ module.exports = async (app, req, res) => { let demonMode = req.query.hasOwnProperty("demonlist") || req.query.hasOwnProperty("demonList") || req.query.type == "demonlist" || req.query.type == "demonList" if (demonMode) { + if (app.isGDPS) return res.send('-1') if (!demonList.list.length || demonList.lastUpdated + 600000 < Date.now()) { // 10 minute cache return request.get('http://www.pointercrate.com/api/v2/demons/listed/?limit=100', function (err, resp, list) { if (err) return res.send("-1") @@ -78,8 +79,6 @@ module.exports = async (app, req, res) => { if (req.query.hasOwnProperty("creators")) filters.type = 12 - if (req.params.text == "*") delete filters.str - let listSize = 10 if (demonMode || req.query.gauntlet || ["mappack", "list", "saved"].some(x => req.query.hasOwnProperty(x))) { filters.type = 10 @@ -88,74 +87,76 @@ module.exports = async (app, req, res) => { filters.str = filters.str.slice(filters.page*amount, filters.page*amount + amount).join() filters.page = 0 } + + if (req.params.text == "*") delete filters.str request.post(app.endpoint + 'getGJLevels21.php', req.gdParams(filters), async function(err, resp, body) { - if (err || !body || body == '-1' || body.startsWith(" app.parseResponse(x, '~|~')) - songs.forEach(x => {songList[x['~1']] = x['2']}) + if (err || !body || body == '-1' || body.startsWith(" 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]]}) + authors.forEach(x => { + 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 = [] + let levelArray = preRes.map(x => app.parseResponse(x)).filter(x => x[1]) + let parsedLevels = [] - levelArray.forEach(async (x, y) => { + levelArray.forEach(async (x, y) => { - let level = new Level(x) - let songSearch = songs.find(y => y['~1'] == x[35]) || [] + let level = new Level(x) + let songSearch = songs.find(y => y['~1'] == x[35]) || [] - 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 (level.customSong) { - level.songName = app.clean(songSearch[2] || "Unknown") - level.songAuthor = songSearch[4] || "Unknown" - level.songSize = (songSearch[5] || "0") + "MB" - level.songID = songSearch[1] || level.customSong - } - else { - let foundSong = require('../misc/level.json').music[parseInt(x[12]) + 1] || {"null": true} - level.songName = foundSong[0] || "Unknown" - level.songAuthor = foundSong[1] || "Unknown" - level.songSize = "0MB" - level.songID = "Level " + [parseInt(x[12]) + 1] - } - - //this is broken if you're not on page 0, blame robtop - if (filters.page == 0 && y == 0) { - let pages = splitBody[3].split(":"); - - if (filters.gauntlet) { // gauntlet page stuff - level.results = levelArray.length - level.pages = 1 + if (level.customSong) { + level.songName = app.clean(songSearch[2] || "Unknown") + level.songAuthor = songSearch[4] || "Unknown" + level.songSize = (songSearch[5] || "0") + "MB" + level.songID = songSearch[1] || level.customSong + } + else { + let foundSong = require('../misc/level.json').music[parseInt(x[12]) + 1] || {"null": true} + level.songName = foundSong[0] || "Unknown" + level.songAuthor = foundSong[1] || "Unknown" + level.songSize = "0MB" + level.songID = "Level " + [parseInt(x[12]) + 1] } - else if (filters.type == 10) { // custom page stuff - level.results = listSize - level.pages = +Math.ceil(listSize / (amount || 10)) + //this is broken if you're not on page 0, blame robtop + if (filters.page == 0 && y == 0) { + let pages = splitBody[3].split(":"); + + if (filters.gauntlet) { // gauntlet page stuff + 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)) + } + + else { // normal page stuff + level.results = +pages[0]; + level.pages = +pages[0] == 9999 ? 1000 : +Math.ceil(pages[0] / amount); + } + } - else { // normal page stuff - level.results = +pages[0]; - level.pages = +pages[0] == 9999 ? 1000 : +Math.ceil(pages[0] / amount); - } + parsedLevels[y] = level + }) - } - - parsedLevels[y] = level - }) - - if (filters.type == 10) parsedLevels = parsedLevels.slice((+filters.page) * amount, (+filters.page + 1) * amount) - return res.send(parsedLevels) + if (filters.type == 10) parsedLevels = parsedLevels.slice((+filters.page) * amount, (+filters.page + 1) * amount) + return res.send(parsedLevels) }) } \ No newline at end of file diff --git a/api/song.js b/api/song.js index 9769707..d103af2 100644 --- a/api/song.js +++ b/api/song.js @@ -8,7 +8,7 @@ module.exports = async (app, req, res) => { let songID = req.params.song - request.post(app.endpoint + 'testSong.php?songID=' + songID, req.gdParams(), async function(err, resp, body) { + request.post('http://boomlings.com/database/testSong.php?songID=' + songID, req.gdParams(), async function(err, resp, body) { if (err || !body || body == '-1' || body.startsWith(" 1) this.password = pass.slice(1); else this.password = pass; } + + if (this.editorTime == 1 && this.totalEditorTime == 2) { this.editorTime = 0; this.totalEditorTime = 0 } // remove GDPS default values } } diff --git a/html/api.html b/html/api.html index 38708df..d280734 100644 --- a/html/api.html +++ b/html/api.html @@ -27,7 +27,7 @@
Levels Searching - Map Packs + Map Packs + Gauntlets Level Leaderboards
@@ -383,10 +383,11 @@
-

Map Packs

-

/api/mappacks

+

Map Packs + Gauntlets

+

/api/mappacks or /api/gauntlets

-

Returns the list of map packs

+

Returns the list of map packs or gauntlets

+

I'm putting this in the same section because they're basically the same lol


Parameters (0)

@@ -397,11 +398,11 @@

Response (8)

-

The API will return an array of each map pack with the following information:

-

id: The ID of the map

-

name: The name of the pack

-

levels: An array of level IDs in the map pack. Fetch with /search/ using the ?list parameter

-

stars: The amount of stars rewarded for completing the pack

+

*Values in blue are used in gauntlets, everything else is exclusive to map packs

+

id: The ID of the map pack, or index/type of the gauntlet

+

levels: An array of level IDs in the pack. Fetch with /search/ using the ?list parameter

+

name: The name of the map pack

+

stars: The amount of stars rewarded for completing the map pack

coins: Basically the only reason people play map packs LOL

difficulty: The (usually inaccurate) difficulty face of the map pack

barColor: The RGB color of the pack's progress bar

diff --git a/html/gauntlets.html b/html/gauntlets.html index 0cb8570..def23c4 100644 --- a/html/gauntlets.html +++ b/html/gauntlets.html @@ -33,16 +33,17 @@ \ No newline at end of file diff --git a/html/leaderboard.html b/html/leaderboard.html index 24b68c5..7604ef8 100644 --- a/html/leaderboard.html +++ b/html/leaderboard.html @@ -112,12 +112,19 @@ function leaderboard(val) { fetch(`../api/leaderboard?count=250&${val}&type=${sort}${modMode ? "&mod=1" : ""}`).then(res => res.json()).then(res => { + if (type == "accurate" && res == "-2") { // for GDPS'es + $('#accurateTabOn').remove() + $('#accurateTabOff').remove() + $('#scoreTabs').css('margin-left', '-29vh') + return $('#topTabOff').trigger('click') + } + $('#searchBox').html(`
`) $('.ranking').remove() if (modMode && sort == "cp") res = res.sort(function(a, b){return b.cp - a.cp}); - if (val == type && res != -1 && res.length) res.forEach((x, y) => { + if (val == type && res != -1 && res != -2 && res.length) res.forEach((x, y) => { $('#searchBox').append(`
${x.moderator ? `` : ""} @@ -126,7 +133,7 @@ function leaderboard(val) { style="cursor: help; height: 19%; transform: translate(-25%, -10%);" title="Stars">

- = 65535 ? " class='blue'>~" : ">"}${x.diamonds} + = 65535 ? ` class='blue'>${type == "accurate" ? "~" : ""}` : ">"}${x.diamonds} = 149 ? " class='yellow'" : ""}>${x.coins} = 10000 ? " class='brightblue'" : ""}>${x.usercoins} = 1000 ? " class='brightred'" : ""}>${x.demons} diff --git a/html/level.html b/html/level.html index 246848f..eeb3f16 100644 --- a/html/level.html +++ b/html/level.html @@ -118,14 +118,14 @@

By: [[SONGAUTHOR]]

+ -->

- +
@@ -252,14 +252,17 @@ if (!'[[DAILYNUMBER]]'.startsWith("[")) { $('#dailyTime').html(` (${colonize(dailyTime, true)})`) }, 1000); } - - } else $('.dailyLevel').remove() if ("[[SONGID]]".startsWith("Level")) { $('#songInfo').text('[[SONGID]]') - $('.songLink').hide()} + $('.songLink').hide() +} +else if ("[[GDPS]]" == "true") { + $('#playSong').hide() + $('#moreSongs').hide() +} else $('#checkSong').show() if ("[[SONGAUTHOR]]" == "Unknown" || "[[INVALIDSONG]]" == "true") $('.songLink').hide() diff --git a/html/profile.html b/html/profile.html index 988a361..f947e08 100644 --- a/html/profile.html +++ b/html/profile.html @@ -175,7 +175,7 @@ $('#followOff').click(function() { $('#followOn').click(function() { followed = localStorage.followed ? JSON.parse(localStorage.followed) : [] - localStorage.followed = JSON.stringify(followed.filter(x => x != [[ACCOUNTID]])) + localStorage.followed = JSON.stringify(followed.filter(x => x != '[[ACCOUNTID]]')) $('#followOff').show() $('#followOn').hide() }) diff --git a/index.js b/index.js index e80187c..2d0d516 100644 --- a/index.js +++ b/index.js @@ -78,6 +78,8 @@ app.timeSince = function(time=app.lastSuccess) { return `${minsPassed}m ${secsPassed}s` } +app.isGDPS = app.endpoint != "http://boomlings.com/database/" + app.run = {} directories.forEach(d => { fs.readdirSync('./api/' + d).forEach(x => {if (x.includes('.')) app.run[x.split('.')[0]] = require('./api/' + d + "/" + x) }) @@ -100,17 +102,18 @@ catch(e) { app.parseResponse = function (responseBody, splitter) { if (!responseBody || responseBody == "-1") return {}; - if (responseBody.startsWith("\nWarning:")) responseBody = responseBody.split("\n").slice(2).join("\n") // GDPS'es are wild + if (responseBody.startsWith("\nWarning:")) responseBody = responseBody.split("\n").slice(2).join("\n").trim() // GDPS'es are wild + if (responseBody.startsWith("
")) responseBody = responseBody.split("
").slice(2).join("
").trim() // Seriously screw this let response = responseBody.split('#')[0].split(splitter || ':'); let res = {}; for (let i = 0; i < response.length; i += 2) { res[response[i]] = response[i + 1]} - return res } + return res +} //xss bad app.clean = function(text) {if (!text || typeof text != "string") return text; else return text.replace(/&/g, "&").replace(//g, ">").replace(/=/g, "=").replace(/"/g, """).replace(/'/g, "'")} - // ASSETS app.use('/assets', express.static(__dirname + '/assets', {maxAge: "7d"})); @@ -184,10 +187,11 @@ app.get("/api/analyze/:id", RL, async function(req, res) { app.run.level(app, re 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/credits", function(req, res) { res.send(require('./misc/credits.json')) }) +app.get("/api/gauntlets", async 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/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/mappacks", async function(req, res) { app.run.mappacks(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) }) app.get("/api/song/:song", function(req, res){ app.run.song(app, req, res) })