More GDPS improvements + Better gauntlets

This commit is contained in:
GDColon 2021-01-15 10:29:46 -05:00
parent 87a6ae8eaa
commit 45a8ab134b
17 changed files with 144 additions and 94 deletions

View file

@ -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)

21
api/gauntlets.js Normal file
View file

@ -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("<!")) return res.send("-1")
let gauntlets = body.split('#')[0].split('|').map(x => 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)
})
}

View file

@ -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]

View file

@ -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 => {

View file

@ -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("<!")) {
if (err || !body || body == '-1' || body.startsWith("<!") || body.startsWith("##")) {
if (!api) return res.redirect('search/' + req.params.id)
else return res.send("-1")
}
@ -52,6 +52,8 @@ module.exports = async (app, req, res, api, analyze) => {
level.songID = "Level " + [parseInt(levelInfo[12]) + 1]
}
if (app.isGDPS) level.gdps = true
function sendLevel() {
if (api) return res.send(level)

View file

@ -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]],

View file

@ -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}`)
})

View file

@ -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("<!") || !b1) ? req.params.id : app.parseResponse(b1.split("|")[0])[16]
if (getLevels) {
@ -20,7 +19,6 @@ module.exports = async (app, req, res, api, getLevels) => {
}
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)

View file

@ -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("<!")) return res.send("-1")
let splitBody = body.split('#')
let preRes = splitBody[0].split('|')
let authorList = {}
let songList = {}
let authors = splitBody[1].split('|')
let songs = '~' + splitBody[2]; songs = songs.split(':').map(x => app.parseResponse(x, '~|~'))
songs.forEach(x => {songList[x['~1']] = x['2']})
if (err || !body || body == '-1' || body.startsWith("<!")) return res.send("-1")
let splitBody = body.split('#')
let preRes = splitBody[0].split('|')
let authorList = {}
let songList = {}
let authors = splitBody[1].split('|')
let songs = '~' + splitBody[2]; songs = songs.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]]})
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)
})
}

View file

@ -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("<!")) return res.send(info)
request.post(app.endpoint + 'getGJSongInfo.php', req.gdParams({songID: songID}), async function(err2, resp, songAllowed) {

View file

@ -57,6 +57,8 @@ class Level {
if (pass.length > 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
}
}

View file

@ -27,7 +27,7 @@
<div class="category-content">
<a class="header-link" href="#level">Levels</a>
<a class="header-link" href="#search">Searching</a>
<a class="header-link" href="#mappacks">Map Packs</a>
<a class="header-link" href="#mappacks">Map Packs + Gauntlets</a>
<a class="header-link" href="#levelleaderboard">Level Leaderboards</a>
</div>
</div>
@ -383,10 +383,11 @@
<main>
<div id="mappacks" class="anchor"></div>
<div class="main-block">
<h1>Map Packs</h1>
<p>/api/mappacks</p>
<h1>Map Packs + Gauntlets</h1>
<p>/api/mappacks or /api/gauntlets</p>
<p>Returns the list of map packs</p>
<p>Returns the list of map packs or gauntlets</p>
<p style="font-size: 14px">I'm putting this in the same section because they're basically the same lol</p>
<br>
<p class="reveal" onclick="$('#params-mappacks').slideToggle(100)"><b>Parameters (0)</b></p>
@ -397,11 +398,11 @@
<br>
<p class="reveal" onclick="$('#response-mappacks').slideToggle(100)"><b>Response (8)</b></p>
<div class="subdiv" id="response-mappacks">
<p>The API will return an array of each map pack with the following information:</p>
<p>id: The ID of the map</p>
<p>name: The name of the pack</p>
<p>levels: An array of level IDs in the map pack. Fetch with /search/ using the ?list parameter</p>
<p>stars: The amount of stars rewarded for completing the pack</p>
<p class="br">*Values in <span style="color:#00abee">blue</span> are used in gauntlets, everything else is exclusive to map packs</p>
<p class="blue">id: The ID of the map pack, or index/type of the gauntlet</p>
<p class="blue">levels: An array of level IDs in the pack. Fetch with /search/ using the ?list parameter</p>
<p>name: The name of the map pack</p>
<p>stars: The amount of stars rewarded for completing the map pack</p>
<p>coins: Basically the only reason people play map packs LOL</p>
<p>difficulty: The (usually inaccurate) difficulty face of the map pack</p>
<p>barColor: The RGB color of the pack's progress bar</p>

View file

@ -33,16 +33,17 @@
<script async type="text/javascript" src="../sizecheck.js"></script>
<script>
let gauntlets = ["Fire", "Ice", "Poison", "Shadow", "Lava", "Bonus", "Chaos", "Demon", "Time", "Crystal", "Magic", "Spike", "Monster", "Doom", "Death"]
let gauntletNames = ["Fire", "Ice", "Poison", "Shadow", "Lava", "Bonus", "Chaos", "Demon", "Time", "Crystal", "Magic", "Spike", "Monster", "Doom", "Death"]
gauntlets.forEach((x, y) => {
$('#gauntletList').append(`
fetch('../api/gauntlets').then(res => res.json()).then(gauntlets => {
gauntlets.forEach((x, y) => {
let name = gauntletNames[x.id - 1]
$('#gauntletList').append(`
<div class="gauntlet">
<a href="../search/level?gauntlet=${y + 1}">
<img src="../assets/gauntlets/${x.toLowerCase()}.png" height="300%"><br>
<h3 class="gauntletText"">${x}<br>Gauntlet</h3></div></a>`)
})
<a href="../search/*?gauntlet=${x.id}">
<img src="../assets/gauntlets/${name.toLowerCase()}.png" height="300%"><br>
<h3 class="gauntletText"">${name}<br>Gauntlet</h3></div></a>`)
})
});
</script>

