Added comment liking!

I also added level liking, but I decided to comment it all out (on level.html) because GD levels take a few minutes to update. It would just be confusing to the client :P
This commit is contained in:
GDColon 2019-11-18 18:39:17 -05:00
parent 0b2421c114
commit e8d7c092bd
11 changed files with 244 additions and 23 deletions

45
api/like.js Normal file
View file

@ -0,0 +1,45 @@
const request = require('request')
const XOR = require('../misc/XOR.js');
const xor = new XOR();
const crypto = require('crypto')
function sha1(data) { return crypto.createHash("sha1").update(data, "binary").digest("hex"); }
module.exports = async (app, req, res) => {
if (!req.body.ID) return res.status(400).send("No ID provided!")
if (!req.body.accountID) return res.status(400).send("No account ID provided!")
if (!req.body.password) return res.status(400).send("No password provided!")
if (!req.body.like) return res.status(400).send("No like flag provided! (1=like, 0=dislike)")
if (!req.body.type) return res.status(400).send("No type provided! (1=level, 2=comment, 3=profile")
if (!req.body.extraID) return res.status(400).send("No extra ID provided! (this should be a level ID, account ID, or '0' for levels")
let params = {
gameVersion: '21',
binaryVersion: '35',
secret: app.secret,
udid: '0',
uuid: '0',
rs: '8f0l0ClAN1'
}
params.itemID = req.body.ID.toString()
params.gjp = xor.encrypt(req.body.password, 37526)
params.accountID = req.body.accountID.toString()
params.like = req.body.like.toString()
params.special = req.body.extraID.toString()
params.type = req.body.type.toString()
let chk = params.special + params.itemID + params.like + params.type + params.rs + params.accountID + params.udid + params.uuid + "ysg6pUrtjn0J"
chk = sha1(chk)
chk = xor.encrypt(chk, 58281)
params.chk = chk
request.post('http://boomlings.com/database/likeGJItem211.php', {
form: 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")
if (!body || body == "-1") return res.status(400).send("The Geometry Dash servers rejected your vote! Make sure your username and password are entered correctly.")
res.status(200).send((params.like == 1 ? 'Successfully liked!' : 'Successfully disliked!') + " (this will only take effect if this is your first time doing so)")
})
}

View file

