Lots of QOL + Better profile system

- Most profile links now use account IDs instead of username
- Level leaderboards display an error message if they can't load
- Fixed up coins in level analysis so they look normal
- Added an option in level analysis to sort group IDs
This commit is contained in:
GDColon 2021-04-02 20:50:22 -04:00
parent e1f81b1f5d
commit c4cbee3816
11 changed files with 65 additions and 34 deletions

View file

@ -157,7 +157,7 @@ function analyze_level(level, rawData) {
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 => x.coin + " " + 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))
response.coinsVerified = level.verifiedCoins
response.orbs = orb_array

View file

@ -18,9 +18,9 @@ module.exports = async (app, req, res) => {
req.gdRequest('getGJLevelScores211', params, function(err, resp, body) {
if (err || body == -1 || !body) return res.send("-1")
if (err || body == -1 || !body) return res.send({error: true, lastWorked: app.timeSince(req.id)})
scores = body.split('|').map(x => app.parseResponse(x)).filter(x => x[1])
if (!scores.length) return res.send("-1")
if (!scores.length) return res.send([])
else app.trackSuccess(req.id)
scores.forEach(x => {

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -44,10 +44,7 @@
<h3 style="margin-top: -0.25%" id="hdText"></h3>
</div>
<h1 class="topMargin" id="coinText">Coin order</h1>
<div class="transparentBox analysis" id="coins"></div>
<h1 class="topMargin">Portal order</h1>
<h1 class="topMargin">Portal Order</h1>
<div class="transparentBox analysis" id="portals" style="height: 23%"></div>
<div>
<div class="portalSetting"><h3><input checked type="checkbox" class="portalToggle" id="box1" portal="form"> <label for="box1" class="gdcheckbox gdButton portalButton"></label>Form Portals</h3></div>
@ -60,6 +57,9 @@
</div>
<h1 class="topMargin" id="coinText">User Coins</h1>
<div class="transparentBox analysis" id="coins"></div>
<h1 class="topMargin2" id="triggerText">Triggers</h1>
<div class="transparentBox analysis" id="triggers"></div>
@ -77,6 +77,7 @@
<h1 class="topMargin2" id="grouptext">Trigger Groups</h1>
<div class="transparentBox analysis" id="groups" style="height: 18%"></div>
<h3 style="margin-right: 1.2vh" class="inline">Sort:</h3><h3 id="triggerSort" class="inline gdButton gold" style="text-decoration: underline;">Ascending</h3>
<h1 class="topMargin2">Color Channels</h1>
<div class="transparentBox analysis" id="colorDiv"></div>
@ -104,6 +105,7 @@
function clean(text) {return text.toString().replace(/&/g, "&#38;").replace(/</g, "&#60;").replace(/>/g, "&#62;").replace(/=/g, "&#61;").replace(/"/g, "&#34;").replace(/'/g, "&#39;")}
let disabledPortals = []
let altTriggerSort = false
let formPortals = ['cube', 'ship', 'ball', 'ufo', 'wave', 'robot', 'spider']
let speedPortals = ['-1x', '1x', '2x', '3x', '4x']
let sizePortals = ['mini', 'big']
@ -140,14 +142,12 @@ else {
}
let triggerList = Object.keys(res.triggers)
let groupList = Object.keys(res.triggerGroups)
let orbList = Object.keys(res.orbs)
let miscList = Object.keys(res.misc)
let blockList = Object.keys(res.blocks)
let colorList = Object.keys(res.colors)
let portals = res.portals.split(", ").map(x => x.split(" "))
let coins = res.coins.split(", ").map(x => x.split(" "))
function commafy(num) { return (+num || 0).toString().replace(/(\d)(?=(\d\d\d)+$)/g, "$1,") }
@ -168,18 +168,32 @@ function appendPortals() {
if (!x || x[0] == "") return;
$('#portals').append(`<div class="inline portalDiv"><img class="portalImage ${x[0].match(/[0-9]x/) ? "speedPortal" : ""}" src='../assets/objects/portals/${x[0]}.png'><h3>${x[1]}</h3></div>`)
}
)}
)}
function appendTriggerGroups() {
$('#groups').html("")
let groupList = Object.keys(res.triggerGroups)
if (!altTriggerSort) groupList = groupList.sort((a, b) => Number(a.slice(6)) - Number(b.slice(6)))
groupList.forEach(x => {
if (x == "total") $('#grouptext').text(`Trigger Groups (${commafy(res.triggerGroups[x])})`)
else $('#groups').append(`<div class="inline groupDiv"><h1 class="groupID">${x.slice(6)}</h1><h3 style="padding-top: 7%">x${commafy(res.triggerGroups[x])}</h3></div>`)
})
}
appendPortals()
appendPortals()
appendTriggerGroups()
coins.forEach(x => {
if (!x || x[0] == "") {
if (!res.coins || !res.coins.length) {
$('#coinText').remove()
$('#coins').remove()
}
else $('#coins').append(`<div class="inline coinDiv"><img height="40%" src='../assets/${res.coinsVerified ? "silvercoin" : "browncoin"}.png'><h3>${x[1]}</h3></div>`)
else {
$('#coinText').text(`User Coins (${res.coins.length})`)
res.coins.forEach(x => {
$('#coins').append(`<div class="inline orbDiv"><img height="50%" src='../assets/objects/${res.coinsVerified ? "coin" : "browncoin"}.png'><h3 style="padding-top: 7%">${x}%</h3></div>`)
})
}
triggerList.forEach(x => {
if (x == "total") $('#triggerText').text(`Triggers (${commafy(res.triggers[x])})`)
@ -200,10 +214,6 @@ appendPortals()
else $('#misc').append(`<div class="inline miscDiv"><img height="40%" src='../assets/objects/${x.slice(0, -1)}.png'><h3 style="padding-top: 15%">x${commafy(res.misc[x][0])}<br>${res.misc[x][1]}</h3></div>`)
})
groupList.forEach(x => {
if (x == "total") $('#grouptext').text(`Trigger Groups (${commafy(res.triggerGroups[x])})`)
else $('#groups').append(`<div class="inline groupDiv"><h1 class="groupID">${x.slice(6)}</h1><h3 style="padding-top: 7%">x${commafy(res.triggerGroups[x])}</h3></div>`)
})
let bgCol = res.colors.find(x => x.channel == "BG")
let grCol = res.colors.find(x => x.channel == "G")
@ -232,6 +242,12 @@ appendPortals()
if (colorList.length == 0) $('#colorDiv').append('<h3 style="margin-top: 7vh">Could not get color info!</h3>')
$('#triggerSort').click(function() {
altTriggerSort = !altTriggerSort
$('#triggerSort').text(altTriggerSort ? "Most Used" : "Ascending")
appendTriggerGroups()
})
$(".portalToggle").click(function() {
if ($(this).prop('checked')) disabledPortals = disabledPortals.filter(x => x != $(this).attr('portal'))
else disabledPortals.push($(this).attr('portal'))

View file

@ -187,7 +187,7 @@ Fetch(target).then(lvl => {
$('#levelAuthor').addClass("green").addClass("unregistered")
$('#authorLink').attr('href', '../search/' + lvl.playerID + "?user")
}
else $('#authorLink').attr('href', '../u/' + lvl.author)
else $('#authorLink').attr('href', `../u/${lvl.accountID}.`)
$('#levelName').text(lvl.name || ("Nonexistent level " + lvlID))
if (!lvl.name) $('#leaveComment').hide()
$('#levelAuthor').text("By " + (lvl.author || "-"))
@ -244,7 +244,6 @@ fetch(`../api${!history ? window.location.pathname : "/comments/" + lvl.playerID
if (auto) bgCol = $('.commentBG').first().hasClass('oddComment') ? "evenComment" : "oddComment"
let userName = !history ? x.username : lvl.username
let userLink = encodeURI(userName)
let modNumber = x.moderator || lvl.moderator
if (x.pages) {
@ -260,7 +259,7 @@ fetch(`../api${!history ? window.location.pathname : "/comments/" + lvl.playerID
<div class="commentBG ${bgCol}">
<div class="comment" commentID="${x.ID}">
<img class="inline" src="../icon/icon?form=${x.icon.form}&icon=${x.icon.icon}&col1=${x.icon.col1}&col2=${x.icon.col2}&glow=${x.icon.glow}&size=auto" height=21% style="margin-right: 0.8%">
<a href=../${x.accountID == "0" ? `search/${x.playerID}?user` : `../u/${userLink}`}>
<a href=../${x.accountID == "0" ? `search/${x.playerID}?user` : `../u/${x.accountID}.`}>
<h2 class="inline gdButton ${x.accountID == "0" ? "green unregistered" : ""}">${userName}</h2></a>
${modNumber > 0 ? `<img class="inline" src="../assets/mod${modNumber > 2 ? "-extra" : modNumber == 2 ? "-elder" : ""}.png" height=18% style="margin-left: 0.6%;">` : ""}
<p class="commentPercent inline">${x.percent ? x.percent + "%" : ""}</p>
@ -285,7 +284,7 @@ fetch(`../api${!history ? window.location.pathname : "/comments/" + lvl.playerID
<div class="commentBG compactBG ${bgCol}">
<div class="comment compact" commentID="${x.ID}">
<img class="inline" src="../icon/icon?form=${x.icon.form}&icon=${x.icon.icon}&col1=${x.icon.col1}&col2=${x.icon.col2}&glow=${x.icon.glow}&size=auto" height=21% style="margin-right: 0.8%">
<a href=../${x.accountID == "0" ? `search/${x.playerID}?user` : `../u/${userLink}`}>
<a href=../${x.accountID == "0" ? `search/${x.playerID}?user` : `../u/${x.accountID}.`}>
<h2 class="inline gdButton ${x.accountID == "0" ? "green unregistered" : ""}">${userName}</h2></a>
${modNumber > 0 ? `<img class="inline" src="../assets/mod${modNumber > 2 ? "-extra" : modNumber == 2 ? "-elder" : ""}.png" height=18% style="margin-left: 0.6%;">` : ""}
<p class="commentPercent inline">${x.percent ? x.percent + "%" : ""}</p>

View file

@ -142,7 +142,7 @@ function leaderboard(val) {
let wp = x.weeklyProgress || {}
$('#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)">` : ""}
<h2 class="small inline gdButton" style="margin-top: 1.5%${x.moderator == 2 ? "; color: #FF9977;" : ""}"><a href="${onePointNine ? `../search/${x.playerID}?user` : `../u/${x.username}`}">${x.username}</a></h2>
<h2 class="small inline gdButton" style="margin-top: 1.5%${x.moderator == 2 ? "; color: #FF9977;" : ""}"><a href="${onePointNine ? `../search/${x.playerID}?user` : `../u/${x.accountID}.`}">${x.username}</a></h2>
<h3 class="inline sideSpace${x.stars >= 100000 ? " yellow" : ""}" style="font-size: 4.5vh${type == "weekly" ? "; display: none" : ""};">${x.stars} <img class="help valign" src="../assets/star.png"
style="width: 4vh; transform: translate(-25%, -10%);" title="Stars"></h3>

View file

@ -91,7 +91,7 @@
</div>
<div class="center" style="position:absolute; top: 9%; left: 0%; right: 0%; height: 5%;">
<h2 class="pre inline slightlySmaller normalCursor gdButton" id="authorName"><a class="linkButton" id="authorLink" href="../u/[[AUTHOR]]">By [[AUTHOR]]</a></h2>
<h2 class="pre inline slightlySmaller normalCursor gdButton" id="authorName"><a class="linkButton" id="authorLink" href="../u/[[ACCOUNTID]].">By [[AUTHOR]]</a></h2>
<h2 class="inline slightlySmaller normalCursor sideSpaceC">
<img class="inline valign" id="copiedBadge" style="height: 60%; cursor:help" src="../assets/copied.png" title="Level is a copy or a collaboration">
<img class="inline valign" id="largeBadge" style="height: 60%; margin-left: -7%; cursor:help" src="../assets/large.png" title="Contains more than 40,000 objects"></h2><br>

View file

@ -40,6 +40,12 @@
<img class="spin noSelect" src="../assets/loading.png" height="105%">
</div>
<div id="error" class="supercenter" style="height: 20%; top: 47%; display: none;">
<h1 class="center">No scores available...</h1>
<h3 class="center" style="margin-top: 2%">Either this leaderboard is empty, or the scores weren't able to be obtained from the GD servers.</h3>
<h3 class="center" style="margin-top: 1.5%">Last worked: <span class="gold" id="lastWorked"></span></h3>
</div>
<div class="supercenter" style="left: 87%; top: 24%; height: 10%">
<img class="gdButton darken" id="topMode" src="../assets/leaderboard-top.png" height="90%">
</div>
@ -67,6 +73,7 @@ function leaderboard() {
if (loading == true) return;
$('#error').hide()
$('#searchBox').html(`<div style="height: 4.5%"></div>`)
loading = true;
$('#loading').show()
@ -83,14 +90,20 @@ function leaderboard() {
fetch(`../api/leaderboardLevel/${lvlID}?count=200${weekly ? "&week" : ""}`).then(res => res.json()).then(res => {
if (res == "-1" || !res || !res.length) {$('#loading').hide(); return loading = false;}
if (!res || res.error || res == "-1") {
loading = false;
$('#loading').hide();
$('#lastWorked').html(res.error ? res.lastWorked + " ago": "Unknown")
$('#error').show()
return
}
res.forEach((x, y) => {
let shift = x.rank >= 100 ? [0.4, 50] : x.rank >= 10 ? [0.2, 25] : [0, 10]
$('#searchBox').append(`<div class="searchresult leaderboardSlot" style="padding-left: 25.5vh; height: 15%">
<h2 class="small inline gdButton" style="margin-top: 1.5%; font-size: 6.5vh; margin-right: 3%;"><a href="../u/${x.username}">${x.username}</a></h2>
<h2 class="small inline gdButton" style="margin-top: 1.5%; font-size: 6.5vh; margin-right: 3%;"><a href="../u/${x.accountID}.">${x.username}</a></h2>
<h3 class="inline lessSpaced leaderboardStats" style="transform:translateY(-10%)">
${x.percent}%

View file

@ -247,7 +247,7 @@
$('#msgList').append(`
<div messageID=${x.id} playerID="${x.accountID}" ${x.browserColor ? 'browserColor="true" ' : ""}class="commentBG gdMessage">
<h3 style="color: ${x.browserColor ? 'rgb(120, 200, 255)' : 'white'}; font-size: ${x.subject.length > 35 ? "3" : x.subject.length > 30 ? "3.5" : x.subject.length > 25 ? "3.75" : "4"}vh">${x.subject}${x.unread ? " <cg>!</cg>" : ""}</h3>
<h3 class="gold gdButton msgAuthor hitbox fit"><a href="../u/${x.author}" target="_blank">From: ${x.author}</a></h3>
<h3 class="gold gdButton msgAuthor hitbox fit"><a href="../u/${x.accountID}." target="_blank">From: ${x.author}</a></h3>
<p class="msgDate">${x.date}</p>
<div class="labelButton hitbox">
<input id="message-${y}" type="checkbox" class="chk" messageID=${x.id}>
@ -294,7 +294,7 @@
targetUser = decodeURIComponent(targetUser[2])
fetch(`../api/profile/${targetUser}`).then(res => res.json()).then(res => {
if (res == "-1" || !res) return;
$('#replyAuthor').html(`<a href="../u/${res.username}" target="_blank">To: ${res.username}</a>`)
$('#replyAuthor').html(`<a href="../u/${res.accountID}." target="_blank">To: ${res.username}</a>`)
messageStatus[res.accountID] = [res.messages, res.username]
playerID = res.accountID
if (res.messages == "all") $('#messageStatus').html(`<cy>${res.username}</cy> has messages <cg>enabled</cg>`)

View file

@ -157,6 +157,9 @@
function clean(text) {return text.replace(/&/g, "&#38;").replace(/</g, "&#60;").replace(/>/g, "&#62;").replace(/=/g, "&#61;").replace(/"/g, "&#34;").replace(/'/g, "&#39;")}
// remove ID from URL
if (window.location.pathname.endsWith(".")) window.history.pushState({}, null, window.location.origin + `/u/[[USERNAME]]`);
let messageText = 'Your <cy>Geometry Dash password</cy> will <cg>not be stored</cg> anywhere on the site, both <ca>locally and server-side.</ca> You can view the code used for profile posts <a class="menuLink" target="_blank" href="https://github.com/GDColon/GDBrowser/blob/master/api/post/postProfileComment.js">here</a>.'
$('#message').html(messageText)
$('#likeMessage').html(messageText.replace("profile posts", "liking posts").replace("postProfileComment", "like"))

View file

@ -194,7 +194,7 @@ function Append(firstLoad) {
$('#searchBox').append(`<div class="searchresult" title="${clean(x.description)}">
<h1 class="help lessspaced pre" title="${x.name} (${x.id})" style="width: fit-content; padding-right: 1%">${clean(x.name || " ")}</h1>
<h2 class="lessSpaced pre smaller inline gdButton help ${hasAuthor ? "" : "green unregistered"}" title="Account ID: ${x.accountID}\nPlayer ID: ${x.playerID}">${hasAuthor && !onePointNine ? `<a href="../u/${x.author}">By ${x.author || "-"}</a>` : `<a ${userSearch ? "" : `href="../search/${x.playerID}?user"`}>By ${x.author || "-"}</a>`}</h2><h2 class="inline" style="margin-left: 1.5%; transform:translateY(30%)"> ${x.copiedID == '0' ? "" : `<a target="_blank" href="../${x.copiedID}"><img class="gdButton valign sideSpace" title="Original: ${x.copiedID}" src="../assets/copied.png" height="12%"></a>`}${x.large ? `<img class="help valign sideSpaceD" title="${x.objects}${x.objects == 65535 ? "+" : ""} objects" src="../assets/large.png" height="12%">` : ''}</h2>
<h2 class="lessSpaced pre smaller inline gdButton help ${hasAuthor ? "" : "green unregistered"}" title="Account ID: ${x.accountID}\nPlayer ID: ${x.playerID}">${hasAuthor && !onePointNine ? `<a href="../u/${x.accountID}.">By ${x.author || "-"}</a>` : `<a ${userSearch ? "" : `href="../search/${x.playerID}?user"`}>By ${x.author || "-"}</a>`}</h2><h2 class="inline" style="margin-left: 1.5%; transform:translateY(30%)"> ${x.copiedID == '0' ? "" : `<a target="_blank" href="../${x.copiedID}"><img class="gdButton valign sideSpace" title="Original: ${x.copiedID}" src="../assets/copied.png" height="12%"></a>`}${x.large ? `<img class="help valign sideSpaceD" title="${x.objects}${x.objects == 65535 ? "+" : ""} objects" src="../assets/large.png" height="12%">` : ''}</h2>
<h3 class="lessSpaced help ${noLink ? "" : 'gdButton '}pre ${songColor}" title="${filteredSong} by ${x.songAuthor} (${x.songID})" style="overflow: hidden; max-height: 19%; width: fit-content">${noLink ? filteredSong : `<a target="_blank" style="width: fit-content" href="https://www.newgrounds.com/audio/listen/${x.songID}">${filteredSong}</a>`}</h3>
<h3 class="lessSpaced" style="width: fit-content" title="">
<img class="help valign" title="Length" src="../assets/time.png" height="14%"> ${x.length}