View file

@ -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(`<div style="height: 4.5%"></div>`)
$('.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(`<div class="searchresult leaderboardSlot">
${x.moderator ? `<img title="${x.moderator == 2 ? "Elder " : ""}Moderator" src="../assets/mod${x.moderator == 2 ? "-elder" : ""}.png" style="height: 30%; cursor: help; padding-right: 1.6%; transform: translateY(0.7vh)">` : ""}
@ -126,7 +133,7 @@ function leaderboard(val) {
style="cursor: help; height: 19%; transform: translate(-25%, -10%);" title="Stars"></h3>
<h3 class="lessSpaced leaderboardStats">
<span${x.diamonds >= 65535 ? " class='blue'>~" : ">"}${x.diamonds}</span> <img class="valign" src="../assets/diamond.png" style="cursor: help" title="Diamonds">
<span${x.diamonds >= 65535 ? ` class='blue'>${type == "accurate" ? "~" : ""}` : ">"}${x.diamonds}</span> <img class="valign" src="../assets/diamond.png" style="cursor: help" title="Diamonds">
<span${x.coins >= 149 ? " class='yellow'" : ""}>${x.coins}</span> <img class="valign" src="../assets/coin.png" style="cursor: help" title="Secret Coins">
<span${x.usercoins >= 10000 ? " class='brightblue'" : ""}>${x.usercoins}</span> <img class="valign" src="../assets/silvercoin.png" style="cursor: help" title="User Coins">
<span${x.demons >= 1000 ? " class='brightred'" : ""}>${x.demons}</span> <img class="valign" src="../assets/demon.png" style="cursor: help" title="Demons">

View file

@ -118,14 +118,14 @@
<h2 class="pre smaller">By: [[SONGAUTHOR]]<!--
--><img id="scout" title="Artist is scouted" style="display: none; cursor: help; margin-left: 1.5%; filter: hue-rotate(-55deg);" class="artistIcon valign" src="../assets/check.png" width="5%"><!--
--><img id="whitelist" title="Artist is whitelisted" style="display: none; cursor: help" class="artistIcon valign" src="../assets/check.png" width="5%"><!--
--> <a class="songLink" href="https://[[SONGAUTHOR]].newgrounds.com" target="_blank"><img class="gdButton valign" src="../assets/more.png" width="12%"></a></h2>
--> <a class="songLink" href="https://[[SONGAUTHOR]].newgrounds.com" target="_blank"><img id="moreSongs" class="gdButton valign" src="../assets/more.png" width="12%"></a></h2>
<img id="checkSong" style="display: none; margin-top: 1%" class="gdButton valign" src="../assets/btn-check.png" width="16%">
<h3 id="songLoading" style="display: none; margin-top: 0.5%;">Loading...</h3>
<h3 id="songAllowed" style="display: none; margin-top: 0.5%; color: lime">Song is allowed for use</h3>
<h3 id="songNotAllowed" style="display: none; margin-top: 0.5%; color: red">Song is not allowed for use</h3>
<h3 id="artistInfo" style="display: none; margin-top: 0.5%"></h3>
</div>
<a class="songLink" href="https://www.newgrounds.com/audio/listen/[[SONGID]]" target="_blank"><img class="gdButton sideButton" src="../assets/playsong.png" style="position:absolute; right: 1%; top: 50%; width: 11%; height: auto;"></a>
<a class="songLink" href="https://www.newgrounds.com/audio/listen/[[SONGID]]" target="_blank"><img class="gdButton sideButton" id="playSong" src="../assets/playsong.png" style="position:absolute; right: 1%; top: 50%; width: 11%; height: auto;"></a>
</div>
<div class="center" style="position:absolute; bottom: 5%; left: 0; right: 0">
@ -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()

View file

@ -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()
})

View file

@ -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("<br />")) responseBody = responseBody.split("<br />").slice(2).join("<br />").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, "&#38;").replace(/</g, "&#60;").replace(/>/g, "&#62;").replace(/=/g, "&#61;").replace(/"/g, "&#34;").replace(/'/g, "&#39;")}
// 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) })