Demon Leaderboard!
This commit is contained in:
parent
c15df5d436
commit
16a1b4d491
17 changed files with 150 additions and 36 deletions
2
LICENSE
2
LICENSE
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
BIN
assets/demonleaderboard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
assets/site.png
Normal file
BIN
assets/site.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
assets/trophy-gold.png
Normal file
BIN
assets/trophy-gold.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
|
@ -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
115
html/demon.html
Normal 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>
|
|
@ -181,8 +181,6 @@ fetch('./api/icons').then(res => {
|
|||
$(this).children().not('#iconprogressbar').hide()})
|
||||
|
||||
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()
|
||||
})
|
||||
|
|
|
@ -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' });
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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")) {
|
||||
|
@ -224,14 +229,16 @@ if ([[COINS]] > 1) $("#coins").append(`<img class="squeeze" src="../assets/${coi
|
|||
if ([[COINS]] > 2) $("#coins").append(`<img class="squeeze" src="../assets/${coinColor}.png" height="5%">`)
|
||||
|
||||
if ("[[ACCOUNTID]]" == "0") {
|
||||
$("#authorName").addClass("green").addClass("unregistered")
|
||||
$("#authorLink").attr('href', '/search/[[AUTHORID]]?user')
|
||||
}
|
||||
$("#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
|
||||
|
|
|
@ -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,9 +73,10 @@ 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 + '!')
|
||||
$('#meta-title').attr('content', "Leaderboards for " + lvl.name)
|
||||
$('#meta-desc').attr('content', 'View the leaderboard for ' + lvl.name + ' by ' + lvl.author + '!')
|
||||
})
|
||||
|
||||
|
||||
|
|
11
index.js
11
index.js
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue