Demon Leaderboard!

This commit is contained in:
GDColon 2020-10-28 21:25:13 -04:00
parent c15df5d436
commit 16a1b4d491
17 changed files with 150 additions and 36 deletions

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 Colon
Copyright (c) 2020 Colon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -66,6 +66,7 @@ module.exports = async (app, req, res, api, ID, analyze) => {
level.songID = "Level " + [parseInt(levelInfo[12]) + 1]
}
level.extraString = levelInfo[36]
level.data = levelInfo[4]
if (analyze) return app.run.analyze(app, req, res, level)

View file

@ -143,7 +143,7 @@ h1 {
font-weight: normal;
margin: 0% 0%;
font-size: 6vh;
font-family: Pusab;
font-family: Pusab, Arial;
color: white;
letter-spacing: 0.02em;
overflow: hidden;
@ -157,7 +157,7 @@ h2 {
font-weight: normal;
margin: 0 0;
font-size: 8vh;
font-family: Pusab;
font-family: Pusab, Arial;
color: rgb(255, 200, 0);
letter-spacing: 0.02em;
text-shadow: -0.275vh -0.275vh 0vh #000, 0.275vh -0.275vh 0vh #000, -0.275vh 0.275vh 0vh #000, 0.275vh 0.275vh 0vh #000, 0.5vh 0.5vh 0vh rgba(0,0,0,0.4);
@ -167,7 +167,7 @@ h3, input[type=text], input[type=password], input[type=number] {
font-weight: normal;
margin: 0 0;
font-size: 3.5vh;
font-family: Pusab;
font-family: Pusab, Arial;
color: white;
letter-spacing: 0.02em;
text-shadow: -0.15vh -0.15vh 0vh #000, 0.15vh -0.15vh 0vh #000, -0.15vh 0.15vh 0vh #000, 0.15vh 0.15vh 0vh #000;

BIN
assets/demonleaderboard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
assets/site.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
assets/trophy-gold.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -154,7 +154,8 @@
<p class="red">updated: Time since the level was last updated</p>
<p class="red">password: The password to copy the level. 0 means the level isn't copyable and 1 means it's free to copy</p>
<p class="red">ldm: If the level contains a checkbox for Low Detail Mode</p>
<p class="red">data: The actual data of the level. Don't ask how to use it, because I have no idea</p>
<p class="red">extraString: An unknown string which most likely contains info on how the level was verified</p>
<p class="red">data: The actual data of the level, compressed with GZIP</p>
</div>
<br>

115
html/demon.html Normal file
View file

@ -0,0 +1,115 @@
<head>
<title>Demon Leaderboard</title>
<meta charset="utf-8">
<link href="../css/browser.css" type="text/css" rel="stylesheet">
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-135255146-3"></script><script>window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);}gtag('js', new Date());gtag('config', 'UA-135255146-3');</script>
<link rel="icon" href="../assets/trophy-gold.png">
<meta id="meta-title" property="og:title" content="Demon Leaderboard">
<meta id="meta-desc" property="og:description" content="View the victors of a very hard Geometry Dash level!">
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/trophy-gold.png">
</head>
<body class="levelBG darkBG" onbeforeunload="saveUrl()">
<div id="everything" style="overflow: auto;">
<div class="popup" id="infoDiv">
<div class="fancybox bounce center supercenter" style="width: 90vh">
<h2 class="smaller center" style="font-size: 5.5vh">Credits</h2>
<p class="bigger center" style="line-height: 5vh; margin-top: 1.5vh; margin-bottom: 2.5vh;">
<span style="color: orange">Demon rankings</span> made possible thanks to <a target="_blank" href="https://pointercrate.com"><span style="color:aqua; text-decoration: underline">Pointercrate</span></a>!
All demons and rankings are managed by their <span style="color: #4CDA5B">list staff</span>.
</p>
<p class="bigger center" style="margin-top: 1vh">
Usernames and icons may <span style="color: yellow">differ</span> from what is used in GD
</p>
<img src="../assets/ok.png" width=15%; class="gdButton center" onclick="$('.popup').hide()">
</div>
</div>
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%">
<img class="cornerPiece grayscale" src="../assets/corner.png" width=7%;>
</div>
<div style="position:absolute; bottom: 0%; right: 0%; width: 100%; text-align: right;">
<img class="cornerPiece grayscale" src="../assets/corner.png" width=7%; style="transform: scaleX(-1)">
</div>
<div id="searchBox" class="supercenter dragscroll"; style="width: 124vh">
<div style="height: 4.5%"></div>
</div>
<div class="epicbox supercenter gs" style="width: 126vh; height: 80%; pointer-events: none"></div>
<div class="center" style="position:absolute; top: 8%; left: 0%; right: 0%">
<h1 id="header"></h1>
</div>
<div style="position:absolute; top: 2%; left: 1.5%; width: 10%; height: 25%; pointer-events: none">
<img class="gdButton yesClick" id="backButton" src="../assets/back.png" height="30%" onclick="backButton()">
</div>
<div class="supercenter" id="loading" style="height: 10%; top: 47%">
<img class="spin noSelect" src="../assets/loading.png" height="105%">
</div>
<div style="position:absolute; top: 3%; right: 2%; text-align: right; width: 20%;">
<a target="_blank" id="pointercrate"><img class="inline gdButton" src="../assets/demonButton.png" width="23%" style="margin-right: 4%" onclick="$('#infoDiv').show()"></a>
<img id="creditsButton" class="inline gdButton" src="../assets/credits.png" width="25%" onclick="$('#infoDiv').show()">
</div>
</div>
</body>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery.lazy/1.7.9/jquery.lazy.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery.lazy/1.7.9/jquery.lazy.plugins.min.js"></script>
<script async type="text/javascript" src="../assets/sizecheck.js"></script>
<script type="text/javascript" src="../assets/dragscroll.js"></script>
<script>
let demonID = Math.round(window.location.pathname.split('/')[2])
if (!demonID || demonID > 250 || demonID < 1) window.location.href = "../../../"
fetch(`https://pointercrate.com/api/v1/demons/${demonID}/`).then(res => res.json()).then(demonRes => {
let demon = demonRes.data
if (!demon.id) window.location.href = "../../../"
document.title = "Demon Leaderboard for " + demon.name
$('#header').html(`${demon.name} <span class="smallerer" style="vertical-align: middle">(#${demonID})</span>`)
$('#meta-title').attr('content', "Demon Leaderboard for " + demon.name)
$('#meta-desc').attr('content', 'View the challengers and victors of' + demon.name)
$('#pointercrate').attr('href', `https://pointercrate.com/demonlist/${demonID}`)
demon.records.forEach((x, y) => {
let shift = y >= 999 ? [0.5, 75] : y >= 99 ? [0.4, 60] : y >= 9 ? [0.2, 25] : [0, 10]
let videoIcon = "site"
if (x.video && x.video.includes("youtube.com")) videoIcon = "youtube"
else if (x.video && x.video.includes("twitch.tv")) videoIcon = "twitch"
$('#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.player.name}">${x.player.name}</a></h2>
<h3 class="inline lessSpaced leaderboardStats" style="transform:translateY(-10%)">${x.progress}%</h3>
<div class="center" style="position:absolute; transform:scale(0.82) translate(-28vh, -10vh); height: 10%; width: 12.5%;">
<div class="inline" style="width: 50%; margin: 0% 20% 0% 10%; transform:translateY(-15%)"><h2 class="inline center" style="transform:scale(${1-shift[0]}) translateX(-${shift[1]}%)">${y+1}</h2></div>
<img class="inline spaced lazyLoad" data-src="../icon/${x.player.name}" height="120%" style="margin-bottom: 0%; transform:scale(1.1)">
</div>
<div style="${!x.video ? "display: none; " : ""}position:absolute; width: 12.5%; height: 15%; right: 0%">
<a target="_blank" href="${x.video}">
<img class="gdButton inline spaced" src="../assets/${videoIcon}.png" height="80%" style="transform: translateY(-8.5vh)">
</a>
</div>
</div>`)
})
$('#loading').hide();
$('.lazyLoad').Lazy({ appendScroll: '#searchBox' });
})
</script>

View file

@ -182,8 +182,6 @@ fetch('./api/icons').then(res => {
if ($(forms).html() == "") appendIcon(filterIcon(form), form)
if (form == "swing" && !beenThereDoneThat) {beenThereDoneThat = true; $('#swings').append("<p class='white'>Since the texture was ripped from GD Meltdown, there's no UHD version available.</p>")}
$(forms).show()
})

View file

@ -133,9 +133,7 @@ function leaderboard(val) {
$('#searchBox').append('<div style="height: 4.5%"></div>')
$('#loading').hide();
$('.lazyLoad').Lazy({
appendScroll: '#searchBox'
});
$('.lazyLoad').Lazy({ appendScroll: '#searchBox' });
})
}

View file

@ -18,7 +18,7 @@
<h2 class="smaller center" style="font-size: 5.5vh">Level Info</h2>
<p class="bigger center" id="levelInfo" style="line-height: 5vh; margin-top: 1.5vh;">
<span style="color:lime">[[NAME]]</span><br>
ID: <span style="color:yellow">[[ID]]</span>[[ORIGINALINFO]][[LOWDETAIL]][[PASS]][[UPLOAD]][[UPDATE]]
ID: <span style="color:yellow">[[ID]]</span>[[ORIGINALINFO]][[LOWDETAIL]][[PASS]][[UPLOAD]][[UPDATE]][[HACKED]]
<br>Version: <span style="color:yellow">[[VERSION]]</span>
<br>GD Version: <span style="color:yellow">[[GAMEVERSION]]</span>
[[OBJECTINFO]][[REQUESTED]]
@ -132,7 +132,7 @@
<!-- <img class="gdButton sideButton" id="likeButton" src="../assets/vote.png" onclick="$('#likeDiv').show()"><br> -->
<a href="./analyze/[[ID]]"><img class="gdButton sideButton" src="../assets/edit.png"></a><br>
<a href="./comments/[[ID]]"><img class="gdButton sideButton" src="../assets/comment.png"></a><br>
<a href="./leaderboard/[[ID]]"><img class="gdButton sideButton" src="../assets/leaderboard.png"></a><br>
<a href="./leaderboard/[[ID]]"><img id="leaderboardbtn" class="gdButton sideButton" src="../assets/leaderboard.png"></a><br>
</div>
<div style="position:absolute; top: 2%; left: 1.5%; width: 10%; height: 25%; pointer-events: none">
@ -190,6 +190,7 @@ if (!'[[UPLOADED]]'.startsWith('[')) {
$('#levelInfo').html($('#levelInfo').html()
.replace('[[PASS]]', `<br>Password: <span style="color:orange">${'[[PASSWORD]]' == '0' ? "No copy" : '[[PASSWORD]]' == 1 ? "Free copy" : '[[PASSWORD]]'}</span>`)
.replace('[[LOWDETAIL]]', `<br>Low Detail: <span style="color:orange">${[[LDM]] ? "Yes" : "No"}</span>`)
.replace('[[HACKED]]', `<br>Extra String: <span style="color:orange">${'[[EXTRASTRING]]'.length} chars</span>`)
.replace('[[UPLOAD]]', '[[UPLOADED]]' == "0" ? "" : `<br>Uploaded: <span style="color:orange">[[UPLOADED]]</span>`)
.replace('[[UPDATE]]', '[[UPDATED]]' == "0" ? "" : `<br>Updated: <span style="color:orange">[[UPDATED]]</span>`))}
@ -197,6 +198,7 @@ else {
$('#levelInfo').html($('#levelInfo').html()
.replace('[[PASS]]', "")
.replace('[[LOWDETAIL]]', "")
.replace('[[HACKED]]', "")
.replace('[[UPLOAD]]', "")
.replace('[[UPDATE]]', "") +
`<br><a class="youCanClickThis" href="/[[ID]]?download"><span style="color:aqua">Download additional info</span></a>`
@ -208,7 +210,10 @@ if ([[ORBS]] == 0) $('.orbs').hide()
if ([[STARS]] == 0) $('.stars').hide()
if ([[DIAMONDS]] == 0 || !'[[DEMONLIST]]'.startsWith("[")) $('.diamonds').hide()
if (!'[[DEMONLIST]]'.startsWith("[")) $('.demonList').show()
if (!'[[DEMONLIST]]'.startsWith("[")) {
$('.demonList').show()
$('#leaderboardbtn').attr('src', '../assets/demonleaderboard.png').parent().attr('href', '../demon/[[DEMONLIST]]')
}
else $('.demonList').remove()
if ("[[SONGID]]".startsWith("Level")) {
@ -226,12 +231,14 @@ if ([[COINS]] > 2) $("#coins").append(`<img class="squeeze" src="../assets/${coi
if ("[[ACCOUNTID]]" == "0") {
$("#authorName").addClass("green").addClass("unregistered")
$("#authorLink").attr('href', '/search/[[AUTHORID]]?user')
}
}
if (window.location.pathname == "/weekly") $('body').addClass('darkBG')
if (window.location.pathname == "/weekly") {
$('body').addClass('darkBG')
$('.cornerPiece').addClass('grayscale')
}
$(window).on('load', function() {
if ($('#songname')[0].scrollWidth > $('#songBox')[0].scrollWidth) {
let overflow = ($('#songname')[0].scrollWidth - $('#songBox')[0].scrollWidth) * 0.007
if (overflow > 3) overflow = 3

View file

@ -13,14 +13,6 @@
<div id="everything" style="overflow: auto;">
<div class="popup" id="infoDiv">
<div class="fancybox bounce center supercenter">
<h2 class="smaller center" style="font-size: 5.5vh">Leaderboard Info</h2>
<p class="bigger center" id="infoText" style="line-height: 5vh; margin-top: 1.5vh"></p>
<img src="../assets/ok.png" width=20%; class="gdButton center" onclick="$('.popup').hide()">
</div>
</div>
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%">
<img class="cornerPiece" src="../assets/corner.png" width=7%;>
</div>
@ -66,10 +58,9 @@
<script>
let loading = false;
let lvlID = window.location.pathname.split('/')[2]
let lvlID = Math.round(window.location.pathname.split('/')[2])
if (!Number.isInteger(+lvlID) || lvlID > 99999999 || lvlID < -99999999) window.location.href = window.location.href.replace("leaderboard", "search")
lvlID = Math.round(+lvlID)
if (!lvlID || lvlID > 99999999 || lvlID < -99999999) window.location.href = window.location.href.replace("leaderboard", "search")
function leaderboard() {
@ -82,6 +73,7 @@ function leaderboard() {
fetch(`../api/level/${lvlID}`).then(lvl => lvl.json()).then(lvl => {
if (lvl == "-1") return $('#header').html("Nonexistent level " + lvlID)
document.title = "Leaderboards for " + lvl.name
$('#header').html(lvl.name)
$('#meta-title').attr('content', "Leaderboards for " + lvl.name)
$('#meta-desc').attr('content', 'View the leaderboard for ' + lvl.name + ' by ' + lvl.author + '!')

View file

@ -1,7 +1,7 @@
const express = require('express');
const fs = require("fs")
const timeout = require('connect-timeout')
const compression = require('compression');
const timeout = require('connect-timeout')
const rateLimit = require("express-rate-limit");
// set to false if you're using gdbrowser locally, for obvious reasons
@ -38,7 +38,8 @@ app.use(timeout('30s'));
app.use(haltOnTimedout)
app.set('json spaces', 2)
let directories = ["", "post", "messages"] //this can probably be automated but i'm lazy
let directories = [""]
fs.readdirSync('./api').filter(x => !x.includes(".")).forEach(x => directories.push(x))
app.run = {}
directories.forEach(d => {
@ -102,7 +103,7 @@ app.post("/messages/:id", RL, async function(req, res) { app.run.fetchMessage(ap
app.post("/deleteMessage", RL, function(req, res) { app.run.deleteMessage(app, req, res) })
app.post("/sendMessage", RL, function(req, res) { app.run.sendMessage(app, req, res) })
app.post("/accurateLeaderboard", function(req, res) { app.run.accurateLeaderboard(app, req, res, true) })
app.post("/accurateLeaderboard", function(req, res) { app.run.accurate(app, req, res, true) })
// HTML
@ -115,6 +116,7 @@ app.get("/", function(req, res) {
app.get("/analyze/:id", async function(req, res) { res.sendFile(__dirname + "/html/analyze.html") })
app.get("/api", function(req, res) { res.sendFile(__dirname + "/html/api.html") })
app.get("/comments/:id", function(req, res) { res.sendFile(__dirname + "/html/comments.html") })
app.get("/demon/:id", function(req, res) { res.sendFile(__dirname + "/html/demon.html") })
app.get("/gauntlets", function(req, res) { res.sendFile(__dirname + "/html/gauntlets.html") })
app.get("/iconkit", function(req, res) { res.sendFile(__dirname + "/html/iconkit.html") })
app.get("/leaderboard", function(req, res) { res.sendFile(__dirname + "/html/leaderboard.html") })
@ -130,7 +132,7 @@ app.get("/search/:text", function(req, res) { res.sendFile(__dirname + "/html/se
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/credits", function(req, res) { res.send(require('./misc/credits.json')) })
app.get("/api/leaderboard", function(req, res) { app.run[req.query.hasOwnProperty("accurate") ? "accurateLeaderboard" : "leaderboard"](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", RL, 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) { res.send(require('./misc/mapPacks.json')) })
@ -149,6 +151,7 @@ app.get("/p/:id", function(req, res) { res.redirect('/u/' + req.params.id) })
app.get("/l/:id", function(req, res) { res.redirect('/leaderboard/' + req.params.id) })
app.get("/a/:id", function(req, res) { res.redirect('/analyze/' + req.params.id) })
app.get("/c/:id", function(req, res) { res.redirect('/comments/' + req.params.id) })
app.get("/d/:id", function(req, res) { res.redirect('/demon/' + req.params.id) })
// API AND HTML

View file

@ -11,7 +11,6 @@
"express": "^4.17.1",
"express-rate-limit": "^5.1.3",
"google-spreadsheet": "^3.0.11",
"image-size": "^0.9.1",
"jimp": "^0.8.5",
"plist": "^3.0.1",
"request": "^2.88.2"