@ -20,6 +20,8 @@ module.exports = async (app, req, res) => {
if (!req.body.accountID) return res.status(400).send("No account ID provided!")
if (!req.body.password) return res.status(400).send("No password provided!")
if (req.body.comment.includes('\n')) return res.status(400).send("Comments cannot contain line breaks!")
if (rateLimit[req.body.username]) return res.status(400).send(`Please wait ${getTime(rateLimit[req.body.username] + cooldown - Date.now())} seconds before posting another comment!`)
let params = {
@ -31,26 +33,23 @@ module.exports = async (app, req, res) => {
params.comment = new Buffer(req.body.comment).toString('base64').replace(/\//g, '_').replace(/\+/g, "-")
params.gjp = xor.encrypt(req.body.password, 37526)
params.levelID = req.body.levelID
params.accountID = req.body.accountID
params.levelID = req.body.levelID.toString()
params.accountID = req.body.accountID.toString()
params.userName = req.body.username
let percent = parseInt(req.body.percent)
if (percent && percent > 0 && percent <= 100) params.percent = percent
if (percent && percent > 0 && percent <= 100) params.percent = percent.toString()
let chk = params.userName + params.comment + params.levelID + params.percent + "0xPT6iUrtws0J"
chk = sha1(chk)
chk = xor.encrypt(chk, 29481)
params.chk = chk
console.log(params)
request.post('http://boomlings.com/database/uploadGJComment21.php', {
form: 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")
if (!body || body == "-1") return res.status(400).send("The Geometry Dash servers rejected your comment! Make sure your username and password are entered correctly.")
if (!body || body == "-1") return res.status(400).send("The Geometry Dash servers rejected your comment! Try again later, or make sure your username and password are entered correctly.")
res.status(200).send(`Comment posted to level ${params.levelID} with ID ${body}`)
rateLimit[req.body.username] = Date.now();
setTimeout(() => {delete rateLimit[req.body.username]; }, cooldown);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 B

View file

@ -115,10 +115,14 @@ img, .noSelect {
filter: brightness(50%);
}
.darken {
.darken, .youAreNotTheOne {
filter: brightness(65%);
}
.youAreNotTheOne {
transform: scale(0.85)
}
#everything {
width: 100%;
height: 100%;
@ -217,6 +221,7 @@ textarea::-webkit-scrollbar-thumb {
}
input:-webkit-autofill, input:-webkit-autofill:hover, input:-webkit-autofill:focus, input:-webkit-autofill:active {
box-shadow: 0 0 0px 1000px #764F1A inset !important;
-webkit-box-shadow: 0 0 0px 1000px #764F1A inset !important;
-webkit-text-fill-color: white !important;
}
@ -414,6 +419,7 @@ input::-webkit-inner-spin-button {
cursor: pointer;
z-index: 1;
user-select: none;
pointer-events: all;
}
.gdButton:active {
@ -422,6 +428,11 @@ input::-webkit-inner-spin-button {
transform: scale(1.08);
}
.likeButton {
height: 14vh;
margin: 2% 1.2% 2% 1.2%;
}
.iconRope {
cursor: pointer;
z-index: 1;

BIN
assets/smashDislike.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
assets/smashLike.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/vote.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
assets/voted.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -16,13 +16,13 @@
<div class="popup" id="postComment">
<div class="brownbox bounce center supercenter" style="height: 80%; width: 110vh">
<p style="position:absolute; right: 1vh; margin-top: 0; text-align: left" id="charcount">150</p>
<h1 class="smaller center" style="font-size: 5.5vh">Add Comment (Beta)</h1>
<h1 class="smaller center" style="font-size: 5.5vh">Add Comment</h1>
<textarea placeholder="Insert comment" id="content" maxlength="150" style="margin: 2% 0%"></textarea><br>
<form id="form" action="nothing lol">
<form action="nothing lol">
<h3 class="center">GD Username</h3>
<input type="text" name="gdbrowser" id="username" maxlength="50" style="height: 8vh; width: 90%; text-align: center; margin-top: 0.5%"></textarea>
<input type="text" name="gdbrowser" id="username" maxlength="50" style="height: 8vh; width: 90%; text-align: center; margin-top: 0.5%">
<h3 class="center" style="margin-top: 2%">GD Password</h3>
<input type="password" id="password" maxlength="50" style="height: 8vh; width: 90%; text-align: center; margin-top: 0.5%"></textarea>
<input type="password" id="password" maxlength="50" style="height: 8vh; width: 90%; text-align: center; margin-top: 0.5%">
</form>
<div style="min-height: 16%; max-height: 16%">
<p id="message" style="padding: 0% 10%; margin-top: 1.5%"></p>
@ -31,6 +31,25 @@
<img src="../assets/btn-submit.png" type="submit" height=10%; class="postButton gdButton center" style="margin-left: 1%" id="submitComment">
</div>
</div>
<div class="popup" id="likeComment">
<div class="brownbox bounce center supercenter" style="height: 75%; width: 100vh">
<h1 class="smaller center" style="font-size: 5.5vh">Vote</h1>
<img src="../assets/smashLike.png" id="likebtn" class="inline gdButton likeButton"><!--
--><img src="../assets/smashDislike.png" id="dislikebtn" class="inline gdButton likeButton youAreNotTheOne">
<form action="nothing lol">
<h3 class="center">GD Username</h3>
<input type="text" name="gdbrowser" id="like-username" maxlength="50" style="height: 8vh; width: 90%; text-align: center; margin-top: 0.5%">
<h3 class="center" style="margin-top: 2%">GD Password</h3>
<input type="password" id="like-password" maxlength="50" style="height: 8vh; width: 90%; text-align: center; margin-top: 0.5%">
</form>
<div style="min-height: 18%; max-height: 18%">
<p id="likeMessage" style="padding: 0% 10%; margin-top: 2.5%"></p>
</div>
<img src="../assets/btn-cancel.png" height=10%; class="postButton gdButton center" style="margin-right: 1%" onclick="$('#likeComment').hide(); $('#likebtn').trigger('click');">
<img src="../assets/btn-submit.png" type="submit" height=10%; class="postButton gdButton center" style="margin-left: 1%" id="submitVote">
</div>
</div>
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%">
<img class="cornerPiece" src="../assets/corner.png" width=7%;>
@ -78,7 +97,7 @@
<a id="levelLink"><h2 class="smallGold inline gdButton" id="levelID" style="margin-left: 6vh"></h2></a>
</div>
<div style="position:absolute;bottom: 0%;right: 0%;width: 14%;text-align: right;transform: translate(30%, 40%);">
<div id="leaveComment" style="position:absolute;bottom: 0%;right: 0%;width: 14%;text-align: right;transform: translate(30%, 40%);">
<img class="gdButton" src="../assets/comment.png" width="60%" onclick="$('#postComment').show()">
</div>
@ -99,11 +118,13 @@
let {mode, compact} = JSON.parse(localStorage.getItem('commentPreset') || '{"mode": "top", "compact": true}')
let messageText = 'Your <span style="color: yellow">Geometry Dash password</span> will <span style="color: lime">not be stored</span> anywhere on the site, both <span style="color:rgb(113, 234, 255)">locally and server-side.</span> You can view the code used for posting a comment <a class="menuLink" target="_blank" href="https://github.com/GDColon/GDBrowser/blob/master/api/postComment.js">here</a>.'
$('#message').html(messageText)
$('#likeMessage').html(messageText.replace("posting", "liking").replace("postComment", "like"))
let lvlID = window.location.pathname.split('/')[2]
let history = false;
let history = false
let page = 0
let loadingComments = true
let like = true
if (mode == "top") {
$('#timeSort').attr('src', "../assets/sort-time.png")
@ -114,7 +135,7 @@ $('#compactMode').attr('src', `../assets/compact-${compact ? "on" : "off"}.png`)
let target = `../api/level/${lvlID}`
if (lvlID > 99999999 || lvlID < -99999999) window.location.href = window.location.href.replace("comments", "search")
if (lvlID > 999999999 || lvlID < -999999999) window.location.href = window.location.href.replace("comments", "search")
if (!Number.isInteger(+lvlID)) {history = true; target = `../api/profile/${lvlID}`}
else lvlID = Math.round(+lvlID)
@ -125,6 +146,7 @@ fetch(target).then(res => res.json()).then(lvl => {
if (!lvl.username) return window.location.href = window.location.href.replace("comments", "search")
$('#levelName').text(lvl.username + "'s comments")
$('#leaveComment').hide()
document.title = lvl.username + "'s comments"
$('#meta-title').attr('content', lvl.username + "'s comment history")
@ -195,7 +217,9 @@ fetch(`../api${!history ? window.location.pathname : "/comments/" + lvl.playerID
<p class="commentDate">${x.date}</p>
<div class="commentLikes">
${history ? `<h3 style="margin-right: 1.5vh; pointer-events: all;" class="gold inline"><a href="../${x.levelID}">(${x.levelID})</a></h3>` : ""}
<img id="likeImg" class="inline" ${x.likes < 0 ? "style='transform: translateY(25%)'" : ""} src="../assets/${x.likes < 0 ? "dis" : ""}like.png" height=20% style="margin-right: 0.4%">
<div class="inline gdButton likeComment" commentID="${x.ID}" ${x.levelID ? `levelID="${x.levelID}"` : ""}">
<img class="inline gdButton" ${x.likes < 0 ? "style='transform: translateY(25%); margin-right: 0.4%'" : ""} src="../assets/${x.likes < 0 ? "dis" : ""}like.png" height=20%>
</div>
<h3 class="inline">${x.likes}</h3>
</div>
</div>`) }
@ -217,9 +241,11 @@ fetch(`../api${!history ? window.location.pathname : "/comments/" + lvl.playerID
</div>
</div>
<p class="commentDate compactDate">${x.date}</p>
<div class="commentLikes">
<div class="commentLikes" commentID="${x.ID}" ${x.levelID ? `levelID="${x.levelID}"` : ""}">
${history ? `<h3 style="margin-right: 0.5vh; pointer-events: all;" class="gold inline"><a href="../${x.levelID}">(${x.levelID})</a></h3>` : ""}
<img id="likeImg" class="inline" ${x.likes < 0 ? "style='transform: translateY(15%)'" : ""} src="../assets/${x.likes < 0 ? "dis" : ""}like.png" height=27% style="margin-right: 0.4%">
<div class="inline gdButton likeComment">
<img class="inline" ${x.likes < 0 ? "style='transform: translateY(15%); margin-right: 0.4%'" : ""} src="../assets/${x.likes < 0 ? "dis" : ""}like.png" height=27%>
</div>
<h3 class="inline">${x.likes}</h3>
</div>
</div>`) }
@ -305,7 +331,7 @@ $('#submitComment').click(function() {
if (!res || res == "-1") {$('.postbutton').show(); return $('#message').text("The username you provided doesn't exist!")}
else accountID = res.accountID
$.post("../postComment", {comment, username, password, levelID, accountID, })
$.post("../postComment", {comment, username, password, levelID, accountID })
.done(x => {
$('#content').val("")
$('#postComment').hide()
@ -322,7 +348,75 @@ $('#submitComment').click(function() {
})
})
$(window).on('beforeunload ',function() {
$('#likebtn').click(function() {
$('#likebtn').removeClass('youAreNotTheOne')
$('#dislikebtn').addClass('youAreNotTheOne')
like = true
})
$('#dislikebtn').click(function() {
$('#likebtn').addClass('youAreNotTheOne')
$('#dislikebtn').removeClass('youAreNotTheOne')
like = false
})
let commentID = 0
let lvID = 0
let likeCount, likeImg;
let likedComments;
$(document).on('click', '.likeComment', function(cmnt) {
commentID = $(this).attr('commentID')
likedComments = localStorage.likedComments ? JSON.parse(localStorage.likedComments) : []
if (likedComments.includes(commentID)) return;
lvID = $(this).attr('levelID') || 0
likeImg = $(this).find('img')
likeCount = $(this).parent().find('h3:not(.gold)')
$('#likeComment').show()
})
$('#submitVote').click(function() {
if (likedComments.includes(commentID)) return $('#likeMessage').text("You've already liked/disliked this comment!");
let ID = commentID
let username = $('#like-username').val()
let password = $('#like-password').val()
let extraID = lvID || window.location.pathname.split('/')[2]
let accountID = 0
let likeType = like ? "1" : "0"
if (!ID || !username || !password || loadingComments) return $('#postComment').hide()
$('#likeMessage').text(like ? "Liking..." : "Disliking... :(")
$('.postbutton').hide()
allowEsc = false
fetch(`../api/profile/${username}`).then(res => res.json()).then(res => {
if (!res || res == "-1") {$('.postbutton').show(); return $('#likeMessage').text("The username you provided doesn't exist!")}
else accountID = res.accountID
$.post("../like", { ID, accountID, password, like: likeType, type: 2, extraID })
.done(x => {
let newCount = parseInt(likeCount.text()) + (like ? 1 : -1)
likeCount.text(newCount)
if (newCount < 0) likeImg.attr('src', '../assets/dislike.png').css('transform', compact ? 'translateY(15%)' : 'translateY(25%)')
else likeImg.attr('src', '../assets/like.png').removeAttr('style')
$('#likeComment').hide()
$('#likebtn').trigger('click')
$('.postbutton').show()
$('#likeMessage').html(messageText.replace("posting", "liking").replace("postComment", "like"))
allowEsc = true
likedComments.push(commentID)
localStorage.setItem('likedComments', JSON.stringify(likedComments))
})
.fail(e => {$('.postbutton').show();$('#likeMessage').text(e.responseText.includes("DOCTYPE") ? "Something went wrong..." : e.responseText)})
})
})
$(window).on('beforeunload ', function() {
//0 - recent, 1 - top, 2 - recent/compact, 3 - top/compact
localStorage.setItem('commentPreset', JSON.stringify({
mode,

View file

@ -47,6 +47,25 @@
</div>
</div>
<!-- <div class="popup" id="likeDiv">
<div class="brownbox bounce center supercenter" style="height: 75%; width: 100vh">
<h1 class="smaller center" style="font-size: 5.5vh">Vote</h1>
<img src="../assets/smashLike.png" id="likebtn" class="inline gdButton likeButton">
<img src="../assets/smashDislike.png" id="dislikebtn" class="inline gdButton likeButton youAreNotTheOne">
<form action="nothing lol">
<h3 class="center">GD Username</h3>
<input type="text" name="gdbrowser" id="like-username" maxlength="50" style="height: 8vh; width: 90%; text-align: center; margin-top: 0.5%">
<h3 class="center" style="margin-top: 2%">GD Password</h3>
<input type="password" id="like-password" maxlength="50" style="height: 8vh; width: 90%; text-align: center; margin-top: 0.5%">
</form>
<div style="min-height: 18%; max-height: 18%">
<p id="message" style="padding: 0% 10%; margin-top: 2.5%"></p>
</div>
<img src="../assets/btn-cancel.png" height=10%; class="postButton gdButton center" style="margin-right: 1%" onclick="$('#likeDiv').hide(); $('#likebtn').trigger('click');">
<img src="../assets/btn-submit.png" type="submit" height=10%; class="postButton gdButton center" style="margin-left: 1%" id="submitVote">
</div>
</div> -->
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%">
<img class="cornerPiece" src="../assets/corner.png" width=7%;>
</div>
@ -109,8 +128,9 @@
<div class="levelButtons" style="position:absolute; top: 46%; right: 3.5%; transform: translateY(-50%); height: 75%;">
<img class="gdButton sideButton" id="saveButton" src="../assets/plus.png" onclick="$('#saveDiv').show(); saveLevel()"><br>
<img class="gdButton sideButton" id="infoButton" src="../assets/info.png" onclick="$('#infoDiv').show()"><br>
<a href="./comments/[[ID]]"><img class="gdButton sideButton" src="../assets/comment.png"></a><br>
<!-- <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>
</div>
@ -130,6 +150,9 @@
<script async type="text/javascript" src="../assets/sizecheck.js"></script>
<script>
let messageText = 'Your <span style="color: yellow">Geometry Dash password</span> will <span style="color: lime">not be stored</span> anywhere on the site, both <span style="color:rgb(113, 234, 255)">locally and server-side.</span> You can view the code used for liking a level <a class="menuLink" target="_blank" href="https://github.com/GDColon/GDBrowser/blob/master/api/like.js">here</a>.'
$('#message').html(messageText)
if (window.location.href.endsWith('?download')) $('#infoDiv').show()
let freeze = false;
@ -203,7 +226,6 @@ $(window).on('load', function() {
}
});
let savedLevels = JSON.parse(localStorage.getItem('saved') || '[]');
let deleteMode = false;
if (savedLevels.includes('[[ID]]')) {
@ -219,7 +241,53 @@ function deleteLevel() {
savedLevels = savedLevels.filter(function(el) {return el != '[[ID]]'})
localStorage.setItem('saved', JSON.stringify(savedLevels));
location.reload()
freeze = true;
freeze = true;
}
// let like;
// let likedLevels = localStorage.likedLevels ? JSON.parse(localStorage.likedLevels) : []
// if (likedLevels.includes('[[ID]]')) $('#likeButton').attr('src', '../assets/voted.png').removeClass('gdButton').prop("onclick", null)
// $('#likebtn').click(function() {
// $('#likebtn').removeClass('youAreNotTheOne')
// $('#dislikebtn').addClass('youAreNotTheOne')
// like = true
// })
// $('#dislikebtn').click(function() {
// $('#likebtn').addClass('youAreNotTheOne')
// $('#dislikebtn').removeClass('youAreNotTheOne')
// like = false
// })
// $('#submitVote').click(function() {
// if (likedLevels.includes('[[ID]]')) return $('#message').text("You've already liked/disliked this level!");
// let ID = '[[ID]]'
// let username = $('#like-username').val()
// let password = $('#like-password').val()
// let accountID = 0
// let likeType = like ? "1" : "0"
// if (!ID || !username || !password) return $('#commentDiv').hide()
// $('#message').text(like ? "Liking..." : "Disliking... :(")
// $('.postbutton').hide()
// allowEsc = false
// fetch(`../api/profile/${username}`).then(res => res.json()).then(res => {
// if (!res || res == "-1") {$('.postbutton').show(); return $('#message').text("The username you provided doesn't exist!")}
// else accountID = res.accountID
// $.post("../like", { ID, accountID, password, like: likeType, type: 1, extraID: 0 })
// .done(x => {
// likedLevels.push('[[ID]]')
// localStorage.setItem('likedLevels', JSON.stringify(likedLevels))
// location.reload()
// })
// .fail(e => {$('.postbutton').show();$('#message').text(e.responseText.includes("DOCTYPE") ? "Something went wrong..." : e.responseText)})
// })
// })
</script>

View file

@ -56,6 +56,10 @@ app.post("/postComment", function(req, res) {
app.modules.postComment(app, req, res)
})
app.post("/like", function(req, res) {
app.modules.like(app, req, res)
})
app.get("/api", function(req, res) {
res.sendFile(__dirname + "/html/api.html")
})