A lot of refactoring, and etc #232
316
api/analyze.js
|
@ -1,3 +1,4 @@
|
|||
"use strict";
|
||||
const zlib = require('zlib')
|
||||
const blocks = require('../misc/analysis/blocks.json')
|
||||
const colorStuff = require('../misc/analysis/colorProperties.json')
|
||||
|
@ -7,121 +8,130 @@ const ids = require('../misc/analysis/objects.json')
|
|||
|
||||
module.exports = async (app, req, res, level) => {
|
||||
|
||||
if (!level) {
|
||||
level = {
|
||||
name: (req.body.name || "Unnamed").slice(0, 64),
|
||||
data: (req.body.data || "")
|
||||
}
|
||||
level ||= {
|
||||
name: (req.body.name || "Unnamed").slice(0, 64),
|
||||
data: (req.body.data || "")
|
||||
}
|
||||
|
||||
let unencrypted = level.data.startsWith('kS') // some gdps'es don't encrypt level data
|
||||
let levelString = unencrypted ? level.data : Buffer.from(level.data, 'base64')
|
||||
|
||||
if (unencrypted) {
|
||||
const raw_data = level.data;
|
||||
|
||||
const response_data = analyze_level(level, raw_data);
|
||||
return res.send(response_data);
|
||||
} else {
|
||||
const raw_data = level.data
|
||||
const response_data = analyze_level(level, raw_data)
|
||||
return res.send(response_data)
|
||||
}
|
||||
else {
|
||||
zlib.unzip(levelString, (err, buffer) => {
|
||||
if (err) { return res.status(500).send("-2"); }
|
||||
if (err) return res.status(500).send("-2")
|
||||
|
||||
const raw_data = buffer.toString();
|
||||
const response_data = analyze_level(level, raw_data);
|
||||
return res.send(response_data);
|
||||
});
|
||||
const raw_data = buffer.toString()
|
||||
const response_data = analyze_level(level, raw_data)
|
||||
return res.send(response_data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function sortObj(obj, sortBy) {
|
||||
var sorted = {}
|
||||
var keys = !sortBy ? Object.keys(obj).sort((a,b) => obj[b] - obj[a]) : Object.keys(obj).sort((a,b) => obj[b][sortBy] - obj[a][sortBy])
|
||||
/**
|
||||
* Sorts any `Object` by its keys
|
||||
* @param {{}} obj
|
||||
* @param {PropertyKey} [sortBy] optional inner key to sort
|
||||
*/
|
||||
const sortObj = (obj, sortBy) => {
|
||||
let keys = Object.keys(obj)
|
||||
.sort((a,b) => sortBy ? obj[b][sortBy] - obj[a][sortBy] : obj[b] - obj[a])
|
||||
let sorted = {}
|
||||
keys.forEach(x => {sorted[x] = obj[x]})
|
||||
return sorted
|
||||
}
|
||||
|
||||
function parse_obj(obj, splitter, name_arr, valid_only) {
|
||||
const s_obj = obj.split(splitter);
|
||||
let robtop_obj = {};
|
||||
/**
|
||||
* game-object (**not** JS `Object`) parser
|
||||
* @param {string} obj
|
||||
* @param {string} splitter
|
||||
* @param {string[]} name_arr
|
||||
* @param {boolean} [valid_only]
|
||||
*/
|
||||
const parse_obj = (obj, splitter, name_arr, valid_only) => {
|
||||
const s_obj = obj.split(splitter)
|
||||
let robtop_obj = {}
|
||||
|
||||
// semi-useless optimization depending on where at node js you're at
|
||||
for (let i = 0, obj_l = s_obj.length; i < obj_l; i += 2) {
|
||||
let k_name = s_obj[i];
|
||||
let k_name = s_obj[i]
|
||||
if (s_obj[i] in name_arr) {
|
||||
if (!valid_only) {
|
||||
k_name = name_arr[s_obj[i]];
|
||||
}
|
||||
robtop_obj[k_name] = s_obj[i + 1];
|
||||
if (!valid_only) k_name = name_arr[s_obj[i]]
|
||||
robtop_obj[k_name] = s_obj[i + 1]
|
||||
}
|
||||
}
|
||||
return robtop_obj;
|
||||
return robtop_obj
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{}} level
|
||||
* @param {string} rawData
|
||||
*/
|
||||
function analyze_level(level, rawData) {
|
||||
let response = {};
|
||||
|
||||
let blockCounts = {}
|
||||
let miscCounts = {}
|
||||
let triggerGroups = []
|
||||
let blockCounts = {};
|
||||
let miscCounts = {};
|
||||
/**@type {string[]}*/
|
||||
let triggerGroups = [];
|
||||
let highDetail = 0
|
||||
let alphaTriggers = []
|
||||
/**@type {{}[]}*/
|
||||
let alphaTriggers = [];
|
||||
|
||||
let misc_objects = {};
|
||||
let block_ids = {};
|
||||
|
||||
for (const [name, object_ids] of Object.entries(ids.misc)) {
|
||||
const copied_ids = object_ids.slice(1);
|
||||
const copied_ids = object_ids.slice(1)
|
||||
// funny enough, shift effects the original id list
|
||||
copied_ids.forEach((object_id) => {
|
||||
misc_objects[object_id] = name;
|
||||
});
|
||||
copied_ids.forEach(object_id => { misc_objects[object_id] = name })
|
||||
}
|
||||
|
||||
for (const [name, object_ids] of Object.entries(blocks)) {
|
||||
object_ids.forEach((object_id) => {
|
||||
block_ids[object_id] = name;
|
||||
});
|
||||
}
|
||||
for (const [name, object_ids] of Object.entries(blocks))
|
||||
object_ids.forEach(object_id => { block_ids[object_id] = name });
|
||||
|
||||
const data = rawData.split(";");
|
||||
const header = data.shift();
|
||||
/**@type {(string|{})[]}*/
|
||||
const data = rawData.split(";")
|
||||
const header = data.shift()
|
||||
|
||||
let level_portals = [];
|
||||
let level_coins = [];
|
||||
let level_text = [];
|
||||
|
||||
// "why are these Objects instead of Arrays?" @Rudxain
|
||||
let orb_array = {};
|
||||
let trigger_array = {};
|
||||
|
||||
let last = 0;
|
||||
let last = 0
|
||||
|
||||
const obj_length = data.length;
|
||||
const obj_length = data.length
|
||||
for (let i = 0; i < obj_length; ++i) {
|
||||
obj = parse_obj(data[i], ',', properties);
|
||||
let obj = parse_obj(data[i], ',', properties)
|
||||
|
||||
let id = obj.id
|
||||
let {id} = obj
|
||||
|
||||
if (id in ids.portals) {
|
||||
obj.portal = ids.portals[id];
|
||||
level_portals.push(obj);
|
||||
obj.portal = ids.portals[id]
|
||||
level_portals.push(obj)
|
||||
} else if (id in ids.coins) {
|
||||
obj.coin = ids.coins[id];
|
||||
level_coins.push(obj);
|
||||
obj.coin = ids.coins[id]
|
||||
level_coins.push(obj)
|
||||
} else if (id in ids.orbs) {
|
||||
obj.orb = ids.orbs[id];
|
||||
obj.orb = ids.orbs[id]
|
||||
|
||||
if (obj.orb in orb_array) {
|
||||
orb_array[obj.orb]++;
|
||||
} else {
|
||||
orb_array[obj.orb] = 1;
|
||||
}
|
||||
const orb = orb_array[obj.orb]
|
||||
orb_array[obj.orb] = orb ? +orb + 1 : 1
|
||||
} else if (id in ids.triggers) {
|
||||
obj.trigger = ids.triggers[id];
|
||||
obj.trigger = ids.triggers[id]
|
||||
|
||||
if (obj.trigger in trigger_array) {
|
||||
trigger_array[obj.trigger]++;
|
||||
trigger_array[obj.trigger]++
|
||||
} else {
|
||||
trigger_array[obj.trigger] = 1;
|
||||
trigger_array[obj.trigger] = 1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,60 +140,66 @@ function analyze_level(level, rawData) {
|
|||
}
|
||||
|
||||
if (obj.triggerGroups) obj.triggerGroups.split('.').forEach(x => triggerGroups.push(x))
|
||||
if (obj.highDetail == 1) highDetail += 1
|
||||
if (obj.highDetail == 1) highDetail++
|
||||
|
||||
if (id in misc_objects) {
|
||||
const name = misc_objects[id];
|
||||
const name = misc_objects[id]
|
||||
if (name in miscCounts) {
|
||||
miscCounts[name][0] += 1;
|
||||
miscCounts[name][0]++
|
||||
} else {
|
||||
miscCounts[name] = [1, ids.misc[name][0]];
|
||||
miscCounts[name] = [1, ids.misc[name][0]]
|
||||
}
|
||||
}
|
||||
|
||||
if (id in block_ids) {
|
||||
const name = block_ids[id];
|
||||
const name = block_ids[id]
|
||||
if (name in blockCounts) {
|
||||
blockCounts[name] += 1;
|
||||
blockCounts[name]++
|
||||
} else {
|
||||
blockCounts[name] = 1;
|
||||
blockCounts[name] = 1
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.x) { // sometimes the field doesn't exist
|
||||
last = Math.max(last, obj.x);
|
||||
}
|
||||
// sometimes the field doesn't exist
|
||||
if (obj.x) last = Math.max(last, obj.x)
|
||||
|
||||
if (obj.trigger == "Alpha") { // invisible triggers
|
||||
alphaTriggers.push(obj)
|
||||
}
|
||||
// invisible triggers
|
||||
if (obj.trigger == "Alpha") alphaTriggers.push(obj)
|
||||
|
||||
data[i] = obj;
|
||||
data[i] = obj
|
||||
}
|
||||
|
||||
let invisTriggers = []
|
||||
alphaTriggers.forEach(tr => {
|
||||
if (tr.x < 500 && !tr.touchTriggered && !tr.spawnTriggered && tr.opacity == 0 && tr.duration == 0
|
||||
&& alphaTriggers.filter(x => x.targetGroupID == tr.targetGroupID).length == 1) invisTriggers.push(Number(tr.targetGroupID))
|
||||
if (
|
||||
tr.x < 500
|
||||
&& !tr.touchTriggered && !tr.spawnTriggered
|
||||
&& tr.opacity == 0 && tr.duration == 0
|
||||
&& alphaTriggers.filter(x => x.targetGroupID == tr.targetGroupID).length == 1
|
||||
)
|
||||
invisTriggers.push(Number(tr.targetGroupID))
|
||||
})
|
||||
|
||||
response.level = {
|
||||
name: level.name, id: level.id, author: level.author, playerID: level.playerID, accountID: level.accountID, large: level.large
|
||||
}
|
||||
response.level = {};
|
||||
['name', 'id', 'author', 'playerID', 'accountID', 'large'].forEach(k => {response.level[k] = level[k]})
|
||||
|
||||
response.objects = data.length - 2
|
||||
response.highDetail = highDetail
|
||||
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 => Math.floor(x.x / (Math.max(last, 529.0) + 340.0) * 100))
|
||||
// "I have no idea what to name this lmao" @Rudxain
|
||||
let WTF = x => Math.floor(x.x / (Math.max(last, 529) + 340) * 100)
|
||||
response.portals = level_portals.sort((a, b) => parseInt(a.x) - parseInt(b.x)).map(x => x.portal + " " + WTF(x) + "%").join(", ")
|
||||
response.coins = level_coins.sort((a, b) => parseInt(a.x) - parseInt(b.x)).map(WTF)
|
||||
response.coinsVerified = level.verifiedCoins
|
||||
|
||||
/**@param {number[]} arr*/
|
||||
const sum = arr => arr.reduce((a, x) => a + x, 0)
|
||||
response.orbs = orb_array
|
||||
response.orbs.total = Object.values(orb_array).reduce((a, x) => a + x, 0); // we already have an array of objects, use it
|
||||
response.orbs.total = sum(Object.values(orb_array)) // we already have an array of objects, use it
|
||||
|
||||
response.triggers = trigger_array
|
||||
response.triggers.total = Object.values(trigger_array).reduce((a, x) => a + x, 0);
|
||||
response.triggers.total = sum(Object.values(trigger_array))
|
||||
|
||||
response.triggerGroups = {}
|
||||
response.blocks = sortObj(blockCounts)
|
||||
|
@ -191,7 +207,7 @@ function analyze_level(level, rawData) {
|
|||
response.colors = []
|
||||
|
||||
triggerGroups.forEach(x => {
|
||||
if (response.triggerGroups['Group ' + x]) response.triggerGroups['Group ' + x] += 1
|
||||
if (response.triggerGroups['Group ' + x]) response.triggerGroups['Group ' + x]++
|
||||
else response.triggerGroups['Group ' + x] = 1
|
||||
})
|
||||
|
||||
|
@ -202,99 +218,113 @@ function analyze_level(level, rawData) {
|
|||
// find alpha group with the most objects
|
||||
response.invisibleGroup = triggerKeys.find(x => invisTriggers.includes(x))
|
||||
|
||||
response.text = level_text.sort(function (a, b) {return parseInt(a.x) - parseInt(b.x)}).map(x => [Buffer.from(x.message, 'base64').toString(), Math.round(x.x / last * 99) + "%"])
|
||||
response.text = level_text.sort((a, b) => parseInt(a.x) - parseInt(b.x)).map(x => [Buffer.from(x.message, 'base64').toString(), Math.round(x.x / last * 99) + "%"])
|
||||
|
||||
const header_response = parse_header(header);
|
||||
response.settings = header_response.settings;
|
||||
response.colors = header_response.colors;
|
||||
const header_response = parse_header(header)
|
||||
response.settings = header_response.settings
|
||||
response.colors = header_response.colors
|
||||
|
||||
response.dataLength = rawData.length
|
||||
response.data = rawData
|
||||
|
||||
return response;
|
||||
return response
|
||||
}
|
||||
|
||||
function parse_header(header) {
|
||||
let response = {};
|
||||
response.settings = {};
|
||||
response.colors = [];
|
||||
function parse_header(/**@type {string}*/ header) {
|
||||
let response = {}
|
||||
response.settings = {}
|
||||
response.colors = []
|
||||
|
||||
const header_keyed = parse_obj(header, ',', init.values, true);
|
||||
const header_keyed = parse_obj(header, ',', init.values, true)
|
||||
|
||||
Object.keys(header_keyed).forEach(x => {
|
||||
let val = init.values[x]
|
||||
Object.keys(header_keyed).forEach(k => {
|
||||
let val = init.values[k]
|
||||
/**@type {string}*/
|
||||
let name = val[0]
|
||||
let property = header_keyed[x]
|
||||
let property = header_keyed[k]
|
||||
switch (val[1]) {
|
||||
case 'list':
|
||||
val = init[(val[0] + "s")][property];
|
||||
break;
|
||||
break
|
||||
case 'number':
|
||||
val = Number(property);
|
||||
break;
|
||||
break
|
||||
case 'bump':
|
||||
val = Number(property) + 1;
|
||||
break;
|
||||
break
|
||||
case 'bool':
|
||||
val = property != "0";
|
||||
break;
|
||||
break
|
||||
case 'extra-legacy-color': { // scope?
|
||||
// you can only imagine my fear when i discovered this was a thing
|
||||
// these literally are keys set the value, and to convert this to the color list we have to do this fun messy thing that shouldn't exist
|
||||
// since i wrote the 1.9 color before this, a lot of explaination will be there instead
|
||||
const colorInfo = name.split('-');
|
||||
const color = colorInfo[2]; // r,g,b
|
||||
const channel = colorInfo[1];
|
||||
const colorInfo = name.split('-')
|
||||
/** r,g,b */
|
||||
const color = colorInfo[2]
|
||||
const channel = colorInfo[1]
|
||||
|
||||
// first we create the color object
|
||||
if (color == 'r') response.colors.push({"channel": channel, "opacity": 1})
|
||||
|
||||
if (color == 'r') {
|
||||
// first we create the color object
|
||||
response.colors.push({"channel": channel, "opacity": 1});
|
||||
}
|
||||
// from here we touch the color object
|
||||
let currentChannel = response.colors.find(k => k.channel == channel);
|
||||
if (color == 'blend') {
|
||||
currentChannel.blending = true; // only one color has blending though lol
|
||||
} else if (color == 'pcol' && property != 0) {
|
||||
currentChannel.pColor = property;
|
||||
}
|
||||
currentChannel[color] = property;
|
||||
break;
|
||||
let currentChannel = response.colors.find(k => k.channel == channel)
|
||||
if (color == 'blend') currentChannel.blending = true // only one color has blending though lol
|
||||
if (color == 'pcol' && property != 0) currentChannel.pColor = property
|
||||
|
||||
currentChannel[color] = property
|
||||
break
|
||||
}
|
||||
case 'legacy-color': {
|
||||
// if a level has a legacy color, we can assume that it does not have a kS38 at all
|
||||
const color = parse_obj(property, "_", colorStuff.properties);
|
||||
const color = parse_obj(property, "_", colorStuff.properties)
|
||||
|
||||
let colorObj = color
|
||||
|
||||
// so here we parse the color to something understandable by the rest
|
||||
// slightly smart naming but it is also pretty gross
|
||||
// in a sense - the name would be something like legacy-G -> G
|
||||
const colorVal = name.split('-').pop()
|
||||
const colorVal = name.split('-').at(-1)
|
||||
|
||||
colorObj.channel = colorVal
|
||||
|
||||
// from here stuff can continue as normal, ish
|
||||
if (colorObj.pColor == "-1" || colorObj.pColor == "0") delete colorObj.pColor;
|
||||
colorObj.opacity = 1; // 1.9 colors don't have this!
|
||||
if (colorObj.blending && colorObj.blending == '1') colorObj.blending = true; // 1.9 colors manage to always think they're blending - they're not
|
||||
else delete colorObj.blending;
|
||||
if (colorObj.pColor == "-1" || colorObj.pColor == "0")
|
||||
delete colorObj.pColor
|
||||
colorObj.opacity = 1 // 1.9 colors don't have this!
|
||||
|
||||
if (colorVal == '3DL') { response.colors.splice(4, 0, colorObj); } // hardcode the position of 3DL, it typically goes at the end due to how RobTop make the headers
|
||||
else if (colorVal == 'Line') { colorObj.blending = true; response.colors.push(colorObj); } // in line with 2.1 behavior
|
||||
else { response.colors.push(colorObj); } // bruh whatever was done to make the color list originally was long
|
||||
break;
|
||||
if (colorObj?.blending === '1')
|
||||
colorObj.blending = true // 1.9 colors manage to always think they're blending - they're not
|
||||
else
|
||||
delete colorObj.blending
|
||||
|
||||
switch (colorVal) {
|
||||
case '3DL':
|
||||
response.colors.splice(4, 0, colorObj) // hardcode the position of 3DL, it typically goes at the end due to how RobTop make the headers
|
||||
break
|
||||
|
||||
case 'Line': {
|
||||
colorObj.blending = true; response.colors.push(colorObj) // in line with 2.1 behavior
|
||||
break
|
||||
}
|
||||
|
||||
default:
|
||||
response.colors.push(colorObj) // bruh whatever was done to make the color list originally was long
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'colors': {
|
||||
let colorList = property.split("|")
|
||||
colorList.forEach((x, y) => {
|
||||
const color = parse_obj(x, "_", colorStuff.properties)
|
||||
let colorObj = color
|
||||
if (!color.channel) return colorList = colorList.filter((h, i) => y != i)
|
||||
if (!color.channel) return colorList = colorList.filter((_, i) => y != i)
|
||||
|
||||
if (colorStuff.channels[colorObj.channel]) colorObj.channel = colorStuff.channels[colorObj.channel]
|
||||
if (colorObj.channel > 1000) return;
|
||||
if (colorObj.channel > 1000) return
|
||||
if (colorStuff.channels[colorObj.copiedChannel]) colorObj.copiedChannel = colorStuff.channels[colorObj.copiedChannel]
|
||||
if (colorObj.copiedChannel > 1000) delete colorObj.copiedChannel;
|
||||
if (colorObj.copiedChannel > 1000) delete colorObj.copiedChannel
|
||||
if (colorObj.pColor == "-1") delete colorObj.pColor
|
||||
if (colorObj.blending) colorObj.blending = true
|
||||
if (colorObj.copiedHSV) {
|
||||
|
@ -303,37 +333,39 @@ function parse_header(header) {
|
|||
hsv.forEach((x, y) => { colorObj.copiedHSV[colorStuff.hsv[y]] = x })
|
||||
colorObj.copiedHSV['s-checked'] = colorObj.copiedHSV['s-checked'] == 1
|
||||
colorObj.copiedHSV['v-checked'] = colorObj.copiedHSV['v-checked'] == 1
|
||||
if (colorObj.copyOpacity == 1) colorObj.copyOpacity = true
|
||||
if (colorObj.copyOpacity == 1) colorObj.copyOpacity = true
|
||||
}
|
||||
colorObj.opacity = +Number(colorObj.opacity).toFixed(2)
|
||||
colorList[y] = colorObj
|
||||
});
|
||||
})
|
||||
// we assume this is only going to be run once so... some stuff can go here
|
||||
colorList = colorList.filter(x => typeof x == "object")
|
||||
if (!colorList.find(x => x.channel == "Obj")) colorList.push({"r": "255", "g": "255", "b": "255", "channel": "Obj", "opacity": "1"})
|
||||
|
||||
const specialSort = ["BG", "G", "G2", "Line", "Obj", "3DL"]
|
||||
let specialColors = colorList.filter(x => isNaN(x.channel)).sort(function (a, b) {return specialSort.indexOf( a.channel ) > specialSort.indexOf( b.channel ) } )
|
||||
let regularColors = colorList.filter(x => !isNaN(x.channel)).sort(function(a, b) {return (+a.channel) - (+b.channel) } );
|
||||
let specialColors = colorList.filter(x => isNaN(x.channel)).sort((a, b) => specialSort.indexOf(a.channel) > specialSort.indexOf(b.channel))
|
||||
let regularColors = colorList.filter(x => !isNaN(x.channel)).sort((a, b) => a.channel - b.channel)
|
||||
response.colors = specialColors.concat(regularColors)
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
response.settings[name] = val
|
||||
})
|
||||
|
||||
if (!response.settings.ground || response.settings.ground > 17) response.settings.ground = 1
|
||||
if (!response.settings.background || response.settings.background > 20) response.settings.background = 1
|
||||
if (!response.settings.font) response.settings.font = 1
|
||||
if (!response.settings.ground || response.settings.ground > 17)
|
||||
response.settings.ground = 1
|
||||
if (!response.settings.background || response.settings.background > 20)
|
||||
response.settings.background = 1
|
||||
if (!response.settings.font)
|
||||
response.settings.font = 1
|
||||
|
||||
if (response.settings.alternateLine == 2) response.settings.alternateLine = true
|
||||
else response.settings.alternateLine = false
|
||||
response.settings.alternateLine = response.settings.alternateLine == 2
|
||||
|
||||
Object.keys(response.settings).filter(k => {
|
||||
// this should be parsed into color list instead
|
||||
if (k.includes('legacy')) delete response.settings[k];
|
||||
});
|
||||
if (k.includes('legacy')) delete response.settings[k]
|
||||
})
|
||||
|
||||
delete response.settings['colors'];
|
||||
return response;
|
||||
delete response.settings['colors']
|
||||
return response
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"use strict";
|
||||
const Player = require('../classes/Player.js')
|
||||
|
||||
module.exports = async (app, req, res) => {
|
||||
|
@ -8,8 +9,8 @@ module.exports = async (app, req, res) => {
|
|||
if (count > 1000) count = 1000
|
||||
|
||||
let params = {
|
||||
userID : req.params.id,
|
||||
accountID : req.params.id,
|
||||
userID : req.params.id,
|
||||
accountID : req.params.id,
|
||||
levelID: req.params.id,
|
||||
page: +req.query.page || 0,
|
||||
count,
|
||||
|
@ -20,7 +21,7 @@ module.exports = async (app, req, res) => {
|
|||
if (req.query.type == "commentHistory") { path = "getGJCommentHistory"; delete params.levelID }
|
||||
else if (req.query.type == "profile") path = "getGJAccountComments20"
|
||||
|
||||
req.gdRequest(path, req.gdParams(params), function(err, resp, body) {
|
||||
req.gdRequest(path, req.gdParams(params), function(err, resp, body) {
|
||||
|
||||
if (err) return res.sendError()
|
||||
|
||||
|
@ -32,7 +33,7 @@ module.exports = async (app, req, res) => {
|
|||
if (!comments.length) return res.status(204).send([])
|
||||
|
||||
let pages = body.split('#')[1].split(":")
|
||||
let lastPage = +Math.ceil(+pages[0] / +pages[2]);
|
||||
let lastPage = +Math.ceil(+pages[0] / +pages[2])
|
||||
|
||||
let commentArray = []
|
||||
|
||||
|
@ -41,7 +42,7 @@ module.exports = async (app, req, res) => {
|
|||
var x = c[0] //comment info
|
||||
var y = c[1] //account info
|
||||
|
||||
if (!x[2]) return;
|
||||
if (!x[2]) return
|
||||
|
||||
let comment = {}
|
||||
comment.content = Buffer.from(x[2], 'base64').toString();
|
||||
|
@ -50,9 +51,9 @@ module.exports = async (app, req, res) => {
|
|||
comment.date = (x[9] || "?") + req.timestampSuffix
|
||||
if (comment.content.endsWith("⍟") || comment.content.endsWith("☆")) {
|
||||
comment.content = comment.content.slice(0, -1)
|
||||
comment.browserColor = true
|
||||
comment.browserColor = true
|
||||
}
|
||||
|
||||
|
||||
if (req.query.type != "profile") {
|
||||
let commentUser = new Player(y)
|
||||
Object.keys(commentUser).forEach(k => {
|
||||
|
@ -74,7 +75,7 @@ module.exports = async (app, req, res) => {
|
|||
|
||||
commentArray.push(comment)
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
return res.send(commentArray)
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"use strict";
|
||||
const request = require('request')
|
||||
const fs = require('fs')
|
||||
const Level = require('../classes/Level.js')
|
||||
|
@ -5,27 +6,27 @@ const Level = require('../classes/Level.js')
|
|||
module.exports = async (app, req, res, api, ID, analyze) => {
|
||||
|
||||
function rejectLevel() {
|
||||
if (!api) return res.redirect('search/' + req.params.id)
|
||||
else return res.sendError()
|
||||
return !api ? res.redirect('search/' + req.params.id) : res.sendError()
|
||||
}
|
||||
|
||||
if (req.offline) {
|
||||
if (!api && levelID < 0) return res.redirect('/')
|
||||
return rejectLevel()
|
||||
return !api && levelID < 0 ? res.redirect('/') : rejectLevel()
|
||||
}
|
||||
|
||||
let levelID = ID || req.params.id
|
||||
if (levelID == "daily") levelID = -1
|
||||
else if (levelID == "weekly") levelID = -2
|
||||
else levelID = levelID.replace(/[^0-9]/g, "")
|
||||
levelID = (
|
||||
levelID == "daily" ? -1 :
|
||||
levelID == "weekly" ? -2 :
|
||||
levelID.replace(/\D/g, "")
|
||||
)
|
||||
|
||||
req.gdRequest('downloadGJLevel22', { levelID }, function (err, resp, body) {
|
||||
|
||||
if (err) {
|
||||
if (analyze && api && req.server.downloadsDisabled) return res.status(403).send("-3")
|
||||
else if (!api && levelID < 0) return res.redirect(`/?daily=${levelID * -1}`)
|
||||
else return rejectLevel()
|
||||
}
|
||||
if (err) return (
|
||||
analyze && api && req.server.downloadsDisabled ? res.status(403).send("-3")
|
||||
: !api && levelID < 0 ? res.redirect(`/?daily=${levelID * -1}`)
|
||||
: rejectLevel()
|
||||
)
|
||||
|
||||
let authorData = body.split("#")[3] // daily/weekly only, most likely
|
||||
|
||||
|
@ -43,7 +44,7 @@ module.exports = async (app, req, res, api, ID, analyze) => {
|
|||
if (err2 && (foundID || authorData)) {
|
||||
let authorInfo = foundID || authorData.split(":")
|
||||
level.author = authorInfo[1] || "-"
|
||||
level.accountID = authorInfo[0] && authorInfo[0].includes(",") ? "0" : authorInfo[0]
|
||||
level.accountID = authorInfo[0]?.includes(",") ? "0" : authorInfo[0]
|
||||
}
|
||||
|
||||
else if (!err && b2 != '-1') {
|
||||
|
@ -72,7 +73,7 @@ module.exports = async (app, req, res, api, ID, analyze) => {
|
|||
if (api) return res.send(level)
|
||||
|
||||
else return fs.readFile('./html/level.html', 'utf8', function (err, data) {
|
||||
let html = data;
|
||||
let html = data
|
||||
let variables = Object.keys(level)
|
||||
variables.forEach(x => {
|
||||
let regex = new RegExp(`\\[\\[${x.toUpperCase()}\\]\\]`, "g")
|
||||
|
@ -89,7 +90,7 @@ module.exports = async (app, req, res, api, ID, analyze) => {
|
|||
level.nextDaily = +dailyTime
|
||||
level.nextDailyTimestamp = Math.round((Date.now() + (+dailyTime * 1000)) / 100000) * 100000
|
||||
return sendLevel()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
else if (req.server.demonList && level.difficulty == "Extreme Demon") {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"use strict";
|
||||
let cache = {}
|
||||
let gauntletNames = ["Fire", "Ice", "Poison", "Shadow", "Lava", "Bonus", "Chaos", "Demon", "Time", "Crystal", "Magic", "Spike", "Monster", "Doom", "Death"]
|
||||
|
||||
|
@ -6,17 +7,19 @@ module.exports = async (app, req, res) => {
|
|||
if (req.offline) return res.sendError()
|
||||
|
||||
let cached = cache[req.id]
|
||||
if (app.config.cacheGauntlets && cached && cached.data && cached.indexed + 2000000 > Date.now()) return res.send(cached.data) // half hour cache
|
||||
if (app.config.cacheGauntlets && cached && cached.data && cached.indexed + 2000000 > Date.now())
|
||||
return res.send(cached.data) // half hour cache
|
||||
|
||||
req.gdRequest('getGJGauntlets21', {}, function (err, resp, body) {
|
||||
|
||||
if (err) return res.sendError()
|
||||
let gauntlets = body.split('#')[0].split('|').map(x => app.parseResponse(x)).filter(x => x[3])
|
||||
let gauntlets = body.split('#', 1)[0].split('|').map(x => app.parseResponse(x)).filter(x => x[3])
|
||||
let gauntletList = gauntlets.map(x => ({ id: +x[1], name: gauntletNames[+x[1] - 1] || "Unknown", levels: x[3].split(",") }))
|
||||
|
||||
if (app.config.cacheGauntlets) cache[req.id] = {data: gauntletList, indexed: Date.now()}
|
||||
if (app.config.cacheGauntlets)
|
||||
cache[req.id] = {data: gauntletList, indexed: Date.now()}
|
||||
res.send(gauntletList)
|
||||
|
||||
})
|
||||
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
const {GoogleSpreadsheet} = require('google-spreadsheet');
|
||||
const sheet = new GoogleSpreadsheet('1ADIJvAkL0XHGBDhO7PP9aQOuK3mPIKB2cVPbshuBBHc'); // accurate leaderboard spreadsheet
|
||||
"use strict";
|
||||
const {GoogleSpreadsheet} = require('google-spreadsheet')
|
||||
const sheet = new GoogleSpreadsheet('1ADIJvAkL0XHGBDhO7PP9aQOuK3mPIKB2cVPbshuBBHc') // accurate leaderboard spreadsheet
|
||||
|
||||
let indexes = ["stars", "coins", "demons", "diamonds"]
|
||||
|
||||
|
@ -9,39 +10,41 @@ let caches = [{"stars": null, "coins": null, "demons": null, "diamonds": null},
|
|||
|
||||
module.exports = async (app, req, res, post) => {
|
||||
|
||||
// Accurate leaderboard returns 418 because private servers do not use.
|
||||
if (req.isGDPS) return res.status(418).send("-2")
|
||||
if (!app.sheetsKey) return res.status(500).send([])
|
||||
let gdMode = post || req.query.hasOwnProperty("gd")
|
||||
let modMode = !gdMode && req.query.hasOwnProperty("mod")
|
||||
let cache = caches[gdMode ? 2 : modMode ? 1 : 0]
|
||||
// Accurate leaderboard returns 418 because private servers do not use.
|
||||
if (req.isGDPS) return res.status(418).send("-2")
|
||||
if (!app.sheetsKey) return res.status(500).send([])
|
||||
const gdMode = post || req.query.hasOwnProperty("gd")
|
||||
const modMode = !gdMode && req.query.hasOwnProperty("mod")
|
||||
let cache = caches[gdMode ? 2 : modMode ? 1 : 0]
|
||||
|
||||
let type = req.query.type ? req.query.type.toLowerCase() : 'stars'
|
||||
if (type == "usercoins") type = "coins"
|
||||
if (!indexes.includes(type)) type = "stars"
|
||||
if (lastIndex[modMode ? 1 : 0][type] + 600000 > Date.now() && cache[type]) return res.send(gdMode ? cache[type] : JSON.parse(cache[type])) // 10 min cache
|
||||
let type = req.query.type ? req.query.type.toLowerCase() : 'stars'
|
||||
if (type == "usercoins") type = "coins"
|
||||
if (!indexes.includes(type)) type = "stars"
|
||||
if (lastIndex[modMode ? 1 : 0][type] + 600000 > Date.now() && cache[type])
|
||||
return res.send(gdMode ? cache[type] : JSON.parse(cache[type])) // 10 min cache
|
||||
|
||||
sheet.useApiKey(app.sheetsKey)
|
||||
sheet.loadInfo().then(async () => {
|
||||
let tab = sheet.sheetsById[1555821000]
|
||||
await tab.loadCells('A2:H2')
|
||||
sheet.useApiKey(app.sheetsKey)
|
||||
sheet.loadInfo().then(async () => {
|
||||
let tab = sheet.sheetsById[1555821000]
|
||||
await tab.loadCells('A2:H2')
|
||||
|
||||
let cellIndex = indexes.findIndex(x => type == x)
|
||||
if (modMode) cellIndex += indexes.length
|
||||
let cellIndex = indexes.indexOf(type)
|
||||
if (modMode) cellIndex += indexes.length
|
||||
|
||||
let cell = tab.getCell(1, cellIndex).value
|
||||
if (!cell || typeof cell != "string" || cell.startsWith("GoogleSpreadsheetFormulaError")) { console.log("Spreadsheet Error:"); console.log(cell); return res.sendError() }
|
||||
let leaderboard = JSON.parse(cell.replace(/~( |$)/g, ""))
|
||||
|
||||
let gdFormatting = ""
|
||||
leaderboard.forEach(x => {
|
||||
app.userCache(req.id, x.accountID, x.playerID, x.username)
|
||||
gdFormatting += `1:${x.username}:2:${x.playerID}:13:${x.coins}:17:${x.usercoins}:6:${x.rank}:9:${x.icon.icon}:10:${x.icon.col1}:11:${x.icon.col2}:14:${forms.indexOf(x.icon.form)}:15:${x.icon.glow ? 2 : 0}:16:${x.accountID}:3:${x.stars}:8:${x.cp}:46:${x.diamonds}:4:${x.demons}|`
|
||||
})
|
||||
caches[modMode ? 1 : 0][type] = JSON.stringify(leaderboard)
|
||||
caches[2][type] = gdFormatting
|
||||
lastIndex[modMode ? 1 : 0][type] = Date.now()
|
||||
return res.send(gdMode ? gdFormatting : leaderboard)
|
||||
let cell = tab.getCell(1, cellIndex).value
|
||||
if (!cell || typeof cell != "string" || cell.startsWith("GoogleSpreadsheetFormulaError")) {
|
||||
console.log("Spreadsheet Error:"); console.log(cell); return res.sendError()
|
||||
}
|
||||
let leaderboard = JSON.parse(cell.replace(/~( |$)/g, ""))
|
||||
|
||||
let gdFormatting = ""
|
||||
leaderboard.forEach(x => {
|
||||
app.userCache(req.id, x.accountID, x.playerID, x.username)
|
||||
gdFormatting += `1:${x.username}:2:${x.playerID}:13:${x.coins}:17:${x.usercoins}:6:${x.rank}:9:${x.icon.icon}:10:${x.icon.col1}:11:${x.icon.col2}:14:${forms.indexOf(x.icon.form)}:15:${x.icon.glow ? 2 : 0}:16:${x.accountID}:3:${x.stars}:8:${x.cp}:46:${x.diamonds}:4:${x.demons}|`
|
||||
})
|
||||
caches[modMode ? 1 : 0][type] = JSON.stringify(leaderboard)
|
||||
caches[2][type] = gdFormatting
|
||||
lastIndex[modMode ? 1 : 0][type] = Date.now()
|
||||
return res.send(gdMode ? gdFormatting : leaderboard)
|
||||
})
|
||||
}
|
|
@ -1,12 +1,15 @@
|
|||
"use strict";
|
||||
const request = require('request')
|
||||
|
||||
module.exports = async (app, req, res) => {
|
||||
|
||||
// Accurate leaderboard returns 418 because Private servers do not use.
|
||||
if (req.isGDPS) return res.status(418).send("0")
|
||||
// Accurate leaderboard returns 418 because Private servers do not use.
|
||||
if (req.isGDPS) return res.status(418).send("0")
|
||||
|
||||
request.post('http://robtopgames.com/Boomlings/get_scores.php', {
|
||||
form : { secret: app.config.params.secret || "Wmfd2893gb7", name: "Player" } }, function(err, resp, body) {
|
||||
request.post(
|
||||
'http://robtopgames.com/Boomlings/get_scores.php',
|
||||
{ form : { secret: app.config.params.secret || "Wmfd2893gb7", name: "Player" } },
|
||||
function(err, resp, body) {
|
||||
|
||||
if (err || !body || body == 0) return res.status(500).send("0")
|
||||
|
||||
|
@ -24,7 +27,7 @@ module.exports = async (app, req, res) => {
|
|||
score: +scores.slice(3, 10),
|
||||
boomling: +visuals.slice(5, 7),
|
||||
boomlingLevel: +visuals.slice(2, 4),
|
||||
powerups: [+visuals.slice(7, 9), +visuals.slice(9, 11), +visuals.slice(11, 13)].map(x => (x > 8 || x < 1) ? 0 : x),
|
||||
powerups: [+visuals.slice(7, 9), +visuals.slice(9, 11), +visuals.slice(11, 13)].map(x => (x > 8 || x < 1) ? 0 : x),
|
||||
|
||||
unknownVisual: +visuals.slice(0, 2),
|
||||
unknownScore: +scores.slice(0, 1),
|
||||
|
@ -34,10 +37,10 @@ module.exports = async (app, req, res) => {
|
|||
if (!user.boomling || user.boomling > 66 || user.boomling < 0) user.boomling = 0
|
||||
if (!user.boomlingLevel || user.boomlingLevel > 25 || user.boomlingLevel < 1) user.boomlingLevel = 25
|
||||
|
||||
users.push(user)
|
||||
users.push(user)
|
||||
})
|
||||
|
||||
return res.send(users)
|
||||
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
|
@ -1,53 +1,50 @@
|
|||
const colors = require('../../iconkit/sacredtexts/colors.json');
|
||||
"use strict";
|
||||
const colors = require('../../iconkit/sacredtexts/colors.json')
|
||||
|
||||
module.exports = async (app, req, res) => {
|
||||
|
||||
if (req.offline) return res.sendError()
|
||||
|
||||
let amount = 100;
|
||||
let count = req.query.count ? parseInt(req.query.count) : null
|
||||
if (count && count > 0) {
|
||||
if (count > 200) amount = 200
|
||||
else amount = count;
|
||||
}
|
||||
let amount = 100
|
||||
let count = req.query.count ? parseInt(req.query.count) : null
|
||||
if (count && count > 0) amount = Math.min(count, 200)
|
||||
|
||||
let params = {
|
||||
levelID: req.params.id,
|
||||
accountID: app.id,
|
||||
gjp: app.gjp,
|
||||
type: req.query.hasOwnProperty("week") ? "2" : "1",
|
||||
}
|
||||
let params = {
|
||||
levelID: req.params.id,
|
||||
accountID: app.id,
|
||||
gjp: app.gjp,
|
||||
type: req.query.hasOwnProperty("week") ? "2" : "1",
|
||||
}
|
||||
|
||||
req.gdRequest('getGJLevelScores211', params, function(err, resp, body) {
|
||||
req.gdRequest('getGJLevelScores211', params, function(err, resp, body) {
|
||||
|
||||
if (err) return res.status(500).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.status(500).send([])
|
||||
else app.trackSuccess(req.id)
|
||||
if (err) return res.status(500).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.status(500).send([])
|
||||
app.trackSuccess(req.id)
|
||||
|
||||
scores.forEach(x => {
|
||||
let keys = Object.keys(x)
|
||||
x.rank = x[6]
|
||||
x.username = x[1]
|
||||
x.percent = +x[3]
|
||||
x.coins = +x[13]
|
||||
x.playerID = x[2]
|
||||
x.accountID = x[16]
|
||||
x.date = x[42] + req.timestampSuffix
|
||||
x.icon = {
|
||||
form: ['icon', 'ship', 'ball', 'ufo', 'wave', 'robot', 'spider'][+x[14]],
|
||||
icon: +x[9],
|
||||
col1: +x[10],
|
||||
col2: +x[11],
|
||||
glow: +x[15] > 1,
|
||||
col1RGB: colors[x[10]] || colors["0"],
|
||||
col2RGB: colors[x[11]] || colors["3"]
|
||||
}
|
||||
keys.forEach(k => delete x[k])
|
||||
app.userCache(req.id, x.accountID, x.playerID, x.username)
|
||||
})
|
||||
scores.forEach(x => {
|
||||
let keys = Object.keys(x)
|
||||
x.rank = x[6]
|
||||
x.username = x[1]
|
||||
x.percent = +x[3]
|
||||
x.coins = +x[13]
|
||||
x.playerID = x[2]
|
||||
x.accountID = x[16]
|
||||
x.date = x[42] + req.timestampSuffix
|
||||
x.icon = {
|
||||
form: ['icon', 'ship', 'ball', 'ufo', 'wave', 'robot', 'spider'][+x[14]],
|
||||
icon: +x[9],
|
||||
col1: +x[10],
|
||||
col2: +x[11],
|
||||
glow: +x[15] > 1,
|
||||
col1RGB: colors[x[10]] || colors["0"],
|
||||
col2RGB: colors[x[11]] || colors["3"]
|
||||
}
|
||||
keys.forEach(k => delete x[k])
|
||||
app.userCache(req.id, x.accountID, x.playerID, x.username)
|
||||
})
|
||||
|
||||
return res.send(scores.slice(0, amount))
|
||||
|
||||
})
|
||||
return res.send(scores.slice(0, amount))
|
||||
})
|
||||
}
|
|
@ -1,33 +1,35 @@
|
|||
"use strict";
|
||||
const Player = require('../../classes/Player.js')
|
||||
|
||||
module.exports = async (app, req, res) => {
|
||||
|
||||
if (req.offline) return res.sendError()
|
||||
if (req.offline) return res.sendError()
|
||||
|
||||
let amount = 100;
|
||||
let count = req.query.count ? parseInt(req.query.count) : null
|
||||
if (count && count > 0) {
|
||||
if (count > 10000) amount = 10000
|
||||
else amount = count;
|
||||
}
|
||||
let amount = 100
|
||||
let count = req.query.count ? parseInt(req.query.count) : 0
|
||||
if (count > 0) amount = Math.min(count, 10000)
|
||||
|
||||
let params = {count: amount, type: "top"}
|
||||
let params = {count: amount, type: "top"}
|
||||
|
||||
if (["creators", "creator", "cp"].some(x => req.query.hasOwnProperty(x) || req.query.type == x)) params.type = "creators"
|
||||
else if (["week", "weekly"].some(x => req.query.hasOwnProperty(x) || req.query.type == x)) params.type = "week"
|
||||
else if (["global", "relative"].some(x => req.query.hasOwnProperty(x) || req.query.type == x)) {
|
||||
params.type = "relative"
|
||||
params.accountID = req.query.accountID
|
||||
}
|
||||
let isInQuery = (...args) => args.some(x => req.query.hasOwnProperty(x) || req.query.type == x)
|
||||
|
||||
req.gdRequest('getGJScores20', params, function(err, resp, body) {
|
||||
if (isInQuery("creators", "creator", "cp"))
|
||||
params.type = "creators"
|
||||
else if (isInQuery("week", "weekly"))
|
||||
params.type = "week"
|
||||
else if (isInQuery("global", "relative")) {
|
||||
params.type = "relative"
|
||||
params.accountID = req.query.accountID
|
||||
}
|
||||
|
||||
if (err) return res.sendError()
|
||||
scores = body.split('|').map(x => app.parseResponse(x)).filter(x => x[1])
|
||||
if (!scores.length) return res.sendError()
|
||||
req.gdRequest('getGJScores20', params, function(err, resp, body) {
|
||||
|
||||
scores = scores.map(x => new Player(x))
|
||||
scores.forEach(x => app.userCache(req.id, x.accountID, x.playerID, x.username))
|
||||
return res.send(scores.slice(0, amount))
|
||||
})
|
||||
if (err) return res.sendError()
|
||||
scores = body.split('|').map(x => app.parseResponse(x)).filter(x => x[1])
|
||||
if (!scores.length) return res.sendError()
|
||||
|
||||
scores = scores.map(x => new Player(x))
|
||||
scores.forEach(x => app.userCache(req.id, x.accountID, x.playerID, x.username))
|
||||
return res.send(scores.slice(0, amount))
|
||||
})
|
||||
}
|
20
api/level.js
|
@ -1,3 +1,4 @@
|
|||
"use strict";
|
||||
const request = require('request')
|
||||
const fs = require('fs')
|
||||
const Level = require('../classes/Level.js')
|
||||
|
@ -5,17 +6,14 @@ const Level = require('../classes/Level.js')
|
|||
module.exports = async (app, req, res, api, analyze) => {
|
||||
|
||||
function rejectLevel() {
|
||||
if (!api) return res.redirect('search/' + req.params.id)
|
||||
else return res.sendError()
|
||||
return !api ? res.redirect('search/' + req.params.id) : res.sendError()
|
||||
}
|
||||
|
||||
if (req.offline) return rejectLevel()
|
||||
|
||||
let levelID = req.params.id
|
||||
if (levelID == "daily") return app.run.download(app, req, res, api, 'daily', analyze)
|
||||
else if (levelID == "weekly") return app.run.download(app, req, res, api, 'weekly', analyze)
|
||||
else if (levelID.match(/[^0-9]/)) return rejectLevel()
|
||||
else levelID = levelID.replace(/[^0-9]/g, "")
|
||||
if (levelID == "daily" || levelID == "weekly") return app.run.download(app, req, res, api, levelID, analyze)
|
||||
else if (/\D/.test(levelID)) return rejectLevel()
|
||||
|
||||
if (analyze || req.query.hasOwnProperty("download")) return app.run.download(app, req, res, api, levelID, analyze)
|
||||
|
||||
|
@ -23,9 +21,11 @@ module.exports = async (app, req, res, api, analyze) => {
|
|||
|
||||
if (err || body.startsWith("##")) return rejectLevel()
|
||||
|
||||
let preRes = body.split('#')[0].split('|', 10)
|
||||
let author = body.split('#')[1].split('|')[0].split(':')
|
||||
let song = '~' + body.split('#')[2];
|
||||
// "revolutionary name XD" @Rudxain
|
||||
const bodySplit = body.split('#')
|
||||
let preRes = bodySplit[0].split('|', 10)
|
||||
let author = bodySplit[1].split('|', 1)[0].split(':')
|
||||
let song = '~' + bodySplit[2]
|
||||
song = app.parseResponse(song, '~|~')
|
||||
|
||||
let levelInfo = app.parseResponse(preRes.find(x => x.startsWith(`1:${levelID}`)) || preRes[0])
|
||||
|
@ -40,7 +40,7 @@ module.exports = async (app, req, res, api, analyze) => {
|
|||
if (api) return res.send(level)
|
||||
|
||||
else return fs.readFile('./html/level.html', 'utf8', function (err, data) {
|
||||
let html = data;
|
||||
let html = data
|
||||
let filteredSong = level.songName.replace(/[^ -~]/g, "") // strip off unsupported characters
|
||||
level.songName = filteredSong || level.songName
|
||||
let variables = Object.keys(level)
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
"use strict";
|
||||
let difficulties = ["auto", "easy", "normal", "hard", "harder", "insane", "demon", "demon-easy", "demon-medium", "demon-insane", "demon-extreme"]
|
||||
let cache = {}
|
||||
|
||||
module.exports = async (app, req, res) => {
|
||||
|
||||
if (req.offline) return res.sendError()
|
||||
|
||||
|
||||
let cached = cache[req.id]
|
||||
if (app.config.cacheMapPacks && cached && cached.data && cached.indexed + 5000000 > Date.now()) return res.send(cached.data) // 1.5 hour cache
|
||||
if (app.config.cacheMapPacks && cached && cached.data && cached.indexed + 5000000 > Date.now())
|
||||
return res.send(cached.data) // 1.5 hour cache
|
||||
let params = { count: 250, page: 0 }
|
||||
let packs = []
|
||||
|
||||
|
@ -15,7 +17,7 @@ module.exports = async (app, req, res) => {
|
|||
|
||||
if (err) return res.sendError()
|
||||
|
||||
let newPacks = body.split('#')[0].split('|').map(x => app.parseResponse(x)).filter(x => x[2])
|
||||
let newPacks = body.split('#', 1)[0].split('|').map(x => app.parseResponse(x)).filter(x => x[2])
|
||||
packs = packs.concat(newPacks)
|
||||
|
||||
// not all GDPS'es support the count param, which means recursion time!!!
|
||||
|
@ -23,7 +25,7 @@ module.exports = async (app, req, res) => {
|
|||
params.page++
|
||||
return mapPackLoop()
|
||||
}
|
||||
|
||||
|
||||
let mappacks = packs.map(x => ({ // "packs.map()" laugh now please
|
||||
id: +x[1],
|
||||
name: x[2],
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
"use strict";
|
||||
module.exports = async (app, req, res) => {
|
||||
const send = (msg, c=400) => res.status(c).send(msg)
|
||||
|
||||
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
|
||||
if (req.method !== 'POST') return send("Method not allowed.", 405)
|
||||
|
||||
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.accountID) return send("No account ID provided!")
|
||||
if (!req.body.password) return send("No password provided!")
|
||||
|
||||
let params = {
|
||||
accountID: req.body.accountID,
|
||||
|
@ -13,11 +15,11 @@ module.exports = async (app, req, res) => {
|
|||
|
||||
req.gdRequest('getGJUserInfo20', params, function (err, resp, body) {
|
||||
|
||||
if (err) return res.status(400).send(`Error counting messages! Messages get blocked a lot so try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
else app.trackSuccess(req.id)
|
||||
if (err) return send(`Error counting messages! Messages get blocked a lot so try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
app.trackSuccess(req.id)
|
||||
let count = app.parseResponse(body)[38]
|
||||
if (!count) return res.status(400).send("Error fetching unread messages!")
|
||||
else res.send(count)
|
||||
if (!count) return send("Error fetching unread messages!")
|
||||
res.send(count)
|
||||
})
|
||||
|
||||
}
|
|
@ -1,23 +1,26 @@
|
|||
"use strict";
|
||||
module.exports = async (app, req, res) => {
|
||||
const send = (msg, c=400) => res.status(c).send(msg)
|
||||
|
||||
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
|
||||
if (req.method !== 'POST') return send("Method not allowed.", 405)
|
||||
|
||||
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.id) return res.status(400).send("No message ID(s) provided!")
|
||||
if (!req.body.accountID) return send("No account ID provided!")
|
||||
if (!req.body.password) return send("No password provided!")
|
||||
if (!req.body.id) return send("No message ID(s) provided!")
|
||||
|
||||
let params = {
|
||||
accountID: req.body.accountID,
|
||||
gjp: app.xor.encrypt(req.body.password, 37526),
|
||||
// serialize to CSV if needed
|
||||
messages: Array.isArray(req.body.id) ? req.body.id.map(x => x.trim()).join(",") : req.body.id,
|
||||
}
|
||||
|
||||
let deleted = params.messages.split(",").length
|
||||
let deleted = params.messages.split(",").length // CSV record count
|
||||
|
||||
req.gdRequest('deleteGJMessages20', params, function (err, resp, body) {
|
||||
|
||||
if (body != 1) return res.status(400).send(`The Geometry Dash servers refused to delete the message! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
else res.send(`${deleted == 1 ? "1 message" : `${deleted} messages`} deleted!`)
|
||||
if (body != 1) return send(`The Geometry Dash servers refused to delete the message! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
res.send(`${deleted} message${deleted == 1 ? "" : "s"} deleted!`)
|
||||
app.trackSuccess(req.id)
|
||||
})
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
"use strict";
|
||||
module.exports = async (app, req, res) => {
|
||||
const send = (msg, c=400) => res.status(c).send(msg)
|
||||
|
||||
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
|
||||
if (req.method !== 'POST') return send("Method not allowed.", 405)
|
||||
|
||||
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.accountID) return send("No account ID provided!")
|
||||
if (!req.body.password) return send("No password provided!")
|
||||
|
||||
let params = req.gdParams({
|
||||
accountID: req.body.accountID,
|
||||
|
@ -13,24 +15,25 @@ module.exports = async (app, req, res) => {
|
|||
|
||||
req.gdRequest('downloadGJMessage20', params, function (err, resp, body) {
|
||||
|
||||
if (err) return res.status(400).send(`Error fetching message! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
else app.trackSuccess(req.id)
|
||||
if (err) return send(`Error fetching message! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
app.trackSuccess(req.id)
|
||||
|
||||
let x = app.parseResponse(body)
|
||||
let msg = {}
|
||||
msg.id = x[1];
|
||||
msg.playerID = x[3]
|
||||
msg.accountID = x[2]
|
||||
msg.author = x[6]
|
||||
msg.subject = Buffer.from(x[4], "base64").toString().replace(/^Re: ☆/, "Re: ")
|
||||
msg.content = app.xor.decrypt(x[5], 14251)
|
||||
msg.date = x[7] + req.timestampSuffix
|
||||
if (msg.subject.endsWith("☆") || msg.subject.startsWith("☆")) {
|
||||
if (msg.subject.endsWith("☆")) msg.subject = msg.subject.slice(0, -1)
|
||||
else msg.subject = msg.subject.slice(1)
|
||||
msg.browserColor = true
|
||||
}
|
||||
|
||||
let subject = Buffer.from(x[4], "base64").toString().replace(/^Re: ☆/, "Re: ")
|
||||
let msg = {
|
||||
id: x[1],
|
||||
playerID: x[3],
|
||||
accountID: x[2],
|
||||
author: x[6],
|
||||
subject,
|
||||
content: app.xor.decrypt(x[5], 14251),
|
||||
date: x[7] + req.timestampSuffix
|
||||
}
|
||||
if (/^☆|☆$/.test(subject)) {
|
||||
msg.subject = subject.slice(...(subject.endsWith("☆") ? [0, -1] : [1]))
|
||||
msg.browserColor = true
|
||||
}
|
||||
|
||||
return res.send(msg)
|
||||
})
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
"use strict";
|
||||
module.exports = async (app, req, res) => {
|
||||
const send = (msg, c=400) => res.status(c).send(msg)
|
||||
|
||||
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
|
||||
if (req.method !== 'POST') return send("Method not allowed.", 405)
|
||||
|
||||
if (req.body.count) return app.run.countMessages(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.accountID) return send("No account ID provided!")
|
||||
if (!req.body.password) return send("No password provided!")
|
||||
|
||||
let params = req.gdParams({
|
||||
accountID: req.body.accountID,
|
||||
|
@ -15,26 +17,26 @@ module.exports = async (app, req, res) => {
|
|||
|
||||
req.gdRequest('getGJMessages20', params, function (err, resp, body) {
|
||||
|
||||
if (err) return res.status(400).send(`Error fetching messages! Messages get blocked a lot so try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
if (err) return send(`Error fetching messages! Messages get blocked a lot so try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
else app.trackSuccess(req.id)
|
||||
|
||||
let messages = body.split("|").map(msg => app.parseResponse(msg))
|
||||
let messageArray = []
|
||||
messages.forEach(x => {
|
||||
let msg = {}
|
||||
|
||||
msg.id = x[1];
|
||||
msg.playerID = x[3]
|
||||
msg.accountID = x[2]
|
||||
msg.author = x[6]
|
||||
msg.subject = Buffer.from(x[4], "base64").toString().replace(/^Re: ☆/, "Re: ")
|
||||
msg.date = x[7] + req.timestampSuffix
|
||||
msg.unread = x[8] != "1"
|
||||
if (msg.subject.endsWith("☆") || msg.subject.startsWith("☆")) {
|
||||
if (msg.subject.endsWith("☆")) msg.subject = msg.subject.slice(0, -1)
|
||||
else msg.subject = msg.subject.slice(1)
|
||||
msg.browserColor = true
|
||||
}
|
||||
let subject = Buffer.from(x[4], "base64").toString().replace(/^Re: ☆/, "Re: ")
|
||||
let msg = {
|
||||
id: x[1],
|
||||
playerID: x[3],
|
||||
accountID: x[2],
|
||||
author: x[6],
|
||||
subject,
|
||||
date: x[7] + req.timestampSuffix,
|
||||
unread: x[8] != "1"
|
||||
}
|
||||
if (/^☆|☆$/.test(subject)) {
|
||||
msg.subject = subject.slice(...(subject.endsWith("☆") ? [0, -1] : [1]))
|
||||
msg.browserColor = true
|
||||
}
|
||||
|
||||
app.userCache(req.id, msg.accountID, msg.playerID, msg.author)
|
||||
messageArray.push(msg)
|
||||
|
|
|
@ -1,25 +1,33 @@
|
|||
"use strict";
|
||||
module.exports = async (app, req, res) => {
|
||||
const send = (msg, c=400) => res.status(c).send(msg)
|
||||
|
||||
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
|
||||
if (req.method !== 'POST') return send("Method not allowed.", 405)
|
||||
|
||||
if (!req.body.targetID) return res.status(400).send("No target ID provided!")
|
||||
if (!req.body.message) return res.status(400).send("No message 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.targetID) return send("No target ID provided!")
|
||||
if (!req.body.message) return send("No message provided!")
|
||||
if (!req.body.accountID) return send("No account ID provided!")
|
||||
if (!req.body.password) return send("No password provided!")
|
||||
|
||||
let subject = Buffer.from(req.body.subject ? (req.body.color ? "☆" : "") + (req.body.subject.slice(0, 50)) : (req.body.color ? "☆" : "") + "No subject").toString('base64').replace(/\//g, '_').replace(/\+/g, "-")
|
||||
let subject = Buffer.from(
|
||||
(req.body.color ? "☆" : "") + (req.body.subject ? req.body.subject.slice(0, 50) : "No subject")
|
||||
).toString('base64url')
|
||||
let body = app.xor.encrypt(req.body.message.slice(0, 300), 14251)
|
||||
|
||||
let params = req.gdParams({
|
||||
accountID: req.body.accountID,
|
||||
gjp: app.xor.encrypt(req.body.password, 37526),
|
||||
toAccountID: req.body.targetID,
|
||||
subject, body,
|
||||
subject, body
|
||||
})
|
||||
|
||||
req.gdRequest('uploadGJMessage20', params, function (err, resp, body) {
|
||||
if (body != 1) return res.status(400).send(`The Geometry Dash servers refused to send the message! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
else res.send('Message sent!')
|
||||
if (body != 1) return send(
|
||||
`The Geometry Dash servers refused to send the message! `+
|
||||
`Try again later, or make sure your username and password are entered correctly. `+
|
||||
`Last worked: ${app.timeSince(req.id)} ago.`
|
||||
)
|
||||
res.send('Message sent!')
|
||||
app.trackSuccess(req.id)
|
||||
})
|
||||
|
||||
|
|
|
@ -1,17 +1,31 @@
|
|||
"use strict";
|
||||
const crypto = require('crypto')
|
||||
function sha1(data) { return crypto.createHash("sha1").update(data, "binary").digest("hex"); }
|
||||
const sha1 = data => crypto.createHash("sha1").update(data, "binary").digest("hex")
|
||||
|
||||
module.exports = async (app, req, res) => {
|
||||
const send = (msg, c=400) => res.status(c).send(msg)
|
||||
|
||||
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
|
||||
if (req.method !== 'POST') return send("Method not allowed.", 405)
|
||||
|
||||
if (!req.body.ID) return send("No ID provided!")
|
||||
if (!req.body.accountID) return send("No account ID provided!")
|
||||
if (!req.body.password) return send("No password provided!")
|
||||
if (!req.body.like) return send("No like flag provided! (1=like, 0=dislike)")
|
||||
if (!req.body.type) return send("No type provided! (1=level, 2=comment, 3=profile")
|
||||
if (!req.body.extraID) return send("No extra ID provided! (this should be a level ID, account ID, or '0' for levels")
|
||||
/*
|
||||
// A compound error message is more helpful, but IDK if this may cause bugs,
|
||||
// so this is commented-out
|
||||
let errMsg = ""
|
||||
if (!req.body.ID) errMsg += "No ID provided!\n"
|
||||
if (!req.body.accountID) errMsg += "No account ID provided!\n"
|
||||
if (!req.body.password) errMsg += "No password provided!\n"
|
||||
if (!req.body.like) errMsg += "No like flag provided! (1=like, 0=dislike)\n"
|
||||
if (!req.body.type) errMsg += "No type provided! (1=level, 2=comment, 3=profile\n"
|
||||
if (!req.body.extraID) errMsg += "No extra ID provided! (this should be a level ID, account ID, or '0' for levels)\n"
|
||||
if (errMsg) return send(errMsg)
|
||||
*/
|
||||
|
||||
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 = {
|
||||
udid: '0',
|
||||
uuid: '0',
|
||||
|
@ -25,14 +39,15 @@ module.exports = async (app, req, res) => {
|
|||
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"
|
||||
let chk = "";
|
||||
['special', 'itemID', 'like', 'type', 'rs', 'accountID', 'udid', 'uuid'].forEach(k => chk += params[k])
|
||||
chk += "ysg6pUrtjn0J"
|
||||
chk = sha1(chk)
|
||||
chk = app.xor.encrypt(chk, 58281)
|
||||
|
||||
params.chk = chk
|
||||
|
||||
req.gdRequest('likeGJItem211', params, function (err, resp, body) {
|
||||
if (err) return res.status(400).send(`The Geometry Dash servers rejected your vote! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
if (err) return send(`The Geometry Dash servers rejected your vote! Try again later, or make sure your username and password are entered correctly. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
else app.trackSuccess(req.id)
|
||||
res.send((params.like == 1 ? 'Successfully liked!' : 'Successfully disliked!') + " (this will only take effect if this is your first time doing so)")
|
||||
})
|
||||
|
|
|
@ -1,31 +1,46 @@
|
|||
"use strict";
|
||||
const crypto = require('crypto')
|
||||
function sha1(data) { return crypto.createHash("sha1").update(data, "binary").digest("hex"); }
|
||||
const sha1 = data => crypto.createHash("sha1").update(data, "binary").digest("hex")
|
||||
|
||||
Bruh Bruh
|
||||
let rateLimit = {};
|
||||
let rateLimit = {}
|
||||
let cooldown = 15000 // GD has a secret rate limit and doesn't return -1 when a comment is rejected, so this keeps track
|
||||
|
||||
// converts timestamp miliseconds to s (wrapped-around minutes)
|
||||
function getTime(time) {
|
||||
let seconds = Math.ceil(time / 1000);
|
||||
seconds = seconds % 60;
|
||||
return seconds}
|
||||
let seconds = Math.ceil(time / 1000)
|
||||
seconds %= 60
|
||||
return seconds
|
||||
}
|
||||
|
||||
module.exports = async (app, req, res) => {
|
||||
const send = (msg, c=400) => res.status(c).send(msg)
|
||||
|
||||
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
|
||||
if (req.method !== 'POST') return send("Method not allowed.", 405)
|
||||
|
||||
if (!req.body.comment) return res.status(400).send("No comment provided!")
|
||||
if (!req.body.username) return res.status(400).send("No username provided!")
|
||||
if (!req.body.levelID) return res.status(400).send("No level 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.comment) return send("No comment provided!")
|
||||
if (!req.body.username) return send("No username provided!")
|
||||
if (!req.body.levelID) return send("No level ID provided!")
|
||||
if (!req.body.accountID) return send("No account ID provided!")
|
||||
if (!req.body.password) return send("No password provided!")
|
||||
/*
|
||||
// A compound error message is more helpful, but IDK if this may cause bugs,
|
||||
// so this is commented-out
|
||||
let errMsg = ""
|
||||
if (!req.body.comment) errMsg += "No comment provided!\n"
|
||||
if (!req.body.username) errMsg += "No username provided!\n"
|
||||
if (!req.body.levelID) errMsg += "No level ID provided!\n"
|
||||
if (!req.body.accountID) errMsg += "No account ID provided!\n"
|
||||
if (!req.body.password) errMsg += "No password provided!\n"
|
||||
if (errMsg) return send(errMsg)
|
||||
*/
|
||||
|
||||
if (req.body.comment.includes('\n')) return res.status(400).send("Comments cannot contain line breaks!")
|
||||
if (req.body.comment.includes('\n')) return send("Comments cannot contain line breaks!")
|
||||
|
||||
if (rateLimit[req.body.username]) return send(`Please wait ${getTime(rateLimit[req.body.username] + cooldown - Date.now())} seconds before posting another comment!`)
|
||||
|
||||
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 = { percent: 0 }
|
||||
|
||||
params.comment = Buffer.from(req.body.comment + (req.body.color ? "☆" : "")).toString('base64').replace(/\//g, '_').replace(/\+/g, "-")
|
||||
params.comment = Buffer.from(req.body.comment + (req.body.color ? "☆" : "")).toString('base64url')
|
||||
params.gjp = app.xor.encrypt(req.body.password, 37526)
|
||||
params.levelID = req.body.levelID.toString()
|
||||
params.accountID = req.body.accountID.toString()
|
||||
|
@ -40,15 +55,22 @@ module.exports = async (app, req, res) => {
|
|||
params.chk = chk
|
||||
|
||||
req.gdRequest('uploadGJComment21', params, function (err, resp, body) {
|
||||
if (err) 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. Last worked: ${app.timeSince(req.id)} ago.`)
|
||||
if (err) return send(
|
||||
`The Geometry Dash servers rejected your comment! `+
|
||||
`Try again later, or make sure your username and password are entered correctly. `+
|
||||
`Last worked: ${app.timeSince(req.id)} 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"}`)
|
||||
return send(
|
||||
`You have been banned from commenting for ${(parseInt(banStuff[1]) / 86400).toFixed(0)} days. `+
|
||||
`Reason: ${banStuff[2] || "None"}`
|
||||
)
|
||||
}
|
||||
|
||||
res.send(`Comment posted to level ${params.levelID} with ID ${body}`)
|
||||
app.trackSuccess(req.id)
|
||||
rateLimit[req.body.username] = Date.now();
|
||||
setTimeout(() => {delete rateLimit[req.body.username]; }, cooldown);
|
||||
rateLimit[req.body.username] = Date.now()
|
||||
setTimeout(() => {delete rateLimit[req.body.username]}, cooldown);
|
||||
})
|
||||
}
|
|
@ -1,20 +1,32 @@
|
|||
"use strict";
|
||||
const crypto = require('crypto')
|
||||
function sha1(data) { return crypto.createHash("sha1").update(data, "binary").digest("hex"); }
|
||||
const sha1 = data => crypto.createHash("sha1").update(data, "binary").digest("hex")
|
||||
|
||||
Use of a broken or weak cryptographic algorithmSensitive data from an access to username is used in a broken or weak cryptographic algorithm. ## Use of a broken or weak cryptographic algorithm
Sensitive data from [an access to username](1) is used in a broken or weak cryptographic algorithm.
Sensitive data from [an access to userName](2) is used in a broken or weak cryptographic algorithm.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/74)
LMAO I just changed the function to arrow fn LMAO I just changed the function to arrow fn
|
||||
module.exports = async (app, req, res) => {
|
||||
const send = (msg, c=400) => res.status(c).send(msg)
|
||||
|
||||
if (req.method !== 'POST') return res.status(405).send("Method not allowed.")
|
||||
if (req.method !== 'POST') return send("Method not allowed.", 405)
|
||||
|
||||
if (!req.body.comment) return res.status(400).send("No comment provided!")
|
||||
if (!req.body.username) return res.status(400).send("No username 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.comment) return send("No comment provided!")
|
||||
if (!req.body.username) return send("No username provided!")
|
||||
if (!req.body.accountID) return send("No account ID provided!")
|
||||
if (!req.body.password) return send("No password provided!")
|
||||
/*
|
||||
// A compound error message is more helpful, but IDK if this may cause bugs,
|
||||
// so this is commented-out
|
||||
let errMsg = ""
|
||||
if (!req.body.comment) errMsg += "No comment provided!\n"
|
||||
if (!req.body.username) errMsg += "No username provided!\n"
|
||||
if (!req.body.accountID) errMsg += "No account ID provided!\n"
|
||||
if (!req.body.password) errMsg += "No password provided!\n"
|
||||
if (errMsg) return send(errMsg)
|
||||
*/
|
||||
|
||||
if (req.body.comment.includes('\n')) return send("Profile posts cannot contain line breaks!")
|
||||
|
||||
if (req.body.comment.includes('\n')) return res.status(400).send("Profile posts cannot contain line breaks!")
|
||||
|
||||
let params = { cType: '1' }
|
||||
|
||||
params.comment = Buffer.from(req.body.comment.slice(0, 190) + (req.body.color ? "☆" : "")).toString('base64').replace(/\//g, '_').replace(/\+/g, "-")
|
||||
params.comment = Buffer.from(req.body.comment.slice(0, 190) + (req.body.color ? "☆" : "")).toString('base64url')
|
||||
params.gjp = app.xor.encrypt(req.body.password, 37526)
|
||||
params.accountID = req.body.accountID.toString()
|
||||
params.userName = req.body.username
|
||||
|
@ -25,10 +37,10 @@ module.exports = async (app, req, res) => {
|
|||
params.chk = chk
|
||||
|
||||
req.gdRequest('uploadGJAccComment20', params, function (err, resp, body) {
|
||||
if (err) 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(req.id)} ago.`)
|
||||
if (err) return 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(req.id)} ago.`)
|
||||
else 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"}`)
|
||||
return send(`You have been banned from commenting for ${(parseInt(banStuff[1]) / 86400).toFixed(0)} days. Reason: ${banStuff[2] || "None"}`)
|
||||
}
|
||||
else app.trackSuccess(req.id)
|
||||
res.send(`Comment posted to ${params.userName} with ID ${body}`)
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
"use strict";
|
||||
const fs = require('fs')
|
||||
const Player = require('../classes/Player.js')
|
||||
|
||||
module.exports = async (app, req, res, api, getLevels) => {
|
||||
|
||||
if (req.offline) {
|
||||
if (!api) return res.redirect('/search/' + req.params.id)
|
||||
else return res.sendError()
|
||||
function rejectLevel() {
|
||||
// this variant has an extra "/"
|
||||
return !api ? res.redirect('/search/' + req.params.id) : res.sendError()
|
||||
}
|
||||
|
||||
|
||||
if (req.offline) return rejectLevel()
|
||||
|
||||
let username = getLevels || req.params.id
|
||||
let probablyID
|
||||
if (username.endsWith(".") && req.isGDPS) {
|
||||
|
@ -17,18 +19,18 @@ module.exports = async (app, req, res, api, getLevels) => {
|
|||
let accountMode = !req.query.hasOwnProperty("player") && Number(req.params.id)
|
||||
let foundID = app.userCache(req.id, username)
|
||||
let skipRequest = accountMode || foundID || probablyID
|
||||
let searchResult;
|
||||
let searchResult
|
||||
|
||||
// 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)
|
||||
req.gdRequest(skipRequest ? "" : 'getGJUsers20', skipRequest ? {} : { str: username, page: 0 }, function (err1, res1, b1) {
|
||||
req.gdRequest(skipRequest ? "" : 'getGJUsers20', skipRequest ? {} : { str: username, page: 0 }, function (err1, res1, b1) {
|
||||
|
||||
if (foundID) searchResult = foundID[0]
|
||||
else if (accountMode || err1 || b1 == '-1' || b1.startsWith("<") || !b1) searchResult = probablyID ? username : req.params.id
|
||||
else if (!req.isGDPS) searchResult = app.parseResponse(b1.split("|")[0])[16]
|
||||
else if (!req.isGDPS) searchResult = app.parseResponse(b1.split("|", 1)[0])[16]
|
||||
else { // GDPS's return multiple users, GD no longer does this
|
||||
let userResults = b1.split("|").map(x => app.parseResponse(x))
|
||||
searchResult = userResults.find(x => x[1].toLowerCase() == username.toLowerCase() || x[2] == username) || ""
|
||||
if (searchResult) searchResult = searchResult[16]
|
||||
searchResult &&= searchResult[16]
|
||||
}
|
||||
|
||||
if (getLevels) {
|
||||
|
@ -40,20 +42,17 @@ module.exports = async (app, req, res, api, getLevels) => {
|
|||
|
||||
let account = app.parseResponse(body || "")
|
||||
let dumbGDPSError = req.isGDPS && (!account[16] || account[1].toLowerCase() == "undefined")
|
||||
|
||||
if (err2 || dumbGDPSError) {
|
||||
if (!api) return res.redirect('/search/' + req.params.id)
|
||||
else return res.sendError()
|
||||
}
|
||||
|
||||
|
||||
if (err2 || dumbGDPSError) return rejectLevel()
|
||||
|
||||
if (!foundID) app.userCache(req.id, account[16], account[2], account[1])
|
||||
|
||||
let userData = new Player(account)
|
||||
|
||||
|
||||
let userData = new Player(account)
|
||||
|
||||
if (api) return res.send(userData)
|
||||
|
||||
else fs.readFile('./html/profile.html', 'utf8', function(err, data) {
|
||||
let html = data;
|
||||
let html = data
|
||||
let variables = Object.keys(userData)
|
||||
variables.forEach(x => {
|
||||
let regex = new RegExp(`\\[\\[${x.toUpperCase()}\\]\\]`, "g")
|
||||
|
@ -61,7 +60,6 @@ module.exports = async (app, req, res, api, getLevels) => {
|
|||
})
|
||||
return res.send(html)
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
124
api/search.js
|
@ -1,94 +1,92 @@
|
|||
"use strict";
|
||||
const request = require('request')
|
||||
const music = require('../misc/music.json')
|
||||
const Level = require('../classes/Level.js')
|
||||
let demonList = {}
|
||||
|
||||
module.exports = async (app, req, res) => {
|
||||
const {query} = req
|
||||
if (req.offline) return res.status(500).send(query.hasOwnProperty("err") ? "err" : "-1")
|
||||
|
||||
if (req.offline) return res.status(500).send(req.query.hasOwnProperty("err") ? "err" : "-1")
|
||||
|
||||
let demonMode = req.query.hasOwnProperty("demonlist") || req.query.hasOwnProperty("demonList") || req.query.type == "demonlist" || req.query.type == "demonList"
|
||||
let demonMode = query.hasOwnProperty("demonlist") || query.hasOwnProperty("demonList") || query.type == "demonlist" || query.type == "demonList"
|
||||
if (demonMode) {
|
||||
if (!req.server.demonList) return res.sendError(400)
|
||||
let dList = demonList[req.id]
|
||||
if (!dList || !dList.list.length || dList.lastUpdated + 600000 < Date.now()) { // 10 minute cache
|
||||
return request.get(req.server.demonList + 'api/v2/demons/listed/?limit=100', function (err1, resp1, list1) {
|
||||
let demonStr = req.server.demonList + 'api/v2/demons/listed/?limit=100'
|
||||
return request.get(demonStr, function (err1, resp1, list1) {
|
||||
if (err1) return res.sendError()
|
||||
else return request.get(req.server.demonList + 'api/v2/demons/listed/?limit=100&after=100', function (err2, resp2, list2) {
|
||||
else return request.get(demonStr + '&after=100', function (err2, resp2, list2) {
|
||||
if (err2) return res.sendError()
|
||||
demonList[req.id] = {list: JSON.parse(list1).concat(JSON.parse(list2)).map(x => String(x.level_id)), lastUpdated: Date.now()}
|
||||
demonList[req.id] = {
|
||||
list: JSON.parse(list1).concat(JSON.parse(list2))
|
||||
.map(x => String(x.level_id)),
|
||||
lastUpdated: Date.now()
|
||||
}
|
||||
return app.run.search(app, req, res)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let amount = 10;
|
||||
let count = req.isGDPS ? 10 : +req.query.count
|
||||
if (count && count > 0) {
|
||||
if (count > 500) amount = 500
|
||||
else amount = count;
|
||||
}
|
||||
|
||||
let amount = 10
|
||||
let count = req.isGDPS ? 10 : +query.count
|
||||
if (count && count > 0) amount = Math.min(count, 500)
|
||||
|
||||
let filters = {
|
||||
str: req.params.text,
|
||||
|
||||
diff: req.query.diff,
|
||||
demonFilter: req.query.demonFilter,
|
||||
page: req.query.page || 0,
|
||||
gauntlet: req.query.gauntlet || 0,
|
||||
len: req.query.length,
|
||||
song: req.query.songID,
|
||||
followed: req.query.creators,
|
||||
diff: query.diff,
|
||||
demonFilter: query.demonFilter,
|
||||
page: query.page || 0,
|
||||
gauntlet: query.gauntlet || 0,
|
||||
len: query.length,
|
||||
song: query.songID,
|
||||
followed: query.creators,
|
||||
|
||||
featured: req.query.hasOwnProperty("featured") ? 1 : 0,
|
||||
originalOnly: req.query.hasOwnProperty("original") ? 1 : 0,
|
||||
twoPlayer: req.query.hasOwnProperty("twoPlayer") ? 1 : 0,
|
||||
coins: req.query.hasOwnProperty("coins") ? 1 : 0,
|
||||
epic: req.query.hasOwnProperty("epic") ? 1 : 0,
|
||||
star: req.query.hasOwnProperty("starred") ? 1 : 0,
|
||||
noStar: req.query.hasOwnProperty("noStar") ? 1 : 0,
|
||||
customSong: req.query.hasOwnProperty("customSong") ? 1 : 0,
|
||||
featured: query.hasOwnProperty("featured") ? 1 : 0,
|
||||
originalOnly: query.hasOwnProperty("original") ? 1 : 0,
|
||||
twoPlayer: query.hasOwnProperty("twoPlayer") ? 1 : 0,
|
||||
coins: query.hasOwnProperty("coins") ? 1 : 0,
|
||||
epic: query.hasOwnProperty("epic") ? 1 : 0,
|
||||
star: query.hasOwnProperty("starred") ? 1 : 0,
|
||||
noStar: query.hasOwnProperty("noStar") ? 1 : 0,
|
||||
customSong: query.hasOwnProperty("customSong") ? 1 : 0,
|
||||
|
||||
type: req.query.type || 0,
|
||||
type: query.type || 0,
|
||||
count: amount
|
||||
}
|
||||
|
||||
if (req.query.type) {
|
||||
let filterCheck = req.query.type.toLowerCase()
|
||||
switch(filterCheck) {
|
||||
case 'mostdownloaded': filters.type = 1; break;
|
||||
case 'mostliked': filters.type = 2; break;
|
||||
case 'trending': filters.type = 3; break;
|
||||
case 'recent': filters.type = 4; break;
|
||||
case 'featured': filters.type = 6; break;
|
||||
case 'magic': filters.type = 7; break;
|
||||
case 'awarded': filters.type = 11; break;
|
||||
case 'starred': filters.type = 11; break;
|
||||
case 'halloffame': filters.type = 16; break;
|
||||
case 'hof': filters.type = 16; break;
|
||||
case 'gdw': filters.type = 17; break;
|
||||
case 'gdworld': filters.type = 17; break;
|
||||
if (query.type) {
|
||||
let filterCheck = query.type.toLowerCase()
|
||||
let typeMap = {
|
||||
'mostdownloaded': 1, 'mostliked': 2,
|
||||
'trending': 3, 'recent': 4,
|
||||
'featured': 6, 'magic': 7,
|
||||
'awarded': 11, 'starred': 11,
|
||||
'halloffame': 16, 'hof': 16,
|
||||
'gdw': 17, 'gdworld': 17
|
||||
}
|
||||
if (typeMap.hasOwnProperty(filterCheck)) // JIC there's no match
|
||||
filters.type = typeMap[filterCheck]
|
||||
}
|
||||
|
||||
if (req.query.hasOwnProperty("user")) {
|
||||
if (query.hasOwnProperty("user")) {
|
||||
let accountCheck = app.userCache(req.id, filters.str)
|
||||
filters.type = 5
|
||||
if (accountCheck) filters.str = accountCheck[1]
|
||||
else if (!filters.str.match(/^[0-9]*$/)) return app.run.profile(app, req, res, null, req.params.text)
|
||||
}
|
||||
else if ( !(/^\d*$/).test(filters.str) ) return app.run.profile(app, req, res, null, req.params.text)
|
||||
}
|
||||
|
||||
if (req.query.hasOwnProperty("creators")) filters.type = 12
|
||||
if (query.hasOwnProperty("creators")) filters.type = 12
|
||||
|
||||
let listSize = 10
|
||||
if (demonMode || req.query.gauntlet || req.query.type == "saved" || ["mappack", "list", "saved"].some(x => req.query.hasOwnProperty(x))) {
|
||||
if (demonMode || query.gauntlet || query.type == "saved" || ["mappack", "list", "saved"].some(x => query.hasOwnProperty(x))) {
|
||||
filters.type = 10
|
||||
filters.str = demonMode ? demonList[req.id].list : filters.str.split(",")
|
||||
listSize = filters.str.length
|
||||
filters.str = filters.str.slice(filters.page*amount, filters.page*amount + amount)
|
||||
if (!filters.str.length) return res.sendError(400)
|
||||
filters.str = filters.str.map(x => String(Number(x) + (+req.query.l || 0))).join()
|
||||
filters.str = filters.str.map(x => String(Number(x) + (+query.l || 0))).join()
|
||||
filters.page = 0
|
||||
}
|
||||
|
||||
|
@ -103,25 +101,25 @@ module.exports = async (app, req, res) => {
|
|||
let authorList = {}
|
||||
let songList = {}
|
||||
let authors = splitBody[1].split('|')
|
||||
let songs = splitBody[2]; songs = songs.split('~:~').map(x => app.parseResponse(`~${x}~`, '~|~'))
|
||||
let songs = splitBody[2].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]]})
|
||||
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 = []
|
||||
|
||||
levelArray.forEach((x, y) => {
|
||||
|
||||
let songSearch = songs.find(y => y['~1'] == x[35]) || []
|
||||
|
||||
let level = new Level(x, req.server).getSongInfo(songSearch)
|
||||
if (!level.id) return
|
||||
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 (demonMode) {
|
||||
if (!y) level.demonList = req.server.demonList
|
||||
|
@ -133,21 +131,21 @@ module.exports = async (app, req, res) => {
|
|||
|
||||
//this is broken if you're not on page 0, blame robtop
|
||||
if (filters.page == 0 && y == 0 && splitBody[3]) {
|
||||
let pages = splitBody[3].split(":");
|
||||
let pages = splitBody[3].split(":")
|
||||
|
||||
if (filters.gauntlet) { // gauntlet page stuff
|
||||
level.results = levelArray.length
|
||||
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))
|
||||
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);
|
||||
level.results = +pages[0]
|
||||
level.pages = +pages[0] == 9999 ? 1000 : Math.ceil(pages[0] / amount)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
"use strict";
|
||||
module.exports = async (app, req, res) => {
|
||||
|
||||
if (req.offline) return res.sendError()
|
||||
|
||||
let songID = req.params.song
|
||||
req.gdRequest('getGJSongInfo', {songID: songID}, function(err, resp, body) {
|
||||
if (err) return res.sendError(400)
|
||||
return res.send(!body.startsWith("-") && body.length > 10)
|
||||
return err
|
||||
? res.sendError(400)
|
||||
: res.send(!body.startsWith("-") && body.length > 10)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -184,7 +184,7 @@ h2 {
|
|||
.brownBox {
|
||||
border: 2.5vh solid transparent;
|
||||
border-radius: 3vh;
|
||||
background-color: #995533;
|
||||
background-color: #953;
|
||||
border-image: url('../../assets/brownbox.png') 10% round;
|
||||
}
|
||||
|
||||
|
@ -205,4 +205,4 @@ h2 {
|
|||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,9 +54,9 @@ img, .noSelect {
|
|||
}
|
||||
|
||||
.supercenter {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
|
||||
|
@ -252,7 +252,7 @@ textarea::-webkit-scrollbar {
|
|||
width: 1.5vh;
|
||||
background: #6d3c24;
|
||||
}
|
||||
|
||||
|
||||
textarea::-webkit-scrollbar-thumb {
|
||||
background: rgb(83, 47, 28);
|
||||
overflow: hidden;
|
||||
|
@ -345,7 +345,7 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button {
|
|||
border-width: 2.5vh;
|
||||
border-style: solid;
|
||||
border-radius: 3vh;
|
||||
background-color: #995533;
|
||||
background-color: #953;
|
||||
border-image: url('../../assets/brownbox.png') 10% round;
|
||||
}
|
||||
|
||||
|
@ -353,7 +353,7 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button {
|
|||
border-width: 2.5vh;
|
||||
border-style: solid;
|
||||
border-radius: 3vh;
|
||||
background-color: #334499;
|
||||
background-color: #349;
|
||||
border-image: url('../../assets/bluebox.png') 10% round;
|
||||
}
|
||||
|
||||
|
@ -563,8 +563,8 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button {
|
|||
}
|
||||
|
||||
.popup {
|
||||
position: fixed;
|
||||
display: none;
|
||||
position: fixed;
|
||||
display: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
|
@ -619,9 +619,9 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button {
|
|||
}
|
||||
|
||||
#scoreTabs {
|
||||
position: absolute;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: 2.45%;
|
||||
top: 2.45%;
|
||||
width: 100%;
|
||||
margin-left: -13.5vh
|
||||
}
|
||||
|
@ -629,13 +629,13 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button {
|
|||
#searchBox {
|
||||
background-color: rgb(173, 115, 76);
|
||||
width: 122vh;
|
||||
height: 75%;
|
||||
overflow-y: auto;
|
||||
height: 75%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#searchBox::-webkit-scrollbar, #statusDiv::-webkit-scrollbar, #commentBox::-webkit-scrollbar {
|
||||
display: none;
|
||||
#searchBox::-webkit-scrollbar, #statusDiv::-webkit-scrollbar, #commentBox::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.searchResult {
|
||||
|
@ -703,7 +703,7 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button {
|
|||
|
||||
|
||||
.comment h2, .smallGold {
|
||||
background: -webkit-linear-gradient(#e28000, #ffee44);
|
||||
background: -webkit-linear-gradient(#e28000, #fe4);
|
||||
background-clip: text;
|
||||
width: fit-content;
|
||||
vertical-align: top;
|
||||
|
@ -902,7 +902,7 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button {
|
|||
background-color: #BE6F3F;
|
||||
overflow-y: scroll;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
#msgList::-webkit-scrollbar {
|
||||
|
@ -1029,7 +1029,7 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button {
|
|||
}
|
||||
|
||||
.analysis::-webkit-scrollbar-thumb, .levelCode::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
@ -1292,7 +1292,7 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button {
|
|||
.gdpslogo {
|
||||
margin-bottom: 0%;
|
||||
border-radius: 10%;
|
||||
filter: drop-shadow(0.5vh 0.5vh 0.15vh rgba(0, 0, 0, 0.6))
|
||||
filter: drop-shadow(0.5vh 0.5vh 0.15vh rgba(0, 0, 0, 0.6))
|
||||
}
|
||||
|
||||
.menuDisabled, .downloadDisabled {
|
||||
|
@ -1311,14 +1311,14 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button {
|
|||
|
||||
cr { color: #ff5a5a }
|
||||
co { color: #ffa54b }
|
||||
cy { color: #ffff00 }
|
||||
cy { color: #ff0 }
|
||||
cg { color: #40e348 }
|
||||
ca { color: #00ffff }
|
||||
ca { color: #0ff }
|
||||
cb { color: #60abef }
|
||||
cp { color: #ff00ff }
|
||||
cp { color: #f0f }
|
||||
|
||||
.red {
|
||||
color: #ff0000 !important;
|
||||
color: #f00 !important;
|
||||
}
|
||||
|
||||
.yellow {
|
||||
|
@ -1350,11 +1350,11 @@ cp { color: #ff00ff }
|
|||
}
|
||||
|
||||
.brightblue {
|
||||
color: #99ffff
|
||||
color: #9ff
|
||||
}
|
||||
|
||||
.brightred {
|
||||
color: #ffaaaa;
|
||||
color: #faa;
|
||||
}
|
||||
|
||||
.gray {
|
||||
|
@ -1380,10 +1380,10 @@ cp { color: #ff00ff }
|
|||
@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
|
||||
@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
|
||||
|
||||
@keyframes spin {
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform:rotate(360deg); }
|
||||
@keyframes spin {
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform:rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes boxAnimator {
|
||||
|
@ -1434,11 +1434,11 @@ cp { color: #ff00ff }
|
|||
* Also disabled on devices that may be slow to render new frames for performance optimization
|
||||
*/
|
||||
@media screen and
|
||||
(prefers-reduced-motion: reduce),
|
||||
(prefers-reduced-motion: reduce),
|
||||
(update: slow) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0.001ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.001ms !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
}
|
||||
|
||||
body {
|
||||
background-color: 555555;
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
p {
|
||||
|
@ -144,9 +144,9 @@ input:focus, select:focus, textarea:focus, button:focus {
|
|||
}
|
||||
|
||||
.supercenter {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
|
||||
|
@ -194,7 +194,7 @@ input:focus, select:focus, textarea:focus, button:focus {
|
|||
padding: 10 10 10 10;
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
border-radius: 8px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
#symbols p {
|
||||
|
@ -238,8 +238,8 @@ input:focus, select:focus, textarea:focus, button:focus {
|
|||
#generate {
|
||||
font-family: "Roboto";
|
||||
border: rgba(0, 0, 0, 0);
|
||||
background-color: #88FF33;
|
||||
box-shadow: 2px 2px 3px #66AA22;
|
||||
background-color: #8F3;
|
||||
box-shadow: 2px 2px 3px #6A2;
|
||||
border-radius: 10px;
|
||||
color: black;
|
||||
padding: 10px 15px 10px 15px;
|
||||
|
@ -259,8 +259,8 @@ input:focus, select:focus, textarea:focus, button:focus {
|
|||
.miniButton {
|
||||
font-family: "Roboto";
|
||||
border: rgba(0, 0, 0, 0);
|
||||
background-color: #88FF33;
|
||||
box-shadow: 1.5px 1.5px 2px #66AA22;
|
||||
background-color: #8F3;
|
||||
box-shadow: 1.5px 1.5px 2px #6A2;
|
||||
border-radius: 10px;
|
||||
color: black;
|
||||
padding: 7px 9px 7px 9px;
|
||||
|
@ -375,11 +375,11 @@ input:focus, select:focus, textarea:focus, button:focus {
|
|||
#colors::-webkit-scrollbar, #iconKitParent::-webkit-scrollbar {
|
||||
width: 9px;
|
||||
height: 10px;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
#colors::-webkit-scrollbar-thumb, #iconKitParent::-webkit-scrollbar-thumb {
|
||||
background: rgb(185, 185, 185);
|
||||
background: rgb(185, 185, 185);
|
||||
}
|
||||
|
||||
#iconKitParent {
|
||||
|
@ -394,7 +394,7 @@ input:focus, select:focus, textarea:focus, button:focus {
|
|||
|
||||
.iconColor div {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
#gdfloor {
|
||||
|
@ -423,13 +423,13 @@ input:focus, select:focus, textarea:focus, button:focus {
|
|||
}
|
||||
|
||||
#iconprogressbar {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
height: 7px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
#iconloading {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
height: 7px;
|
||||
width: 0%;
|
||||
}
|
||||
|
@ -447,8 +447,8 @@ body::-webkit-scrollbar {
|
|||
}
|
||||
|
||||
.popup {
|
||||
position: fixed;
|
||||
display: none;
|
||||
position: fixed;
|
||||
display: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
|
@ -459,7 +459,7 @@ body::-webkit-scrollbar {
|
|||
.brownBox {
|
||||
border: 17px solid rgba(0, 0, 0, 0);
|
||||
border-radius: 25px;
|
||||
background-color: #995533;
|
||||
background-color: #953;
|
||||
border-image: url('../../assets/brownbox.png') 10% round;
|
||||
}
|
||||
|
||||
|
@ -686,4 +686,4 @@ input[type="range"]::-webkit-slider-thumb:active { background-image: url("../../
|
|||
|
||||
@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
|
||||
@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
|
||||
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
|
||||
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
const XOR = require(__dirname + "/../classes/XOR");
|
||||
const music = require(__dirname + "/../misc/music.json");
|
||||
"use strict";
|
||||
const XOR = require("./XOR")
|
||||
const music = require("../misc/music.json")
|
||||
|
||||
let orbs = [0, 0, 50, 75, 125, 175, 225, 275, 350, 425, 500]
|
||||
let length = ['Tiny', 'Short', 'Medium', 'Long', 'XL']
|
||||
// this can't be shortened with a loop
|
||||
let difficulty = { 0: 'Unrated', 10: 'Easy', 20: 'Normal', 30: 'Hard', 40: 'Harder', 50: 'Insane' }
|
||||
let demonTypes = { 3: "Easy", 4: "Medium", 5: "Insane", 6: "Extreme" }
|
||||
let dailyLimit = 100000
|
||||
|
||||
class Level {
|
||||
constructor(levelInfo, server, download, author = []) {
|
||||
this.name = levelInfo[2] || "-";
|
||||
this.id = levelInfo[1] || 0;
|
||||
this.description = Buffer.from((levelInfo[3] || ""), "base64").toString() || "(No description provided)";
|
||||
this.name = levelInfo[2] || "-"
|
||||
this.id = levelInfo[1] || 0
|
||||
this.description = Buffer.from((levelInfo[3] || ""), "base64").toString() || "(No description provided)"
|
||||
this.author = author[1] || "-"
|
||||
this.playerID = levelInfo[6] || 0
|
||||
this.accountID = author[2] || 0
|
||||
|
@ -29,8 +32,8 @@ class Level {
|
|||
if (levelInfo[29]) this.updated = levelInfo[29] + (server.timestampSuffix || "")
|
||||
if (levelInfo[46]) this.editorTime = +levelInfo[46] || 0
|
||||
if (levelInfo[47]) this.totalEditorTime = +levelInfo[47] || 0
|
||||
if (levelInfo[27]) this.password = levelInfo[27];
|
||||
this.version = +levelInfo[5] || 0;
|
||||
if (levelInfo[27]) this.password = levelInfo[27]
|
||||
this.version = +levelInfo[5] || 0
|
||||
this.copiedID = levelInfo[30] || "0"
|
||||
this.twoPlayer = levelInfo[31] > 0
|
||||
this.officialSong = +levelInfo[35] ? 0 : parseInt(levelInfo[12]) + 1
|
||||
|
@ -39,21 +42,24 @@ class Level {
|
|||
this.verifiedCoins = levelInfo[38] > 0
|
||||
this.starsRequested = +levelInfo[39] || 0
|
||||
this.ldm = levelInfo[40] > 0
|
||||
if (+levelInfo[41] > 100000) this.weekly = true
|
||||
if (+levelInfo[41]) { this.dailyNumber = (+levelInfo[41] > 100000 ? +levelInfo[41] - 100000 : +levelInfo[41]); this.nextDaily = null; this.nextDailyTimestamp = null }
|
||||
if (+levelInfo[41] > dailyLimit) this.weekly = true
|
||||
if (+levelInfo[41]) {
|
||||
this.dailyNumber = (+levelInfo[41] > dailyLimit ? +levelInfo[41] - dailyLimit : +levelInfo[41])
|
||||
this.nextDaily = null
|
||||
this.nextDailyTimestamp = null
|
||||
}
|
||||
this.objects = +levelInfo[45] || 0
|
||||
this.large = levelInfo[45] > 40000;
|
||||
this.large = levelInfo[45] > 40000
|
||||
this.cp = Number((this.stars > 0) + this.featured + this.epic)
|
||||
|
||||
if (levelInfo[17] > 0) this.difficulty = (demonTypes[levelInfo[43]] || "Hard") + " Demon"
|
||||
if (levelInfo[25] > 0) this.difficulty = 'Auto'
|
||||
this.difficultyFace = `${levelInfo[17] != 1 ? this.difficulty.toLowerCase() : `demon-${this.difficulty.toLowerCase().split(' ')[0]}`}${this.epic ? '-epic' : `${this.featured ? '-featured' : ''}`}`
|
||||
this.difficultyFace = `${levelInfo[17] != 1 ? this.difficulty.toLowerCase() : `demon-${this.difficulty.toLowerCase().split(' ', 1)[0]}`}${this.epic ? '-epic' : `${this.featured ? '-featured' : ''}`}`
|
||||
|
||||
if (this.password && this.password != 0) {
|
||||
let xor = new XOR();
|
||||
let pass = xor.decrypt(this.password, 26364);
|
||||
if (pass.length > 1) this.password = pass.slice(1);
|
||||
else this.password = pass;
|
||||
let xor = new XOR()
|
||||
let pass = xor.decrypt(this.password, 26364)
|
||||
this.password = pass.length > 1 ? pass.slice(1) : pass
|
||||
}
|
||||
|
||||
if (server.onePointNine) {
|
||||
|
@ -83,9 +89,9 @@ class Level {
|
|||
this.songSize = "0MB"
|
||||
this.songID = "Level " + this.officialSong
|
||||
}
|
||||
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Level;
|
||||
module.exports = Level
|
|
@ -1,4 +1,4 @@
|
|||
const colors = require('../iconkit/sacredtexts/colors.json');
|
||||
const colors = require('../iconkit/sacredtexts/colors.json')
|
||||
|
||||
class Player {
|
||||
constructor(account) {
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
//https://nodejs.org/docs/latest/api/buffer.html#buffers-and-character-encodings
|
||||
//both only work on "binary strings" and "URI-safe B64"
|
||||
let toB64 = str => Buffer.from(str).toString('base64url')
|
||||
let fromB64 = str => Buffer.from(str, 'base64').toString()
|
||||
|
||||
const defKey = 37526
|
||||
|
||||
module.exports = class XOR {
|
||||
xor(str, key) { return String.fromCodePoint(...str.split('').map((char, i) => char.charCodeAt(0) ^ key.toString().charCodeAt(i % key.toString().length))) }
|
||||
encrypt(str, key = 37526) { return Buffer.from(this.xor(str, key)).toString('base64').replace(/./gs, c => ({'/': '_', '+': '-'}[c] || c)); }
|
||||
decrypt(str, key = 37526) { return this.xor(Buffer.from(str.replace(/./gs, c => ({'/': '_', '+': '-'}[c] || c)), 'base64').toString(), key) }
|
||||
}
|
||||
xor(str, key) {
|
||||
key = key.toString()
|
||||
return String.fromCodePoint(...str.split('')
|
||||
.map((c, i) => c.charCodeAt(0) ^ key.charCodeAt(i % key.length)))
|
||||
}
|
||||
encrypt(str, key = defKey) { return toB64(this.xor(str, key)) }
|
||||
decrypt(str, key = defKey) { return this.xor(fromB64(str), key) }
|
||||
}
|
|
@ -21,23 +21,23 @@
|
|||
|
||||
<div id="rewardLabel">
|
||||
<img filter="rewardFilter" class="achSelect selectAll" style="margin: 0% 2% 1.9% 0%" class="gdButton inline" src="../assets/select-all.png" height="5%">
|
||||
<h1 class="smaller inline" style="margin-bottom: 1.5%">Reward</h1>
|
||||
<h1 class="smaller inline" style="margin-bottom: 1.5%">Reward</h1>
|
||||
<img filter="rewardFilter" class="achSelect selectNone" style="margin: 0% 0% 1.9% 2%" class="gdButton inline" src="../assets/select-none.png" height="5%">
|
||||
</div>
|
||||
</div>
|
||||
<div id="forms"></div>
|
||||
|
||||
<div id="typeLabel">
|
||||
<img filter="typeFilter" class="achSelect selectAll" style="margin: 0% 2% 1.4% 0%" class="gdButton inline" src="../assets/select-all.png" height="5%">
|
||||
<h1 class="smaller inline" style="margin-top: 3%; margin-bottom: 1%">Requirement</h1>
|
||||
<h1 class="smaller inline" style="margin-top: 3%; margin-bottom: 1%">Requirement</h1>
|
||||
<img filter="typeFilter" class="achSelect selectNone" style="margin: 0% 0% 1.4% 2%" class="gdButton inline" src="../assets/select-none.png" height="5%">
|
||||
</div>
|
||||
</div>
|
||||
<div id="types"></div>
|
||||
|
||||
<div id="gameLabel">
|
||||
<img filter="gameFilter" class="achSelect selectAll" style="margin: 0% 2% 1.8% 0%" class="gdButton inline" src="../assets/select-all.png" height="5%">
|
||||
<h1 class="smaller inline" style="margin-top: 1%; margin-bottom: 1.3%">Game</h1>
|
||||
<h1 class="smaller inline" style="margin-top: 1%; margin-bottom: 1.3%">Game</h1>
|
||||
<img filter="gameFilter" class="achSelect selectNone" style="margin: 0% 0% 1.8% 2%" class="gdButton inline" src="../assets/select-none.png" height="5%">
|
||||
</div>
|
||||
</div>
|
||||
<div id="games">
|
||||
<img class="gdButton achFilter gameFilter" src="../assets/achievements/gd.png" height="12%" style="margin: 0% 1%" title="Geometry Dash" filter="gd">
|
||||
<img class="gdButton achFilter gameFilter" src="../assets/achievements/gdm.png" height="12%" style="margin: 0% 1%" title="Geometry Dash Meltdown" filter="meltdown">
|
||||
|
@ -59,7 +59,7 @@
|
|||
<div id="searchBox" class="supercenter dragscroll" style="width: 128vh">
|
||||
<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%">
|
||||
|
@ -79,10 +79,10 @@
|
|||
|
||||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="../dragscroll.js"></script>
|
||||
<script type="text/javascript" src="./global.js?v=1"></script>
|
||||
<script type="text/javascript" src="./dragscroll.js"></script>
|
||||
<script>
|
||||
|
||||
"use strict";
|
||||
let disabledFilters = {reward: [], type: [], game: []}
|
||||
let forms = ["icon", "ship", "ball", "ufo", "wave", "robot", "spider"]
|
||||
let gameColors = {gd: "255,200,0", meltdown: "255, 100, 0", world: "100,220,0", subzero: "0,255,255"}
|
||||
|
@ -99,7 +99,7 @@ function append(reset=true) {
|
|||
$('#searchBox').html(`<div style="height: 4.5%"></div>`)
|
||||
achievements.forEach(x => {
|
||||
|
||||
let iconImg = `"`;
|
||||
let iconImg = `"`
|
||||
if (forms.includes(x.rewardType)) iconImg = `../iconkit/premade/${x.rewardType}_${x.rewardID}.png" width="90%" title="${x.rewardType}_${x.rewardID < 10 ? "0" : ""}${x.rewardID}"`
|
||||
else if (x.rewardType.startsWith("color")) {
|
||||
let col = colors[x.rewardID]
|
||||
|
@ -129,8 +129,7 @@ Object.keys(ach.types).forEach(x => {
|
|||
$('#types').append(`<img class="gdButton achFilter typeFilter" filter="${ach.types[x][1].join(" ")}" src="../assets/achievements/${x}.png" title="${ach.types[x][0]}" height="8.5%" style="margin: 0.6% 0.4%">`)
|
||||
})
|
||||
|
||||
achievements = ach.achievements
|
||||
colors = ach.colors
|
||||
{achievements, colors} = ach
|
||||
append()
|
||||
|
||||
function label(labelName) {
|
||||
|
@ -148,23 +147,23 @@ function label(labelName) {
|
|||
|
||||
$(labelFilter).click(function() {
|
||||
let filters = $(this).attr('filter').split(" ")
|
||||
let args
|
||||
if (!$(this).hasClass('achDeselected')) {
|
||||
$(this).addClass('achDeselected')
|
||||
filters.forEach(x => disabledFilters[labelName].push(x))
|
||||
if (labelName == "reward") $(this).attr('src', $(this).attr('src').replace("_on", "_off"))
|
||||
args = ['_on', '_off']
|
||||
}
|
||||
else {
|
||||
$(this).removeClass('achDeselected')
|
||||
filters.forEach(x => disabledFilters[labelName] = disabledFilters[labelName].filter(y => y != x))
|
||||
if (labelName == "reward") $(this).attr('src', $(this).attr('src').replace("_off", "_on"))
|
||||
args = ['_off', '_on']
|
||||
}
|
||||
|
||||
if (labelName == "reward") $(this).attr('src', $(this).attr('src').replace(...args))
|
||||
})
|
||||
}
|
||||
|
||||
label("reward")
|
||||
label("type")
|
||||
label("game")
|
||||
const labels = ['reward', 'type', 'game']
|
||||
labels.forEach(label)
|
||||
|
||||
$(document).on('click', '.selectNone', function() { $(`.${$(this).attr('filter')}:not(.achDeselected)`).trigger('click'); $('#selectNone').hide(); $('#selectAll').show() })
|
||||
$(document).on('click', '.selectAll', function() { $(`.${$(this).attr('filter')}.achDeselected`).trigger('click'); $('#selectNone').show(); $('#selectAll').hide() })
|
||||
|
@ -173,23 +172,20 @@ $('#submitFilters').click(function() {
|
|||
|
||||
$('.popup').hide()
|
||||
|
||||
if (!$('.rewardFilter:not(.achDeselected)').length) $('#rewardLabel .selectAll').trigger('click')
|
||||
if (!$('.typeFilter:not(.achDeselected)').length) $('#typeLabel .selectAll').trigger('click')
|
||||
if (!$('.gameFilter:not(.achDeselected)').length) $('#gameLabel .selectAll').trigger('click')
|
||||
labels.forEach(x => {
|
||||
if (!$(`.${x}Filter:not(.achDeselected)`).length) $(`#${x}Label .selectAll`).trigger('click')
|
||||
})
|
||||
|
||||
achievements = ach.achievements
|
||||
.filter(x => !disabledFilters.reward.includes(x.rewardType))
|
||||
.filter(x => !disabledFilters.type.some(y => x.id.startsWith(y)))
|
||||
.filter(x => !disabledFilters.game.includes(x.game))
|
||||
.filter(x => !disabledFilters.reward.includes(x.rewardType))
|
||||
.filter(x => !disabledFilters.type.some(y => x.id.startsWith(y)))
|
||||
.filter(x => !disabledFilters.game.includes(x.game))
|
||||
append()
|
||||
})
|
||||
|
||||
$('#check').click(function() {
|
||||
completed = !completed
|
||||
if (completed) $('#check').attr('src', '../assets/check-on.png')
|
||||
else $('#check').attr('src', '../assets/check-off.png')
|
||||
$('#check').click(() => {
|
||||
$('#check').attr('src', `../assets/check-o${completed = !completed ? 'n' : 'ff'}.png`)
|
||||
append(false)
|
||||
})
|
||||
}))
|
||||
|
||||
</script>
|
|
@ -3,11 +3,12 @@
|
|||
<meta charset="utf-8">
|
||||
<meta property="og:type" content="website">
|
||||
<meta id="meta-title" property="og:title" content="Level Analysis">
|
||||
<meta id="meta-desc" property="og:description" content="Analyze a Geometry Dash level and view it's objects, portals, color channels, code, and more!">
|
||||
<meta id="meta-desc" property="og:description" content="Analyze a Geometry Dash level and view it's objects, portals, color channels, code, and more!">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/cp.png">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<link href="../assets/css/browser.css?v=1" 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>
|
||||
<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/cp.png">
|
||||
</head>
|
||||
|
||||
|
@ -100,25 +101,27 @@
|
|||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js"></script>
|
||||
<script type="text/javascript" src="/misc/global.js"></script>
|
||||
<script>
|
||||
|
||||
function clean(text) {return text.toString().replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/=/g, "=").replace(/"/g, """).replace(/'/g, "'")}
|
||||
|
||||
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']
|
||||
let dualPortals = ['dual', 'single']
|
||||
let mirrorPortals = ['mirrorOn', 'mirrorOff']
|
||||
const PORTALS = {
|
||||
form: ['cube', 'ship', 'ball', 'ufo', 'wave', 'robot', 'spider'],
|
||||
speed: ['-1x', '1x', '2x', '3x', '4x'],
|
||||
size: ['mini', 'big'],
|
||||
dual: ['dual', 'single'],
|
||||
mirror: ['mirrorOn', 'mirrorOff']
|
||||
}
|
||||
|
||||
fetch(`/api${window.location.pathname}`).then(res => res.json()).then(res => {
|
||||
|
||||
fetch(`../api${window.location.pathname}`).then(res => res.json()).then(res => {
|
||||
|
||||
if (!res.level) {
|
||||
switch(res) {
|
||||
case -1: $('#errorMessage').html("This level could not be be <cr>downloaded</cr>. Either the servers rejected the request, or the level simply <co>doesn't exist at all</co>."); break;
|
||||
case -2: $('#errorMessage').html("This level's data appears to be <cr>corrupt</cr> and cannot be <cy>parsed</cy>. It most likely won't load in GD."); break;
|
||||
case -1: $('#errorMessage').html("This level could not be be <cr>downloaded</cr>. Either the servers rejected the request, or the level simply <co>doesn't exist at all</co>."); break
|
||||
case -2: $('#errorMessage').html("This level's data appears to be <cr>corrupt</cr> and cannot be <cy>parsed</cy>. It most likely won't load in GD."); break
|
||||
case -3: $('#errorMessage').html("This level's data could not be obtained because <ca>RobTop</ca> has disabled <cg>level downloading</cg>."); break;
|
||||
}
|
||||
popupEsc = false
|
||||
|
@ -129,8 +132,8 @@ fetch(`../api${window.location.pathname}`).then(res => res.json()).then(res => {
|
|||
$('#objectCount').text(commafy(res.objects) + " objects")
|
||||
document.title = "Analysis of " + res.level.name
|
||||
|
||||
$('#meta-title').attr('content', "Analysis of " + res.level.name)
|
||||
$('#meta-desc').attr('content', `${res.portals.split(",").length}x portals, ${res.orbs.total || 0}x orbs, ${res.triggers.total || 0}x triggers, ${res.misc.glow || 0}x glow...`)
|
||||
$('#meta-title').attr('content', "Analysis of " + res.level.name)
|
||||
$('#meta-desc').attr('content', `${res.portals.split(",").length}x portals, ${res.orbs.total || 0}x orbs, ${res.triggers.total || 0}x triggers, ${res.misc.glow || 0}x glow...`)
|
||||
|
||||
|
||||
let hdPercent = (res.highDetail / res.objects) * 100
|
||||
|
@ -216,7 +219,7 @@ function appendTriggerGroups() {
|
|||
})
|
||||
|
||||
miscList.forEach(x => {
|
||||
if (x == "objects") return;
|
||||
if (x == "objects") return
|
||||
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>`)
|
||||
})
|
||||
|
||||
|
@ -259,11 +262,8 @@ function appendTriggerGroups() {
|
|||
else disabledPortals.push($(this).attr('portal'))
|
||||
|
||||
portals = res.portals.split(", ").map(x => x.split(" "))
|
||||
if (disabledPortals.includes('form')) portals = portals.filter(x => !formPortals.includes(x[0]))
|
||||
if (disabledPortals.includes('speed')) portals = portals.filter(x => !speedPortals.includes(x[0]))
|
||||
if (disabledPortals.includes('size')) portals = portals.filter(x => !sizePortals.includes(x[0]))
|
||||
if (disabledPortals.includes('dual')) portals = portals.filter(x => !dualPortals.includes(x[0]))
|
||||
if (disabledPortals.includes('mirror')) portals = portals.filter(x => !mirrorPortals.includes(x[0]))
|
||||
for (let P in PORTALS)
|
||||
if (disabledPortals.includes(P)) portals = portals.filter(x => !PORTALS[P].includes(x[0]))
|
||||
|
||||
if (disabledPortals.includes('dupe')) {
|
||||
portals.reverse().forEach((x, y) => {if (portals[y+1] && portals[y+1][0] == x[0]) portals[y][0] = null;})
|
||||
|
@ -293,7 +293,8 @@ function appendTriggerGroups() {
|
|||
hsv.s = Number(hsv.s).toFixed(2)
|
||||
hsv.v = Number(hsv.v).toFixed(2)
|
||||
}
|
||||
let hex = "#" + ((1 << 24) + (+col.r << 16) + (+col.g << 8) + +col.b).toString(16).slice(1)
|
||||
// padded (fixed-size) RGB hex
|
||||
let hex = "#" + ((1 << 24) | (col.r << 16) | (col.g << 8) | col.b).toString(16).slice(1) // remove sentinel nibble
|
||||
$('#colorStuff').html(`
|
||||
<h2 class="slightlySmaller">${isNaN(col.channel) ? col.channel : "Color " + col.channel}</h2>
|
||||
<div class="colorSection">
|
||||
|
@ -343,6 +344,5 @@ function appendTriggerGroups() {
|
|||
$('#loadingDiv').hide()
|
||||
$('#analysisDiv').show()
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
<head>
|
||||
<title>GD Level Browser API</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" href="../assets/difficulties/auto.png">
|
||||
<link href="../assets/css/api.css" type="text/css" rel="stylesheet">
|
||||
<link rel="icon" href="/assets/difficulties/auto.png">
|
||||
<link href="/assets/css/api.css" type="text/css" rel="stylesheet">
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,600,700,800&display=swap" rel="stylesheet">
|
||||
|
||||
|
||||
<meta id="meta-title" property="og:title" content="GDBrowser API">
|
||||
<meta id="meta-desc" property="og:description" content="It's basically the Geometry Dash API, but not terrible!">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/difficulties/auto.png">
|
||||
|
@ -35,22 +35,22 @@
|
|||
// smooth scrolling through anchors
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
document.querySelector(this.getAttribute('href')).scrollIntoView({
|
||||
behavior: 'smooth'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// menu button
|
||||
document.getElementById('menu-btn').onclick = function(){
|
||||
document.getElementsByClassName('header-links')[0].classList.toggle('hid');
|
||||
document.getElementsByClassName('header-links')[0].classList.toggle('hid')
|
||||
document.getElementById('menu-btn').classList.toggle('active');
|
||||
}
|
||||
|
||||
|
||||
for(let i = 0; i < document.getElementsByClassName('header-link').length; i++){
|
||||
document.getElementsByClassName('header-link')[i].onclick = function(){
|
||||
document.getElementsByClassName('header-links')[0].classList.toggle('hid');
|
||||
document.getElementsByClassName('header-links')[0].classList.toggle('hid')
|
||||
document.getElementById('menu-btn').classList.toggle('active');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
<head>
|
||||
<title>GD Level Browser API</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" href="../assets/difficulties/auto.png">
|
||||
<link href="../assets/css/api.css" type="text/css" rel="stylesheet">
|
||||
<link rel="icon" href="/assets/difficulties/auto.png">
|
||||
<link href="/assets/css/api.css" type="text/css" rel="stylesheet">
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,600,700,800&display=swap" rel="stylesheet">
|
||||
|
||||
|
||||
<meta id="meta-title" property="og:title" content="GDBrowser API">
|
||||
<meta id="meta-desc" property="og:description" content="It's basically the Geometry Dash API, but not terrible!">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/difficulties/auto.png">
|
||||
|
@ -19,7 +19,7 @@
|
|||
<div class="main-header-wrap">
|
||||
<div class="main-header">
|
||||
<div class="header-drawer" id="menu-btn">
|
||||
<img src="../assets/menu-ic.svg" alt="Menu" id="menu-btn-img">
|
||||
<img src="/assets/menu-ic.svg" alt="Menu" id="menu-btn-img">
|
||||
</div>
|
||||
<div class="header-links hid">
|
||||
<a class="header-link" href="#intro">Introduction</a>
|
||||
|
@ -37,24 +37,24 @@
|
|||
<div class="category-content">
|
||||
<a class="header-link" href="#profile">Profiles</a>
|
||||
<a class="header-link" href="#leaderboard">Leaderboards</a>
|
||||
<a class="header-link" href="#comments">Comments & Posts</a>
|
||||
<a class="header-link" href="#comments">Comments & Posts</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-category">
|
||||
<div class="category-name">Account</div>
|
||||
<div class="category-content">
|
||||
<a class="header-link" href="#commenting">Commenting</a>
|
||||
<a class="header-link" href="#profileposting">Profile Posting</a>
|
||||
<a class="header-link" href="#liking">Liking</a>
|
||||
<a class="header-link" href="#messages">Messages</a>
|
||||
<a class="header-link" href="#commenting">Commenting</a>
|
||||
<a class="header-link" href="#profileposting">Profile Posting</a>
|
||||
<a class="header-link" href="#liking">Liking</a>
|
||||
<a class="header-link" href="#messages">Messages</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-category">
|
||||
<div class="category-name">Misc</div>
|
||||
<div class="category-content">
|
||||
<a class="header-link" href="#analyze">Level Analysis</a>
|
||||
<a class="header-link" href="#artist">Song Verification</a>
|
||||
<a class="header-link" href="#icons">Icons</a>
|
||||
<a class="header-link" href="#analyze">Level Analysis</a>
|
||||
<a class="header-link" href="#artist">Song Verification</a>
|
||||
<a class="header-link" href="#icons">Icons</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -186,7 +186,7 @@
|
|||
<main>
|
||||
|
||||
<div id="profile" class="anchor"></div>
|
||||
|
||||
|
||||
<div class="main-block">
|
||||
<h1>Profiles</h1>
|
||||
<p>/api/profile/username-or-id</p>
|
||||
|
@ -244,7 +244,7 @@
|
|||
<main>
|
||||
|
||||
<div id="search" class="anchor"></div>
|
||||
|
||||
|
||||
<div class="main-block">
|
||||
<h1>Searching</h1>
|
||||
<p>/api/search/search-query</p>
|
||||
|
@ -540,10 +540,10 @@
|
|||
<div class="main-block">
|
||||
<h1>Commenting (usually broken)</h1>
|
||||
<p>POST: /postComment</p>
|
||||
|
||||
|
||||
<p>Leaves a comment on a level. This one is a POST request!</p>
|
||||
<p>*Commenting has a rate limit of 15 seconds</p>
|
||||
|
||||
|
||||
<br>
|
||||
<p class="reveal" onclick="revealSection('#params-commenting')"><b>Parameters (6)</b></p>
|
||||
<div class="subdiv" id="params-commenting">
|
||||
|
@ -555,7 +555,7 @@
|
|||
<p>percent: The percent shown on the comment (optional)</p>
|
||||
<p>color: If the comment should have a special pink color on GDBrowser (optional)</p>
|
||||
</div>
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
<p class="reveal" onclick="revealSection('#request-commenting')"><b>Example</b></p>
|
||||
|
@ -571,7 +571,7 @@
|
|||
<br>
|
||||
<p>If a status of 200 is returned, then the comment was successfully posted. Otherwise, a 400 will return with an error message.</p>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="seperator"></div>
|
||||
</main>
|
||||
|
@ -581,9 +581,9 @@
|
|||
<div class="main-block">
|
||||
<h1>Profile Posting (usually broken)</h1>
|
||||
<p>POST: /postProfileComment</p>
|
||||
|
||||
|
||||
<p>Leaves a profile post. This one is a POST request!</p>
|
||||
|
||||
|
||||
<br>
|
||||
<p class="reveal" onclick="revealSection('#params-profileposting')"><b>Parameters (5)</b></p>
|
||||
<div class="subdiv" id="params-profileposting">
|
||||
|
@ -593,7 +593,7 @@
|
|||
<p>password: Your password (as plain text)</p>
|
||||
<p>color: If the comment should have a special pink color on GDBrowser (optional)</p>
|
||||
</div>
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
<p class="reveal" onclick="revealSection('#request-profileposting')"><b>Example</b></p>
|
||||
|
@ -607,7 +607,7 @@
|
|||
<br>
|
||||
<p>If a status of 200 is returned, then the profile post was successfully posted. Otherwise, a 400 will return with an error message.</p>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="seperator"></div>
|
||||
</main>
|
||||
|
@ -618,9 +618,9 @@
|
|||
<div class="main-block">
|
||||
<h1>Liking (usually broken)</h1>
|
||||
<p>POST: /like</p>
|
||||
|
||||
|
||||
<p>Likes/dislikes level, comment, or post. This one is a POST request!</p>
|
||||
|
||||
|
||||
<br>
|
||||
<p class="reveal" onclick="revealSection('#params-liking')"><b>Parameters (6)</b></p>
|
||||
<div class="subdiv" id="params-liking">
|
||||
|
@ -631,7 +631,7 @@
|
|||
<p>accountID: Your account ID</p>
|
||||
<p>password: Your password (as plain text)</p>
|
||||
</div>
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
<p class="reveal" onclick="revealSection('#request-liking')"><b>Example</b></p>
|
||||
|
@ -649,7 +649,7 @@
|
|||
<p>A status of 200 will return if everything goes well, otherwise a 400 will return with an error message.<br>
|
||||
Liking a comment multiple times on the same account will return a 200, but not actually increase the in-game like counter.</p>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="seperator"></div>
|
||||
</main>
|
||||
|
@ -665,7 +665,7 @@
|
|||
<b>/sendMessage</b> (sends a message)</p>
|
||||
|
||||
<p>I decided to put all 4 of these requests in one section because they're fairly similar ¯\_(ツ)_/¯</p>
|
||||
|
||||
|
||||
<br>
|
||||
<p class="reveal" onclick="revealSection('#params-msg')"><b>Parameters</b></p>
|
||||
<div class="subdiv" id="params-msg">
|
||||
|
@ -687,7 +687,7 @@
|
|||
<p>message: The content of the message, max 300 characters</p>
|
||||
<p>color: If the message should have a special pink color on GDBrowser (optional)</p>
|
||||
</div>
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
<p class="reveal" onclick="revealSection('#request-msg')"><b>Example</b></p>
|
||||
|
@ -699,7 +699,7 @@
|
|||
&accountID=106255<br>
|
||||
&password=KitsuneColon333<br>
|
||||
<br>
|
||||
|
||||
|
||||
<p>Read message with ID of 177013:</p>
|
||||
<p>POST /messages/177013<br>
|
||||
?accountID=106255<br>
|
||||
|
@ -712,7 +712,7 @@
|
|||
&id=177013<br>
|
||||
&password=KitsuneColon333<br>
|
||||
<br>
|
||||
|
||||
|
||||
<p>Send "Hello!" to Tubular9:</p>
|
||||
<p>POST /sendMessage<br>
|
||||
?accountID=106255<br>
|
||||
|
@ -877,22 +877,22 @@
|
|||
// smooth scrolling through anchors
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
document.querySelector(this.getAttribute('href')).scrollIntoView({
|
||||
behavior: 'smooth'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// menu button
|
||||
document.getElementById('menu-btn').onclick = function(){
|
||||
document.getElementsByClassName('header-links')[0].classList.toggle('hid');
|
||||
document.getElementsByClassName('header-links')[0].classList.toggle('hid')
|
||||
document.getElementById('menu-btn').classList.toggle('active');
|
||||
}
|
||||
|
||||
|
||||
for(let i = 0; i < document.getElementsByClassName('header-link').length; i++){
|
||||
document.getElementsByClassName('header-link')[i].onclick = function(){
|
||||
document.getElementsByClassName('header-links')[0].classList.toggle('hid');
|
||||
document.getElementsByClassName('header-links')[0].classList.toggle('hid')
|
||||
document.getElementById('menu-btn').classList.toggle('active');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
<meta charset="utf-8">
|
||||
<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/folder.png">
|
||||
<link rel="icon" href="/assets/folder.png">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta id="meta-desc" property="og:description" content='i only upload high quality geometry dash asset rips'>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-image: linear-gradient(#2b2b2b, #171717) !important;
|
||||
background-image: linear-gradient(#2b2b2b, #171717) !important
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
|
@ -21,16 +21,16 @@
|
|||
}
|
||||
|
||||
h1, p {
|
||||
color: white;
|
||||
font-family: aller, helvetica, arial;
|
||||
color: white
|
||||
font-family: aller, helvetica, arial
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 300px;
|
||||
display: inline-block;
|
||||
margin: 0 5 4 5;
|
||||
font-family: aller, helvetica, arial;
|
||||
width: 300px
|
||||
display: inline-block
|
||||
margin: 0 5 4 5
|
||||
font-family: aller, helvetica, arial
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<head>
|
||||
<title>Boomlings Leaderboard</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/boomlings.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/boomlings.css?v=1" 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/boomlings/red.png">
|
||||
<link rel="icon" href="/assets/boomlings/red.png">
|
||||
<meta id="meta-title" property="og:title" content="Boomlings Leaderboard">
|
||||
<meta id="meta-desc" property="og:description" content='"Never ask me for anything ever again." - Masahiro Sakurai (probably)'>
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/boomlings/red.png">
|
||||
|
@ -22,19 +22,19 @@
|
|||
<div id="borderbox" class="supercenter dragscroll"></div>
|
||||
|
||||
<div class="supercenter" id="loading" style="height: 10%; top: 47%; display: none;">
|
||||
<img class="spin noSelect" src="../assets/loading.png" height="105%">
|
||||
<img class="spin noSelect" src="/assets/loading.png" height="105%">
|
||||
</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()">
|
||||
<img class="gdButton yesClick" id="backButton" src="/assets/back.png" height="30%" onclick="backButton()">
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%;>
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%;>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="position:absolute; bottom: 0%; right: 0%; width: 100%; text-align: right;">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -42,14 +42,14 @@
|
|||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/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="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="../dragscroll.js"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/dragscroll.js"></script>
|
||||
<script>
|
||||
|
||||
$('#boomerbox').html('')
|
||||
$('#loading').show()
|
||||
|
||||
fetch(`../api/boomlings`).then(res => res.json()).then(res => {
|
||||
fetch(`/api/boomlings`).then(res => res.json()).then(res => {
|
||||
|
||||
if (res == "0") res = []
|
||||
$('#boomerbox').html('')
|
||||
|
@ -59,19 +59,19 @@
|
|||
|
||||
$('#boomerbox').append(`<div class="inline leaderboardSlot">
|
||||
<div class="flex" style="width: 7vh; height: 100%"><h1 class="rankNumber" style="width: inherit">${x.rank}</h1></div>
|
||||
<img src="../assets/boomlings/icons/${x.boomling}.png" style="width: 12vh; align-self: center">
|
||||
|
||||
<img src="/assets/boomlings/icons/${x.boomling}.png" style="width: 12vh; align-self: center">
|
||||
|
||||
<p class="flex username" style="width: 48%">${x.name}</p>
|
||||
|
||||
<div class="flex" style="width: 22%">
|
||||
<h1 class="level">Level ${x.level}<br><span class="score">${x.score}</span>
|
||||
<img class="powerup inline" height="20%" src="../assets/boomlings/powerups/${x.powerups[0]}.png">` +
|
||||
`<img class="powerup inline" height="20%" src="../assets/boomlings/powerups/${x.powerups[1]}.png">` +
|
||||
`<img class="powerup inline" height="20%" src="../assets/boomlings/powerups/${x.powerups[2]}.png">
|
||||
<img class="powerup inline" height="20%" src="/assets/boomlings/powerups/${x.powerups[0]}.png">` +
|
||||
`<img class="powerup inline" height="20%" src="/assets/boomlings/powerups/${x.powerups[1]}.png">` +
|
||||
`<img class="powerup inline" height="20%" src="/assets/boomlings/powerups/${x.powerups[2]}.png">
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<img src="../assets/boomlings/levels/${x.boomlingLevel}.png" style="width: 6.5%; align-self: center">
|
||||
<img src="/assets/boomlings/levels/${x.boomlingLevel}.png" style="width: 6.5%; align-self: center">
|
||||
</div>`)
|
||||
})
|
||||
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<head>
|
||||
<title>Coming Soon...</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link rel="icon" href="../assets/coin.png">
|
||||
<link href="/assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link rel="icon" href="/assets/coin.png">
|
||||
</head>
|
||||
|
||||
<body class="levelBG">
|
||||
<div class="supercenter" style="height: 70%;">
|
||||
<h1>Coming soon!</h1>
|
||||
<br>
|
||||
<img src="../assets/javi.png" style="width: 400px; border-radius: 20px; border: 2px solid black;">
|
||||
<img src="/assets/javi.png" style="width: 400px; border-radius: 20px; border: 2px solid black;">
|
||||
<br>
|
||||
<br>
|
||||
<div class="gdbutton">
|
||||
<a href="https://twitter.com/TheRealGDColon"><img class="inline"src="../assets/twitter.png" width=6%> <h2 class="inline" style="margin-left: 2%;">stay updated</h2></a>
|
||||
<a href="https://twitter.com/TheRealGDColon"><img class="inline"src="/assets/twitter.png" width=6%> <h2 class="inline" style="margin-left: 2%;">stay updated</h2></a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title>Comments</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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/like.png">
|
||||
<link rel="icon" href="/assets/like.png">
|
||||
<meta id="meta-title" property="og:title" content="Level Comments">
|
||||
<meta id="meta-desc" property="og:description" content="View the comments of a Geometry Dash level!">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/like.png">
|
||||
|
@ -28,16 +28,16 @@
|
|||
<div style="min-height: 16%; max-height: 16%">
|
||||
<p id="message" style="padding: 0% 10%; margin-top: 1.5%"></p>
|
||||
</div>
|
||||
<img src="../assets/btn-cancel.png" height=10%; class="postButton gdButton center" style="margin-right: 1%" onclick="$('#postComment').hide(); $('textarea').val('')">
|
||||
<img src="../assets/btn-submit.png" type="submit" height=10%; class="postButton gdButton center" style="margin-left: 1%" id="submitComment">
|
||||
<img src="/assets/btn-cancel.png" height=10%; class="postButton gdButton center" style="margin-right: 1%" onclick="$('#postComment').hide(); $('textarea').val('')">
|
||||
<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">
|
||||
<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%">
|
||||
|
@ -47,17 +47,17 @@
|
|||
<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">
|
||||
<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%;>
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%;>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; right: 0%; width: 100%; text-align: right;">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
</div>
|
||||
|
||||
<div style="text-align: right; position:absolute; top: 1%; right: 1.25%">
|
||||
|
@ -69,39 +69,39 @@
|
|||
<div class="lightBox center dragscroll" id="commentBox" style="margin: 4.5% auto; width: 115vh; height: 86%; background-color: #934E27"></div>
|
||||
|
||||
<div class="supercenter" style="left: 97%; top: 15.5%; height: 8.5%">
|
||||
<img class="gdButton" id="lastPage" src="../assets/double-arrow.png" height="90%">
|
||||
<img class="gdButton" id="lastPage" src="/assets/double-arrow.png" height="90%">
|
||||
</div>
|
||||
|
||||
<div class="supercenter" id="firstPage" style="left: 97%; top: 27.5%; height: 8.5%; display: none;">
|
||||
<img class="gdButton refreshBtn" src="../assets/double-arrow.png" style="transform: scaleX(-1);" height="90%">
|
||||
<img class="gdButton refreshBtn" src="/assets/double-arrow.png" style="transform: scaleX(-1);" height="90%">
|
||||
</div>
|
||||
|
||||
<div class="supercenter" id="refreshButton" style="left: 97%; top: 27.5%; height: 10%">
|
||||
<img class="gdButton refreshBtn" src="../assets/refresh.png" height="90%">
|
||||
<img class="gdButton refreshBtn" src="/assets/refresh.png" height="90%">
|
||||
</div>
|
||||
|
||||
<div class="supercenter" style="left: 3%; top: 15%; height: 10%">
|
||||
<img class="gdButton" id="topSort" src="../assets/sort-likes.png" height="90%">
|
||||
<img class="gdButton" id="topSort" src="/assets/sort-likes.png" height="90%">
|
||||
</div>
|
||||
|
||||
<div class="supercenter" style="left: 3%; top: 25.5%; height: 10%">
|
||||
<img class="gdButton" id="timeSort" src="../assets/sort-time.png" height="90%">
|
||||
<img class="gdButton" id="timeSort" src="/assets/sort-time.png" height="90%">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="supercenter" style="left: 3%; top: 36%; height: 10%">
|
||||
<img class="gdButton" id="compactMode" src="../assets/compact-off.png" height="90%">
|
||||
<img class="gdButton" id="compactMode" src="/assets/compact-off.png" height="90%">
|
||||
</div>
|
||||
|
||||
<div class="supercenter" style="left: 3%; top: 63%; height: 11%">
|
||||
<img class="gdButton" id="autoMode" src="../assets/playbutton.png" height="90%">
|
||||
<img class="gdButton" id="autoMode" src="/assets/playbutton.png" height="90%">
|
||||
</div>
|
||||
|
||||
<div class="supercenter" id="pageDown" style="left: 3%; top: 50%; height: 10%; display: none;">
|
||||
<img class="gdButton" src="../assets/arrow-left.png" height="95%">
|
||||
<img class="gdButton" src="/assets/arrow-left.png" height="95%">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="supercenter" id="pageUp" style="left: 97%; top: 50%; height: 10%;">
|
||||
<img class="gdButton" src="../assets/arrow-right.png" height="95%">
|
||||
<img class="gdButton" src="/assets/arrow-right.png" height="95%">
|
||||
</div>
|
||||
|
||||
<div class="supercenter" style="top: 4.8%; height: 10%; width: 100%;">
|
||||
|
@ -114,15 +114,15 @@
|
|||
<h2 class="smallGold inline" id="levelVersion"></h2>
|
||||
<a id="levelLink"><h2 class="smallGold inline gdButton" id="levelID" style="margin-left: 6vh"></h2></a>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="leaveComment" style="display: none; 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="$('#content').trigger('input'); $('#postComment').show();">
|
||||
<img class="gdButton" src="/assets/comment.png" width="60%" onclick="$('#content').trigger('input'); $('#postComment').show();">
|
||||
</div>
|
||||
|
||||
</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()">
|
||||
<img class="gdButton yesClick" id="backButton" src="/assets/back.png" height="30%" onclick="backButton()">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -130,9 +130,9 @@
|
|||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/6.2.2/browser/pixi.js"></script>
|
||||
<script type="text/javascript" src="../iconkit/icon.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="../dragscroll.js"></script>
|
||||
<script type="text/javascript" src="/iconkit/icon.js"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/dragscroll.js"></script>
|
||||
<script>
|
||||
|
||||
let {mode, compact} = JSON.parse(localStorage.getItem('commentPreset') || '{"mode": "top", "compact": true}')
|
||||
|
@ -150,13 +150,13 @@ let auto = false
|
|||
let interval = null
|
||||
let commentCache = {}
|
||||
|
||||
let target = `../api/level/${lvlID}`
|
||||
let target = `/api/level/${lvlID}`
|
||||
if (lvlID > 999999999 || lvlID < -999999999) window.location.href = window.location.href.replace("comments", "search")
|
||||
if (!Number.isInteger(+lvlID)) {history = true; target = `../api/profile/${lvlID}`}
|
||||
if (!Number.isInteger(+lvlID)) {history = true; target = `/api/profile/${lvlID}`}
|
||||
else lvlID = Math.round(+lvlID)
|
||||
|
||||
if (mode == "top") { mode = "top"; $('#topSort').attr('src', "../assets/sort-likes-on.png") }
|
||||
else $('#timeSort').attr('src', "../assets/sort-time-on.png")
|
||||
if (mode == "top") { mode = "top"; $('#topSort').attr('src', "/assets/sort-likes-on.png") }
|
||||
else $('#timeSort').attr('src', "/assets/sort-time-on.png")
|
||||
|
||||
function clean(text) {return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/=/g, "=").replace(/"/g, """).replace(/'/g, "'")}
|
||||
|
||||
|
@ -197,7 +197,7 @@ function buildComments(lvl) {
|
|||
if (!lvl.name) $('#leaveComment').hide()
|
||||
$('#levelAuthor').text("By " + (lvl.author || "-"))
|
||||
$('#levelID').text("ID: " + lvlID)
|
||||
if (lvl.accountID && lvl.author != "-")
|
||||
if (lvl.accountID && lvl.author != "-")
|
||||
if (lvl.id) $('#levelLink').attr('href', '../' + lvl.id)
|
||||
else $('#levelID').removeClass("gdButton")
|
||||
$('#levelVersion').text("Version: " + (lvl.version || 0))
|
||||
|
@ -211,10 +211,10 @@ function buildComments(lvl) {
|
|||
|
||||
function appendComments(auto, noCache) {
|
||||
|
||||
if (loadingComments) return;
|
||||
else loadingComments = true;
|
||||
if (loadingComments) return
|
||||
else loadingComments = true
|
||||
|
||||
if (!auto) $('#commentBox').html(`<div class="supercenter" id="loading" style="height: 12%;"><img class="spin noSelect" src="../assets/loading.png" height="105%"></div>`)
|
||||
if (!auto) $('#commentBox').html(`<div class="supercenter" id="loading" style="height: 12%;"><img class="spin noSelect" src="/assets/loading.png" height="105%"></div>`)
|
||||
|
||||
if (page == 0) {
|
||||
$('#pageDown').hide()
|
||||
|
@ -230,13 +230,12 @@ else {
|
|||
}
|
||||
|
||||
if (!noCache && commentCache[page]) addComments(commentCache[page])
|
||||
fetch(`../api${!history ? window.location.pathname : "/comments/" + lvl.playerID}?count=${compact && !auto ? 20 : 10}&page=${page}${history ? "&type=commentHistory" : ""}&${mode}`).then((res) => {
|
||||
if (res.status === 204) return [];
|
||||
return res.json();
|
||||
}).then(addComments)
|
||||
fetch(
|
||||
`/api${!history ? window.location.pathname : "/comments/" + lvl.playerID}?count=${compact && !auto ? 20 : 10}&page=${page}${history ? "&type=commentHistory" : ""}&${mode}`
|
||||
).then(res => res.status === 204 ? [] : res.json()).then(addComments)
|
||||
|
||||
function addComments(res) {
|
||||
|
||||
|
||||
if (history && lvl.commentHistory != "all") $('#pageUp').hide()
|
||||
|
||||
if (res == -1 || (history && lvl.commentHistory != "all")) {
|
||||
|
@ -275,7 +274,7 @@ function addComments(res) {
|
|||
<gdicon class="commentIcon inline" cacheID=${x.playerID} iconID=${x.icon.icon} iconForm="${x.icon.form}" col1="${x.icon.col1}" col2="${x.icon.col2}" glow="${x.icon.glow}"></gdicon>
|
||||
<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" style="margin-left: 1%; width: 3.5%">` : ""}
|
||||
${modNumber > 0 ? `<img class="inline" src="/assets/mod${modNumber > 2 ? "-extra" : modNumber == 2 ? "-elder" : ""}.png" style="margin-left: 1%; width: 3.5%">` : ""}
|
||||
<p class="commentPercent inline">${x.percent ? x.percent + "%" : ""}</p>
|
||||
</div>
|
||||
|
||||
|
@ -287,14 +286,14 @@ function addComments(res) {
|
|||
<div class="commentLikes">
|
||||
${history ? `<h3 style="margin-right: 1.5vh; pointer-events: all;" class="gold inline"><a href="../${x.levelID}">(${x.levelID})</a></h3>` : ""}
|
||||
<div class="inline gdButton likeComment" commentID="${x.ID}" ${x.levelID ? `levelID="${x.levelID}"` : ""}">
|
||||
<img id="thumb-${x.ID}" class="inline gdButton" ${x.likes < 0 ? "style='transform: translateY(25%); margin-right: 0.4%'" : ""} src="../assets/${x.likes < 0 ? "dis" : ""}like.png" height=20%>
|
||||
<img id="thumb-${x.ID}" 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 id="likes-${x.ID}" class="inline">${x.likes}</h3>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
</div>`
|
||||
|
||||
////// COMPACT MODE //////
|
||||
|
||||
|
||||
: `
|
||||
<div class="commentBG compactBG ${bgCol}">
|
||||
<div class="comment compact" commentID="${x.ID}">
|
||||
|
@ -302,7 +301,7 @@ function addComments(res) {
|
|||
<gdicon class="commentIcon inline" cacheID=${x.playerID} iconID=${x.icon.icon} iconForm="${x.icon.form}" col1="${x.icon.col1}" col2="${x.icon.col2}" glow="${x.icon.glow}"></gdicon>
|
||||
<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" style="margin-left: 1.2%; width: 3.2%">` : ""}
|
||||
${modNumber > 0 ? `<img class="inline" src="/assets/mod${modNumber > 2 ? "-extra" : modNumber == 2 ? "-elder" : ""}.png" style="margin-left: 1.2%; width: 3.2%">` : ""}
|
||||
<p class="commentPercent inline">${x.percent ? x.percent + "%" : ""}</p>
|
||||
</div>
|
||||
|
||||
|
@ -314,7 +313,7 @@ function addComments(res) {
|
|||
<div class="commentLikes">
|
||||
${history ? `<h3 style="margin-right: 0.5vh; pointer-events: all;" class="gold inline"><a href="../${x.levelID}">(${x.levelID})</a></h3>` : ""}
|
||||
<div class="inline gdButton likeComment" commentID="${x.ID}"${x.levelID ? `levelID="${x.levelID}"` : ""}>
|
||||
<img id="thumb-${x.ID}" class="inline" ${x.likes < 0 ? "style='transform: translateY(15%); margin-right: 0.4%'" : ""} src="../assets/${x.likes < 0 ? "dis" : ""}like.png" height=27%>
|
||||
<img id="thumb-${x.ID}" 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 id="likes-${x.ID}" class="inline">${x.likes}</h3>
|
||||
</div>
|
||||
|
@ -331,7 +330,7 @@ function addComments(res) {
|
|||
$(this).css('font-size', (3.5 - (overflow)) + 'vh')
|
||||
}
|
||||
|
||||
});
|
||||
})
|
||||
|
||||
renderIcons()
|
||||
$('#loading').hide()
|
||||
|
@ -356,39 +355,39 @@ function resetSort() {
|
|||
}
|
||||
|
||||
$('#topSort').click(function() {
|
||||
if (mode == "top" || loadingComments) return;
|
||||
if (mode == "top" || loadingComments) return
|
||||
resetSort()
|
||||
mode = "top";
|
||||
$('#timeSort').attr('src', "../assets/sort-time.png")
|
||||
$('#topSort').attr('src', "../assets/sort-likes-on.png")
|
||||
$('#timeSort').attr('src', "/assets/sort-time.png")
|
||||
$('#topSort').attr('src', "/assets/sort-likes-on.png")
|
||||
appendComments()
|
||||
})
|
||||
|
||||
$('#timeSort').click(function() {
|
||||
if (mode == "time" || loadingComments) return;
|
||||
if (mode == "time" || loadingComments) return
|
||||
resetSort()
|
||||
mode = "time";
|
||||
$('#timeSort').attr('src', "../assets/sort-time-on.png")
|
||||
$('#topSort').attr('src', "../assets/sort-likes.png")
|
||||
$('#timeSort').attr('src', "/assets/sort-time-on.png")
|
||||
$('#topSort').attr('src', "/assets/sort-likes.png")
|
||||
appendComments()
|
||||
})
|
||||
|
||||
$('#compactMode').click(function() {
|
||||
if (loadingComments) return;
|
||||
if (loadingComments) return
|
||||
compact = !compact
|
||||
lastPage = 0;
|
||||
castPage = 0;
|
||||
page = 0;
|
||||
$('#compactMode').attr('src', `../assets/compact-${compact ? "on" : "off"}.png`)
|
||||
appendComments()
|
||||
})
|
||||
|
||||
$('#autoMode').click(function() {
|
||||
if (loadingComments) return;
|
||||
if (loadingComments) return
|
||||
auto = !auto
|
||||
mode = "time"
|
||||
page = 0;
|
||||
$('#timeSort').attr('src', "../assets/sort-time-on.png")
|
||||
$('#topSort').attr('src', "../assets/sort-likes.png")
|
||||
$('#timeSort').attr('src', "/assets/sort-time-on.png")
|
||||
$('#topSort').attr('src', "/assets/sort-likes.png")
|
||||
|
||||
if (auto) {
|
||||
document.title = "[LIVE] " + document.title
|
||||
|
@ -407,8 +406,8 @@ $('#autoMode').click(function() {
|
|||
|
||||
$(document).on('click', '.refreshBtn', function () {
|
||||
if (loadingComments) return
|
||||
lastPage = 0;
|
||||
page = 0;
|
||||
lastPage = 0
|
||||
page = 0
|
||||
appendComments(false, true)
|
||||
})
|
||||
|
||||
|
@ -430,7 +429,7 @@ $('#submitComment').click(function() {
|
|||
$('.postbutton').hide()
|
||||
allowEsc = false
|
||||
|
||||
fetch(`../api/profile/${username}`).then(res => res.json()).then(res => {
|
||||
fetch(`/api/profile/${username}`).then(res => res.json()).then(res => {
|
||||
if (!res || res == "-1") {allowEsc = true; $('.postbutton').show(); return $('#message').text("The username you provided doesn't exist!")}
|
||||
else accountID = res.accountID
|
||||
|
||||
|
@ -440,13 +439,13 @@ $('#submitComment').click(function() {
|
|||
$('#postComment').hide()
|
||||
$('.postbutton').show()
|
||||
$('#message').html(messageText)
|
||||
$('#timeSort').attr('src', "../assets/sort-time-on.png")
|
||||
$('#topSort').attr('src', "../assets/sort-likes.png")
|
||||
$('#timeSort').attr('src', "/assets/sort-time-on.png")
|
||||
$('#topSort').attr('src', "/assets/sort-likes.png")
|
||||
allowEsc = true
|
||||
mode = "time"
|
||||
page = 0
|
||||
appendComments()
|
||||
})
|
||||
})
|
||||
.fail(e => {allowEsc = true; $('.postbutton').show();$('#message').text(e.responseText.includes("DOCTYPE") ? "Something went wrong..." : e.responseText)})
|
||||
})
|
||||
})
|
||||
|
@ -465,7 +464,7 @@ $('#dislikebtn').click(function() {
|
|||
|
||||
let commentID = 0
|
||||
let lvID = 0
|
||||
let likeCount, likeImg;
|
||||
let likeCount, likeImg
|
||||
let likedComments;
|
||||
|
||||
$(document).on('click', '.likeComment', function(cmnt) {
|
||||
|
@ -473,7 +472,7 @@ $(document).on('click', '.likeComment', function(cmnt) {
|
|||
commentID = $(this).attr('commentID')
|
||||
|
||||
likedComments = localStorage.likedComments ? JSON.parse(localStorage.likedComments) : []
|
||||
if (likedComments.includes(commentID)) return;
|
||||
if (likedComments.includes(commentID)) return
|
||||
|
||||
lvID = $(this).attr('levelID') || 0
|
||||
likeImg = $(this).find('img')
|
||||
|
@ -483,7 +482,7 @@ $(document).on('click', '.likeComment', function(cmnt) {
|
|||
|
||||
$('#submitVote').click(function() {
|
||||
|
||||
if (likedComments.includes(commentID)) return $('#likeMessage').text("You've already liked/disliked this comment!");
|
||||
if (likedComments.includes(commentID)) return $('#likeMessage').text("You've already liked/disliked this comment!")
|
||||
|
||||
let ID = commentID
|
||||
let username = $('#like-username').val()
|
||||
|
@ -491,14 +490,14 @@ $('#submitVote').click(function() {
|
|||
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 => {
|
||||
fetch(`/api/profile/${username}`).then(res => res.json()).then(res => {
|
||||
if (!res || res == "-1") {allowEsc = true; $('.postbutton').show(); return $('#likeMessage').text("The username you provided doesn't exist!")}
|
||||
else accountID = res.accountID
|
||||
|
||||
|
@ -506,8 +505,8 @@ $('#submitVote').click(function() {
|
|||
.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')
|
||||
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()
|
||||
|
@ -515,7 +514,7 @@ $('#submitVote').click(function() {
|
|||
allowEsc = true
|
||||
likedComments.push(commentID)
|
||||
localStorage.setItem('likedComments', JSON.stringify(likedComments))
|
||||
})
|
||||
})
|
||||
.fail(e => {allowEsc = true; $('.postbutton').show();$('#likeMessage').text(e.responseText.includes("DOCTYPE") ? "Something went wrong..." : e.responseText)})
|
||||
})
|
||||
})
|
||||
|
@ -534,12 +533,12 @@ $(document).keydown(function(k) {
|
|||
if (k.which == 13) k.preventDefault() //enter
|
||||
}
|
||||
|
||||
if (loadingComments || $('.popup').is(":visible")) return;
|
||||
if (loadingComments || $('.popup').is(":visible")) return
|
||||
|
||||
if (k.which == 37 && $('#pageDown').is(":visible")) { //left
|
||||
$('#pageDown').trigger('click')
|
||||
}
|
||||
|
||||
|
||||
if (k.which == 39 && $('#pageUp').is(":visible")) { //right
|
||||
$('#pageUp').trigger('click')
|
||||
}
|
||||
|
@ -548,4 +547,3 @@ $(document).keydown(function(k) {
|
|||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title>Demon Leaderboard</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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-demon.png">
|
||||
<link rel="icon" href="/assets/trophy-demon.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-demon.png">
|
||||
|
@ -24,22 +24,22 @@
|
|||
<p class="bigger center" style="margin-top: 1vh">
|
||||
Usernames may <cy>differ</cy> from what is used in GD
|
||||
</p>
|
||||
<img src="../assets/ok.png" width=15%; class="gdButton center" onclick="$('.popup').hide()">
|
||||
<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%;>
|
||||
<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)">
|
||||
<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%">
|
||||
|
@ -47,35 +47,35 @@
|
|||
</div>
|
||||
|
||||
<div style="position: absolute; left: 7%; top: 45%; height: 10%;">
|
||||
<a id="pageDown"><img class="gdButton" src="../assets/arrow-left.png" height="90%"></a>
|
||||
<a id="pageDown"><img class="gdButton" src="/assets/arrow-left.png" height="90%"></a>
|
||||
</div>
|
||||
|
||||
<div style="position: absolute; right: 7%; top: 45%; height: 10%;">
|
||||
<a id="pageUp"><img class="gdButton" src="../assets/arrow-right.png" height="90%"></a>
|
||||
<a id="pageUp"><img class="gdButton" src="/assets/arrow-right.png" height="90%"></a>
|
||||
</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()">
|
||||
<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%">
|
||||
<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%"></a>
|
||||
<img id="creditsButton" class="inline gdButton" src="../assets/credits.png" width="25%" onclick="$('#infoDiv').show()">
|
||||
<a target="_blank" id="pointercrate"><img class="inline gdButton" src="/assets/demonButton.png" width="23%" style="margin-right: 4%"></a>
|
||||
<img id="creditsButton" class="inline gdButton" src="/assets/credits.png" width="25%" onclick="$('#infoDiv').show()">
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 5.5%; right: 3.5%; text-align: right; width: 18%;">
|
||||
<a id="realLeaderboardLink"><img class="gdButton" src="../assets/leaderboard.png" width="35%"></a>
|
||||
<a id="realLeaderboardLink"><img class="gdButton" src="/assets/leaderboard.png" width="35%"></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script type="text/javascript" src="../dragscroll.js"></script>
|
||||
<script>
|
||||
|
||||
|
@ -83,7 +83,7 @@ let max = 250
|
|||
let trophies = [1, 5, 10, 25, 50, 100, max]
|
||||
|
||||
let demonID = Math.round(window.location.pathname.split('/')[2])
|
||||
let illegal = (!demonID || demonID > max || demonID < 1)
|
||||
let illegal = (!demonID || demonID > max || demonID < 1)
|
||||
|
||||
if (demonID > 1) $('#pageDown').attr('href', `./${demonID - 1}`)
|
||||
else $('#pageDown').hide()
|
||||
|
@ -91,8 +91,8 @@ else $('#pageDown').hide()
|
|||
if (demonID < max) $('#pageUp').attr('href', `./${demonID + 1}`)
|
||||
else $('#pageUp').hide()
|
||||
|
||||
Fetch(`../api/gdps?current=1`).then(server => {
|
||||
if (illegal || !server.demonList) return $('#loading').hide();
|
||||
Fetch(`/api/gdps?current=1`).then(server => {
|
||||
if (illegal || !server.demonList) return $('#loading').hide()
|
||||
|
||||
fetch(`${server.demonList}api/v2/demons/listed?after=${demonID-1}&before=${demonID+1}`).then(res => res.json()).then(rawDemon => {
|
||||
|
||||
|
@ -116,16 +116,16 @@ fetch(`${server.demonList}api/v2/demons/listed?after=${demonID-1}&before=${demon
|
|||
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="align-items: center; padding-left: 1vh; height: 15%; width: 100%; position: relative;">
|
||||
$('#searchBox').append(`<div class="searchresult leaderboardSlot" style="align-items: center; padding-left: 1vh; height: 15%; width: 100%; position: relative;">
|
||||
|
||||
<h2 class="center" style="width: 12%; margin: 0% 0% 0% 0.5%; transform: scale(${1 - (Math.max(0, String(y+1).length - 1) * 0.2)}">${y+1}</h2>
|
||||
<img class="inline spaced" src="../assets/trophies/${trophies.findIndex(z => y+1 <= z) + 1}.png" style="margin-bottom: 0%; height: 80%;">
|
||||
<img class="inline spaced" src="/assets/trophies/${trophies.findIndex(z => y+1 <= z) + 1}.png" style="margin-bottom: 0%; height: 80%;">
|
||||
<h2 class="small gdButton" style="font-size: 6.5vh; margin-right: 3%; margin-left: 3%"><a href="../u/${x.player.name}">${x.player.name}</a></h2>
|
||||
<h3 class="lessSpaced" style="font-size: 4vh; margin-top: 1.3%; margin-right: 2%">${x.progress}%</h3>
|
||||
|
||||
<div style="${!x.video ? "display: none; " : ""}position:absolute; margin-top: 1.5%; width: 12.5%; height: 90%; right: 0%;">
|
||||
<a target="_blank" href="${x.video}">
|
||||
<img class="gdButton inline spaced" src="../assets/${videoIcon}.png" height="80%">
|
||||
<img class="gdButton inline spaced" src="/assets/${videoIcon}.png" height="80%">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title>Level Search</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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/coin.png">
|
||||
<link rel="icon" href="/assets/coin.png">
|
||||
<meta id="meta-title" property="og:title" content="Level Search">
|
||||
<meta id="meta-desc" property="og:description" content="Search for Geometry Dash levels, and filter by length, difficulty, song + more!">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/coin.png">
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
<div id="filters" class="popup">
|
||||
<div id="filterStuff" class="brownBox bounce center supercenter" style="width: 101vh; height: 50%; padding-top: 0.3%; padding-bottom: 3.5%; padding-left: 1%">
|
||||
<img class="gdButton" src="../assets/close.png" width="9%" style="position: absolute; top: -8.5%; left: -5.5vh" onclick="$('#filters').hide()">
|
||||
<img class="gdButton" src="/assets/close.png" width="9%" style="position: absolute; top: -8.5%; left: -5.5vh" onclick="$('#filters').hide()">
|
||||
<h1 style="margin-bottom: 4%">Advanced Options</h1><br>
|
||||
<div><h1><input type="checkbox" id="box-featured" url="&featured"><label for="box-featured" class="gdcheckbox gdButton"></label>Featured</h1></div>
|
||||
<div><h1><input type="checkbox" id="box-epic" url="&epic"><label for="box-epic" class="gdcheckbox gdButton"></label>Epic</h1></div>
|
||||
|
@ -25,21 +25,21 @@
|
|||
<div><h1><input type="checkbox" id="box-2player" url="&twoPlayer"><label for="box-2player" class="gdcheckbox gdButton"></label>2-Player</h1></div>
|
||||
<div style="margin-bottom: 5%"><h1><input type="checkbox" id="box-coins" url="&coins"><label for="box-coins" class="gdcheckbox gdButton"></label>Coins</h1></div>
|
||||
<h1 class="smallerer lessSpaced">Song</h1>
|
||||
<img id="normalSong" class="gdButton inline gray" style="margin-right: 0.5%" src="../assets/song-normal.png" height="8%">
|
||||
<img id="customSong" class="gdButton inline" style="margin-left: 0.5%" src="../assets/song-custom.png" height="8%">
|
||||
<img id="normalSong" class="gdButton inline gray" style="margin-right: 0.5%" src="/assets/song-normal.png" height="8%">
|
||||
<img id="customSong" class="gdButton inline" style="margin-left: 0.5%" src="/assets/song-custom.png" height="8%">
|
||||
<br>
|
||||
<input id="songID" type="number" placeholder="Custom Song ID" style="height: 15%; width: 70%; text-align: center; margin-top: 2%">
|
||||
<div id="songSelect" style="width: 100%; display: none; margin-top: 3%; text-align: center">
|
||||
<img style="width: 4%" id="songDown" class="gdButton inline valign songChange" jump="-1" src="../assets/whitearrow-left.png">
|
||||
<img style="width: 4%" id="songDown" class="gdButton inline valign songChange" jump="-1" src="/assets/whitearrow-left.png">
|
||||
<h1 class="inline valign smallerer center" id="songName" style="min-width: 60%"></h1>
|
||||
<img style="width: 4%" id="songUp" class="gdButton inline valign songChange" jump="1" id="nextSong" src="../assets/whitearrow-right.png">
|
||||
<img style="width: 4%" id="songUp" class="gdButton inline valign songChange" jump="1" id="nextSong" src="/assets/whitearrow-right.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="customlist" class="popup">
|
||||
<div class="brownBox bounce center supercenter" style="width: 100vh; height: 56%; padding-top: 0.3%; padding-bottom: 3.5%; padding-left: 1%">
|
||||
<img class="gdButton" src="../assets/close.png" width="9%" style="position: absolute; top: -8.5%; left: -5.5vh" onclick="$('#customlist').hide()">
|
||||
<img class="gdButton" src="/assets/close.png" width="9%" style="position: absolute; top: -8.5%; left: -5.5vh" onclick="$('#customlist').hide()">
|
||||
<h1>Custom List</h1><br>
|
||||
<p id="listInfo" style="margin-top: 1%; margin-bottom: 1.5%">Paste a <cy>comma-separated</cy> list of <ca>Level IDs</ca> to create a custom list!</p>
|
||||
<textarea id="listLevels" placeholder="18025697, 23189196, 27786218, 27728679, 25706351" style="margin-bottom: 2%; font-size: 2.5vh"></textarea>
|
||||
|
@ -53,24 +53,24 @@
|
|||
<input id="pageSize" type="number" value="10" style="font-size: 4vh; height: 13%; width: 45%; text-align: center;">
|
||||
</div>
|
||||
|
||||
<a id="listLink"><img src="../assets/btn-submit.png" type="submit" height=12.5%; class="disabled gdButton" style="margin-left: 1%" id="createList"></a>
|
||||
<a id="listLink"><img src="/assets/btn-submit.png" type="submit" height=12.5%; class="disabled gdButton" style="margin-left: 1%" id="createList"></a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%;>
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%;>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; right: 0%; width: 100%; text-align: right;">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%; style="transform: scaleX(-1); pointer-events: none">
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%; style="transform: scaleX(-1); pointer-events: none">
|
||||
</div>
|
||||
|
||||
<div class="transparentBox center" style="width: 115vh; height: 9%; margin: 1.5% auto 1% auto; padding-bottom: 0.2%">
|
||||
<div>
|
||||
<input type="text" id="levelName" placeholder="Enter a level, user, or ID" maxlength=20>
|
||||
<img search="0" src="../assets/search.png" id="searchBtn" width="20%" class="valign gdButton levelSearch" style="margin-left: 1%; margin-bottom: 2.2%">
|
||||
<img id="userSearch" src="../assets/search-user.png" width="9.6%" class="valign gdButton" style="margin-left: 1%; margin-bottom: 2.2%">
|
||||
<img search="0" src="/assets/search.png" id="searchBtn" width="20%" class="valign gdButton levelSearch" style="margin-left: 1%; margin-bottom: 2.2%">
|
||||
<img id="userSearch" src="/assets/search-user.png" width="9.6%" class="valign gdButton" style="margin-left: 1%; margin-bottom: 2.2%">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -79,17 +79,17 @@
|
|||
</div>
|
||||
|
||||
<div class="transparentBox center" style="width: 115vh; height: 35%; margin: 0.5% auto 1% auto; padding-top: 1.1%">
|
||||
<img src="../assets/btn-top.png" height="27%" class="valign gdButton spaced levelSearch" search="mostdownloaded">
|
||||
<img src="/assets/btn-top.png" height="27%" class="valign gdButton spaced levelSearch" search="mostdownloaded">
|
||||
<span style="margin-right: 3%"></span>
|
||||
<img src="../assets/btn-liked.png" height="27%" class="valign gdButton spaced levelSearch" search="mostliked">
|
||||
<img src="/assets/btn-liked.png" height="27%" class="valign gdButton spaced levelSearch" search="mostliked">
|
||||
<br>
|
||||
<img src="../assets/btn-trending.png" height="27%" class="valign gdButton spaced levelSearch" search="trending">
|
||||
<img src="../assets/btn-recent.png" height="27%" class="valign gdButton spaced levelSearch" search="recent" style="margin-left: 2%; margin-right: 2%">
|
||||
<img src="../assets/btn-magic.png" height="27%" class="valign gdButton spaced levelSearch" search="magic">
|
||||
<img src="/assets/btn-trending.png" height="27%" class="valign gdButton spaced levelSearch" search="trending">
|
||||
<img src="/assets/btn-recent.png" height="27%" class="valign gdButton spaced levelSearch" search="recent" style="margin-left: 2%; margin-right: 2%">
|
||||
<img src="/assets/btn-magic.png" height="27%" class="valign gdButton spaced levelSearch" search="magic">
|
||||
<br>
|
||||
<img src="../assets/btn-awarded.png" height="27%" class="valign gdButton levelSearch" search="awarded">
|
||||
<img src="../assets/btn-featured.png" height="27%" class="valign gdButton levelSearch" search="featured" style="margin: 0% 2%">
|
||||
<img src="../assets/btn-followed.png" height="27%" id="followedSearch" class="valign gdButton levelSearch" search="followed">
|
||||
<img src="/assets/btn-awarded.png" height="27%" class="valign gdButton levelSearch" search="awarded">
|
||||
<img src="/assets/btn-featured.png" height="27%" class="valign gdButton levelSearch" search="featured" style="margin: 0% 2%">
|
||||
<img src="/assets/btn-followed.png" height="27%" id="followedSearch" class="valign gdButton levelSearch" search="followed">
|
||||
</div>
|
||||
|
||||
<div class="center">
|
||||
|
@ -97,56 +97,56 @@
|
|||
</div>
|
||||
|
||||
<div id="difficulties" class="transparentBox center" style="width: 115vh; height: 12%; margin: 0.5% auto 1% auto; padding-top: 1%; padding-bottom: 1%;">
|
||||
<div class="diffDiv gdButton" diff="-1"><img src="../assets/difficulties/unrated.png"><h3 class="mini">N/A</h3></div>
|
||||
<div class="diffDiv gdButton" diff=1><img src="../assets/difficulties/easy.png"><h3 class="mini">Easy</h3></div>
|
||||
<div class="diffDiv gdButton" diff=2><img src="../assets/difficulties/normal.png"><h3 class="mini">Normal</h3></div>
|
||||
<div class="diffDiv gdButton" diff=3><img src="../assets/difficulties/hard.png"><h3 class="mini">Hard</h3></div>
|
||||
<div class="diffDiv gdButton" diff=4><img src="../assets/difficulties/harder.png"><h3 class="mini">Harder</h3></div>
|
||||
<div class="diffDiv gdButton" diff=5><img src="../assets/difficulties/insane.png"><h3 class="mini">Insane</h3></div>
|
||||
<div class="diffDiv gdButton" diff="-1"><img src="/assets/difficulties/unrated.png"><h3 class="mini">N/A</h3></div>
|
||||
<div class="diffDiv gdButton" diff=1><img src="/assets/difficulties/easy.png"><h3 class="mini">Easy</h3></div>
|
||||
<div class="diffDiv gdButton" diff=2><img src="/assets/difficulties/normal.png"><h3 class="mini">Normal</h3></div>
|
||||
<div class="diffDiv gdButton" diff=3><img src="/assets/difficulties/hard.png"><h3 class="mini">Hard</h3></div>
|
||||
<div class="diffDiv gdButton" diff=4><img src="/assets/difficulties/harder.png"><h3 class="mini">Harder</h3></div>
|
||||
<div class="diffDiv gdButton" diff=5><img src="/assets/difficulties/insane.png"><h3 class="mini">Insane</h3></div>
|
||||
|
||||
<div class="diffDiv gdButton" id="demonBtn" diff=-2><img src="../assets/difficulties/demon.png" style="width: 85%"><h3 class="mini">Demon</h3></div>
|
||||
<div class="diffDiv gdButton" id="demonBtn" diff=-2><img src="/assets/difficulties/demon.png" style="width: 85%"><h3 class="mini">Demon</h3></div>
|
||||
|
||||
<!-- <div class="diffDiv gdButton" style="filter: brightness(100%)" id="demonBtn" diff=-2><img class="darkDiff" src="../assets/difficulties/demon.png" style="width: 85%"><h3 class="darkDiff mini">Demon</h3> -->
|
||||
<!-- <img src="../assets/exclamation.png" style="position: absolute; width: 19%; left: 86%; bottom: 68%"></div> -->
|
||||
<!-- <div class="diffDiv gdButton" style="filter: brightness(100%)" id="demonBtn" diff=-2><img class="darkDiff" src="/assets/difficulties/demon.png" style="width: 85%"><h3 class="darkDiff mini">Demon</h3> -->
|
||||
<!-- <img src="/assets/exclamation.png" style="position: absolute; width: 19%; left: 86%; bottom: 68%"></div> -->
|
||||
|
||||
<div class="diffDiv gdButton" diff=-3><img src="../assets/difficulties/auto.png"><h3 class="mini">Auto</h3></div>
|
||||
<div class="diffDiv gdButton" diff=-3><img src="/assets/difficulties/auto.png"><h3 class="mini">Auto</h3></div>
|
||||
</div>
|
||||
|
||||
<div id="demons" class="transparentBox" style="display: none; width: 115vh; height: 12%; margin: 0.5% auto 1% auto; padding-top: 0.6%; padding-bottom: 1.4%;">
|
||||
<div class="diffDiv gdButton demonDiff" diff=1 style="margin-left: 3.5%"><img src="../assets/difficulties/demon-easy.png" style="width: 90%"><h3 class="mini center">Easy</h3></div>
|
||||
<div class="diffDiv gdButton demonDiff" diff=2><img src="../assets/difficulties/demon-medium.png" style="width: 90%"><h3 class="mini center smallTextWoo">Medium</h3></div>
|
||||
<div class="diffDiv gdButton demonDiff" diff=3><img src="../assets/difficulties/demon-hard.png" style="width: 90%"><h3 class="mini center">Hard</h3></div>
|
||||
<div class="diffDiv gdButton demonDiff" diff=4><img src="../assets/difficulties/demon-insane.png" style="width: 95%"><h3 class="mini center smallTextWoo">Insane</h3></div>
|
||||
<div class="diffDiv gdButton demonDiff" diff=5><img src="../assets/difficulties/demon-extreme.png" style="width: 100%"><h3 class="mini center smallTextWoo">Extreme</h3></div>
|
||||
<div class="diffDiv gdButton goBack" diff=-2 style="margin-left: 2.3%; filter: none"><img src="../assets/difficulties/demon.png" style="width: 90%"><h3 class="mini">Demon</h3></div>
|
||||
<a id="demonList" style="display: none" href="./search/*?type=demonlist"><div class="gdButton diffDiv" style="filter: none"><img src="../assets/trophy2.png" style="width: 95%"><h3 class="yellow mini center">List</h3></div></a>
|
||||
<div class="diffDiv gdButton demonDiff" diff=1 style="margin-left: 3.5%"><img src="/assets/difficulties/demon-easy.png" style="width: 90%"><h3 class="mini center">Easy</h3></div>
|
||||
<div class="diffDiv gdButton demonDiff" diff=2><img src="/assets/difficulties/demon-medium.png" style="width: 90%"><h3 class="mini center smallTextWoo">Medium</h3></div>
|
||||
<div class="diffDiv gdButton demonDiff" diff=3><img src="/assets/difficulties/demon-hard.png" style="width: 90%"><h3 class="mini center">Hard</h3></div>
|
||||
<div class="diffDiv gdButton demonDiff" diff=4><img src="/assets/difficulties/demon-insane.png" style="width: 95%"><h3 class="mini center smallTextWoo">Insane</h3></div>
|
||||
<div class="diffDiv gdButton demonDiff" diff=5><img src="/assets/difficulties/demon-extreme.png" style="width: 100%"><h3 class="mini center smallTextWoo">Extreme</h3></div>
|
||||
<div class="diffDiv gdButton goBack" diff=-2 style="margin-left: 2.3%; filter: none"><img src="/assets/difficulties/demon.png" style="width: 90%"><h3 class="mini">Demon</h3></div>
|
||||
<a id="demonList" style="display: none" href="./search/*?type=demonlist"><div class="gdButton diffDiv" style="filter: none"><img src="/assets/trophy2.png" style="width: 95%"><h3 class="yellow mini center">List</h3></div></a>
|
||||
</div>
|
||||
|
||||
<div class="transparentBox center" style="width: 115vh; height: 6%; margin: 0.5% auto 1% auto; padding-top: 1%; padding-bottom: 0.5%;">
|
||||
<!-- <div class="lengthDiv" style="pointer-events: none" len=0><h1 class="gdButton smaller" style="pointer-events: none"><img src="../assets/time.png" height="90%" style="pointer-events: none"></h1></div> -->
|
||||
<!-- <div class="lengthDiv" style="pointer-events: none" len=0><h1 class="gdButton smaller" style="pointer-events: none"><img src="/assets/time.png" height="90%" style="pointer-events: none"></h1></div> -->
|
||||
<div class="lengthDiv" len=0><h1 class="gdButton smaller">Tiny</h1></div>
|
||||
<div class="lengthDiv" len=1><h1 class="gdButton smaller">Short</h1></div>
|
||||
<div class="lengthDiv" len=2><h1 class="gdButton smaller">Medium</h1></div>
|
||||
<div class="lengthDiv" len=3><h1 class="gdButton smaller">Long</h1></div>
|
||||
<div class="lengthDiv" len=4><h1 class="gdButton smaller">XL</h1></div>
|
||||
<div class="lengthDiv" id="starCheck"><img src="../assets/star.png" class="gdButton" height="90%"></div>
|
||||
<div class="lengthDiv" id="starCheck"><img src="/assets/star.png" class="gdButton" height="90%"></div>
|
||||
</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()">
|
||||
<img class="gdButton yesClick" id="backButton" src="/assets/back.png" height="30%" onclick="backButton()">
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; top: 2%; right: 1.5%; width: 10%; text-align: right">
|
||||
<img class="gdButton" style="margin-bottom: 12%" src="../assets/close.png" width="60%" onclick="clearFilters()">
|
||||
<img class="gdButton" style="margin-bottom: 12%" id="showFilters" src="../assets/plus.png" width="60%" onclick="$('#filters').show()">
|
||||
<img class="gdButton" src="../assets/listbutton.png" width="60%" onclick="$('#customlist').show()">
|
||||
<img class="gdButton" style="margin-bottom: 12%" src="/assets/close.png" width="60%" onclick="clearFilters()">
|
||||
<img class="gdButton" style="margin-bottom: 12%" id="showFilters" src="/assets/plus.png" width="60%" onclick="$('#filters').show()">
|
||||
<img class="gdButton" src="/assets/listbutton.png" width="60%" onclick="$('#customlist').show()">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script>
|
||||
|
||||
let filters = []
|
||||
|
@ -174,7 +174,7 @@ $('.levelSearch').click(function() {
|
|||
let difficulties = []
|
||||
$('.diffDiv').each(function() {if ($(this).hasClass('selectedFilter')) difficulties.push($(this).attr('diff'))})
|
||||
demonFilter = demonMode && difficulties[0] > 0
|
||||
|
||||
|
||||
if (!difficulties.length) url += ""
|
||||
else if (!demonFilter) url += "&diff=" + undupe(difficulties).join(",")
|
||||
else url += "&diff=-2&demonFilter=" + difficulties[0]
|
||||
|
@ -212,15 +212,15 @@ function getDiffFilters() {
|
|||
}
|
||||
|
||||
function showDemonDiffs() {
|
||||
$('#difficulties').hide();
|
||||
$('#demons').show();
|
||||
demonMode = true;
|
||||
$('#difficulties').hide()
|
||||
$('#demons').show()
|
||||
demonMode = true
|
||||
}
|
||||
|
||||
function hideDemonDiffs() {
|
||||
$('#difficulties').show();
|
||||
$('#demons').hide();
|
||||
demonMode = false;
|
||||
$('#difficulties').show()
|
||||
$('#demons').hide()
|
||||
demonMode = false
|
||||
}
|
||||
|
||||
$('.diffDiv').click(function() {
|
||||
|
@ -262,16 +262,16 @@ $('.lengthDiv').click(function() {
|
|||
$(document).keydown(function(k) {
|
||||
let searchFocus = $(':focus-visible').length == 1 && $(':focus-visible').first().attr('id') == "levelName"
|
||||
if ((!$(':focus-visible').length || searchFocus) && k.which == 13) { // enter
|
||||
if (!$('#customlist').is(':hidden')) k.preventDefault();
|
||||
if (!$('#customlist').is(':hidden')) k.preventDefault()
|
||||
else if ($('#filters').is(':hidden')) $('#searchBtn').trigger('click')
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#pageSize').on('input blur', function (event) {
|
||||
var x = +$(this).val(); var max = 250; var min = 1
|
||||
if (event.type == "input") { if (x > max || x < min) $(this).addClass('red'); else $(this).removeClass('red')}
|
||||
else {
|
||||
$(this).val(Math.max(Math.min(Math.floor(x), max), min));
|
||||
$(this).val(clamp(Math.floor(x), min, max))
|
||||
$(this).removeClass('red')
|
||||
}
|
||||
$('#listLevels').trigger('input')
|
||||
|
@ -279,7 +279,7 @@ $('#pageSize').on('input blur', function (event) {
|
|||
|
||||
let listMsg = $('#listInfo').html()
|
||||
$('#listLevels, #listName').on('input blur', function (event) {
|
||||
let levels = $('#listLevels').val().replace(/\n| /g, ",").split(",").map(x => x.replace(/[^0-9]/g, "")).filter(x => +x > 0 && +x < 100000000000)
|
||||
let levels = $('#listLevels').val().replace(/\n| /g, ",").split(",").map(x => x.replace(/\D/g, "")).filter(x => +x > 0 && +x < 10**11)
|
||||
levels = undupe(levels)
|
||||
|
||||
if (levels.length > 1 && levels.length <= 100) {
|
||||
|
@ -376,11 +376,11 @@ else if (+savedFilters.song && +savedFilters.song > 0) $('#songID').val(savedFil
|
|||
|
||||
checkExtraFilters()
|
||||
|
||||
Fetch(`../api/music`).then(music => {
|
||||
Fetch(`/api/music`).then(music => {
|
||||
|
||||
$('#songName').html("1: " + music[1][0])
|
||||
|
||||
$(document).on('click', '.songChange', function () {
|
||||
$(document).on('click', '.songChange', function () {
|
||||
officialSong += Number($(this).attr('jump'))
|
||||
if (officialSong < 1) officialSong = 1
|
||||
$('#songName').html(`${officialSong}: ${music[officialSong] ? music[officialSong][0] : officialSong == 69 ? "Nice" : "Unknown"}`)
|
||||
|
@ -395,10 +395,10 @@ Fetch(`../api/music`).then(music => {
|
|||
}
|
||||
|
||||
$(document).keydown(function(k) {
|
||||
if (customSong) return;
|
||||
if (customSong) return
|
||||
if (k.which == 37) $('#songDown').trigger('click') // left
|
||||
if (k.which == 39) $('#songUp').trigger('click') // right
|
||||
});
|
||||
})
|
||||
|
||||
if (onePointNine) {
|
||||
$('#userSearch').hide()
|
||||
|
@ -406,7 +406,7 @@ Fetch(`../api/music`).then(music => {
|
|||
$('#levelName').css('width', '76%')
|
||||
}
|
||||
|
||||
if (gdps) Fetch(`../api/gdps?current=1`).then(res => { if (res.demonList) $('#demonList').show() })
|
||||
if (gdps) Fetch(`/api/gdps?current=1`).then(res => { if (res.demonList) $('#demonList').show() })
|
||||
else $('#demonList').show()
|
||||
})
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title>Gauntlets</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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/gauntlet.png">
|
||||
<link rel="icon" href="/assets/gauntlet.png">
|
||||
<meta id="meta-title" property="og:title" content="Gauntlets">
|
||||
<meta id="meta-desc" property="og:description" content="Because RobTop wanted to leave behind the monstrosity that is Map Packs.">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/gauntlet.png">
|
||||
|
@ -15,34 +15,34 @@
|
|||
<div id="everything" class="center" style="width: 100%; height: 100%;">
|
||||
|
||||
<div style="position:absolute; top: 2%; left: -1.95%; width: 10%; height: 25%; pointer-events: none">
|
||||
<img class="gdButton yesClick" id="backButton" src="../assets/back.png" height="30%" onclick="backButton()">
|
||||
<img class="gdButton yesClick" id="backButton" src="/assets/back.png" height="30%" onclick="backButton()">
|
||||
</div>
|
||||
|
||||
<div class="center" width="100%" style="margin-top: 2.5%; margin-bottom: 1%;">
|
||||
<img src="../assets/gauntlets.png" width="50%">
|
||||
<img src="/assets/gauntlets.png" width="50%">
|
||||
</div>
|
||||
|
||||
<img id="loading" style="margin-top: 1%" class="spin noSelect" src="../assets/loading.png" height="12%">
|
||||
<img id="loading" style="margin-top: 1%" class="spin noSelect" src="/assets/loading.png" height="12%">
|
||||
|
||||
<div id="gauntletList">
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script>
|
||||
|
||||
fetch('../api/gauntlets').then(res => res.json()).then(gauntlets => {
|
||||
fetch('/api/gauntlets').then(res => res.json()).then(gauntlets => {
|
||||
$('#loading').hide()
|
||||
gauntlets.forEach((x, y) => {
|
||||
$('#gauntletList').append(`
|
||||
<div class="gauntlet">
|
||||
<a href="../search/*?gauntlet=${x.id}">
|
||||
<img src="../assets/gauntlets/${x.name.toLowerCase()}.png" height="300%"><br>
|
||||
<img src="/assets/gauntlets/${x.name.toLowerCase()}.png" height="300%"><br>
|
||||
<h3 class="gauntletText"">${x.name}<br>Gauntlet</h3></div></a>`)
|
||||
})
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title>GD Multiverse Navigation Terminal</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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/unlock.png">
|
||||
<link rel="icon" href="/assets/unlock.png">
|
||||
<meta id="meta-title" property="og:title" content="GD Multiverse Navigation Terminal">
|
||||
<meta id="meta-desc" property="og:description" content="That's uhh... that's just fancy talk for GDPS Browser. Select a popular GD private server and view its levels, creators, packs, leaderboards, and more!">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/unlock.png">
|
||||
|
@ -26,43 +26,43 @@
|
|||
Please note that I only add <cg>relatively large</cg> servers to the list.
|
||||
Servers which are <cr>inactive</cr> or have <cr>few levels/members</cr> will not be accepted.
|
||||
</p>
|
||||
<img src="../assets/ok.png" width=15%; class="gdButton center" onclick="$('.popup').hide()">
|
||||
<img src="/assets/ok.png" width=15%; class="gdButton center" onclick="$('.popup').hide()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="searchBox" class="supercenter dragscroll"; style="width: 127vh"></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 class="pre" id="header">GD Private Servers</h1>
|
||||
</div>
|
||||
</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()">
|
||||
<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%">
|
||||
<img class="spin noSelect" src="/assets/loading.png" height="105%">
|
||||
</div>
|
||||
|
||||
<div style="position: absolute; left: 7%; top: 45%; height: 10%;">
|
||||
<img class="gdButton" id="pageDown" src="../assets/arrow-left.png" style="display: none"; height="90%">
|
||||
<img class="gdButton" id="pageDown" src="/assets/arrow-left.png" style="display: none"; height="90%">
|
||||
</div>
|
||||
|
||||
<div style="position: absolute; right: 7%; top: 45%; height: 10%;">
|
||||
<img class="gdButton" id="pageUp" src="../assets/arrow-right.png" style="display: none"; height="90%">
|
||||
<img class="gdButton" id="pageUp" src="/assets/arrow-right.png" style="display: none"; height="90%">
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; top: 3%; right: 2%; text-align: right; width: 20%;">
|
||||
<img id="plusButton" class="inline gdButton" src="../assets/plus.png" width="25%" onclick="$('#infoDiv').show()">
|
||||
<img id="plusButton" class="inline gdButton" src="/assets/plus.png" width="25%" onclick="$('#infoDiv').show()">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script type="text/javascript" src="../dragscroll.js"></script>
|
||||
<script>
|
||||
|
||||
|
@ -71,7 +71,7 @@ let page = 1
|
|||
let localhost = window.location.hostname == "localhost"
|
||||
let host = window.location.host.split(".").slice(-2).join(".")
|
||||
|
||||
Fetch('../api/gdps').then(servers => {
|
||||
Fetch('/api/gdps').then(servers => {
|
||||
|
||||
let currentServer = servers.find(x => x.id == gdps)
|
||||
servers = [currentServer].concat(servers.filter(x => x.id != gdps)).filter(x => x)
|
||||
|
@ -89,15 +89,15 @@ Fetch('../api/gdps').then(servers => {
|
|||
|
||||
serverPage.forEach(x => {
|
||||
$('#searchBox').append(`<div class="searchresult" style="height: 19%; padding-top: 1.2%">
|
||||
<h1 class="lessspaced blue" style="color: ${(gdps || "") == x.id ? "#00DDFF" : "white"}">${x.name}</h1>
|
||||
<h1 class="lessspaced blue" style="color: ${(gdps || "") == x.id ? "#0DF" : "white"}">${x.name}</h1>
|
||||
<h2 class="lessSpaced smaller inline gdButton"><a href="${x.authorLink}" target="_blank">By ${x.author}</a></h2>
|
||||
|
||||
|
||||
<div class="center" style="position:absolute; height: 10%; width: 12.5%; left: 3%; transform:translateY(-160%)">
|
||||
<a href="${x.link}" target="_blank"><img class="gdButton spaced gdpslogo" src="../assets/gdps/${x.id || "gd"}_icon.png" height="130%"></a>
|
||||
<a href="${x.link}" target="_blank"><img class="gdButton spaced gdpslogo" src="/assets/gdps/${x.id || "gd"}_icon.png" height="130%"></a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="center" style="position:absolute; right: 7%; transform:translateY(-150%); height: 10%">
|
||||
<a href="http://${x.id || ""}${x.id && localhost ? ".x" : ""}${x.id ? "." : ""}${host}"><img style="margin-bottom: 4.5%" class="valign gdButton" src="../assets/view.png" height="105%"></a>
|
||||
<a href="http://${x.id || ""}${x.id && localhost ? ".x" : ""}${x.id ? "." : ""}${host}"><img style="margin-bottom: 4.5%" class="valign gdButton" src="/assets/view.png" height="105%"></a>
|
||||
</div>
|
||||
</div>`)
|
||||
})
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title>Geometry Dash Browser!</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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/coin.png">
|
||||
<link rel="icon" href="/assets/coin.png">
|
||||
<meta id="meta-title" property="og:title" content="Geometry Dash Browser!">
|
||||
<meta id="meta-desc" property="og:description" content="Browse all of Geometry Dash's online features, right from this handy little website! Levels, profiles, leaderboards, comments, and more!">
|
||||
<meta id="meta-image" name="og:image" content="https://gdbrowser.com/assets/coin.png" itemprop="image">
|
||||
|
@ -18,76 +18,76 @@
|
|||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%; pointer-events: none">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%;>
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%;>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; top: 0%; left: 0%; width: 100%; pointer-events: none">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%; style="transform: scaleY(-1)">
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%; style="transform: scaleY(-1)">
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; top: 1.7%; right: 2%; text-align: right; width: 10%;">
|
||||
<img id="creditsButton" class="gdButton" src="../assets/credits.png" width="60%" onclick="loadCredits()">
|
||||
<img id="creditsButton" class="gdButton" src="/assets/credits.png" width="60%" onclick="loadCredits()">
|
||||
</div>
|
||||
|
||||
<div class="menu-achievements" style="position:absolute; top: 5.5%; left: 3%; width: 12%;">
|
||||
<a href="../achievements"><img class="gdButton" src="../assets/achievements.png" width="40%"></a>
|
||||
<a href="../achievements"><img class="gdButton" src="/assets/achievements.png" width="40%"></a>
|
||||
</div>
|
||||
|
||||
<div class="menu-messages" style="position:absolute; top: -1.7%; left: 11%; text-align: left; width: 10%;">
|
||||
<a href="../messages"><img class="iconRope" src="../assets/messagerope.png" width="40%"></a>
|
||||
<a href="../messages"><img class="iconRope" src="/assets/messagerope.png" width="40%"></a>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; top: -1.5%; right: 10%; text-align: right; width: 10%;">
|
||||
<a href="../iconkit"><img class="iconRope" src="../assets/iconrope.png" width="40%"></a>
|
||||
<a href="../iconkit"><img class="iconRope" src="/assets/iconrope.png" width="40%"></a>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dl" style="display: none; position:absolute; top: 15%; right: 0.5%; text-align: center; width: 17%">
|
||||
<h1 class="smaller" style="margin-bottom: 1%">Note</h1>
|
||||
<p style="font-size: 2.2vh; margin-top: 1.2%"><ca>Level downloading</ca> has been <cr>blocked</cr> by RobTop.
|
||||
<cy>Level analysis, daily levels, and downloading extra info</cy> will <cg>not work</cg> until he chooses to unblock downloads.
|
||||
These features still work <ca><a class="underline" target="_blank" href="https://github.com/GDColon/GDBrowser">locally</a></ca> and on <ca><a class="underline" href="../gdps">private servers</a></ca></p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="supercenter center" id="menuButtons" style="bottom: 5%;">
|
||||
<table>
|
||||
<tr class="menuButtonList">
|
||||
<td><a tabindex="1" href="./search/*?type=saved"><img class="menubutton menu-saved" src="../assets/category-saved.png" title="Saved Levels"></a></td>
|
||||
<td><a tabindex="1" href="./daily"><img class="menubutton menu-daily" src="../assets/category-daily.png" title="Daily Level"></a></td>
|
||||
<td style="display: block" id="menu_weekly"><a tabindex="1" href="./weekly"><img class="menubutton menu-weekly" src="../assets/category-weekly.png" title="Weekly Demon"></a></td>
|
||||
<td style="display: none" id="menu_featured"><a tabindex="1" href="./search/*?type=featured"><img class="menubutton menu-featured" src="../assets/category-featured.png" title="Featured"></a></td>
|
||||
<td><a tabindex="1" href="./gauntlets"><img class="menubutton menu-gauntlets" src="../assets/category-gauntlets.png" title="Gauntlets"></a></td>
|
||||
<td><a tabindex="1" href="./search/*?type=saved"><img class="menubutton menu-saved" src="/assets/category-saved.png" title="Saved Levels"></a></td>
|
||||
<td><a tabindex="1" href="./daily"><img class="menubutton menu-daily" src="/assets/category-daily.png" title="Daily Level"></a></td>
|
||||
<td style="display: block" id="menu_weekly"><a tabindex="1" href="./weekly"><img class="menubutton menu-weekly" src="/assets/category-weekly.png" title="Weekly Demon"></a></td>
|
||||
<td style="display: none" id="menu_featured"><a tabindex="1" href="./search/*?type=featured"><img class="menubutton menu-featured" src="/assets/category-featured.png" title="Featured"></a></td>
|
||||
<td><a tabindex="1" href="./gauntlets"><img class="menubutton menu-gauntlets" src="/assets/category-gauntlets.png" title="Gauntlets"></a></td>
|
||||
</tr>
|
||||
<tr class="menuButtonList">
|
||||
<td><a tabindex="1" href="./leaderboard"><img class="menubutton menu-leaderboard" src="../assets/category-scores.png" title="Scores"></a></td>
|
||||
<td><a tabindex="1" href="./leaderboard"><img class="menubutton menu-leaderboard" src="/assets/category-scores.png" title="Scores"></a></td>
|
||||
<!-- <img src="./assets/exclamation.png" style="position: absolute; height: 18%; left: 3.5%; bottom: 23%; pointer-events: none; z-index: 50;"> -->
|
||||
<td><a tabindex="1" href="./search/*?type=hof"><img class="menubutton menu-hof" src="../assets/category-hof.png" title="Hall Of Fame"></a></td>
|
||||
<td><a tabindex="1" href="./mappacks"><img class="menubutton menu-mappacks" src="../assets/category-packs.png" title="Map Packs"></a></td>
|
||||
<td><a tabindex="1" href="./search"><img class="menubutton menu-search" src="../assets/category-search.png" title="Search"></a></td>
|
||||
<td><a tabindex="1" href="./search/*?type=hof"><img class="menubutton menu-hof" src="/assets/category-hof.png" title="Hall Of Fame"></a></td>
|
||||
<td><a tabindex="1" href="./mappacks"><img class="menubutton menu-mappacks" src="/assets/category-packs.png" title="Map Packs"></a></td>
|
||||
<td><a tabindex="1" href="./search"><img class="menubutton menu-search" src="/assets/category-search.png" title="Search"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p style="margin-bottom: 2%">Website created by <a class="menuLink" href="https://twitter.com/TheRealGDColon" title="Colon">Colon</a> :<br>Pretty much everything other than that belongs to <a class="menuLink" href="http://robtopgames.com" title="RobTop Games">RobTop Games</a>.</p>
|
||||
<p style="margin-top: 0%"><a class="menuLink" href="https://gdcolon.com/tools" title="GD Tools">GD Tools</a>
|
||||
|
||||
|
||||
<a class="menuLink" href="https://gdcolon.com" title="API">More Projects</a>
|
||||
|
||||
|
||||
<a class="menuLink" href="https://github.com/GDColon/GDBrowser" title="GitHub">GitHub</a>
|
||||
|
||||
<a class="menuLink" href="https://store.steampowered.com/app/322170/Geometry_Dash/" title="Buy Geometry Dash!">Buy Geometry Dash!</a></p>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 17%; right: 7%; width: 9%; text-align: right; pointer-events: none">
|
||||
<img src="../assets/privateservers.png" width=85%;">
|
||||
<img src="/assets/privateservers.png" width=85%;">
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 2.5%; right: 1.5%; text-align: right; width: 18%;">
|
||||
<a href="../gdps" title="GD Private Servers"><img class="gdButton" src="../assets/basement.png" width="40%"></a>
|
||||
<a href="../gdps" title="GD Private Servers"><img class="gdButton" src="/assets/basement.png" width="40%"></a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="center" width="100%" style="margin-top: 2%">
|
||||
<img src="../assets/gdlogo.png" height="11.5%"><br>
|
||||
<img id="browserlogo" src="../assets/browser.png" height="7%" style="margin: 0.5% 0% 0% 30%">
|
||||
<img src="/assets/gdlogo.png" height="11.5%"><br>
|
||||
<img id="browserlogo" src="/assets/browser.png" height="7%" style="margin: 0.5% 0% 0% 30%">
|
||||
</div>
|
||||
|
||||
<div id="noDaily" style="display: none;">
|
||||
|
@ -101,12 +101,12 @@
|
|||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/6.2.2/browser/pixi.js"></script>
|
||||
<script type="text/javascript" src="../iconkit/icon.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/iconkit/icon.js"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script>
|
||||
|
||||
let page = 1
|
||||
$('#browserlogo').css('filter', `hue-rotate(${Math.floor(Math.random() * (330 - 60)) + 60}deg) saturate(${Math.floor(Math.random() * (150 - 100)) + 100}%)`)
|
||||
$('#browserlogo').css('filter', `hue-rotate(${Math.floor(randRange(60, 330))}deg) saturate(${Math.floor(randRange(100, 150))}%)`)
|
||||
|
||||
let xButtonPos = '43%'
|
||||
let lastPage
|
||||
|
@ -126,7 +126,7 @@ function loadCredits() {
|
|||
$('#credits').show()
|
||||
if (page == lastPage) $('#closeCredits').css('height', '52%')
|
||||
else $('#closeCredits').css('height', xButtonPos)
|
||||
$('.creditsIcon:not(".creditLoaded"):visible').each(async function() { // only load icons when necessary
|
||||
$('.creditsIcon:not(".creditLoaded"):visible').each(async function() { // only load icons when necessary
|
||||
$(this).addClass('creditLoaded')
|
||||
let profile = await Fetch(`./api/profile/${$(this).attr('ign')}?forceGD=1`).catch(e => {}) || {}
|
||||
$(this).append(`<gdicon cacheID=${profile.playerID} iconID=${profile.icon} col1="${profile.col1}" col2="${profile.col2}" glow="${profile.glow}"></gdicon>`)
|
||||
|
@ -140,19 +140,19 @@ Fetch(`./api/credits`).then(async res => {
|
|||
lastPage = res.credits.length + 1
|
||||
res.credits.forEach(async (x, y) => {
|
||||
$('#credits').append(`<div id="credits${y+1}" class="subCredits" style="display: none;">
|
||||
<img class="gdButton" src="../assets/arrow-left.png" style="${y == 0 ? "display: none; " : ""}position: absolute; top: 45%; right: 75%; width: 4.5%" tabindex="0" onclick="page -= 1; loadCredits()">
|
||||
<img class="gdButton" src="/assets/arrow-left.png" style="${y == 0 ? "display: none; " : ""}position: absolute; top: 45%; right: 75%; width: 4.5%" tabindex="0" onclick="page -= 1; loadCredits()">
|
||||
<div class="brownBox center supercenter" style="width: 80vh; height: 43%; padding-top: 1.5%; padding-bottom: 3.5%;">
|
||||
<h1>${x.header}</h1>
|
||||
<h2 style="margin-bottom: 1.5%; margin-top: 1.5%" class="gdButton biggerShadow"><a href="https://gdbrowser.com/u/${x.ign || x.name}" title=${x.name}>${x.name}</h2></a>
|
||||
|
||||
|
||||
<div class="creditsIcon" ign="${x.ign || x.name}"></div>
|
||||
|
||||
<a target=_blank href="${x.youtube[0]}" title="YouTube"><img src="../assets/${x.youtube[1]}.png" width="11%" class="gdButton"></a>
|
||||
<a target=_blank href="${x.twitter[0]}" title="Twitter"><img src="../assets/${x.twitter[1]}.png" width="11%" class="sideSpace gdButton"></a>
|
||||
<a target=_blank href="${x.github[0]}" title="GitHub"><img src="../assets/${x.github[1]}.png" width="11%" class="sideSpace gdButton"></a>
|
||||
<a target=_blank href="${x.youtube[0]}" title="YouTube"><img src="/assets/${x.youtube[1]}.png" width="11%" class="gdButton"></a>
|
||||
<a target=_blank href="${x.twitter[0]}" title="Twitter"><img src="/assets/${x.twitter[1]}.png" width="11%" class="sideSpace gdButton"></a>
|
||||
<a target=_blank href="${x.github[0]}" title="GitHub"><img src="/assets/${x.github[1]}.png" width="11%" class="sideSpace gdButton"></a>
|
||||
<br>
|
||||
</div>
|
||||
<img class="gdButton" src="../assets/arrow-right.png" style="position: absolute; top: 45%; left: 75%; width: 4.5%" tabindex="0" onclick="page += 1; loadCredits()">
|
||||
<img class="gdButton" src="/assets/arrow-right.png" style="position: absolute; top: 45%; left: 75%; width: 4.5%" tabindex="0" onclick="page += 1; loadCredits()">
|
||||
</div>`)
|
||||
})
|
||||
|
||||
|
@ -160,7 +160,7 @@ Fetch(`./api/credits`).then(async res => {
|
|||
<div id="specialthanks" class="brownBox center supercenter" style="width: 80vh; height: 55%; padding-top: 1.5%; padding-bottom: 3.5%;">
|
||||
<h1>Special Thanks!</h1><br>
|
||||
</div>
|
||||
<img class="gdButton" src="../assets/arrow-left.png" style="position: absolute; top: 45%; right: 75%; width: 4.5%" tabindex="0" onclick="page -= 1; loadCredits()">
|
||||
<img class="gdButton" src="/assets/arrow-left.png" style="position: absolute; top: 45%; right: 75%; width: 4.5%" tabindex="0" onclick="page -= 1; loadCredits()">
|
||||
</div>`)
|
||||
|
||||
res.specialThanks.forEach(async (x, y) => {
|
||||
|
@ -173,7 +173,7 @@ Fetch(`./api/credits`).then(async res => {
|
|||
|
||||
|
||||
$('#credits').append(`<div id="closeCredits" class="center supercenter" style="z-index: 10; width: 80vh; height: ${xButtonPos}%; pointer-events: none;">
|
||||
<img class="closeWindow gdButton" src="../assets/close.png" width="14%" style="position: absolute; top: -24%; left: -7vh; pointer-events: all;" tabindex="0" onclick="$('#credits').hide(); page = 1;" title="Close"></div>`)
|
||||
<img class="closeWindow gdButton" src="/assets/close.png" width="14%" style="position: absolute; top: -24%; left: -7vh; pointer-events: all;" tabindex="0" onclick="$('#credits').hide(); page = 1;" title="Close"></div>`)
|
||||
|
||||
$(document).keydown(function(k) {
|
||||
|
||||
|
@ -182,11 +182,11 @@ Fetch(`./api/credits`).then(async res => {
|
|||
if (k.which == 37 && page > 1) { //left
|
||||
page -= 1; loadCredits();
|
||||
}
|
||||
|
||||
|
||||
if (k.which == 39 && page < lastPage) { //right
|
||||
page += 1; loadCredits();
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<head>
|
||||
<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>
|
||||
<title>Online Icon Kit</title>
|
||||
<link href="../assets/css/iconkit.css?v=3" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/iconkit.css?v=3" type="text/css" rel="stylesheet">
|
||||
<meta name="viewport" content="width=1024">
|
||||
<meta property="og:description" content="Build and save your very own Geometry Dash icons, right from the internet!">
|
||||
<meta property="og:title" content="Geometry Dash Online Icon Kit">
|
||||
<meta property="og:type" content="website">
|
||||
<meta name="og:image" itemprop="image" content="https://gdbrowser.com/assets/icon.png">
|
||||
<meta name="theme-color" content="#CCFF55">
|
||||
<meta name="theme-color" content="#CF5">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<link rel="icon" href="../assets/icon.png">
|
||||
<link rel="icon" href="/assets/icon.png">
|
||||
</link>
|
||||
</head>
|
||||
<body style="background: linear-gradient(rgb(139, 139, 139), rgb(100, 100, 100)) no-repeat center center fixed;" onbeforeunload="sessionStorage.setItem('prevUrl', window.location.href)">
|
||||
|
@ -21,11 +21,11 @@
|
|||
<p id="copyFrom" class="white" style="font-size: 24px; margin: 10px auto 5px auto"></p>
|
||||
<input type="text" name="gdbrowser" id="playerName" autocomplete="off" placeholder="Username" maxlength="32" style="height: 58px; width: 90%; text-align: center; margin-top: 25px; margin-bottom: 10px;">
|
||||
<div id="copyForms"></div>
|
||||
<img src="../assets/ok.png" height=55px; class="postButton gdButton center" style="margin-top: 30px" id="fetchUser">
|
||||
<img class="gdButton xButton" src="../assets/close.png" width="70px" onclick="$('#steal').hide()">
|
||||
<img src="/assets/ok.png" height=55px; class="postButton gdButton center" style="margin-top: 30px" id="fetchUser">
|
||||
<img class="gdButton xButton" src="/assets/close.png" width="70px" onclick="$('#steal').hide()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="popup" data-nosnippet id="settings">
|
||||
<div class="brownbox bounce center supercenter" style="height: 380px; width: 820px">
|
||||
<h1 class="center gold" style="margin-top: 10px; margin-bottom: 20px;">Settings</h1>
|
||||
|
@ -33,10 +33,10 @@
|
|||
<div class="help" help="Removes the clear dome on top of UFOs"><input type="checkbox" class="iconsetting" id="box-ufo"><label for="box-ufo" class="gdcheckbox gdButton"></label><h2>No UFO Dome</h2></div>
|
||||
<div class="help" help="Sorts the colors by internal ID instead of their in-game order"><input type="checkbox" class="iconsetting" id="box-sort"><label for="box-sort" class="gdcheckbox gdButton"></label><h2>Unsort Colors</h2></div>
|
||||
<div class="help" help="Allows robots to play spider animations and vice versa"><input type="checkbox" class="iconsetting" id="box-cursed"><label for="box-cursed" class="gdcheckbox gdButton"></label><h2>Cursed animations</h2></div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="white" id="helpText" style="font-size: 24px; margin-bottom: 0;">(Hover over a setting for information)</p>
|
||||
<img src="../assets/ok.png" height=55px; class="postButton gdButton center" style="margin-top: 30px" onclick="$('#settings').hide()">
|
||||
<img class="gdButton xButton" src="../assets/close.png" width="70px" onclick="$('#settings').hide()">
|
||||
<img src="/assets/ok.png" height=55px; class="postButton gdButton center" style="margin-top: 30px" onclick="$('#settings').hide()">
|
||||
<img class="gdButton xButton" src="/assets/close.png" width="70px" onclick="$('#settings').hide()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -45,14 +45,14 @@
|
|||
<h1 class="center gold" style="margin-top: 12px">Enable 2.2 icons?</h1>
|
||||
<p style="font-size: 26px; color: white; width: 620px; margin: 17px auto">The newest update for Geometry Dash Lite revealed 500 new icons across all forms. Enabling this setting will reveal all these icons, however they will be lower quality since no UHD textures were provided.</p>
|
||||
<p style="font-size: 30px; color: yellow">THIS WILL REVEAL <u>EVERY</u> ICON.<br>PRESS CANCEL IF YOU DON'T WANT TO BE SPOILED!!!</p>
|
||||
<img src="../assets/iconkitbuttons/btn-reveal.png" height=60px; style="margin-right: 33px" class="gdButton center" onclick="clickedSpoilerWarning = true; toggleSpoilers(); $('#spoilerwarning').hide()">
|
||||
<img src="../assets/btn-cancel.png" height=60px; class="gdButton center" onclick="$('#spoilerwarning').hide()">
|
||||
<img class="gdButton xButton" src="../assets/close.png" width="70px" onclick="$('#spoilerwarning').hide()">
|
||||
<img src="/assets/iconkitbuttons/btn-reveal.png" height=60px; style="margin-right: 33px" class="gdButton center" onclick="clickedSpoilerWarning = true; toggleSpoilers(); $('#spoilerwarning').hide()">
|
||||
<img src="/assets/btn-cancel.png" height=60px; class="gdButton center" onclick="$('#spoilerwarning').hide()">
|
||||
<img class="gdButton xButton" src="/assets/close.png" width="70px" onclick="$('#spoilerwarning').hide()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img id="iconkitlogo" src="../assets/iconkit.png" style="margin: 7px 0px; height: 50px"><br>
|
||||
<h2 style="margin: 5 auto 0 auto; display: none; height: 45px" id="howto"><span style='color: #aaaaaa'>(hover over an icon for info)</span></h2>
|
||||
<img id="iconkitlogo" src="/assets/iconkit.png" style="margin: 7px 0px; height: 50px"><br>
|
||||
<h2 style="margin: 5 auto 0 auto; display: none; height: 45px" id="howto"><span style='color: #aaa'>(hover over an icon for info)</span></h2>
|
||||
|
||||
<div id="iconbox">
|
||||
<canvas id="result" style="transform: translateY(-35px)">
|
||||
|
@ -60,14 +60,14 @@
|
|||
|
||||
<hr id="gdfloor">
|
||||
<div id="menuButtons" style="height: 65px; margin: 0 0 8 0;">
|
||||
<button class="blankButton menuButton" id="customColors" title="Settings" onclick="$('#settings').show()"><img src="../assets/iconkitbuttons/cog.png" width=60px></button>
|
||||
<button class="blankButton menuButton" onclick="icon.psdExport()" title="Download layered PSD"><img src="../assets/iconkitbuttons/psd.png" width=60px></button>
|
||||
<button class="blankButton menuButton" id="copyToClipboard" title="Copy to clipboard"><img src="../assets/iconkitbuttons/copy.png" width=60px></button>
|
||||
<button class="blankButton menuButton" onclick="icon.pngExport()" title="Download icon"><img src="../assets/iconkitbuttons/save.png" width=60px></a></button>
|
||||
<button class="blankButton menuButton" id="getUserIcon" title="Get player icon"><img src="../assets/iconkitbuttons/steal.png" width=60px></button>
|
||||
<button class="blankButton menuButton" id="randomIcon" title="Random Icon"><img src="../assets/iconkitbuttons/shuffle.png" width=60px></button>
|
||||
<button class="blankButton menuButton" id="unlockIcon" title="Unlock details"><img id="lock" src="../assets/iconkitbuttons/unlock.png" width=60px></button>
|
||||
<button class="blankButton menuButton" onclick="clickedSpoilerWarning ? toggleSpoilers() : $('#spoilerwarning').show()" title="2.2 icons (spoilers!!!)"><img id="newIconBtn" src="../assets/iconkitbuttons/spoilers.png" width=60px></button>
|
||||
<button class="blankButton menuButton" id="customColors" title="Settings" onclick="$('#settings').show()"><img src="/assets/iconkitbuttons/cog.png" width=60px></button>
|
||||
<button class="blankButton menuButton" onclick="icon.psdExport()" title="Download layered PSD"><img src="/assets/iconkitbuttons/psd.png" width=60px></button>
|
||||
<button class="blankButton menuButton" id="copyToClipboard" title="Copy to clipboard"><img src="/assets/iconkitbuttons/copy.png" width=60px></button>
|
||||
<button class="blankButton menuButton" onclick="icon.pngExport()" title="Download icon"><img src="/assets/iconkitbuttons/save.png" width=60px></a></button>
|
||||
<button class="blankButton menuButton" id="getUserIcon" title="Get player icon"><img src="/assets/iconkitbuttons/steal.png" width=60px></button>
|
||||
<button class="blankButton menuButton" id="randomIcon" title="Random Icon"><img src="/assets/iconkitbuttons/shuffle.png" width=60px></button>
|
||||
<button class="blankButton menuButton" id="unlockIcon" title="Unlock details"><img id="lock" src="/assets/iconkitbuttons/unlock.png" width=60px></button>
|
||||
<button class="blankButton menuButton" onclick="clickedSpoilerWarning ? toggleSpoilers() : $('#spoilerwarning').show()" title="2.2 icons (spoilers!!!)"><img id="newIconBtn" src="/assets/iconkitbuttons/spoilers.png" width=60px></button>
|
||||
</div>
|
||||
|
||||
<div id="iconTabs"></div><br>
|
||||
|
@ -79,12 +79,12 @@
|
|||
|
||||
<div style="width: 1200px; margin: 0 auto; position: relative; right: 42px">
|
||||
<div style="padding-top: 15px; width: 75px; vertical-align: top;" class="colTypes inline">
|
||||
<button id="cc1" class="colorLabel blankButton" onclick="$('#cp1').trigger('click')" title="Primary Color"><img src="../assets/col1.png"></button><input type="color" id="cp1" class="colorPicker">
|
||||
<button id="cc2" class="colorLabel blankButton" onclick="$('#cp2').trigger('click')" title="Secondary Color"><img src="../assets/col2.png"></button><input type="color" id="cp2" class="colorPicker">
|
||||
<button id="cc1" class="colorLabel blankButton" onclick="$('#cp1').trigger('click')" title="Primary Color"><img src="/assets/col1.png"></button><input type="color" id="cp1" class="colorPicker">
|
||||
<button id="cc2" class="colorLabel blankButton" onclick="$('#cp2').trigger('click')" title="Secondary Color"><img src="/assets/col2.png"></button><input type="color" id="cp2" class="colorPicker">
|
||||
<div class="colorSplit" style="height: 12.5px"></div>
|
||||
<button id="ccG" class="colorLabel blankButton" onclick="$('#cpG').trigger('click')" title="Glow Color"><img src="../assets/colG.png"></button><input type="color" id="cpG" class="colorPicker">
|
||||
<button id="ccW" class="colorLabel blankButton" onclick="$('#cpW').trigger('click')" title="White Highlights" style="display: none"><img src="../assets/colW.png" style="background-color: rgb(255, 255, 255)";></button><input type="color" id="cpW" class="colorPicker">
|
||||
<button id="ccU" class="colorLabel blankButton" onclick="$('#cpU').trigger('click')" title="UFO Dome" style="display: none"><img src="../assets/colU.png" style="background-color: rgb(255, 255, 255)";></button><input type="color" id="cpU" class="colorPicker">
|
||||
<button id="ccG" class="colorLabel blankButton" onclick="$('#cpG').trigger('click')" title="Glow Color"><img src="/assets/colG.png"></button><input type="color" id="cpG" class="colorPicker">
|
||||
<button id="ccW" class="colorLabel blankButton" onclick="$('#cpW').trigger('click')" title="White Highlights" style="display: none"><img src="/assets/colW.png" style="background-color: rgb(255, 255, 255)";></button><input type="color" id="cpW" class="colorPicker">
|
||||
<button id="ccU" class="colorLabel blankButton" onclick="$('#cpU').trigger('click')" title="UFO Dome" style="display: none"><img src="/assets/colU.png" style="background-color: rgb(255, 255, 255)";></button><input type="color" id="cpU" class="colorPicker">
|
||||
</div>
|
||||
<div id="colors" class="inline iconKit">
|
||||
<div id="col1"></div>
|
||||
|
@ -116,27 +116,32 @@
|
|||
</p>
|
||||
|
||||
<div class="hideIfSmall" style="position:absolute; top: 20px; left: 20px; width: 64px; height: 64px; pointer-events: none">
|
||||
<img class="gdButton" style="pointer-events: all" id="backButton" src="../assets/back.png" height="100%" onclick="backButton()">
|
||||
<img class="gdButton" style="pointer-events: all" id="backButton" src="/assets/back.png" height="100%" onclick="backButton()">
|
||||
</div>
|
||||
|
||||
<div class="hideIfSmall" id="extraInfo" style="position:absolute; top: 20px; right: 15px"></div>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/6.2.2/browser/pixi.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/6.2.2/browser/pixi.min.js"></script>
|
||||
<script type="text/javascript" src="./libs/ag-psd.js"></script>
|
||||
<script type="text/javascript" src="./libs/pixi-ease.js"></script>
|
||||
<script type="text/javascript" src="./libs/imagesloaded.js"></script>
|
||||
<script type="text/javascript" src="./icon.js"></script>
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
// these 3 fns are available in `global.js`
|
||||
const clamp = (x, min, max) => x < min ? min : (x > max ? max : x)
|
||||
const randRange = (min, max) => Math.random() * (max - min) + +min
|
||||
const randInt = (min, max) => Math.floor(randRange(min, max))
|
||||
|
||||
// hi there hello! this code is really old, so it's shit. i should rewrite it some time omg
|
||||
|
||||
$('.hidden').show();
|
||||
|
||||
let mobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)
|
||||
$('.hidden').show()
|
||||
// avoid possible name collision with isMobile.js (AJAX Node module)
|
||||
let is_mobile = /Android|webOS|iPhone|iP[ao]d|BlackBerry/i.test(navigator.userAgent)
|
||||
let currentForm = 'icon'
|
||||
let glowbtnformCopy = 'icon'
|
||||
const yOffsets = { ball: -10, ufo: 30, spider: 7, swing: -15 }
|
||||
|
@ -149,7 +154,7 @@ let selectedCol2 = 3
|
|||
let selectedColG = 3
|
||||
let selectedColW = null
|
||||
let selectedColU = null
|
||||
let enableGlow = 0
|
||||
let enableGlow = false
|
||||
|
||||
let enableSpoilers = false
|
||||
let clickedSpoilerWarning = false
|
||||
|
@ -164,25 +169,28 @@ let animationMultiplier = 1
|
|||
|
||||
let icon = null
|
||||
|
||||
let iconCanvas = document.getElementById('result');
|
||||
let app = new PIXI.Application({ view: iconCanvas, width: 300, height: 300, backgroundAlpha: 0 });
|
||||
let iconCanvas = document.getElementById('result')
|
||||
let app = new PIXI.Application({ view: iconCanvas, width: 300, height: 300, backgroundAlpha: 0 })
|
||||
|
||||
if (mobile) $('#logo').attr('width', '80%');
|
||||
if (is_mobile) $('#logo').attr('width', '80%')
|
||||
|
||||
let iconSettings = (localStorage.iconkit || "").split(",")
|
||||
iconSettings.forEach(x => {
|
||||
$(`#box-${x}`).prop('checked', true)
|
||||
})
|
||||
|
||||
function capitalize(str) { return str[0].toUpperCase() + str.substr(1) }
|
||||
function randInt(min, max) { return Math.floor(Math.random() * (max - min + 1) ) + min }
|
||||
function colorBG(e, c, hex) {
|
||||
let capitalize = str => str[0].toUpperCase() + str.substr(1)
|
||||
function colorBG(e, c, hex) {
|
||||
$(`#cc${e} img`).css('background-color', hex ? `#${c}` : `rgb(${c.r}, ${c.g}, ${c.b})`)
|
||||
if (!hex) $(`#cp${e}`).val(toHexCode(rgbToDecimal(c.r, c.g, c.b)))
|
||||
if (!hex) $(`#cp${e}`).val(toHexCode(rgb2Pac(c.r, c.g, c.b)))
|
||||
}
|
||||
function colorSplit() {
|
||||
if ($("#colG").is(':visible') || $("#colW").is(':visible') || $("#colU").is(':visible')) $('.colorSplit').show()
|
||||
else $('.colorSplit').hide()
|
||||
function colorSplit() {
|
||||
$('.colorSplit')[
|
||||
$("#colG").is(':visible') ||
|
||||
$("#colW").is(':visible') ||
|
||||
$("#colU").is(':visible')
|
||||
? "show" : "hide"
|
||||
]()
|
||||
}
|
||||
|
||||
function setColor(type, col) {
|
||||
|
@ -215,10 +223,9 @@ function checkWhite() {
|
|||
// check if animation selector should be visible
|
||||
function checkAnimation() {
|
||||
let animationData = iconData.robotAnimations.animations[selectedForm]
|
||||
if (animationData && !$(`#robotAnimation[form="${selectedForm}"]`).is(":visible")) {
|
||||
if (animationData && !$(`#robotAnimation[form="${selectedForm}"]`).is(":visible"))
|
||||
appendAnimations(selectedForm, animationData)
|
||||
}
|
||||
else if (!animationData) $('#animationOptions').hide()
|
||||
if (!animationData) $('#animationOptions').hide()
|
||||
}
|
||||
|
||||
function animationSort(anim) {
|
||||
|
@ -249,8 +256,8 @@ function setExtras() {
|
|||
}
|
||||
|
||||
if ($('#colG').is(":visible") && (getCol(selectedColG) != getCol(selectedCol2))) extraInfo["Glow"] = extraColString(selectedColG)
|
||||
if ($('#colW').is(":visible") && (getCol(selectedColW) != 0xffffff)) extraInfo["White"] = extraColString(selectedColW)
|
||||
if ($('#colU').is(":visible") && (getCol(selectedColU) != 0xffffff)) extraInfo["UFO Dome"] = extraColString(selectedColU)
|
||||
if ($('#colW').is(":visible") && (getCol(selectedColW) != WHITE)) extraInfo["White"] = extraColString(selectedColW)
|
||||
if ($('#colU').is(":visible") && (getCol(selectedColU) != WHITE)) extraInfo["UFO Dome"] = extraColString(selectedColU)
|
||||
|
||||
let foundCredit = iconStuff.iconCredits.find(x => x.form == selectedForm && x.id == selectedIcon)
|
||||
if (foundCredit) extraInfo["🎨 Artist"] = foundCredit.name
|
||||
|
@ -265,8 +272,8 @@ function setExtras() {
|
|||
|
||||
function extraColString(col) {
|
||||
let realCol = getCol(col)
|
||||
let hexCol = toHexCode(realCol)
|
||||
let foundGDCol = Object.entries(iconStuff.colors).find(x => rgbToDecimal(x[1]) == realCol)
|
||||
let hexCol = toHexCode(realCol)
|
||||
let foundGDCol = Object.entries(iconStuff.colors).find(x => rgb2Pac(x[1]) == realCol)
|
||||
return foundGDCol ? `${foundGDCol[0]} (${hexCol})` : hexCol
|
||||
}
|
||||
|
||||
|
@ -274,194 +281,198 @@ function getCol(id) {
|
|||
return parseIconColor(id, iconStuff.colors)
|
||||
}
|
||||
|
||||
function toHexCode(decimal) {
|
||||
return "#" + decimal.toString(16).padStart(6, "0")
|
||||
function toHexCode(pack) {
|
||||
return "#" + pack.toString(16).padStart(6, "0")
|
||||
}
|
||||
|
||||
let iconData = null
|
||||
fetch('../api/icons').then(res => res.json()).then(sacredTexts => {
|
||||
fetch('../api/iconkit').then(res => res.json()).then(iconKitData => {
|
||||
fetch('/api/icons').then(res => res.json()).then(sacredTexts => {
|
||||
fetch('/api/iconkit').then(res => res.json()).then(iconKitData => {
|
||||
|
||||
iconStuff = Object.assign(sacredTexts, iconKitData)
|
||||
iconData = sacredTexts
|
||||
iconStuff = Object.assign(sacredTexts, iconKitData)
|
||||
iconData = sacredTexts
|
||||
|
||||
let forms = Object.keys(iconStuff.forms)
|
||||
let forms = Object.keys(iconStuff.forms)
|
||||
|
||||
forms.forEach(form => {
|
||||
let spoil = ["swing", "jetpack"].includes(form)
|
||||
$("#iconTabs").append(`<button form="${form}"${spoil ? `isnew="true" style="display: none"` : ""} title="${iconStuff.forms[form].name}" class="blankButton iconTabButton"><img src="../assets/iconkitbuttons/${form}_off.png" style="width: 50px"></button>`)
|
||||
$("#copyForms").append(`<button form="${form}"${spoil ? `isnew="true" style="display: none"` : ""} title="${iconStuff.forms[form].name}" class="blankButton copyForm"><img src="../assets/iconkitbuttons/${form}_off.png" style="width: 50px"></button>`)
|
||||
})
|
||||
$("#iconTabs").append(`<button title="Glow" class="blankButton glowToggle" id="glowbtn"><img id="glow" src="../assets/iconkitbuttons/streak_off.png" style="width: 50px"></button>`)
|
||||
forms.forEach(form => {
|
||||
let spoil = ["swing", "jetpack"].includes(form)
|
||||
$("#iconTabs").append(`<button form="${form}"${spoil ? `isnew="true" style="display: none"` : ""} title="${iconStuff.forms[form].name}" class="blankButton iconTabButton"><img src="/assets/iconkitbuttons/${form}_off.png" style="width: 50px"></button>`)
|
||||
$("#copyForms").append(`<button form="${form}"${spoil ? `isnew="true" style="display: none"` : ""} title="${iconStuff.forms[form].name}" class="blankButton copyForm"><img src="/assets/iconkitbuttons/${form}_off.png" style="width: 50px"></button>`)
|
||||
})
|
||||
$("#iconTabs").append(`<button title="Glow" class="blankButton glowToggle" id="glowbtn"><img id="glow" src="/assets/iconkitbuttons/streak_off.png" style="width: 50px"></button>`)
|
||||
|
||||
forms.forEach(form => {$("#iconKitParent").append(`<div id="${form}s" class="iconContainer"></div>`)})
|
||||
forms.forEach(form => {$("#iconKitParent").append(`<div id="${form}s" class="iconContainer"></div>`)})
|
||||
|
||||
if (iconStuff.noCopy) $('#getUserIcon').remove()
|
||||
else if (iconStuff.server) {
|
||||
$('#copyFrom').html(`Copying from the <cy>${iconStuff.server}</cy> servers`)
|
||||
$('#stealBox').css('height', '385px')
|
||||
}
|
||||
if (iconStuff.noCopy) $('#getUserIcon').remove()
|
||||
else if (iconStuff.server) {
|
||||
$('#copyFrom').html(`Copying from the <cy>${iconStuff.server}</cy> servers`)
|
||||
$('#stealBox').css('height', '385px')
|
||||
}
|
||||
|
||||
function generateIcon(cb) {
|
||||
let noDome = selectedForm == "ufo" && iconSettings.includes("ufo")
|
||||
let foundForm = parseIconForm(selectedForm)
|
||||
function generateIcon(cb) {
|
||||
//let noDome = selectedForm == "ufo" && iconSettings.includes("ufo")
|
||||
let foundForm = parseIconForm(selectedForm)
|
||||
|
||||
loadIconLayers(foundForm, selectedIcon, function(l, sprites, isNew) {
|
||||
let iconArgs = {app, form: foundForm, id: selectedIcon, col1: getCol(selectedCol1), col2: getCol(selectedCol2), glow: enableGlow > 0, new: isNew}
|
||||
if (selectedCol2 != selectedColG) iconArgs.colG = getCol(selectedColG)
|
||||
if (selectedColW) iconArgs.colW = getCol(selectedColW)
|
||||
if (selectedColU) iconArgs.colU = getCol(selectedColU)
|
||||
if (iconSettings.includes("ufo")) iconArgs.noUFODome = true
|
||||
if (animationMultiplier != 1) iconArgs.animationSpeed = animationMultiplier
|
||||
if (currentAnimation.form && (iconSettings.includes("cursed") || currentAnimation.form == selectedForm)) {
|
||||
iconArgs.animation = currentAnimation.name
|
||||
iconArgs.animationForm = currentAnimation.form
|
||||
}
|
||||
|
||||
icon = new Icon(iconArgs)
|
||||
icon.sprite.position.set(app.renderer.width / 2, (app.renderer.height / 2) + (yOffsets[selectedForm] || 0))
|
||||
updateDetails()
|
||||
checkWhite()
|
||||
|
||||
if (cb) cb()
|
||||
})
|
||||
}
|
||||
|
||||
function filterIcon(name) {
|
||||
return iconStuff.previewIcons.concat(iconStuff.newPreviewIcons).filter(x => x.startsWith(name)).sort(function (a,b) {return a.replace(/[^0-9]/g, "") - b.replace(/[^0-9]/g, "");})
|
||||
}
|
||||
|
||||
function appendIcon(form, formName) {
|
||||
|
||||
let imagesLoaded = 0
|
||||
let totalLoaded = 0
|
||||
let formContainer = $('#' + formName + 's')
|
||||
|
||||
let hasMini = form[0].endsWith("_0.png")
|
||||
if (hasMini) form.shift()
|
||||
|
||||
form.forEach(function (i, p) {
|
||||
let newOne = iconStuff.newPreviewIcons.includes(i)
|
||||
formContainer.append(`<button num="${p + 1}" form="${formName}"${newOne ? ` isnew="true"${enableSpoilers ? "" : ` style="display: none"`}` : ""} class="blankButton iconButton" id="${formName}-${p + 1}"><img src="./${newOne ? "new" : ""}premade/${i}" title="${capitalize(formName)} ${p + 1}"></button>`)
|
||||
})
|
||||
|
||||
if (hasMini) formContainer.append(`<button num="0" form="${formName}" class="blankButton iconButton" id="${formName}-0"><img src="./premade/${formName}_0.png" title="Mini ${formName}"></button>`)
|
||||
|
||||
formContainer.imagesLoaded(function() {}).progress(function() {
|
||||
imagesLoaded += 1;
|
||||
totalLoaded = imagesLoaded / formContainer.find('img').length * 100
|
||||
$('#iconloading').css('width', `${totalLoaded}%`)
|
||||
loadIconLayers(foundForm, selectedIcon, function(l, sprites, isNew) {
|
||||
let iconArgs = {app, form: foundForm, id: selectedIcon, col1: getCol(selectedCol1), col2: getCol(selectedCol2), glow: enableGlow, new: isNew}
|
||||
if (selectedCol2 != selectedColG) iconArgs.colG = getCol(selectedColG)
|
||||
if (selectedColW) iconArgs.colW = getCol(selectedColW)
|
||||
if (selectedColU) iconArgs.colU = getCol(selectedColU)
|
||||
if (iconSettings.includes("ufo")) iconArgs.noUFODome = true
|
||||
if (animationMultiplier != 1) iconArgs.animationSpeed = animationMultiplier
|
||||
if (currentAnimation.form && (iconSettings.includes("cursed") || currentAnimation.form == selectedForm)) {
|
||||
iconArgs.animation = currentAnimation.name
|
||||
iconArgs.animationForm = currentAnimation.form
|
||||
}
|
||||
)}
|
||||
|
||||
function loadColors(devmode) {
|
||||
let colTypes = [1, 2, "G", "W", "U"]
|
||||
colTypes.forEach(x => $(`#col${x}`).html(""))
|
||||
iconStuff.colorOrder.forEach(function (p, n) {
|
||||
if (iconSettings.includes("sort")) p = n;
|
||||
colTypes.forEach(c => {
|
||||
let colRGB = iconStuff.colors[p]
|
||||
$(`#col${c}`).append(`<button col=${p} colType=color${c} class="blankButton color${c} iconColor" title="Color ${p} (#${toHexCode(rgbToDecimal(colRGB))})" id="col${c}-${p}"><div style="background-color: rgb(${colRGB.r}, ${colRGB.g}, ${colRGB.b})"></button>`)
|
||||
})
|
||||
icon = new Icon(iconArgs)
|
||||
icon.sprite.position.set(app.renderer.width / 2, (app.renderer.height / 2) + (yOffsets[selectedForm] || 0))
|
||||
updateDetails()
|
||||
checkWhite()
|
||||
|
||||
if (cb) cb()
|
||||
})
|
||||
}
|
||||
|
||||
function filterIcon(name) {
|
||||
return (
|
||||
iconStuff.previewIcons.concat(iconStuff.newPreviewIcons)
|
||||
.filter(x => x.startsWith(name))
|
||||
.sort( (a,b) => a.replace(/\D/g, "") - b.replace(/\D/g, "") )
|
||||
)
|
||||
}
|
||||
|
||||
function appendIcon(form, formName) {
|
||||
|
||||
let imagesLoaded = 0
|
||||
let totalLoaded = 0
|
||||
let formContainer = $(`#${formName}s`)
|
||||
|
||||
let hasMini = form[0].endsWith("_0.png")
|
||||
if (hasMini) form.shift()
|
||||
|
||||
form.forEach((i, p) => {
|
||||
let newOne = iconStuff.newPreviewIcons.includes(i)
|
||||
formContainer.append(`<button num="${p + 1}" form="${formName}"${newOne ? ` isnew="true"${enableSpoilers ? "" : ` style="display: none"`}` : ""} class="blankButton iconButton" id="${formName}-${p + 1}"><img src="/iconkit/${newOne ? "new" : ""}premade/${i}" title="${capitalize(formName)} ${p + 1}"></button>`)
|
||||
})
|
||||
|
||||
if (hasMini) formContainer.append(`<button num="0" form="${formName}" class="blankButton iconButton" id="${formName}-0"><img src="/iconkit/premade/${formName}_0.png" title="Mini ${formName}"></button>`)
|
||||
|
||||
formContainer.imagesLoaded(function() {}).progress(function() {
|
||||
imagesLoaded++;
|
||||
totalLoaded = imagesLoaded / formContainer.find('img').length * 100
|
||||
$('#iconloading').css('width', `${totalLoaded}%`)
|
||||
}
|
||||
)}
|
||||
|
||||
function loadColors(devmode) {
|
||||
let colTypes = [1, 2, "G", "W", "U"]
|
||||
colTypes.forEach(x => $(`#col${x}`).html(""))
|
||||
iconStuff.colorOrder.forEach(function (p, n) {
|
||||
if (iconSettings.includes("sort")) p = n
|
||||
colTypes.forEach(c => {
|
||||
let colRGB = iconStuff.colors[p]
|
||||
$(`#col${c}`).append(`<button col=${p} colType=color${c} class="blankButton color${c} iconColor" title="Color ${p} (#${toHexCode(rgb2Pac(colRGB))})" id="col${c}-${p}"><div style="background-color: rgb(${colRGB.r}, ${colRGB.g}, ${colRGB.b})"></button>`)
|
||||
})
|
||||
$('#col1').append("<span style='min-width: 10px'></span>")
|
||||
}
|
||||
})
|
||||
$('#col1').append("<span style='min-width: 10px'></span>")
|
||||
}
|
||||
|
||||
loadColors()
|
||||
let icons = filterIcon('icon');
|
||||
|
||||
let sample = JSON.parse(iconStuff.sample);
|
||||
enableGlow = sample[3] * 2;
|
||||
[selectedIcon, selectedCol1, selectedCol2] = sample;
|
||||
selectedColG = selectedCol2
|
||||
loadColors()
|
||||
let icons = filterIcon('icon')
|
||||
|
||||
$('body').imagesLoaded(function () {
|
||||
appendIcon(icons, "icon")
|
||||
$(`[num="${sample[0]}"][form="icon"]`).addClass('iconSelected');
|
||||
let sample = JSON.parse(iconStuff.sample)
|
||||
enableGlow = !!(sample[3] * 2);
|
||||
[eselectedIcon, selectedCol1, selectedCol2] = sample
|
||||
selectedColG = selectedCol2
|
||||
|
||||
$('body').imagesLoaded(function () {
|
||||
appendIcon(icons, "icon")
|
||||
$(`[num="${sample[0]}"][form="icon"]`).addClass('iconSelected');
|
||||
})
|
||||
|
||||
$(`.color1[col="${sample[1]}"]`).addClass('iconSelected');
|
||||
$(`.color2[col="${sample[2]}"]`).addClass('iconSelected');
|
||||
$(`.colorG[col="${sample[2]}"]`).addClass('iconSelected');
|
||||
$('.colorW[col="12"]').addClass('iconSelected');
|
||||
$('.colorU[col="12"]').addClass('iconSelected')
|
||||
|
||||
colorBG(1, iconStuff.colors[sample[1]])
|
||||
colorBG(2, iconStuff.colors[sample[2]])
|
||||
colorBG('G', iconStuff.colors[sample[2]])
|
||||
|
||||
$('.colorLabel img').show()
|
||||
|
||||
generateIcon(() => { icon.glow = enableGlow = false } ) // disable glow after first generated
|
||||
|
||||
$(document).on('click', '.iconTabButton', function() {
|
||||
let form = $(this).attr('form')
|
||||
let formElement = `#${form}s`
|
||||
|
||||
currentForm = form
|
||||
|
||||
$('.iconTabButton').each(function() {
|
||||
$(this).children().first().attr('src', $(this).children().first().attr('src').replace('_on', '_off'))
|
||||
})
|
||||
|
||||
$(`.color1[col="${sample[1]}"]`).addClass('iconSelected');
|
||||
$(`.color2[col="${sample[2]}"]`).addClass('iconSelected');
|
||||
$(`.colorG[col="${sample[2]}"]`).addClass('iconSelected');
|
||||
$('.colorW[col="12"]').addClass('iconSelected');
|
||||
$('.colorU[col="12"]').addClass('iconSelected');
|
||||
let img = $(this).children().first()
|
||||
img.attr('src', img.attr('src').replace('_off', '_on'));
|
||||
|
||||
colorBG(1, iconStuff.colors[sample[1]])
|
||||
colorBG(2, iconStuff.colors[sample[2]])
|
||||
colorBG('G', iconStuff.colors[sample[2]])
|
||||
$('#iconKitParent').each(function() { $(this).children().not('#iconprogressbar').hide() })
|
||||
|
||||
$('.colorLabel img').show()
|
||||
if ($(formElement).html() == "") appendIcon(filterIcon(form), form)
|
||||
|
||||
generateIcon(() => { icon.glow = false; enableGlow = 0 } ) // disable glow after first generated
|
||||
$(formElement).show()
|
||||
})
|
||||
|
||||
$(document).on('click', '.iconTabButton', function () {
|
||||
let form = $(this).attr('form')
|
||||
let formElement = '#' + form + 's'
|
||||
$('#iconTabs').find('.iconTabButton')
|
||||
.first().children()
|
||||
.first().attr(
|
||||
'src',
|
||||
$('.iconTabButton').first().children()
|
||||
.first().attr('src').replace('_off', '_on')
|
||||
)
|
||||
|
||||
currentForm = form
|
||||
function setGlowAttr(glow) {
|
||||
$("#glow").attr('src', $("#glow").attr('src').replace( ...(glow ? ['_off', '_on'] : ['_on', '_off']) ))
|
||||
}
|
||||
|
||||
$('.iconTabButton').each(function(x, y) {
|
||||
$(this).children().first().attr('src', $(this).children().first().attr('src').replace('_on', '_off'))
|
||||
})
|
||||
$("#randomIcon").click(function() {
|
||||
|
||||
let img = $(this).children().first()
|
||||
img.attr('src', img.attr('src').replace('_off', '_on'));
|
||||
let iconPool = iconStuff.previewIcons.concat(enableSpoilers ? iconStuff.newPreviewIcons : [])
|
||||
let pickedIcon = iconPool[randInt(0, iconPool.length)].split(".", 1)[0].split("_")
|
||||
let [randomForm, randomID] = pickedIcon
|
||||
|
||||
$('#iconKitParent').each(function(x, y) { $(this).children().not('#iconprogressbar').hide() })
|
||||
let colorCount = Object.keys(iconStuff.colors).length
|
||||
selectedForm = randomForm
|
||||
selectedIcon = randomID
|
||||
selectedCol1 = randInt(0, colorCount)
|
||||
selectedCol2 = randInt(0, colorCount)
|
||||
selectedColW = null
|
||||
selectedColU = null
|
||||
enableGlow = !randInt(0, 3) // 1 in 3 chance of glow
|
||||
generateIcon()
|
||||
|
||||
if ($(formElement).html() == "") appendIcon(filterIcon(form), form)
|
||||
|
||||
$(formElement).show()
|
||||
})
|
||||
$('#glow').attr('src', '/assets/iconkitbuttons/streak_off.png')
|
||||
|
||||
$('#iconTabs').find('.iconTabButton').first().children().first().attr('src', $('.iconTabButton').first().children().first().attr('src').replace('_off', '_on'))
|
||||
$(`.iconTabButton[form=${selectedForm}]`).trigger('click')
|
||||
$(`#${selectedForm}-${selectedIcon}`).trigger('click')
|
||||
$(`#col1-${selectedCol1}`).trigger('click')
|
||||
$(`#col2-${selectedCol2}`).trigger('click')
|
||||
$(`#colG-${selectedCol2}`).trigger('click')
|
||||
$('#colW-12').trigger('click')
|
||||
$('#colU-12').trigger('click')
|
||||
setGlowAttr(enableGlow)
|
||||
})
|
||||
|
||||
$("#randomIcon").click(function() {
|
||||
|
||||
let iconPool = iconStuff.previewIcons.concat(enableSpoilers ? iconStuff.newPreviewIcons : [])
|
||||
let pickedIcon = iconPool[Math.floor(Math.random() * iconPool.length)].split(".")[0].split("_")
|
||||
let [randomForm, randomID] = pickedIcon
|
||||
|
||||
let colorCount = Object.keys(iconStuff.colors).length
|
||||
selectedForm = randomForm
|
||||
selectedIcon = randomID
|
||||
selectedCol1 = randInt(0, colorCount - 1)
|
||||
selectedCol2 = randInt(0, colorCount - 1)
|
||||
selectedColW = null
|
||||
selectedColU = null
|
||||
enableGlow = randInt(0, 2) == 1 ? 1 : 0 // 1 in 3 chance of glow
|
||||
generateIcon()
|
||||
|
||||
$('#glow').attr('src', '../assets/iconkitbuttons/streak_off.png')
|
||||
|
||||
$(`.iconTabButton[form=${selectedForm}]`).trigger('click')
|
||||
$(`#${selectedForm}-${selectedIcon}`).trigger('click')
|
||||
$(`#col1-${selectedCol1}`).trigger('click')
|
||||
$(`#col2-${selectedCol2}`).trigger('click')
|
||||
$(`#colG-${selectedCol2}`).trigger('click')
|
||||
$('#colW-12').trigger('click')
|
||||
$('#colU-12').trigger('click')
|
||||
if (enableGlow == 1) $("#glow").attr('src', $("#glow").attr('src').replace('_off', '_on'))
|
||||
else $("#glow").attr('src', $("#glow").attr('src').replace('_on', '_off'))
|
||||
})
|
||||
|
||||
$('#glowbtn').click(function () {
|
||||
|
||||
if (enableGlow) {
|
||||
$("#glow").attr('src', $("#glow").attr('src').replace('_on', '_off'))
|
||||
enableGlow = 0;
|
||||
}
|
||||
|
||||
else {
|
||||
$("#glow").attr('src', $("#glow").attr('src').replace('_off', '_on'))
|
||||
enableGlow = 1;
|
||||
}
|
||||
|
||||
icon.setGlow(enableGlow > 0, false)
|
||||
$('#glowbtn').click(function() {
|
||||
setGlowAttr(enableGlow)
|
||||
enableGlow = !enableGlow
|
||||
icon.setGlow(enableGlow, false)
|
||||
updateDetails()
|
||||
|
||||
})
|
||||
|
||||
|
||||
$(document).on('click', '.copyForm', function () {
|
||||
$('.copyForm').each(function(x, y) {$(this).children().first().attr('src', $(this).children().first().attr('src').replace('_on', '_off'))})
|
||||
formCopy = $(this).attr('form')
|
||||
|
@ -471,10 +482,10 @@ fetch('../api/iconkit').then(res => res.json()).then(iconKitData => {
|
|||
|
||||
$(document).on('click', '.iconButton', function () {
|
||||
$(".iconButton").removeClass("iconSelected");
|
||||
$(this).addClass('iconSelected');
|
||||
$(this).addClass('iconSelected')
|
||||
let oldForm = selectedForm
|
||||
selectedIcon = $(this).attr('num');
|
||||
selectedForm = $(this).attr('form');
|
||||
selectedIcon = $(this).attr('num')
|
||||
selectedForm = $(this).attr('form')
|
||||
|
||||
if (selectedForm == "ufo") { $('#colU').show(); $('#ccU').show() }
|
||||
else { $('#colU').hide(); $('#ccU').hide(); $(`#colU-12`).trigger('click'); }
|
||||
|
@ -488,99 +499,99 @@ fetch('../api/iconkit').then(res => res.json()).then(iconKitData => {
|
|||
|
||||
$(document).on('click', '.color1', function () {
|
||||
$(".color1").removeClass("iconSelected");
|
||||
$(this).addClass('iconSelected');
|
||||
selectedCol1 = $(this).attr('col');
|
||||
colorBG(1, iconStuff.colors[$(this).attr('col')]);
|
||||
$(this).addClass('iconSelected')
|
||||
selectedCol1 = $(this).attr('col')
|
||||
colorBG(1, iconStuff.colors[$(this).attr('col')])
|
||||
setColor("1", selectedCol1)
|
||||
})
|
||||
|
||||
$(document).on('click', '.color2', function () {
|
||||
$(".color2").removeClass("iconSelected");
|
||||
$(this).addClass('iconSelected');
|
||||
selectedCol2 = $(this).attr('col');
|
||||
$(this).addClass('iconSelected')
|
||||
selectedCol2 = $(this).attr('col')
|
||||
colorBG(2, iconStuff.colors[$(this).attr('col')]);
|
||||
$(`#colG-${$(this).attr('col')}`).trigger('click')
|
||||
selectedColG = $(this).attr('col');
|
||||
selectedColG = $(this).attr('col')
|
||||
setColor("2", selectedCol2)
|
||||
})
|
||||
|
||||
$(document).on('click', '.colorG', function () {
|
||||
$(".colorG").removeClass("iconSelected");
|
||||
$(this).addClass('iconSelected');
|
||||
selectedColG = $(this).attr('col');
|
||||
colorBG('G', iconStuff.colors[$(this).attr('col')]);
|
||||
$(this).addClass('iconSelected')
|
||||
selectedColG = $(this).attr('col')
|
||||
colorBG('G', iconStuff.colors[$(this).attr('col')])
|
||||
setColor("g", selectedColG)
|
||||
})
|
||||
|
||||
$(document).on('click', '.colorW', function () {
|
||||
$(".colorW").removeClass("iconSelected");
|
||||
$(this).addClass('iconSelected');
|
||||
selectedColW = $(this).attr('col');
|
||||
$(this).addClass('iconSelected')
|
||||
selectedColW = $(this).attr('col')
|
||||
if (selectedColW == 12) selectedColW = null
|
||||
colorBG('W', iconStuff.colors[$(this).attr('col')]);
|
||||
colorBG('W', iconStuff.colors[$(this).attr('col')])
|
||||
setColor("w", selectedColW)
|
||||
})
|
||||
|
||||
$(document).on('click', '.colorU', function () {
|
||||
$(".colorU").removeClass("iconSelected");
|
||||
$(this).addClass('iconSelected');
|
||||
selectedColU = $(this).attr('col');
|
||||
$(this).addClass('iconSelected')
|
||||
selectedColU = $(this).attr('col')
|
||||
if (selectedColU == 12) selectedColU = null
|
||||
colorBG('U', iconStuff.colors[$(this).attr('col')]);
|
||||
colorBG('U', iconStuff.colors[$(this).attr('col')])
|
||||
setColor("u", selectedColU)
|
||||
})
|
||||
|
||||
$("#cp1").on('input change', function() {
|
||||
colorBG(1, $(this).val(), true);
|
||||
$(".color1").removeClass("iconSelected");
|
||||
$(".color1").removeClass("iconSelected")
|
||||
selectedCol1 = $('#cp1').val().slice(1)
|
||||
setColor("1", selectedCol1)
|
||||
})
|
||||
|
||||
$("#cp2").on('input change', function() {
|
||||
colorBG(2, $(this).val(), true);
|
||||
$(".color2").removeClass("iconSelected");
|
||||
$(".color2").removeClass("iconSelected")
|
||||
selectedCol2 = $('#cp2').val().slice(1)
|
||||
setColor("2", selectedCol2)
|
||||
})
|
||||
|
||||
$("#cpG").on('input change', function() {
|
||||
colorBG('G', $(this).val(), true);
|
||||
$(".colorG").removeClass("iconSelected");
|
||||
$(".colorG").removeClass("iconSelected")
|
||||
selectedColG = $('#cpG').val().slice(1)
|
||||
setColor("g", selectedColG)
|
||||
})
|
||||
|
||||
$("#cpW").on('input change', function() {
|
||||
colorBG('W', $(this).val(), true);
|
||||
$(".colorW").removeClass("iconSelected");
|
||||
$(".colorW").removeClass("iconSelected")
|
||||
selectedColW = $('#cpW').val().slice(1)
|
||||
setColor("w", selectedColW)
|
||||
})
|
||||
|
||||
$("#cpU").on('input change', function() {
|
||||
colorBG('U', $(this).val(), true);
|
||||
$(".colorU").removeClass("iconSelected");
|
||||
$(".colorU").removeClass("iconSelected")
|
||||
selectedColU = $('#cpU').val().slice(1)
|
||||
setColor("u", selectedColU)
|
||||
})
|
||||
|
||||
|
||||
$("#getUserIcon").click(function() {
|
||||
$(`.copyForm[form=${currentForm}]`).trigger('click')
|
||||
$('#steal').show();
|
||||
$('#playerName').focus()
|
||||
$('#playerName').select()
|
||||
$('#playerName').focus()
|
||||
$('#playerName').select()
|
||||
})
|
||||
|
||||
|
||||
$('#copyToClipboard').click(function() {
|
||||
if ($(this).hasClass('greyedOut')) return
|
||||
icon.copyToClipboard()
|
||||
let copyIcon = $(this).find('img')
|
||||
$(this).addClass('greyedOut')
|
||||
copyIcon.attr('src', '../assets/iconkitbuttons/copied.png')
|
||||
copyIcon.attr('src', '/assets/iconkitbuttons/copied.png')
|
||||
setTimeout(() => {
|
||||
$(this).removeClass('greyedOut')
|
||||
copyIcon.attr('src', '../assets/iconkitbuttons/copy.png')
|
||||
copyIcon.attr('src', '/assets/iconkitbuttons/copy.png')
|
||||
}, 420);
|
||||
})
|
||||
|
||||
|
@ -595,12 +606,12 @@ fetch('../api/iconkit').then(res => res.json()).then(iconKitData => {
|
|||
})
|
||||
|
||||
let hoverText = $('#helpText').html()
|
||||
$(".help").hover(function() {
|
||||
$(".help").hover(function() {
|
||||
$(this).css('color', 'rgba(200, 255, 255)')
|
||||
$('#helpText').html($(this).attr('help'))
|
||||
$('#helpText').html($(this).attr('help'))
|
||||
}, function() {
|
||||
$(this).css('color', 'white')
|
||||
$('#helpText').html(hoverText)
|
||||
$('#helpText').html(hoverText)
|
||||
})
|
||||
|
||||
$(document).on('change', '.iconsetting', function (e) {
|
||||
|
@ -608,11 +619,11 @@ fetch('../api/iconkit').then(res => res.json()).then(iconKitData => {
|
|||
$('.iconsetting:checkbox:checked').each((i, x) => { checkedSettings.push(x.id.split('-')[1]) })
|
||||
iconSettings = checkedSettings
|
||||
switch ($(this).attr('id').slice(4)) {
|
||||
case "sort": loadColors(); break;
|
||||
case "ufo": generateIcon(); break;
|
||||
case "sort": loadColors(); break
|
||||
case "ufo": generateIcon(); break
|
||||
case "cursed":
|
||||
$('#animationOptions').hide();
|
||||
checkAnimation();
|
||||
c('#animationOptions').hide();
|
||||
checkAnimation();
|
||||
$('#robotAnimation').trigger('change');
|
||||
break;
|
||||
}
|
||||
|
@ -620,8 +631,8 @@ fetch('../api/iconkit').then(res => res.json()).then(iconKitData => {
|
|||
})
|
||||
|
||||
$('#unlockIcon').click(function() {
|
||||
if (!achievements.length) {
|
||||
fetch('../api/achievements').then(res => { res.json().then(x => {
|
||||
if (!achievements.length) {
|
||||
fetch('/api/achievements').then(res => { res.json().then(x => {
|
||||
achievements = x.achievements
|
||||
shopIcons = iconStuff.shops
|
||||
unlockMode = true
|
||||
|
@ -635,19 +646,19 @@ fetch('../api/iconkit').then(res => res.json()).then(iconKitData => {
|
|||
else { $('#lock').attr('src', $('#lock').attr('src').replace('_on.png', '.png')); $('#howto').hide() }
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
$(document).on('mouseover', '.iconButton, .color1, .color2', function () {
|
||||
if (unlockMode && achievements.length) {
|
||||
$(this).addClass('iconHover')
|
||||
let form = $(this).attr('form') || $(this).attr('colType')
|
||||
let iconNumber = $(this).attr('num') || $(this).attr('col')
|
||||
$('#howto').html(getUnlockMethod(iconNumber, form) || `<span style='color: #aaaaaa'>(no info available)</span>`)
|
||||
$('#howto').html(getUnlockMethod(iconNumber, form) || `<span style='color: #aaa'>(no info available)</span>`)
|
||||
}
|
||||
})
|
||||
|
||||
$(document).on('mouseleave', '.iconButton, .color1, .color2', function () {
|
||||
$(this).removeClass('iconHover')
|
||||
$('#howto').html("<span style='color: #aaaaaa'>(hover over an icon for info)</span>")
|
||||
$('#howto').html("<span style='color: #aaa'>(hover over an icon for info)</span>")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -657,11 +668,11 @@ fetch('../api/iconkit').then(res => res.json()).then(iconKitData => {
|
|||
if (!user || !user.length) return $("#steal").hide()
|
||||
|
||||
$(`.iconTabButton[form=${formCopy}]`).trigger('click')
|
||||
$('#glow').attr('src', '../assets/iconkitbuttons/streak_off.png')
|
||||
$('#glow').attr('src', '/assets/iconkitbuttons/streak_off.png')
|
||||
$("#steal").hide()
|
||||
enableGlow = 0
|
||||
enableGlow = false
|
||||
|
||||
let info = await fetch('../api/profile/' + user).then(res => res.json()).catch(e => {})
|
||||
let info = await fetch('/api/profile/' + user).then(res => res.json()).catch(e => {})
|
||||
if (info == "-1") info = {}
|
||||
|
||||
$(`#${formCopy}-${Math.min(info[formCopy] || 1, $(`.iconButton[form=${formCopy}]`).length)}`).trigger('click')
|
||||
|
@ -724,20 +735,21 @@ $('#animationSpeed').on('input', function() {
|
|||
})
|
||||
|
||||
$('#animationSpeedBox').change(function() {
|
||||
animationMultiplier = Number(Math.abs(Number($(this).val()) || 1).toFixed(2))
|
||||
if (animationMultiplier > 99) animationMultiplier = 99
|
||||
else if (animationMultiplier <= 0) animationMultiplier = 0.1
|
||||
animationMultiplier = Number( Math.abs( Number( $(this).val() ) || 1 ).toFixed(2) )
|
||||
animationMultiplier = clamp(animationMultiplier, 0, 99)
|
||||
animationMultiplier ||= 0.1
|
||||
$('#animationSpeed').val(animationMultiplier)
|
||||
$('#animationSpeedBox').val(animationMultiplier)
|
||||
if (icon.complex) icon.animationSpeed = animationMultiplier
|
||||
})
|
||||
|
||||
$(document).keydown(function(k) {
|
||||
if (k.keyCode == 13) { // enter
|
||||
// standard and Numpad support
|
||||
if (k.code.endsWith('Enter')) {
|
||||
if ($("#steal").is(":visible")) $("#fetchUser").trigger('click')
|
||||
else if ($(".popup").is(":visible")) return
|
||||
}
|
||||
if (k.keyCode == 27) { //esc
|
||||
if (k.code == 'Escape') {
|
||||
if ($(".popup").is(":visible")) return $('.popup').hide()
|
||||
k.preventDefault()
|
||||
$('#backButton').trigger('click')
|
||||
|
@ -751,5 +763,4 @@ $(document).on('click', '.brownbox', function (e) {
|
|||
$(document).on('click', '.popup', function () {
|
||||
$('.popup').hide()
|
||||
})
|
||||
|
||||
</script>
|
||||
</script>
|
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title>Leaderboard</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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.png">
|
||||
<link rel="icon" href="/assets/trophy.png">
|
||||
<meta id="meta-title" property="og:title" content="Leaderboards">
|
||||
<meta id="meta-desc" property="og:description" content="View Geometry Dash's leaderboards, plus an accurate and updated list of the top players.">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/trophy.png">
|
||||
|
@ -15,74 +15,74 @@
|
|||
<div id="everything" style="overflow: auto;">
|
||||
|
||||
<div id="scoreTabs">
|
||||
<img src="../assets/tab-top-on.png" class="leaderboardTab" id="topTabOn" style="display: none">
|
||||
<img src="../assets/tab-top-off.png" class="leaderboardTab leaderboardClick" id="topTabOff">
|
||||
<img src="/assets/tab-top-on.png" class="leaderboardTab" id="topTabOn" style="display: none">
|
||||
<img src="/assets/tab-top-off.png" class="leaderboardTab leaderboardClick" id="topTabOff">
|
||||
|
||||
<!-- for some GDPS'es -->
|
||||
<img src="../assets/tab-weekly-on.png" class="sideSpaceC leaderboardTab" id="weeklyTabOn" style="display: none">
|
||||
<img src="../assets/tab-weekly-off.png" class="sideSpaceC leaderboardTab leaderboardClick" id="weeklyTabOff" style="display: none">
|
||||
<img src="/assets/tab-weekly-on.png" class="sideSpaceC leaderboardTab" id="weeklyTabOn" style="display: none">
|
||||
<img src="/assets/tab-weekly-off.png" class="sideSpaceC leaderboardTab leaderboardClick" id="weeklyTabOff" style="display: none">
|
||||
|
||||
<img src="../assets/tab-accurate-on.png" class="sideSpaceC leaderboardTab" id="accurateTabOn" style="display: none">
|
||||
<img src="../assets/tab-accurate-off.png" class="sideSpaceC leaderboardTab leaderboardClick" id="accurateTabOff">
|
||||
<img src="/assets/tab-accurate-on.png" class="sideSpaceC leaderboardTab" id="accurateTabOn" style="display: none">
|
||||
<img src="/assets/tab-accurate-off.png" class="sideSpaceC leaderboardTab leaderboardClick" id="accurateTabOff">
|
||||
|
||||
<img src="../assets/tab-creators-on.png" class="sideSpaceC leaderboardTab" id="creatorTabOn" style="display: none">
|
||||
<img src="../assets/tab-creators-off.png" class="sideSpaceC leaderboardTab leaderboardClick" id="creatorTabOff">
|
||||
<img src="/assets/tab-creators-on.png" class="sideSpaceC leaderboardTab" id="creatorTabOn" style="display: none">
|
||||
<img src="/assets/tab-creators-off.png" class="sideSpaceC leaderboardTab leaderboardClick" id="creatorTabOff">
|
||||
</div>
|
||||
|
||||
<div class="popup" id="infoDiv">
|
||||
<div class="fancybox bounce center supercenter" style="width: 80vh">
|
||||
<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()">
|
||||
<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 noClick" src="../assets/corner.png" width=7%;>
|
||||
<img class="cornerPiece noClick" src="/assets/corner.png" width=7%;>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; right: 0%; width: 100%; text-align: right;">
|
||||
<a title="Boomlings Leaderboard?????" href="../boomlings"><img id="boomling" style="position: absolute; width: 6%; top: 2%; right: 1%; display: none"></a>
|
||||
<img class="cornerPiece noClick" src="../assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
<img class="cornerPiece noClick" src="/assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
</div>
|
||||
|
||||
<div id="searchBox" class="supercenter dragscroll">
|
||||
<div style="height: 4.5%"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="leaderboardBox supercenter gs" style="width: 120vh; height: 80%; pointer-events: none">
|
||||
<div id="relativeUser" class="sortDiv" style="position: relative; left: 100%; transform: translateX(4.5vh); top: 12%; width: 0.1%">
|
||||
<img class="gdButton" id="findRelative" style="margin-bottom: 1vh" title="Global Search" src="../assets/magnify.png" height="11%">
|
||||
<img class="gdButton" id="clearRelative" style="margin-bottom: 1vh; display: none" title="Clear Global Search" src="../assets/unmagnify.png" height="11%">
|
||||
<img class="gdButton" id="findRelative" style="margin-bottom: 1vh" title="Global Search" src="/assets/magnify.png" height="11%">
|
||||
<img class="gdButton" id="clearRelative" style="margin-bottom: 1vh; display: none" title="Clear Global Search" src="/assets/unmagnify.png" height="11%">
|
||||
</div>
|
||||
<div class="sortDiv" style="display: none; position: relative; left: 100%; transform: translateX(4.5vh); top: 12%; width: 0.1%">
|
||||
<img class="gdButton" id="modSort" style="margin-bottom: 1vh" title="Moderators" src="../assets/sort-mod.png" height="11%">
|
||||
<img class="gdButton" id="weeklyStats" style="margin-bottom: 1vh" title="Weekly Stats" src="../assets/sort-week.png" height="11%">
|
||||
<img class="gdButton" id="modSort" style="margin-bottom: 1vh" title="Moderators" src="/assets/sort-mod.png" height="11%">
|
||||
<img class="gdButton" id="weeklyStats" style="margin-bottom: 1vh" title="Weekly Stats" src="/assets/sort-week.png" height="11%">
|
||||
</div>
|
||||
<div class="sortDiv" style="display: none; position: relative; right: 10.5%; top: 0%; width: 0.1%; transform: translateY(-33.3%)" id="statSort">
|
||||
<img class="gdButton sortButton" style="margin-bottom: 1vh" sort="stars" title="Most stars" src="../assets/sort-stars-on.png" height="11%" id="starSort">
|
||||
<img class="gdButton sortButton" style="margin-bottom: 1vh" sort="diamonds" title="Most diamonds" src="../assets/sort-diamonds.png" height="11%">
|
||||
<img class="gdButton sortButton" style="margin-bottom: 1vh" sort="coins" title="Most coins" src="../assets/sort-coins.png" height="11%">
|
||||
<img class="gdButton sortButton" style="margin-bottom: 1vh" sort="demons" title="Most demons" src="../assets/sort-demons.png" height="11%">
|
||||
<img class="gdButton sortButton" style="margin-bottom: 1vh; display: none" sort="cp" title="Most creator points" src="../assets/sort-cp.png" height="11%" id="cpSort">
|
||||
<img class="gdButton sortButton" style="margin-bottom: 1vh" sort="stars" title="Most stars" src="/assets/sort-stars-on.png" height="11%" id="starSort">
|
||||
<img class="gdButton sortButton" style="margin-bottom: 1vh" sort="diamonds" title="Most diamonds" src="/assets/sort-diamonds.png" height="11%">
|
||||
<img class="gdButton sortButton" style="margin-bottom: 1vh" sort="coins" title="Most coins" src="/assets/sort-coins.png" height="11%">
|
||||
<img class="gdButton sortButton" style="margin-bottom: 1vh" sort="demons" title="Most demons" src="/assets/sort-demons.png" height="11%">
|
||||
<img class="gdButton sortButton" style="margin-bottom: 1vh; display: none" sort="cp" title="Most creator points" src="/assets/sort-cp.png" height="11%" id="cpSort">
|
||||
</div>
|
||||
</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()">
|
||||
<img class="gdButton yesClick" id="backButton" src="/assets/back.png" height="30%" onclick="backButton()">
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; top: 2.5%; right: 2%; width: 10%; text-align: right;">
|
||||
<img class="gdButton" src="../assets/smallinfo.png" width="32%" onclick="$('#infoDiv').show()">
|
||||
<img class="gdButton" src="/assets/smallinfo.png" width="32%" onclick="$('#infoDiv').show()">
|
||||
</div>
|
||||
|
||||
<div id="discordLinks" style="display: none; position:absolute; top: 12%; right: 1.5%; width: 21%; text-align: right;">
|
||||
<a id="discord" target="_blank" title="Official leaderboard Discord!" href="https://discord.gg/leaderboard"><img class="gdButton" src="../assets/discord.png" width="20%"></a>
|
||||
<a id="altDiscord" target="_blank" title="Accurate leaderboard Discord!" style="display: none; filter: hue-rotate(300deg)" href="https://discord.gg/Uz7pd4d"><img class="gdButton" src="../assets/discord.png" width="20%"></a>
|
||||
<a id="discord" target="_blank" title="Official leaderboard Discord!" href="https://discord.gg/leaderboard"><img class="gdButton" src="/assets/discord.png" width="20%"></a>
|
||||
<a id="altDiscord" target="_blank" title="Accurate leaderboard Discord!" style="display: none; filter: hue-rotate(300deg)" href="https://discord.gg/Uz7pd4d"><img class="gdButton" src="/assets/discord.png" width="20%"></a>
|
||||
</div>
|
||||
|
||||
<div class="supercenter" id="loading" style="height: 10%; top: 47%; display: none;">
|
||||
<img class="spin noSelect" src="../assets/loading.png" height="105%">
|
||||
<img class="spin noSelect" src="/assets/loading.png" height="105%">
|
||||
</div>
|
||||
|
||||
<div class="popup" id="userSearch">
|
||||
|
@ -90,10 +90,10 @@
|
|||
<h2 class="smaller center" style="font-size: 5.5vh; margin-top: 1%">User Search</h2>
|
||||
<p>Enter the <cy>username</cy> of a player to find their position in the <ca>global leaderboard</ca>.</p>
|
||||
<input type="text" id="relativeName" placeholder="Username" style="height: 8vh; width: 90%; text-align: center; margin-top: 0.5%; margin-bottom: 5%"><br>
|
||||
<img src="../assets/btn-cancel.png" class="postButton gdButton center" style="width: 32%; margin-right: 1%" onclick="$('#userSearch').hide()">
|
||||
<img src="../assets/btn-submit.png" class="postButton gdButton center" style="width: 32%; margin-left: 1%" id="relativeSearch">
|
||||
<img src="/assets/btn-cancel.png" class="postButton gdButton center" style="width: 32%; margin-right: 1%" onclick="$('#userSearch').hide()">
|
||||
<img src="/assets/btn-submit.png" class="postButton gdButton center" style="width: 32%; margin-left: 1%" id="relativeSearch">
|
||||
<p id="relativeStatus" style="display: none"></p>
|
||||
<img class="closeWindow gdButton" src="../assets/close.png" width="13%" style="position: absolute; top: -13.5%; left: -6vh" onclick="$('#userSearch').hide()">
|
||||
<img class="closeWindow gdButton" src="/assets/close.png" width="13%" style="position: absolute; top: -13.5%; left: -6vh" onclick="$('#userSearch').hide()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -101,35 +101,36 @@
|
|||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/6.2.2/browser/pixi.js"></script>
|
||||
<script type="text/javascript" src="../iconkit/icon.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="../dragscroll.js"></script>
|
||||
<script type="text/javascript" src="/iconkit/icon.js"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/dragscroll.js"></script>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
let type
|
||||
let sort = "stars"
|
||||
let modMode = false
|
||||
let weekly = false
|
||||
let showWeek = localStorage.weeklyStats == "1"
|
||||
let trophies = [1, 3, 10, 25, 50, 75, 100]
|
||||
let trophies = [1, 3, 10, 25, 50, 75, 100] // it seems this can be optimized into a const Uint8Array
|
||||
let boomColors = ["red", "orange", "yellow", "green", "teal", "blue", "pink"]
|
||||
|
||||
let top250Text =
|
||||
let top250Text =
|
||||
`The <cg>Stars</cg> leaderboard contains the <cg>top 100 players</cg>, sorted by <cy>star</cy> value. It was formerly <co>inaccurate</co> but should be much more <cb>reliable</cb> now.`
|
||||
|
||||
let topGDPSText =
|
||||
let topGDPSText =
|
||||
`The <cg>Stars</cg> leaderboard contains the <cg>top players</cg>, sorted by <cy>star</cy> value.`
|
||||
|
||||
let weeklyText =
|
||||
let weeklyText =
|
||||
`The <cg>Weekly</cg> leaderboard displays the players who have gained the most <cy>stars</cy> in the <cb>past week</cb>. It was officially <co>removed</co> in update 2.0, but lives on in some GDPS'es.`
|
||||
|
||||
let accurateText =
|
||||
`The <cg>Accurate Leaderboard</cg> is an <cy>externally managed</cy> leaderboard which aims to provide <ca>detailed</ca> and hacker-proof stats on top players. It also once provided a way to view an <cg>accurate</cg> list of players with the most <cy>stars</cy> when the official leaderboards were <ca>frozen</ca>. It is managed by <cb>XShadowWizardX, Pepper360, Octeract</cb>, and many many other helpers.`
|
||||
|
||||
let creatorText =
|
||||
let creatorText =
|
||||
`The <cg>Creators Leaderboard</cg> is sorted by <cg>creator points</cg>, rather than stars. A player's <cg>creator points</cg> (CP) is calculated by counting their number of <cy>star rated</cy> levels, plus an extra point for every level that has been <cb>featured</cb>, plus an additional point for <co>epic rated</co> levels.`
|
||||
|
||||
if (showWeek) $('#weeklyStats').attr('src', '../assets/sort-week-on.png')
|
||||
if (showWeek) $('#weeklyStats').attr('src', '/assets/sort-week-on.png')
|
||||
|
||||
function infoText(text, altDiscord) {
|
||||
$('#infoText').html(text)
|
||||
|
@ -147,7 +148,7 @@ function leaderboard(val, leaderboardParams, scrollTo) {
|
|||
$('#clearRelative').hide()
|
||||
$('#loading').show()
|
||||
|
||||
Fetch("../api/leaderboard?" + (leaderboardParams || `count=250&${val}&type=${sort}${modMode ? "&mod=1" : ""}`)).then(res => {
|
||||
Fetch("/api/leaderboard?" + (leaderboardParams || `count=250&${val}&type=${sort}${modMode ? "&mod=1" : ""}`)).then(res => {
|
||||
|
||||
if (gdps && !didGDPSStuff) {
|
||||
didGDPSStuff = true
|
||||
|
@ -155,7 +156,7 @@ function leaderboard(val, leaderboardParams, scrollTo) {
|
|||
$('#accurateTabOn').remove()
|
||||
$('#accurateTabOff').remove()
|
||||
|
||||
Fetch('../api/gdps?current=1').then(ps => {
|
||||
Fetch('/api/gdps?current=1').then(ps => {
|
||||
if (weekly) return
|
||||
else if (ps.weeklyLeaderboard) { $('#weeklyTabOff').show(); weekly = true }
|
||||
else $('#scoreTabs').css('margin-left', '-29vh')
|
||||
|
@ -174,14 +175,14 @@ function leaderboard(val, leaderboardParams, scrollTo) {
|
|||
$('#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 (modMode && sort == "cp") res = res.sort(function(a, b){return b.cp - a.cp})
|
||||
let wk = type == "weekly"
|
||||
|
||||
if ((leaderboardParams ? true : val == type) && res != -1 && res.length) res.forEach((x, y) => {
|
||||
if ((!!leaderboardParams || val == type) && res != -1 && res.length) res.forEach((x, y) => {
|
||||
|
||||
let wp = x.weeklyProgress || {}
|
||||
let cosmetics = x.cosmetics || {}
|
||||
|
||||
|
||||
let bgCol = cosmetics.bgColor
|
||||
let bgString = bgCol ? ` style="background-color: rgb(${bgCol.join()})"` : ""
|
||||
|
||||
|
@ -194,32 +195,32 @@ function leaderboard(val, leaderboardParams, scrollTo) {
|
|||
$('#searchBox').append(`<div class="searchresult leaderboardSlot"${bgString}>
|
||||
|
||||
<div class="center ranking">
|
||||
${x.icon.icon == -1 && type == "accurate" ? `<img class="spaced" src="./assets/trophies/${trophies.findIndex(z => y+1 <= z) + 1}.png" height="150%" style="margin-bottom: 0%; transform:scale(1.1)">` :
|
||||
${x.icon.icon == -1 && type == "accurate" ? `<img class="spaced" src="./assets/trophies/${trophies.findIndex(z => y+1 <= z) + 1}.png" height="150%" style="margin-bottom: 0%; transform:scale(1.1)">` :
|
||||
`<gdicon dontload="true" class="leaderboardIcon" iconID=${x.icon.icon} cacheID=${x.playerID} iconForm="${x.icon.form}" col1="${x.icon.col1}" col2="${x.icon.col2}" glow="${x.icon.glow}"></gdicon>`}
|
||||
<h2 class="slightlySmaller" style="transform: scale(${1 - (Math.max(0, String(x.rank).length - 1) * 0.1)})">${x.rank}</h2>
|
||||
</div>
|
||||
|
||||
<div class="leaderboardSide">
|
||||
<div class="leaderboardStars">
|
||||
${x.moderator ? `<img title="${x.moderator == 2 ? "Elder " : ""}Moderator" src="../assets/mod${x.moderator == 2 ? "-elder" : ""}.png" style="width: 9%; cursor: help; padding-right: 1.6%; transform: translateY(0.7vh)">` : ""}
|
||||
<h2 class="leaderboardName small inline gdButton" style="margin-top: 1.5%${nameString || (x.moderator == 2 ? "; color: #FF9977;" : "")}"><a href="${onePointNine ? `../search/${x.playerID}?user` : `../u/${x.accountID}.`}" accountID="${x.accountID}">${x.username}</a></h2>
|
||||
<h3 class="inline${x.stars >= 100000 ? " yellow" : ""}" style="margin-left: 4%; margin-top: 2%; 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>
|
||||
${x.moderator ? `<img title="${x.moderator == 2 ? "Elder " : ""}Moderator" src="/assets/mod${x.moderator == 2 ? "-elder" : ""}.png" style="width: 9%; cursor: help; padding-right: 1.6%; transform: translateY(0.7vh)">` : ""}
|
||||
<h2 class="leaderboardName small inline gdButton" style="margin-top: 1.5%${nameString || (x.moderator == 2 ? "; color: #F97;" : "")}"><a href="${onePointNine ? `../search/${x.playerID}?user` : `../u/${x.accountID}.`}" accountID="${x.accountID}">${x.username}</a></h2>
|
||||
<h3 class="inline${x.stars >= 100000 ? " yellow" : ""}" style="margin-left: 4%; margin-top: 2%; 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>
|
||||
</div>
|
||||
|
||||
<h3 class="lessSpaced leaderboardStats">
|
||||
${type != "weekly" ? "" : `<span${x.stars >= 1000 ? " class='yellow'" : ""}>+${x.stars}</span> <img class="help valign" src="../assets/star.png" title="Star Gain">`}
|
||||
${wk || onePointNine ? "" : `<span${x.diamonds >= 65535 ? ` class='blue'>` : ">"}${x.diamonds}</span> <img class="help valign" src="../assets/diamond.png" title="Diamonds">`}
|
||||
${wk ? " " : `<span${x.coins >= 149 ? " class='yellow'" : ""}>${x.coins}</span> <img class="help valign" src="../assets/coin.png" title="Secret Coins">`}
|
||||
${wk || onePointNine ? "" : `<span${x.userCoins >= 10000 ? " class='brightblue'" : ""}>${x.userCoins}</span> <img class="help valign" src="../assets/silvercoin.png" title="User Coins">`}
|
||||
${wk ? "" : `<span${x.demons >= 1000 ? " class='brightred'" : ""}>${x.demons}</span> <img class="help valign" src="../assets/demon.png" title="Demons">`}
|
||||
${x.cp <= 0 ? "" : `<span${x.cp >= 100 ? " class='yellow'" : ""}>${x.cp}</span> <img class="help valign" src="../assets/cp.png" title="Creator Points">`}
|
||||
${type != "weekly" ? "" : `<span${x.stars >= 1000 ? " class='yellow'" : ""}>+${x.stars}</span> <img class="help valign" src="/assets/star.png" title="Star Gain">`}
|
||||
${wk || onePointNine ? "" : `<span${x.diamonds >= 65535 ? ` class='blue'>` : ">"}${x.diamonds}</span> <img class="help valign" src="/assets/diamond.png" title="Diamonds">`}
|
||||
${wk ? " " : `<span${x.coins >= 149 ? " class='yellow'" : ""}>${x.coins}</span> <img class="help valign" src="/assets/coin.png" title="Secret Coins">`}
|
||||
${wk || onePointNine ? "" : `<span${x.userCoins >= 10000 ? " class='brightblue'" : ""}>${x.userCoins}</span> <img class="help valign" src="/assets/silvercoin.png" title="User Coins">`}
|
||||
${wk ? "" : `<span${x.demons >= 1000 ? " class='brightred'" : ""}>${x.demons}</span> <img class="help valign" src="/assets/demon.png" title="Demons">`}
|
||||
${x.cp <= 0 ? "" : `<span${x.cp >= 100 ? " class='yellow'" : ""}>${x.cp}</span> <img class="help valign" src="/assets/cp.png" title="Creator Points">`}
|
||||
</h3>
|
||||
|
||||
<h3 class="lessSpaced leaderboardStats weeklyStuff"}>
|
||||
<span${wp.diamonds >= 250 ? " class='blue'" : ""}>${wp.diamonds >= 0 ? "+" : ""}${wp.diamonds}</span> <img class="help valign" src="../assets/diamond.png" title="Diamond Gain">
|
||||
<span${wp.stars >= 1000 ? " class='yellow'" : ""}>${wp.stars >= 0 ? "+" : ""}${wp.stars}</span> <img class="help valign" src="../assets/star.png" title="Star Gain">
|
||||
<span${wp.userCoins >= 250 ? " class='brightblue'" : ""}>${wp.userCoins >= 0 ? "+" : ""}${wp.userCoins}</span> <img class="help valign" src="../assets/silvercoin.png" title="User Coin Gain">
|
||||
<span${wp.demons >= 25 ? " class='brightred'" : ""}>${wp.demons >= 0 ? "+" : ""}${wp.demons}</span> <img class="help valign" src="../assets/demon.png" title="Demon Gain">
|
||||
<span${wp.diamonds >= 250 ? " class='blue'" : ""}>${wp.diamonds >= 0 ? "+" : ""}${wp.diamonds}</span> <img class="help valign" src="/assets/diamond.png" title="Diamond Gain">
|
||||
<span${wp.stars >= 1000 ? " class='yellow'" : ""}>${wp.stars >= 0 ? "+" : ""}${wp.stars}</span> <img class="help valign" src="/assets/star.png" title="Star Gain">
|
||||
<span${wp.userCoins >= 250 ? " class='brightblue'" : ""}>${wp.userCoins >= 0 ? "+" : ""}${wp.userCoins}</span> <img class="help valign" src="/assets/silvercoin.png" title="User Coin Gain">
|
||||
<span${wp.demons >= 25 ? " class='brightred'" : ""}>${wp.demons >= 0 ? "+" : ""}${wp.demons}</span> <img class="help valign" src="/assets/demon.png" title="Demon Gain">
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
|
@ -249,7 +250,7 @@ function leaderboard(val, leaderboardParams, scrollTo) {
|
|||
}).catch(e => {console.log(e); $('#loading').hide();})
|
||||
}
|
||||
|
||||
// $('#boomling').attr('src', `../assets/boomlings/${boomColors[Math.floor(Math.random() * boomColors.length)]}.png`)
|
||||
// $('#boomling').attr('src', `../assets/boomlings/${boomColors[randInt(0, boomColors.length)]}.png`)
|
||||
|
||||
$(document).on('click', '.sortButton', function () {
|
||||
if ($('#loading').is(":visible")) return
|
||||
|
@ -261,7 +262,7 @@ $(document).on('click', '.sortButton', function () {
|
|||
})
|
||||
|
||||
$('#topTabOff').click(function() {
|
||||
if (type == "top") return;
|
||||
if (type == "top") return
|
||||
type = "top"
|
||||
leaderboard(type)
|
||||
$('.leaderboardTab').hide();
|
||||
|
@ -274,7 +275,7 @@ $('#topTabOff').click(function() {
|
|||
})
|
||||
|
||||
$('#accurateTabOff').click(function() {
|
||||
if (type == "accurate") return;
|
||||
if (type == "accurate") return
|
||||
type = "accurate"
|
||||
leaderboard(type)
|
||||
$('.leaderboardTab').hide();
|
||||
|
@ -287,7 +288,7 @@ $('#accurateTabOff').click(function() {
|
|||
})
|
||||
|
||||
$('#weeklyTabOff').click(function() {
|
||||
if (type == "weekly" || !gdps) return;
|
||||
if (type == "weekly" || !gdps) return
|
||||
type = "weekly"
|
||||
leaderboard(type)
|
||||
$('.leaderboardTab').hide();
|
||||
|
@ -299,7 +300,7 @@ $('#weeklyTabOff').click(function() {
|
|||
})
|
||||
|
||||
$('#creatorTabOff').click(function() {
|
||||
if (type == "creator") return;
|
||||
if (type == "creator") return
|
||||
type = "creator"
|
||||
leaderboard(type)
|
||||
$('.leaderboardTab').hide();
|
||||
|
@ -313,7 +314,7 @@ $('#creatorTabOff').click(function() {
|
|||
$('#modSort').click(function() {
|
||||
modMode = !modMode
|
||||
$(this).attr('src', `../assets/sort-mod${modMode ? "-on" : ""}.png`)
|
||||
if (modMode) {
|
||||
if (modMode) {
|
||||
$('#cpSort').show();
|
||||
$('#statSort').css('transform', 'translateY(-26.7%')
|
||||
}
|
||||
|
@ -348,7 +349,7 @@ $('#relativeSearch').click(function() {
|
|||
let relativeUsername = $('#relativeName').val()
|
||||
if (relativeLoading || !relativeUsername) return
|
||||
relativeLoading = true
|
||||
Fetch("../api/profile/" + relativeUsername).then(foundUser => {
|
||||
Fetch("/api/profile/" + relativeUsername).then(foundUser => {
|
||||
if (foundUser && foundUser.accountID && foundUser.rank) {
|
||||
leaderboard(null, "type=relative&accountID=" + foundUser.accountID, foundUser.accountID)
|
||||
$('#userSearch').hide()
|
||||
|
|
129
html/level.html
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title>[[NAME]] ([[ID]])</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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/difficulties/[[DIFFICULTYFACE]].png">
|
||||
<link rel="icon" href="/assets/difficulties/[[DIFFICULTYFACE]].png">
|
||||
<meta id="meta-title" property="og:title" content="[[NAME]] by [[AUTHOR]]">
|
||||
<meta id="meta-desc" property="og:description" content="ID: [[ID]] | Stars: [[STARS]] | Difficulty: [[DIFFICULTY]] | Downloads: [[DOWNLOADS]] | Likes: [[LIKES]] | Length: [[LENGTH]] | Song: [[SONGNAME]] ([[SONGID]])">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/difficulties/[[DIFFICULTYFACE]].png">
|
||||
|
@ -24,7 +24,7 @@
|
|||
<br>GD Version: <cy>[[GAMEVERSION]]</cy>
|
||||
[[OBJECTINFO]][[REQUESTED]]
|
||||
</p>
|
||||
<img src="../assets/ok.png" width=20%; class="gdButton center closeWindow">
|
||||
<img src="/assets/ok.png" width=20%; class="gdButton center closeWindow">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
|||
<p class="bigger center" style="line-height: 5vh; margin-top: 1.5vh;">
|
||||
<cy class="pre">[[NAME]]</cy> has been added to your <a class="youCanClickThis2" style="color:lime" href="../search/levels?type=saved">saved levels</a> list.
|
||||
</p>
|
||||
<img src="../assets/ok.png" width=20%; class="gdButton center" onclick="savedLevel()">
|
||||
<img src="/assets/ok.png" width=20%; class="gdButton center" onclick="savedLevel()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -44,8 +44,8 @@
|
|||
<p class="bigger center" style="line-height: 5vh; margin-top: 1.5vh;">
|
||||
Are you sure you want to <cr>delete</cr> this level from your <a class="youCanClickThis2"style="color:lime" href="../search/levels?type=saved">saved levels </a>list?
|
||||
</p>
|
||||
<img src="../assets/btn-no.png" height=25%; class="gdButton center closeWindow">
|
||||
<img src="../assets/btn-yes.png" height=25%; class="gdButton center sideSpaceB" onclick="deleteLevel()">
|
||||
<img src="/assets/btn-no.png" height=25%; class="gdButton center closeWindow">
|
||||
<img src="/assets/btn-yes.png" height=25%; class="gdButton center sideSpaceB" onclick="deleteLevel()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -55,15 +55,15 @@
|
|||
<p class="bigger center" style="line-height: 5vh; margin-top: 1.5vh;">
|
||||
<cy>Level analysis</cy> is currently <cr>blocked</cr> by <ca>RobTop</ca>. We don't know when or if it will be re-enabled.<br><a class="youCanClickThis" style="color:aqua" href="./analyze/[[ID]]">(click to try anyways)</a>
|
||||
</p>
|
||||
<img src="../assets/ok.png" width=20%; class="gdButton center" onclick="$('.popup').hide()">
|
||||
<img src="/assets/ok.png" width=20%; class="gdButton center" onclick="$('.popup').hide()">
|
||||
</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">
|
||||
<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%">
|
||||
|
@ -73,17 +73,17 @@
|
|||
<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">
|
||||
<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%;>
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%;>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; right: 0%; width: 100%; text-align: right;">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
</div>
|
||||
|
||||
<div class="center" style="width: 70%; margin: 1% auto">
|
||||
|
@ -93,31 +93,31 @@
|
|||
<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/[[ACCOUNTID]].">By [[AUTHOR]]</a></h2>
|
||||
<h2 class="inline slightlySmaller normalCursor sideSpaceC">
|
||||
<img class="inline valign" id="copiedBadge" style="display: none; height: 60%; cursor:help" src="../assets/copied.png" title="Level is a copy or a collaboration">
|
||||
<img class="inline valign" id="largeBadge" style="display: none; height: 60%; margin-left: -7%; cursor:help" src="../assets/large.png" title="Contains more than 40,000 objects">
|
||||
<img class="inline valign" id="2pBadge" style="display: none; height: 60%; margin-left: -7%; cursor:help" src="../assets/twoPlayer.png" title="Two player level">
|
||||
<img class="inline valign" id="copiedBadge" style="display: none; height: 60%; cursor:help" src="/assets/copied.png" title="Level is a copy or a collaboration">
|
||||
<img class="inline valign" id="largeBadge" style="display: none; height: 60%; margin-left: -7%; cursor:help" src="/assets/large.png" title="Contains more than 40,000 objects">
|
||||
<img class="inline valign" id="2pBadge" style="display: none; height: 60%; margin-left: -7%; cursor:help" src="/assets/twoPlayer.png" title="Two player level">
|
||||
</h2><br>
|
||||
<img class="inline spaced dailyLevel" id="dailyIcon" style="height:90%; display: none; margin-right: 0.5%; margin-top: 0.4%; vertical-align: middle;">
|
||||
<h1 class="inline smallerer spaced dailyLevel" style="display: none; margin: 0 0 0 0">#[[DAILYNUMBER]]<span style="font-size: 2.5vh; vertical-align: middle;" class="h3Size" id="dailyTime"></span></h1>
|
||||
</div>
|
||||
|
||||
<div class="center valign" style="position:absolute; top: 10.5%; left: 27%; transform:scale(0.8); height: 100%; width: 20%">
|
||||
<img class="spaced" src="../assets/difficulties/[[DIFFICULTYFACE]].png" height="15%" style="margin-bottom: 0%">
|
||||
<img class="spaced" src="/assets/difficulties/[[DIFFICULTYFACE]].png" height="15%" style="margin-bottom: 0%">
|
||||
<h1 class="smaller" id="difficultytext" style="transform:scale(0.9);">[[DIFFICULTY]]</h1>
|
||||
<h1 class="smaller inline stars" style="transform:scale(0.9)">[[STARS]]</h1> <img class="inline stars" src="../assets/star.png" height=4%; style="transform:translateY(-12%)"><br class="stars">
|
||||
<h1 class="smaller inline diamonds" style="transform:scale(0.9)">[[DIAMONDS]]</h1> <img class="inline diamonds" src="../assets/diamond.png" height=4%; style="transform:translateY(-12%)">
|
||||
<h1 class="smaller inline demonList" style="transform:scale(0.9); display: none;">#[[DEMONLIST]]</h1> <img class="inline demonList" src="../assets/demon.png" height=4.5%; style="transform:translateY(-7%); display: none; margin-left: 1.5%">
|
||||
<h1 class="smaller inline stars" style="transform:scale(0.9)">[[STARS]]</h1> <img class="inline stars" src="/assets/star.png" height=4%; style="transform:translateY(-12%)"><br class="stars">
|
||||
<h1 class="smaller inline diamonds" style="transform:scale(0.9)">[[DIAMONDS]]</h1> <img class="inline diamonds" src="/assets/diamond.png" height=4%; style="transform:translateY(-12%)">
|
||||
<h1 class="smaller inline demonList" style="transform:scale(0.9); display: none;">#[[DEMONLIST]]</h1> <img class="inline demonList" src="/assets/demon.png" height=4.5%; style="transform:translateY(-7%); display: none; margin-left: 1.5%">
|
||||
<div id="coins" style="margin-top: 3%"></div>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; top: 20%; right: 0%; height: 38%; width: 40%; line-height: 8.5vh">
|
||||
<img class="valign inline spaced" src="../assets/download.png" height=15% style="margin-right: 2%">
|
||||
<img class="valign inline spaced" src="/assets/download.png" height=15% style="margin-right: 2%">
|
||||
<h1 class="valign inline smaller spaced">[[DOWNLOADS]]</h1><br>
|
||||
<img id="likeImg" class="valign inline spaced" src="../assets/like.png" height=15% style="margin-right: 2%">
|
||||
<img id="likeImg" class="valign inline spaced" src="/assets/like.png" height=15% style="margin-right: 2%">
|
||||
<h1 class="valign inline smaller spaced">[[LIKES]]</h1><br>
|
||||
<img class="valign inline spaced" src="../assets/time.png" height=15% style="margin-right: 2%">
|
||||
<img class="valign inline spaced" src="/assets/time.png" height=15% style="margin-right: 2%">
|
||||
<h1 class="valign inline smaller spaced">[[LENGTH]]</h1><br>
|
||||
<img class="valign inline spaced orbs" src="../assets/orbs.png" height=15% style="margin-right: 2%">
|
||||
<img class="valign inline spaced orbs" src="/assets/orbs.png" height=15% style="margin-right: 2%">
|
||||
<h1 class="valign inline smaller spaced orbs">[[ORBS]]</h1>
|
||||
</div>
|
||||
|
||||
|
@ -129,16 +129,16 @@
|
|||
<div style="margin-left: 0.5%">
|
||||
<h1 class="pre slightlySmaller" id="songname">[[SONGNAME]]</h1>
|
||||
<h2 class="pre smaller">By: [[SONGAUTHOR]]<!--
|
||||
--><img id="scout" title="Artist is scouted" style="display: none; margin-left: 1.5%; filter: hue-rotate(-55deg);" class="help artistIcon valign" src="../assets/check.png" width="5%"><!--
|
||||
--><img id="whitelist" title="Artist is whitelisted" style="display: none" class="help artistIcon valign" src="../assets/check.png" width="5%"><!--
|
||||
--> <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%" title="Check song verification" class="gdButton valign" src="../assets/btn-check.png" width="16%">
|
||||
--><img id="scout" title="Artist is scouted" style="display: none; margin-left: 1.5%; filter: hue-rotate(-55deg);" class="help artistIcon valign" src="/assets/check.png" width="5%"><!--
|
||||
--><img id="whitelist" title="Artist is whitelisted" style="display: none" class="help artistIcon valign" src="/assets/check.png" width="5%"><!--
|
||||
--> <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%" title="Check song verification" 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" title="Play Song" id="playSong" 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" title="Play Song" 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">
|
||||
|
@ -146,20 +146,20 @@
|
|||
</div>
|
||||
|
||||
<div class="center noClick" style="position:absolute; top: 24%; right: 0%; min-width: 100%">
|
||||
<img class="gdButton yesClick" id="playButton" src="../assets/play.png" width="11%">
|
||||
<img class="gdButton yesClick" id="playButton" src="/assets/play.png" width="11%">
|
||||
</div>
|
||||
|
||||
<div class="levelButtons" style="position:absolute; top: 46%; right: 3.5%; transform: translateY(-50%); height: 75%;">
|
||||
<img class="gdButton sideButton" title="Save level" id="saveButton" src="../assets/plus.png" onclick="$('#saveDiv').show(); saveLevel()"><br>
|
||||
<img class="gdButton sideButton" title="Level Info" id="infoButton" src="../assets/info.png" onclick="$('#infoDiv').show()"><br>
|
||||
<!-- <img class="gdButton sideButton" title="Rate Level" id="likeButton" src="../assets/vote.png" onclick="$('#likeDiv').show()"><br> -->
|
||||
<a href="./analyze/[[ID]]" id="analyzeLink"><img id="analyzeBtn" title="Analyze Level" class="gdButton sideButton" src="../assets/edit.png"></a><br>
|
||||
<a href="./comments/[[ID]]"><img class="gdButton sideButton" title="View Comments" src="../assets/comment.png"></a><br>
|
||||
<a href="./leaderboard/[[ID]]"><img id="leaderboardbtn" title="View Leaderboard" class="gdButton sideButton" src="../assets/leaderboard.png"></a><br>
|
||||
<img class="gdButton sideButton" title="Save level" id="saveButton" src="/assets/plus.png" onclick="$('#saveDiv').show(); saveLevel()"><br>
|
||||
<img class="gdButton sideButton" title="Level Info" id="infoButton" src="/assets/info.png" onclick="$('#infoDiv').show()"><br>
|
||||
<!-- <img class="gdButton sideButton" title="Rate Level" id="likeButton" src="/assets/vote.png" onclick="$('#likeDiv').show()"><br> -->
|
||||
<a href="./analyze/[[ID]]" id="analyzeLink"><img id="analyzeBtn" title="Analyze Level" class="gdButton sideButton" src="/assets/edit.png"></a><br>
|
||||
<a href="./comments/[[ID]]"><img class="gdButton sideButton" title="View Comments" src="/assets/comment.png"></a><br>
|
||||
<a href="./leaderboard/[[ID]]"><img id="leaderboardbtn" title="View Leaderboard" 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">
|
||||
<img class="gdButton yesClick" id="backButton" src="../assets/back.png" height="30%" onclick="backButton()">
|
||||
<img class="gdButton yesClick" id="backButton" src="/assets/back.png" height="30%" onclick="backButton()">
|
||||
</div>
|
||||
<div id="copied" style="display: none;">
|
||||
<div class="copied center noClick" style="position:absolute; top: 36%; left: 50%; transform: translate(-50%,-50%); width: 90vh">
|
||||
|
@ -171,7 +171,7 @@
|
|||
|
||||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script>
|
||||
|
||||
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 liking a level <a class="menuLink" target="_blank" href="https://github.com/GDColon/GDBrowser/blob/master/api/post/like.js">here</a>.'
|
||||
|
@ -193,22 +193,22 @@ if (window.location.href.endsWith('?download')) $('#infoDiv').show()
|
|||
"Get a life", "...", "bruh moment", "Etched into thy's memory!", "h", "I feel physical pain", "Play it in GD!", "[[ID]]", "go away", "Every copy costs 2 cents!", "Un-copied!", "Copied++", "C O P I E D", "help me please", "Open GD to play the level!", "pretend you're playing it", "Anotha one!"]
|
||||
|
||||
let copies = 0
|
||||
let animated = false;
|
||||
let freeze = false;
|
||||
let animated = false
|
||||
let freeze = false
|
||||
let dailyTime = Number('[[NEXTDAILY]]') || null
|
||||
|
||||
$('#playButton').click(function () {
|
||||
if (!($('#copied').is(':animated')) && !animated) {
|
||||
animated = true;
|
||||
animated = true
|
||||
copies += 1
|
||||
$('#copied').stop().fadeIn(200).delay(500).fadeOut(500, function() {
|
||||
animated = false
|
||||
if (copies > 1) $('#copiedText').text(copyMessages[Math.floor(Math.random()*(copies > 4 ? copyMessages.length : 6))].replace("[C]", copies))
|
||||
if (copies > 1) $('#copiedText').text(copyMessages[randInt(0, copies > 4 ? copyMessages.length : 6)].replace("[C]", copies))
|
||||
})
|
||||
}
|
||||
var temp = $("<input>");
|
||||
$("body").append(temp);
|
||||
temp.val('[[ID]]').select();
|
||||
$("body").append(temp)
|
||||
temp.val('[[ID]]').select()
|
||||
document.execCommand("copy"); temp.remove()
|
||||
})
|
||||
$('.closeWindow').click(function () { if (!freeze) $(".popup").attr('style', 'display: none;') })
|
||||
|
@ -238,7 +238,7 @@ else {
|
|||
.replace('[[TIME1]]', "")
|
||||
.replace('[[TIME2]]', "")
|
||||
.replace('[[UPLOAD]]', "")
|
||||
.replace('[[UPDATE]]', "") +
|
||||
.replace('[[UPDATE]]', "") +
|
||||
`<br><a id="additional" class="youCanClickThis" href="/[[ID]]?download"><ca>Download additional info</ca></a>`
|
||||
)}
|
||||
|
||||
|
@ -251,14 +251,13 @@ if ([[DIAMONDS]] == 0 || !'[[DEMONLIST]]'.startsWith("[")) $('.diamonds').hide()
|
|||
|
||||
if (!'[[DEMONLIST]]'.startsWith("[")) {
|
||||
$('.demonList').show()
|
||||
$('#leaderboardbtn').attr('src', '../assets/demonleaderboard.png').parent().attr('href', '../demon/[[DEMONLIST]]')
|
||||
$('#leaderboardbtn').attr('src', '/assets/demonleaderboard.png').parent().attr('href', '../demon/[[DEMONLIST]]')
|
||||
}
|
||||
else $('.demonList').remove()
|
||||
|
||||
if (!'[[DAILYNUMBER]]'.startsWith("[")) {
|
||||
$('#dailyIcon').attr('src', `../assets/crown-${'[[WEEKLY]]'.startsWith("[") ? "daily" : "weekly"}.png`)
|
||||
$('.dailyLevel').show()
|
||||
|
||||
if (dailyTime) {
|
||||
$('#dailyTime').html(` (${colonize(dailyTime, true)})`)
|
||||
setInterval(() => {
|
||||
Potentially unsafe external linkExternal links without noopener/noreferrer are a potential security risk. ## Potentially unsafe external link
External links without noopener/noreferrer are a potential security risk.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/75)
Is this because of using "/" instead of "../"? Is this because of using "/" instead of "../"?
|
||||
|
@ -282,10 +281,10 @@ if (!"[[GDPS]]".startsWith("[")) {
|
|||
}
|
||||
$('#leaderboardbtn').hide()
|
||||
$('#checkSong').remove()
|
||||
}
|
||||
}
|
||||
|
||||
if ("[[SONGAUTHOR]]" == "Unknown" || "[[INVALIDSONG]]" == "true") $('.songLink').hide()
|
||||
if ("[[DISLIKED]]" == "true") $('#likeImg').attr('src', '../assets/dislike.png').css('transform', 'translateY(20%)')
|
||||
if ("[[DISLIKED]]" == "true") $('#likeImg').attr('src', '/assets/dislike.png').css('transform', 'translateY(20%)')
|
||||
|
||||
if ($("#additional").hasClass('downloadDisabled')) {
|
||||
$('#analyzeLink').removeAttr('href')
|
||||
|
@ -295,9 +294,9 @@ if ($("#additional").hasClass('downloadDisabled')) {
|
|||
}
|
||||
|
||||
let coinColor = [[VERIFIEDCOINS]] ? "silvercoin" : "browncoin"
|
||||
if ([[COINS]] > 0) $("#coins").append(`<img src="../assets/${coinColor}.png" height="5%">`)
|
||||
if ([[COINS]] > 1) $("#coins").append(`<img class="squeeze" src="../assets/${coinColor}.png" height="5%">`)
|
||||
if ([[COINS]] > 2) $("#coins").append(`<img class="squeeze" src="../assets/${coinColor}.png" height="5%">`)
|
||||
if ([[COINS]] > 0) $("#coins").append(`<img src="/assets/${coinColor}.png" height="5%">`)
|
||||
if ([[COINS]] > 1) $("#coins").append(`<img class="squeeze" src="/assets/${coinColor}.png" height="5%">`)
|
||||
if ([[COINS]] > 2) $("#coins").append(`<img class="squeeze" src="/assets/${coinColor}.png" height="5%">`)
|
||||
|
||||
if ("[[GDPS]]".startsWith("1.9/")) $("#authorLink").attr('href', '/search/[[PLAYERID]]?user')
|
||||
|
||||
|
@ -319,43 +318,43 @@ $(window).on('load', function() {
|
|||
if (overflow > 3) overflow = 3
|
||||
$('#songname').addClass('smaller').css('font-size', (6 - (overflow)) + 'vh')
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
let savedLevels = JSON.parse(localStorage.getItem('saved') || '[]');
|
||||
let deleteMode = false;
|
||||
if (savedLevels.includes('[[ID]]')) $('#saveButton').attr('src', '../assets/delete.png').attr('onclick', '$("#deleteDiv").show()')
|
||||
let savedLevels = JSON.parse(localStorage.getItem('saved') || '[]')
|
||||
let deleteMode = false
|
||||
if (savedLevels.includes('[[ID]]')) $('#saveButton').attr('src', '/assets/delete.png').attr('onclick', '$("#deleteDiv").show()')
|
||||
|
||||
function saveLevel() {
|
||||
savedLevels.push('[[ID]]');
|
||||
savedLevels.push('[[ID]]')
|
||||
localStorage.setItem('saved', JSON.stringify(savedLevels));
|
||||
}
|
||||
|
||||
function savedLevel() {
|
||||
$('#saveButton').attr('src', '../assets/delete.png').attr('onclick', '$("#deleteDiv").show()')
|
||||
$('#saveButton').attr('src', '/assets/delete.png').attr('onclick', '$("#deleteDiv").show()')
|
||||
$('.popup').hide()
|
||||
}
|
||||
|
||||
function deleteLevel() {
|
||||
savedLevels = savedLevels.filter(function(el) {return el != '[[ID]]'})
|
||||
localStorage.setItem('saved', JSON.stringify(savedLevels));
|
||||
$('#saveButton').attr('src', '../assets/plus.png').attr('onclick', '$("#saveDiv").show(); saveLevel()')
|
||||
$('#saveButton').attr('src', '/assets/plus.png').attr('onclick', '$("#saveDiv").show(); saveLevel()')
|
||||
$('.popup').hide()
|
||||
}
|
||||
|
||||
$('#checkSong').click(function() {
|
||||
$('#checkSong').hide()
|
||||
$('#songLoading').show()
|
||||
fetch(`../api/song/[[SONGID]]`).then(res => res.json()).then(info => {
|
||||
fetch(`/api/song/[[SONGID]]`).then(res => res.json()).then(info => {
|
||||
$('#songLoading').hide()
|
||||
$(info && info != -1 ? '#songAllowed' : '#songNotAllowed').show().addClass('songStatus')
|
||||
// if (info.error) return
|
||||
// if (!info.artist.scouted) {
|
||||
// $('#scout').attr('src', '../assets/x.png')
|
||||
// $('#scout').attr('src', '/assets/x.png')
|
||||
// $('#scout').attr('title', $('#scout').attr('title').replace('is ', 'is NOT '))
|
||||
// $('#scout').css('filter', 'saturate(0.4)')
|
||||
// }
|
||||
// if (!info.artist.whitelisted) {
|
||||
// $('#whitelist').attr('src', '../assets/x.png')
|
||||
// $('#whitelist').attr('src', '/assets/x.png')
|
||||
// $('#whitelist').attr('title', $('#whitelist').attr('title').replace('is ', 'is NOT '))
|
||||
// }
|
||||
// $('#scout').show(); $('#whitelist').show()
|
||||
|
@ -375,7 +374,7 @@ $('.artistIcon').hover(function() {
|
|||
|
||||
// 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)
|
||||
// if (likedLevels.includes('[[ID]]')) $('#likeButton').attr('src', '/assets/voted.png').removeClass('gdButton').prop("onclick", null)
|
||||
|
||||
// $('#likebtn').click(function() {
|
||||
// $('#likebtn').removeClass('youAreNotTheOne')
|
||||
|
@ -405,7 +404,7 @@ $('.artistIcon').hover(function() {
|
|||
// $('.postbutton').hide()
|
||||
// allowEsc = false
|
||||
|
||||
// fetch(`../api/profile/${username}`).then(res => res.json()).then(res => {
|
||||
// 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
|
||||
|
||||
|
@ -414,7 +413,7 @@ $('.artistIcon').hover(function() {
|
|||
// 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)})
|
||||
// })
|
||||
// })
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title>Leaderboard</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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.png">
|
||||
<link rel="icon" href="/assets/trophy.png">
|
||||
<meta id="meta-title" property="og:title" content="Level Leaderboard">
|
||||
<meta id="meta-desc" property="og:description" content="View the leaderboard of a Geometry Dash level!">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/trophy.png">
|
||||
|
@ -15,17 +15,17 @@
|
|||
<div id="everything" style="overflow: auto;">
|
||||
|
||||
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%;>
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%;>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; right: 0%; width: 100%; text-align: right;">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
<img class="cornerPiece" 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%">
|
||||
|
@ -33,13 +33,13 @@
|
|||
</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()">
|
||||
<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%; display: none;">
|
||||
<img class="spin noSelect" src="../assets/loading.png" height="105%">
|
||||
<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>
|
||||
|
@ -47,11 +47,11 @@
|
|||
</div>
|
||||
|
||||
<div class="supercenter" style="left: 87%; top: 24%; height: 10%">
|
||||
<img class="gdButton darken" id="topMode" src="../assets/leaderboard-top.png" height="90%">
|
||||
<img class="gdButton darken" id="topMode" src="/assets/leaderboard-top.png" height="90%">
|
||||
</div>
|
||||
|
||||
<div class="supercenter" style="left: 87%; top: 35%; height: 10%">
|
||||
<img class="gdButton" id="weekMode" src="../assets/leaderboard-week.png" height="90%">
|
||||
<img class="gdButton" id="weekMode" src="/assets/leaderboard-week.png" height="90%">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -59,12 +59,12 @@
|
|||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/6.2.2/browser/pixi.js"></script>
|
||||
<script type="text/javascript" src="../iconkit/icon.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="../dragscroll.js"></script>
|
||||
<script type="text/javascript" src="/iconkit/icon.js"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/dragscroll.js"></script>
|
||||
<script>
|
||||
|
||||
let loading = false;
|
||||
let loading = false
|
||||
let lvlID = Math.round(window.location.pathname.split('/')[2])
|
||||
|
||||
if (!lvlID || lvlID > 99999999 || lvlID < -99999999) window.location.href = window.location.href.replace("leaderboard", "search")
|
||||
|
@ -78,7 +78,7 @@ function leaderboard() {
|
|||
loading = true;
|
||||
$('#loading').show()
|
||||
|
||||
fetch(`../api/level/${lvlID}`).then(lvl => lvl.json()).then(lvl => {
|
||||
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
|
||||
|
@ -86,9 +86,9 @@ function leaderboard() {
|
|||
$('#meta-title').attr('content', "Leaderboards for " + lvl.name)
|
||||
$('#meta-desc').attr('content', 'View the leaderboard for ' + lvl.name + ' by ' + lvl.author + '!')
|
||||
})
|
||||
|
||||
|
||||
fetch(`../api/leaderboardLevel/${lvlID}?count=200${weekly ? "&week" : ""}`).then(res => res.json()).then(res => {
|
||||
|
||||
fetch(`/api/leaderboardLevel/${lvlID}?count=200${weekly ? "&week" : ""}`).then(res => res.json()).then(res => {
|
||||
|
||||
if (!res || res.error || res == "-1") {
|
||||
loading = false;
|
||||
|
@ -101,12 +101,12 @@ function leaderboard() {
|
|||
res.forEach((x, y) => {
|
||||
|
||||
$('#searchBox').append(`<div class="searchresult leaderboardSlot levelboardSlot" style="align-items: center; padding-left: 1vh; height: 15%; width: 100%; position: relative">
|
||||
|
||||
|
||||
<h2 class="center" style="width: 12%; margin: 0% 0% 0% 0.5%; transform: scale(${1 - (Math.max(0, String(x.rank).length - 1) * 0.2)}">${x.rank}</h2>
|
||||
<gdicon dontload="true" iconID=${x.icon.icon} cacheID=${x.playerID} iconForm="${x.icon.form}" col1="${x.icon.col1}" col2="${x.icon.col2}" glow="${x.icon.glow}" style="width: 7%; margin-bottom: 1%" imgStyle="width: 100%"></gdicon>
|
||||
<h2 class="small gdButton" style="font-size: 6.5vh; margin-right: 3%; margin-left: 3%"><a href="../u/${x.accountID}.">${x.username}</a></h2>
|
||||
<h3 class="lessSpaced" style="margin-top: 1.3%; margin-right: 2%">${x.percent}%</h3>
|
||||
${'<div style="width: 2%"><img class="valign" src="../assets/silvercoin.png" style="height: 33%"></div>'.repeat(x.coins)}
|
||||
${'<div style="width: 2%"><img class="valign" src="/assets/silvercoin.png" style="height: 33%"></div>'.repeat(x.coins)}
|
||||
|
||||
<div class="center" style="text-align: right; position:absolute; right: 1.25%; height: 10%; width: 12.5%; top: 100%;">
|
||||
<p class="commentDate">${x.date}</p>
|
||||
|
@ -117,17 +117,17 @@ function leaderboard() {
|
|||
|
||||
$('#searchBox').append('<div style="height: 4.5%"></div>')
|
||||
loading = false;
|
||||
$('#loading').hide();
|
||||
$('#loading').hide()
|
||||
lazyLoadIcons()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
let weekly = false;
|
||||
let weekly = false
|
||||
leaderboard()
|
||||
|
||||
$('#topMode').click(function() {
|
||||
if (!weekly || loading) return;
|
||||
if (!weekly || loading) return
|
||||
weekly = false
|
||||
leaderboard()
|
||||
$('#weekMode').removeClass('darken')
|
||||
|
@ -135,12 +135,12 @@ function leaderboard() {
|
|||
})
|
||||
|
||||
$('#weekMode').click(function() {
|
||||
if (weekly || loading) return;
|
||||
if (weekly || loading) return
|
||||
weekly = true
|
||||
leaderboard()
|
||||
$('#topMode').removeClass('darken')
|
||||
$('#weekMode').addClass('darken')
|
||||
});
|
||||
})
|
||||
|
||||
function lazyLoadIcons() {
|
||||
let newIconFound = false
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title>Map Packs</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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/folder.png">
|
||||
<link rel="icon" href="/assets/folder.png">
|
||||
<meta id="meta-title" property="og:title" content="Map Packs">
|
||||
<meta id="meta-desc" property="og:description" content="Collections of terrible Geometry Dash levels that people only play because of the absurd number of icons they unlock.">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/folder.png">
|
||||
|
@ -18,32 +18,32 @@
|
|||
<h1 style="transform:scale(1.2)">Map Packs</h1>
|
||||
</div>
|
||||
|
||||
<img id="loading" style="margin-top: 1%" class="spin noSelect" src="../assets/loading.png" height="12%">
|
||||
<img id="loading" style="margin-top: 1%" class="spin noSelect" src="/assets/loading.png" height="12%">
|
||||
|
||||
<div id="packList">
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; top: 2%; left: -1.95%; width: 10%; height: 25%; pointer-events: none">
|
||||
<img class="gdButton yesClick" id="backButton" src="../assets/back.png" height="30%" onclick="backButton()">
|
||||
</div>
|
||||
<img class="gdButton yesClick" id="backButton" src="/assets/back.png" height="30%" onclick="backButton()">
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script>
|
||||
|
||||
fetch('../api/mappacks').then(res => res.json()).then(packs => {
|
||||
fetch('/api/mappacks').then(res => res.json()).then(packs => {
|
||||
$('#loading').hide()
|
||||
packs.forEach(x => {
|
||||
$('#packList').append(`
|
||||
<div class="mappack">
|
||||
<a href="../search/${x.levels.join(",")}?list&header=${encodeURIComponent(x.name)}">
|
||||
<img src="../assets/difficulties/${x.difficulty}.png" width="42%"><br>
|
||||
<img src="/assets/difficulties/${x.difficulty}.png" width="42%"><br>
|
||||
<h3 class="gauntletText"">${x.name.replace("Pack", "<br>Pack")}<br>
|
||||
<span style="color: rgb(${x.textColor})">${x.stars}</span><img class="valign" src="../assets/star.png" style="cursor: help; width: 14%; margin-left: 2%; transform: translateY(-10%);" title="Stars">
|
||||
<span style="color: rgb(${x.barColor})">${x.coins}</span><img class="valign" src="../assets/coin.png" style="cursor: help; width: 14%; margin-left: 2%; transform: translateY(-10%);" title="Secret Coins">
|
||||
<span style="color: rgb(${x.textColor})">${x.stars}</span><img class="valign" src="/assets/star.png" style="cursor: help; width: 14%; margin-left: 2%; transform: translateY(-10%);" title="Stars">
|
||||
<span style="color: rgb(${x.barColor})">${x.coins}</span><img class="valign" src="/assets/coin.png" style="cursor: help; width: 14%; margin-left: 2%; transform: translateY(-10%);" title="Secret Coins">
|
||||
</h3></div></a>`)
|
||||
})
|
||||
});
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<head>
|
||||
<title>Messages</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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/messages.png">
|
||||
<link rel="icon" href="/assets/messages.png">
|
||||
<meta id="meta-title" property="og:title" content="Messages">
|
||||
<meta id="meta-desc" property="og:description" content="Read, write, and manage your Geometry Dash messages!">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/messages.png">
|
||||
|
@ -29,9 +29,9 @@
|
|||
<div style="margin-bottom: 3%">
|
||||
<p id="message" style="padding: 0% 10%; margin-top: 1.5%"></p>
|
||||
</div>
|
||||
<img src="../assets/btn-cancel.png" height=11%; class="gdButton postbutton center"
|
||||
<img src="/assets/btn-cancel.png" height=11%; class="gdButton postbutton center"
|
||||
style="margin-right: 1%" onclick="backButton()">
|
||||
<img src="../assets/btn-submit.png" type="submit" height=11%; class="gdButton postbutton center"
|
||||
<img src="/assets/btn-submit.png" type="submit" height=11%; class="gdButton postbutton center"
|
||||
style="margin-left: 1%" id="logIn">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -40,7 +40,7 @@
|
|||
<div class="brownbox center supercenter" style="height: 65%; width: 110vh">
|
||||
<div style="position:absolute; top: 25%; width: 100%">
|
||||
<p id="msgCount" style="font-size: 3.5vh; margin-bottom: 5%"></p>
|
||||
<img class="spin noSelect" id="loadingicon" src="../assets/loading.png" width="10%">
|
||||
<img class="spin noSelect" id="loadingicon" src="/assets/loading.png" width="10%">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -52,25 +52,25 @@
|
|||
</div>
|
||||
|
||||
<div style="text-align: left">
|
||||
<img class="gdButton inline" id="purge" src="../assets/trash-square.png" width="7%">
|
||||
<img class="gdButton inline" id="purge" src="/assets/trash-square.png" width="7%">
|
||||
<div id="selectCount" style="display: none; pointer-events: none;">
|
||||
<h3 class="center" style="font-size: 3vh; margin-top: 12%"></h3>
|
||||
</div>
|
||||
<img class="gdButton inline" id="selectAll" src="../assets/select-all.png" width="15%"
|
||||
<img class="gdButton inline" id="selectAll" src="/assets/select-all.png" width="15%"
|
||||
style="margin: 0% 0% 0.5% 2%">
|
||||
<img class="gdButton inline" id="selectNone" src="../assets/select-none.png" width="15%"
|
||||
<img class="gdButton inline" id="selectNone" src="/assets/select-none.png" width="15%"
|
||||
style="display: none; margin: 0% 0% 0.5% 2%">
|
||||
</div>
|
||||
|
||||
<img src="../assets/refresh.png" style="height: 13%;position: absolute;right: 0%;bottom: 0%;" onclick="page = 0; getMessages()" class="gdButton center sideSpaceB">
|
||||
<img src="/assets/refresh.png" style="height: 13%;position: absolute;right: 0%;bottom: 0%;" onclick="page = 0; getMessages()" class="gdButton center sideSpaceB">
|
||||
|
||||
<div style="position: absolute; left: 0.5%; top: 45%; height: 11%;">
|
||||
<img class="gdButton" style="display: none" id="pageDown" src="../assets/arrow-left.png"
|
||||
<img class="gdButton" style="display: none" id="pageDown" src="/assets/arrow-left.png"
|
||||
height="90%">
|
||||
</div>
|
||||
|
||||
<div style="position: absolute; right: 0.5%; top: 45%; height: 11%;">
|
||||
<img class="gdButton" style="display: none" id="pageUp" src="../assets/arrow-right.png"
|
||||
<img class="gdButton" style="display: none" id="pageUp" src="/assets/arrow-right.png"
|
||||
height="90%">
|
||||
</div>
|
||||
|
||||
|
@ -84,19 +84,19 @@
|
|||
<p class="bigger center" style="line-height: 6vh; margin-top: 1.5vh;">
|
||||
Are you sure you want to <cr>delete</cr> this message?
|
||||
</p>
|
||||
<img src="../assets/btn-cancel-green.png" height=29%; class="gdButton center" onclick="$('#confirmDelete').hide()">
|
||||
<img src="../assets/btn-delete.png" height=29%; id="deleteCurrentMessage" class="gdButton center sideSpaceB">
|
||||
<img src="/assets/btn-cancel-green.png" height=29%; class="gdButton center" onclick="$('#confirmDelete').hide()">
|
||||
<img src="/assets/btn-delete.png" height=29%; id="deleteCurrentMessage" class="gdButton center sideSpaceB">
|
||||
</div>
|
||||
|
||||
<div id="deleting" style="display: none">
|
||||
<h2 class="smaller center" style="font-size: 5.5vh">Delete</h2>
|
||||
<p class="bigger center" style="line-height: 6vh; margin-top: 1.5vh;">Deleting message...</p>
|
||||
<img src="../assets/loading.png" class="spin noSelect" style="height: 35%; margin-top: -2%">
|
||||
<img src="/assets/loading.png" class="spin noSelect" style="height: 35%; margin-top: -2%">
|
||||
</div>
|
||||
|
||||
<div id="delete-error" style="display: none;">
|
||||
<img class="gdButton" src="../assets/close.png" style="width: 15%; position: absolute; top: -17.5%; left: -5.5vh" onclick="$('#delete-error').hide(); $('#confirmDelete').hide(); $('#preDelete').show()">
|
||||
<img src="../assets/exclamation.png" style="height: 40%">
|
||||
<img class="gdButton" src="/assets/close.png" style="width: 15%; position: absolute; top: -17.5%; left: -5.5vh" onclick="$('#delete-error').hide(); $('#confirmDelete').hide(); $('#preDelete').show()">
|
||||
<img src="/assets/exclamation.png" style="height: 40%">
|
||||
<p class="bigger" style="margin-bottom: 0%; margin-top: 2.5%">Something went wrong!</p>
|
||||
<p id="delError" style="font-size: 2.4vh; margin-top: 1%"></p>
|
||||
</div>
|
||||
|
@ -111,9 +111,9 @@
|
|||
Are you sure you want to <cr>delete</cr> <span class="selectedAmount"
|
||||
style="color: yelow"></span>?
|
||||
</p>
|
||||
<img src="../assets/btn-cancel-green.png" height=29%; class="gdButton center"
|
||||
<img src="/assets/btn-cancel-green.png" height=29%; class="gdButton center"
|
||||
onclick="$('#bulkDelete').hide()">
|
||||
<img src="../assets/btn-delete.png" height=29%; id="bulkDeleteMessages"
|
||||
<img src="/assets/btn-delete.png" height=29%; id="bulkDeleteMessages"
|
||||
class="gdButton center sideSpaceB">
|
||||
</div>
|
||||
|
||||
|
@ -121,12 +121,12 @@
|
|||
<h2 class="smaller center" style="font-size: 5.5vh">Delete</h2>
|
||||
<p class="bigger center" style="line-height: 6vh; margin-top: 1.5vh;">Deleting <span
|
||||
class="selectedAmount"></span>...</p>
|
||||
<img src="../assets/loading.png" class="spin noSelect" style="height: 35%; margin-top: -2%">
|
||||
<img src="/assets/loading.png" class="spin noSelect" style="height: 35%; margin-top: -2%">
|
||||
</div>
|
||||
|
||||
<div id="bd-error" style="display: none;">
|
||||
<img class="gdButton" src="../assets/close.png" style="width: 15%; position: absolute; top: -17.5%; left: -5.5vh" onclick="$('#bd-error').hide(); $('#bulkDelete').hide(); $('#preBulkDelete').show()">
|
||||
<img src="../assets/exclamation.png" style="height: 40%">
|
||||
<img class="gdButton" src="/assets/close.png" style="width: 15%; position: absolute; top: -17.5%; left: -5.5vh" onclick="$('#bd-error').hide(); $('#bulkDelete').hide(); $('#preBulkDelete').show()">
|
||||
<img src="/assets/exclamation.png" style="height: 40%">
|
||||
<p class="bigger" style="margin-bottom: 0%; margin-top: 2.5%">Something went wrong!</p>
|
||||
<p id="bdError" style="font-size: 2.4vh; margin-top: 1%"></p>
|
||||
</div>
|
||||
|
@ -136,16 +136,16 @@
|
|||
<div id="selectedMessage" class="popup">
|
||||
<div class="bounce center supercenter" style="height: 70%; width: 115vh">
|
||||
<div class="bluebox center supercenter" style="width: 100%; height: 100%">
|
||||
<img class="gdButton" src="../assets/close.png" width="9%" style="position: absolute; top: -7.5%; left: -6.5vh" onclick="$('#selectedMessage').hide()">
|
||||
<img class="gdButton" src="/assets/close.png" width="9%" style="position: absolute; top: -7.5%; left: -6.5vh" onclick="$('#selectedMessage').hide()">
|
||||
<h1 id="messageSubject" class="smaller center" style="font-size: 5.5vh; min-height: 9%; margin-top: 1%"></h1>
|
||||
<h3 id="messageAuthor" class="gold center gauntletText gdButton"></h3>
|
||||
<div class="transparentBox center" id="theMfMessage">
|
||||
<img id="messageLoad" src="../assets/loading.png" class="spin noSelect" style="width: 10%; margin-top: 15%">
|
||||
<img id="messageLoad" src="/assets/loading.png" class="spin noSelect" style="width: 10%; margin-top: 15%">
|
||||
<p id="messageBody"></p>
|
||||
</div>
|
||||
<div id="messageOptions">
|
||||
<img class="gdButton" style="width: 8%" title="Reply" src="../assets/reply.png" id="replyButton">
|
||||
<img class="gdButton" style="width: 8%" title="Delete" src="../assets/trash.png" id="deleteButton" onclick="$('#confirmDelete').show()">
|
||||
<img class="gdButton" style="width: 8%" title="Reply" src="/assets/reply.png" id="replyButton">
|
||||
<img class="gdButton" style="width: 8%" title="Delete" src="/assets/trash.png" id="deleteButton" onclick="$('#confirmDelete').show()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -163,10 +163,10 @@
|
|||
placeholder="Message"></textarea>
|
||||
</div>
|
||||
<p id="messageStatus" style="margin: 1% 0% 1.5% 0%; min-height: 5%;"></p>
|
||||
<img src="../assets/btn-cancel.png" height=10%; class="gdButton center"
|
||||
<img src="/assets/btn-cancel.png" height=10%; class="gdButton center"
|
||||
onclick="$('textarea').val(''); $('#sendMessage').hide()">
|
||||
<img src="../assets/btn-submit.png" height=10%; id="postMessage" class="gdButton center sideSpaceB">
|
||||
<img src="../assets/trash.png" style="height: 10%; position: absolute; right: 0%"
|
||||
<img src="/assets/btn-submit.png" height=10%; id="postMessage" class="gdButton center sideSpaceB">
|
||||
<img src="/assets/trash.png" style="height: 10%; position: absolute; right: 0%"
|
||||
onclick="$('#postContent').val('');" class="gdButton center sideSpaceB">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -176,19 +176,19 @@
|
|||
<div class="bluebox bounce center supercenter" style="height: 27%; width: 55vh">
|
||||
|
||||
<div id="reply-loading">
|
||||
<img src="../assets/loading.png" class="spin noSelect" style="height: 40%; margin-top: 7.5%">
|
||||
<img src="/assets/loading.png" class="spin noSelect" style="height: 40%; margin-top: 7.5%">
|
||||
<p class="bigger">Sending...</p>
|
||||
</div>
|
||||
|
||||
<div id="reply-sent" style="display: none;">
|
||||
<img class="gdButton" src="../assets/close.png" style="width: 15%; position: absolute; top: -17.5%; left: -5.5vh" onclick="$('.popup').hide()">
|
||||
<img src="../assets/check.png" style="height: 40%; margin-top: 7.5%">
|
||||
<img class="gdButton" src="/assets/close.png" style="width: 15%; position: absolute; top: -17.5%; left: -5.5vh" onclick="$('.popup').hide()">
|
||||
<img src="/assets/check.png" style="height: 40%; margin-top: 7.5%">
|
||||
<p class="bigger">Message sent!</p>
|
||||
</div>
|
||||
|
||||
<div id="reply-error" style="display: none;">
|
||||
<img class="gdButton" src="../assets/close.png" style="width: 15%; position: absolute; top: -17.5%; left: -5.5vh" onclick="$('.popup').hide()">
|
||||
<img src="../assets/exclamation.png" style="height: 40%; margin-top: 7.5%">
|
||||
<img class="gdButton" src="/assets/close.png" style="width: 15%; position: absolute; top: -17.5%; left: -5.5vh" onclick="$('.popup').hide()">
|
||||
<img src="/assets/exclamation.png" style="height: 40%; margin-top: 7.5%">
|
||||
<p class="bigger" style="margin-bottom: 0%;">Something went wrong!</p>
|
||||
<p style="font-size: 2.4vh; margin-top: 1%">Does the recipient have messages enabled?</p>
|
||||
</div>
|
||||
|
@ -197,15 +197,15 @@
|
|||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%; pointer-events: none;">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%;>
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%;>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; right: 0%; width: 100%; text-align: right; pointer-events: none;">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
</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()">
|
||||
<img class="gdButton yesClick" id="backButton" src="/assets/back.png" height="30%" onclick="backButton()">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -213,18 +213,18 @@
|
|||
</body>
|
||||
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script>
|
||||
|
||||
let accountID;
|
||||
let password;
|
||||
let page = 0;
|
||||
let messageID = 0;
|
||||
let playerID = 0;
|
||||
let messages = [];
|
||||
let messageStatus = {};
|
||||
let cache = {};
|
||||
let loading = false;
|
||||
let accountID
|
||||
let password
|
||||
let page = 0
|
||||
let messageID = 0
|
||||
let playerID = 0
|
||||
let messages = []
|
||||
let messageStatus = {}
|
||||
let cache = {}
|
||||
let loading = false
|
||||
|
||||
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> For security, it will be <cy>forgotten</cy> when you exit this page.'
|
||||
$('#message').html(messageText)
|
||||
|
@ -254,7 +254,7 @@
|
|||
<label for="message-${y}" class="gdcheckbox gdButton"></label>
|
||||
</div>${/*
|
||||
<div class="xButton hitbox">
|
||||
<img class="gdButton" style="width: 8%" src="../assets/xbutton.png">
|
||||
<img class="gdButton" style="width: 8%" src="/assets/xbutton.png">
|
||||
</div>*/""}
|
||||
</div>`)
|
||||
})
|
||||
|
@ -272,7 +272,7 @@
|
|||
$('#message').text("Logging in...")
|
||||
$('.postbutton').hide()
|
||||
|
||||
fetch(`../api/profile/${username}`).then(res => res.json()).then(res => {
|
||||
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
|
||||
|
||||
|
@ -292,7 +292,7 @@
|
|||
let targetUser = window.location.search.match(/(\?|&)sendTo=(.+)/)
|
||||
if (targetUser) {
|
||||
targetUser = decodeURIComponent(targetUser[2])
|
||||
fetch(`../api/profile/${targetUser}`).then(res => res.json()).then(res => {
|
||||
fetch(`/api/profile/${targetUser}`).then(res => res.json()).then(res => {
|
||||
if (res == "-1" || !res) return;
|
||||
$('#replyAuthor').html(`<a href="../u/${res.accountID}." target="_blank">To: ${res.username}</a>`)
|
||||
messageStatus[res.accountID] = [res.messages, res.username]
|
||||
|
@ -321,7 +321,7 @@
|
|||
$('#selectCount').hide()
|
||||
$('#selectAll').show()
|
||||
$('#selectNone').hide()
|
||||
$('#msgList').html('<img src="../assets/loading.png" class="spin noSelect" style="margin-top: 20%; height: 20%;">')
|
||||
$('#msgList').html('<img src="/assets/loading.png" class="spin noSelect" style="margin-top: 20%; height: 20%;">')
|
||||
$.post("../messages", { password, accountID, page })
|
||||
.done(msgs => {
|
||||
messages = msgs
|
||||
|
@ -384,7 +384,7 @@
|
|||
$('#deleteButton').show()
|
||||
}
|
||||
|
||||
if (!messageStatus[msg.accountID]) fetch(`../api/profile/${msg.author}`).then(res => res.json()).then(res => {
|
||||
if (!messageStatus[msg.accountID]) fetch(`/api/profile/${msg.author}`).then(res => res.json()).then(res => {
|
||||
messageStatus[msg.accountID] = [res.messages, msg.author]
|
||||
loadMsg()
|
||||
})
|
||||
|
@ -392,10 +392,10 @@
|
|||
loadMsg()
|
||||
}
|
||||
})
|
||||
.fail(e => {
|
||||
.fail(e => {
|
||||
$('#messageAuthor').html(' ')
|
||||
$('#messageSubject').html(' ')
|
||||
$('#messageLoad').hide()
|
||||
$('#messageLoad').hide()
|
||||
$('#messageBody').html(e.responseText).show()
|
||||
$('#theMfMessage').attr('style', 'background-color: rgba(0, 0, 0, 0)')
|
||||
})
|
||||
|
@ -416,7 +416,7 @@
|
|||
$('#preDelete').show()
|
||||
$('#deleting').hide()
|
||||
})
|
||||
.fail(e => {
|
||||
.fail(e => {
|
||||
$('#deleting').hide()
|
||||
$('#delete-error').show()
|
||||
$('#delError').html(e.responseText)
|
||||
|
@ -450,7 +450,7 @@
|
|||
$('#bulkDeleting').hide()
|
||||
$('#preBulkDelete').show()
|
||||
})
|
||||
.fail(e => {
|
||||
.fail(e => {
|
||||
$('#bulkDeleting').hide()
|
||||
$('#bd-error').show()
|
||||
$('#bdError').html(e.responseText)
|
||||
|
@ -458,7 +458,7 @@
|
|||
})
|
||||
|
||||
$('#replyButton').click(function() {
|
||||
if (!messageStatus[playerID]) return;
|
||||
if (!messageStatus[playerID]) return
|
||||
let status = messageStatus[playerID][0]
|
||||
let name = messageStatus[playerID][1]
|
||||
$('#postMessage').removeClass('grayscale')
|
||||
|
@ -475,7 +475,7 @@
|
|||
$('#postMessage').click(function () {
|
||||
let subject = $('#postSubject').val()
|
||||
let message = $('#postContent').val()
|
||||
if (!subject || !message || !messageStatus[playerID] || messageStatus[playerID][0] == "off") return;
|
||||
if (!subject || !message || !messageStatus[playerID] || messageStatus[playerID][0] == "off") return
|
||||
allowEsc = false
|
||||
$('#reply-loading').show()
|
||||
$('#reply-sent').hide()
|
||||
|
@ -488,7 +488,7 @@
|
|||
$('#reply-sent').show()
|
||||
allowEsc = true
|
||||
})
|
||||
.fail(e => {
|
||||
.fail(e => {
|
||||
$('#reply-loading').hide()
|
||||
$('#reply-error').show()
|
||||
allowEsc = true
|
||||
|
@ -518,10 +518,10 @@
|
|||
});
|
||||
|
||||
$(document).keydown(function (k) {
|
||||
if (loading) return;
|
||||
if (loading) return
|
||||
|
||||
if ($('#access').is(':visible')) {
|
||||
if (k.which == 13) $('#logIn').trigger('click') //enter
|
||||
if (k.which == 13) $('#logIn').trigger('click') //enter
|
||||
else return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title>Geometry Dash Browser!</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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/keymaster-head.png">
|
||||
<link rel="icon" href="/assets/keymaster-head.png">
|
||||
<meta id="meta-title" property="og:title" content="Geometry Dash Browser!">
|
||||
<meta id="meta-desc" property="og:description" content="Browse all of Geometry Dash's online features, right from this handy little website! Levels, profiles, leaderboards, comments, and more!">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="https://gdbrowser.com/assets/coin.png">
|
||||
|
@ -15,7 +15,7 @@
|
|||
<div id="everything" class="center" style="overflow: hidden">
|
||||
<h2 style="margin-top: 2%; margin-bottom: 2.2%">RobTop's Purgatory</h2>
|
||||
<h1 id="msg" class="smaller" style="margin-bottom: 1.2%; white-space: normal;"> </h1>
|
||||
<img id="glubfub" src="../assets/keymaster.png" height="25%" class="gdButton">
|
||||
<img id="glubfub" src="/assets/keymaster.png" height="25%" class="gdButton">
|
||||
|
||||
|
||||
<div id="footer" style="position: absolute; left: 1%; bottom: 0%; text-align: left">
|
||||
|
@ -27,33 +27,33 @@
|
|||
</div>
|
||||
|
||||
<div style="position:absolute; top: 2.8%; left: 0.5%; width: 4.5%; text-align: right;">
|
||||
<a href="../?home"><img class="gdButton" src="../assets/arrow-left.png" width=80%;"></a>
|
||||
<a href="../?home"><img class="gdButton" src="/assets/arrow-left.png" width=80%;"></a>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 3%; right: 3%; width: 10%; text-align: right;">
|
||||
<a href="../gdps"><img class="gdButton" src="../assets/basement.png" width=85%;"></a>
|
||||
<a href="../gdps"><img class="gdButton" src="/assets/basement.png" width=85%;"></a>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 22%; right: 7%; width: 10%; text-align: right; pointer-events: none">
|
||||
<img src="../assets/privateservers.png" width=85%;">
|
||||
<img src="/assets/privateservers.png" width=85%;">
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; top: 15.5%; right: 7.5%; width: 10%; text-align: right; pointer-events: none">
|
||||
<img src="../assets/leaderboardarrow.png" width=85%;">
|
||||
<img src="/assets/leaderboardarrow.png" width=85%;">
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; top: 2.2%; right: 2.5%; text-align: right; width: 11%;">
|
||||
<a href="../leaderboard"><img class="gdButton" src="../assets/leaderboard.png" width="55%"></a>
|
||||
<a href="../leaderboard"><img class="gdButton" src="/assets/leaderboard.png" width="55%"></a>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="position:absolute; top: -1.5%; right: 11%; text-align: right; width: 10%;">
|
||||
<a href="../iconkit"><img class="iconRope" src="../assets/iconrope.png" width="40%"></a>
|
||||
</div>
|
||||
<a href="../iconkit"><img class="iconRope" src="/assets/iconrope.png" width="40%"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script>
|
||||
|
||||
let line = 0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<head>
|
||||
<title>[[USERNAME]]'s Profile</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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="">
|
||||
<meta id="meta-title" property="og:title" content="[[USERNAME]]'s profile">
|
||||
|
@ -26,16 +26,16 @@
|
|||
<div style="min-height: 20%; max-height: 20%">
|
||||
<p id="message" style="padding: 0% 10%; margin-top: 2%"></p>
|
||||
</div>
|
||||
<img src="../assets/btn-cancel.png" height=11%; class="postButton gdButton center" style="margin-right: 1%" onclick="$('#leavePost').hide(); $('textarea').val('')">
|
||||
<img src="../assets/btn-submit.png" type="submit" height=11%; class="postButton gdButton center" style="margin-left: 1%" id="submitComment">
|
||||
<img src="/assets/btn-cancel.png" height=11%; class="postButton gdButton center" style="margin-right: 1%" onclick="$('#leavePost').hide(); $('textarea').val('')">
|
||||
<img src="/assets/btn-submit.png" type="submit" height=11%; 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">
|
||||
<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%">
|
||||
|
@ -45,11 +45,11 @@
|
|||
<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">
|
||||
<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 class="popup" id="settingsDiv">
|
||||
<div class="fancybox bounce center supercenter">
|
||||
<h2 class="smaller center" style="font-size: 5.5vh">User Info</h2>
|
||||
|
@ -58,43 +58,43 @@
|
|||
Private Messages: [[DMS]]<br>
|
||||
Comment History: [[COMMENTS]]<br>
|
||||
</p>
|
||||
<img src="../assets/ok.png" width=20%; class="gdButton center" onclick="$('#settingsDiv').hide()">
|
||||
<img src="/assets/ok.png" width=20%; class="gdButton center" onclick="$('#settingsDiv').hide()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%;>
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%;>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; right: 0%; width: 100%; text-align: right;">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
</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()">
|
||||
<img class="gdButton yesClick" id="backButton" src="/assets/back.png" height="30%" onclick="backButton()">
|
||||
</div>
|
||||
|
||||
<div class="brownBox center supercenter" style="width: 135vh; height: 82%; margin-top: -0.7%">
|
||||
|
||||
<div id="globalrank0" style="position: absolute; left: 0.3%; top: 1.5%; width: 18%; text-align: left">
|
||||
<p style="margin: 0;"><img src="../assets/trophy.png" class="inline valign help profileTrophy" width="22%" title="Global Rank"> [[RANK]]</p>
|
||||
<p style="margin: 0;"><img src="/assets/trophy.png" class="inline valign help profileTrophy" width="22%" title="Global Rank"> [[RANK]]</p>
|
||||
</div>
|
||||
|
||||
<h1 class="veryBig inline" style="width: inherit">
|
||||
<img class="inline valign" id="modBadge1" style="display: none; height: 7%; cursor:help" src="../assets/mod.png" title="[[USERNAME]] is a moderator!"><!--
|
||||
--><img class="inline valign" id="modBadge2" style="display: none; height: 7%; cursor:help" src="../assets/mod-elder.png" title="[[USERNAME]] is an elder moderator!"><!--
|
||||
--><img class="inline valign" id="modBadge3" style="display: none; height: 7%; cursor:help" src="../assets/mod-extra.png" title="[[USERNAME]] is a custom moderator! (tier [[MODERATOR]])"><!--
|
||||
<img class="inline valign" id="modBadge1" style="display: none; height: 7%; cursor:help" src="/assets/mod.png" title="[[USERNAME]] is a moderator!"><!--
|
||||
--><img class="inline valign" id="modBadge2" style="display: none; height: 7%; cursor:help" src="/assets/mod-elder.png" title="[[USERNAME]] is an elder moderator!"><!--
|
||||
--><img class="inline valign" id="modBadge3" style="display: none; height: 7%; cursor:help" src="/assets/mod-extra.png" title="[[USERNAME]] is a custom moderator! (tier [[MODERATOR]])"><!--
|
||||
--><span style="margin-left: 1%">[[USERNAME]]</span>
|
||||
</h1>
|
||||
|
||||
|
||||
<hr style="margin-bottom: 2%" class="profilePostHide">
|
||||
<h3 id="collectibles" class="profilePostHide">
|
||||
<span id="stars">[[STARS]]</span> <img class="help valign" src="../assets/star.png" title="Stars">
|
||||
<span id="diamonds">[[DIAMONDS]]</span> <img class="help valign" src="../assets/diamond.png" title="Diamonds">
|
||||
<span id="coins">[[COINS]]</span> <img class="help valign" src="../assets/coin.png" title="Secret Coins">
|
||||
<span id="usercoins">[[USERCOINS]]</span> <img class="help valign"src="../assets/silvercoin.png" title="User Coins">
|
||||
<span id="demons">[[DEMONS]]</span> <img class="help valign"src="../assets/demon.png" title="Demons">
|
||||
<span id="creatorpoints" style="display: none"><span id="cp">[[CP]]</span> <img class="help valign" src="../assets/cp.png" title="Creator Points"></span>
|
||||
<span id="stars">[[STARS]]</span> <img class="help valign" src="/assets/star.png" title="Stars">
|
||||
<span id="diamonds">[[DIAMONDS]]</span> <img class="help valign" src="/assets/diamond.png" title="Diamonds">
|
||||
<span id="coins">[[COINS]]</span> <img class="help valign" src="/assets/coin.png" title="Secret Coins">
|
||||
<span id="usercoins">[[USERCOINS]]</span> <img class="help valign"src="/assets/silvercoin.png" title="User Coins">
|
||||
<span id="demons">[[DEMONS]]</span> <img class="help valign"src="/assets/demon.png" title="Demons">
|
||||
<span id="creatorpoints" style="display: none"><span id="cp">[[CP]]</span> <img class="help valign" src="/assets/cp.png" title="Creator Points"></span>
|
||||
</h3>
|
||||
|
||||
<div class="lightBox center profilePostHide" id="iconsDiv" style="margin: 2% auto; width: 105vh">
|
||||
|
@ -105,45 +105,45 @@
|
|||
<gdicon iconID=[[WAVE]] iconForm="wave" col1="[[COL1]]" col2="[[COL2]]" glow="[[GLOW]]" imgStyle="height: 7%"></gdicon>
|
||||
<gdicon iconID=[[ROBOT]] iconForm="robot" col1="[[COL1]]" col2="[[COL2]]" glow="[[GLOW]]"></gdicon>
|
||||
<gdicon iconID=[[SPIDER]] iconForm="spider" col1="[[COL1]]" col2="[[COL2]]" glow="[[GLOW]]"></gdicon>
|
||||
<img src="../assets/deatheffects/[[DEATHEFFECT]].png" title="Death Effect [[DEATHEFFECT]]" id="deatheffect">
|
||||
<img src="/assets/deatheffects/[[DEATHEFFECT]].png" title="Death Effect [[DEATHEFFECT]]" id="deatheffect">
|
||||
</div>
|
||||
|
||||
<div class="lightBox center dragscroll" id="statusDiv" normalHeight="36vh" compactHeight="69vh" style="margin: 2% auto; width: 105vh; height: 36vh; background-color: #BE6F3F">
|
||||
</div>
|
||||
|
||||
<div class="center profilePostHide" style="margin: 1.5% auto 2.5% auto;">
|
||||
<a id="msgA" target="_blank"><img src="../assets/messages.png" height="10%" id="msgButton" class="sideSpace gdButton" onclick="$('#settingsDiv').show()"></a>
|
||||
<img src="../assets/friends.png" height="10%" id="friendButton" class="sideSpace gdButton" onclick="$('#settingsDiv').show()">
|
||||
<a id="msgA" target="_blank"><img src="/assets/messages.png" height="10%" id="msgButton" class="sideSpace gdButton" onclick="$('#settingsDiv').show()"></a>
|
||||
<img src="/assets/friends.png" height="10%" id="friendButton" class="sideSpace gdButton" onclick="$('#settingsDiv').show()">
|
||||
</div>
|
||||
|
||||
<div style="position: absolute; bottom: 0%; left: 12%;" class="profilePostHide">
|
||||
<p style="text-align: left; font-size: 2.2vh; color: rgba(0, 0, 0, 0.5)">Account ID: [[ACCOUNTID]]<br>Player ID: [[PLAYERID]]</p>
|
||||
</div>
|
||||
|
||||
<img src="../assets/follow-off.png" id="followOff" class="gdButton profilePostHide" style="position: absolute; left: 4.5%; bottom: 1%; width: 6%">
|
||||
<img src="../assets/follow-on.png" id="followOn" class="gdButton profilePostHide" style="position: absolute; left: 4.5%; bottom: 1%; width: 6%; display: none">
|
||||
|
||||
<a id="commentA"><img src="../assets/comments.png" class="gdButton" id="commentButton" style="position: absolute; right: 0.5%; bottom: 50%; width: 6%" onclick="$('#settingsDiv').show()"></a>
|
||||
<img src="../assets/expanded-off.png" class="gdButton" id="compactMode" style="position: absolute; left: 2%; bottom: 45%; width: 6%">
|
||||
<img src="/assets/follow-off.png" id="followOff" class="gdButton profilePostHide" style="position: absolute; left: 4.5%; bottom: 1%; width: 6%">
|
||||
<img src="/assets/follow-on.png" id="followOn" class="gdButton profilePostHide" style="position: absolute; left: 4.5%; bottom: 1%; width: 6%; display: none">
|
||||
|
||||
<a href="../search/[[USERNAME]]?user"><img src="../assets/levels.png" class="gdButton" style="position: absolute; right: 0.5%; bottom: 1%; width: 6%"></a>
|
||||
<a id="commentA"><img src="/assets/comments.png" class="gdButton" id="commentButton" style="position: absolute; right: 0.5%; bottom: 50%; width: 6%" onclick="$('#settingsDiv').show()"></a>
|
||||
<img src="/assets/expanded-off.png" class="gdButton" id="compactMode" style="position: absolute; left: 2%; bottom: 45%; width: 6%">
|
||||
|
||||
<a href="../search/[[USERNAME]]?user"><img src="/assets/levels.png" class="gdButton" style="position: absolute; right: 0.5%; bottom: 1%; width: 6%"></a>
|
||||
|
||||
<div style="position: absolute; right: 0.5%; top: 0%; width: 6%">
|
||||
<a id="youtube" style="display: none" target="_blank" href="https://youtube.com/channel/[[YOUTUBE]]"><img src="../assets/youtube.png" class="gdButton socialButton"></a>
|
||||
<a id="twitter" style="display: none" target="_blank" href="https://twitter.com/[[TWITTER]]"><img src="../assets/twitter.png" class="gdButton socialButton"></a>
|
||||
<a id="twitch" style="display: none" target="_blank" href="https://twitch.tv/[[TWITCH]]"><img src="../assets/twitch.png" class="gdButton socialButton"></a>
|
||||
<a id="youtube" style="display: none" target="_blank" href="https://youtube.com/channel/[[YOUTUBE]]"><img src="/assets/youtube.png" class="gdButton socialButton"></a>
|
||||
<a id="twitter" style="display: none" target="_blank" href="https://twitter.com/[[TWITTER]]"><img src="/assets/twitter.png" class="gdButton socialButton"></a>
|
||||
<a id="twitch" style="display: none" target="_blank" href="https://twitch.tv/[[TWITCH]]"><img src="/assets/twitch.png" class="gdButton socialButton"></a>
|
||||
</div>
|
||||
|
||||
<div class="supercenter" style="left: 5%; top: 65%; height: 10%">
|
||||
<img class="gdButton" id="pageDown" style="display: none" src="../assets/arrow-left.png" height="95%" onclick="page -= 1; appendComments()">
|
||||
<img class="gdButton" id="pageDown" style="display: none" src="/assets/arrow-left.png" height="95%" onclick="page -= 1; appendComments()">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="supercenter" style="left: 95%; top: 65%; height: 10%;">
|
||||
<img class="gdButton" id="pageUp" src="../assets/arrow-right.png" height="95%" onclick="page += 1; appendComments()">
|
||||
<img class="gdButton" id="pageUp" src="/assets/arrow-right.png" height="95%" onclick="page += 1; appendComments()">
|
||||
</div>
|
||||
|
||||
<div id="postButton" style="position:absolute; bottom: 0%; left: 0%; width: 14%; text-align: left; transform: translate(-35%, 40%);">
|
||||
<img class="gdButton" src="../assets/comment.png" width="60%" onclick="$('#content').trigger('input'); $('#leavePost').show();">
|
||||
<img class="gdButton" src="/assets/comment.png" width="60%" onclick="$('#content').trigger('input'); $('#leavePost').show();">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -153,9 +153,9 @@
|
|||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/6.2.2/browser/pixi.js"></script>
|
||||
<script type="text/javascript" src="../iconkit/icon.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="../dragscroll.js"></script>
|
||||
<script type="text/javascript" src="/iconkit/icon.js"></script>
|
||||
<script type="text/javascript" src="/misc/global.js?v=1"></script>
|
||||
<script type="text/javascript" src="/misc/dragscroll.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
|
@ -170,7 +170,7 @@ renderIcons()
|
|||
// set favicon
|
||||
$('#mainIcon').on('DOMNodeInserted', 'img', function () {
|
||||
$("link[rel='icon']").attr("href", $(this).attr("src"));
|
||||
});
|
||||
})
|
||||
|
||||
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)
|
||||
|
@ -211,14 +211,14 @@ if (`[[TWITTER]]` != "null") $('#twitter').show()
|
|||
if (`[[TWITCH]]` != "null") $('#twitch').show()
|
||||
|
||||
let numRank = parseInt("[[RANK]]")
|
||||
if (numRank < 2) $(".profileTrophy").attr("src","../assets/trophies/1.png")
|
||||
else if (numRank <= 10) $(".profileTrophy").attr("src","../assets/trophies/2.png")
|
||||
else if (numRank <= 50 ) $(".profileTrophy").attr("src","../assets/trophies/3.png")
|
||||
else if (numRank <= 100) $(".profileTrophy").attr("src","../assets/trophies/4.png")
|
||||
else if (numRank <= 200) $(".profileTrophy").attr("src","../assets/trophies/5.png")
|
||||
else if (numRank <= 500) $(".profileTrophy").attr("src","../assets/trophies/6.png")
|
||||
else if (numRank <= 1000) $(".profileTrophy").attr("src","../assets/trophies/7.png")
|
||||
else $(".profileTrophy").attr("src","../assets/trophies/0.png")
|
||||
if (numRank < 2) $(".profileTrophy").attr("src","/assets/trophies/1.png")
|
||||
else if (numRank <= 10) $(".profileTrophy").attr("src","/assets/trophies/2.png")
|
||||
else if (numRank <= 50 ) $(".profileTrophy").attr("src","/assets/trophies/3.png")
|
||||
else if (numRank <= 100) $(".profileTrophy").attr("src","/assets/trophies/4.png")
|
||||
else if (numRank <= 200) $(".profileTrophy").attr("src","/assets/trophies/5.png")
|
||||
else if (numRank <= 500) $(".profileTrophy").attr("src","/assets/trophies/6.png")
|
||||
else if (numRank <= 1000) $(".profileTrophy").attr("src","/assets/trophies/7.png")
|
||||
else $(".profileTrophy").attr("src","/assets/trophies/0.png")
|
||||
|
||||
let messages = "[[MESSAGES]]"
|
||||
let commenthistory = "[[COMMENTHISTORY]]"
|
||||
|
@ -227,10 +227,10 @@ let reqMode = [[FRIENDREQUESTS]] ? "<cg>Enabled</cg>" : "<cr>Disabled</cr>"
|
|||
let dmMode = messages == "all" ? "<cg>Public</cg>" : messages == "friends" ? "<cy>Friends Only</cy>" : "<cr>Disabled</cr>"
|
||||
let commentMode = commenthistory == "all" ? "<cg>Public</cg>" : commenthistory == "friends" ? "<cy>Friends Only</cy>" : "<cr>Disabled</cr>"
|
||||
|
||||
if (commenthistory == "friends") $('#commentButton').attr('src', '../assets/comments-yellow.png')
|
||||
else if (commenthistory == "off") $('#commentButton').attr('src', '../assets/comments-grey.png')
|
||||
if (commenthistory == "friends") $('#commentButton').attr('src', '/assets/comments-yellow.png')
|
||||
else if (commenthistory == "off") $('#commentButton').attr('src', '/assets/comments-grey.png')
|
||||
else {
|
||||
$('#commentButton').attr('src', '../assets/comments.png').attr('onclick', '')
|
||||
$('#commentButton').attr('src', '/assets/comments.png').attr('onclick', '')
|
||||
$('#commentA').attr('href', '../comments/[[USERNAME]]')
|
||||
}
|
||||
|
||||
|
@ -239,10 +239,10 @@ if (messages == "all") {
|
|||
$('#msgA').attr('href', '../messages?sendTo=[[USERNAME]]')
|
||||
}
|
||||
|
||||
if (messages == "friends") $('#msgButton').attr('src', '../assets/messages-yellow.png')
|
||||
else if (messages == "off") $('#msgButton').attr('src', '../assets/messages-grey.png')
|
||||
if (messages == "friends") $('#msgButton').attr('src', '/assets/messages-yellow.png')
|
||||
else if (messages == "off") $('#msgButton').attr('src', '/assets/messages-grey.png')
|
||||
|
||||
if (![[FRIENDREQUESTS]]) $('#friendButton').attr('src', '../assets/friends-grey.png')
|
||||
if (![[FRIENDREQUESTS]]) $('#friendButton').attr('src', '/assets/friends-grey.png')
|
||||
|
||||
$('#userInfo').html($('#userInfo').html()
|
||||
.replace("[[REQS]]", reqMode)
|
||||
|
@ -250,15 +250,15 @@ $('#userInfo').html($('#userInfo').html()
|
|||
.replace("[[COMMENTS]]", commentMode) + (messages == "friends" ? "<br style='line-height: 69%'><a target='_blank' style='color: lime' class='youCanClickThis2' href='../messages?sendTo=[[USERNAME]]'>Send message</a><br>(if friended)" : ""))
|
||||
|
||||
function appendComments() {
|
||||
if (loadingComments) return;
|
||||
if (loadingComments) return
|
||||
else loadingComments = true;
|
||||
|
||||
$('#statusDiv').html(`<div class="supercenter" id="loading" style="height: 12%; top: 62%;"><img class="spin noSelect" src="../assets/loading.png" height="105%"></div>`)
|
||||
$('#statusDiv').html(`<div class="supercenter" id="loading" style="height: 12%; top: 62%;"><img class="spin noSelect" src="/assets/loading.png" height="105%"></div>`)
|
||||
|
||||
if (page == 0) $('#pageDown').hide()
|
||||
else $('#pageDown').show()
|
||||
|
||||
Fetch(`../api/comments/[[ACCOUNTID]]?type=profile&page=${page}`).then(res => {
|
||||
Fetch(`/api/comments/[[ACCOUNTID]]?type=profile&page=${page}`).then(res => {
|
||||
|
||||
if (res.length != 10) $('#pageUp').hide()
|
||||
else $('#pageUp').show()
|
||||
|
@ -277,7 +277,7 @@ function appendComments() {
|
|||
</div>
|
||||
<p class="commentDate">${x.date}</p>
|
||||
<div class="commentLikes">
|
||||
<img id="likeImg" class="likeComment gdButton inline" commentID="${x.ID}" ${x.likes < 0 ? "style='transform: translateY(25%)'" : ""} src="../assets/${x.likes < 0 ? "dis" : ""}like.png" height=20% style="margin-right: 0.4%">
|
||||
<img id="likeImg" class="likeComment gdButton inline" commentID="${x.ID}" ${x.likes < 0 ? "style='transform: translateY(25%)'" : ""} src="/assets/${x.likes < 0 ? "dis" : ""}like.png" height=20% style="margin-right: 0.4%">
|
||||
<h3 class="inline">${x.likes}</h3><br>
|
||||
</div>
|
||||
</div>`)
|
||||
|
@ -325,9 +325,9 @@ $('#submitComment').click(function () {
|
|||
.fail(e => { allowEsc = true; $('.postbutton').show(); $('#message').text(e.responseText.includes("DOCTYPE") ? "Something went wrong..." : e.responseText) })
|
||||
})
|
||||
|
||||
let commentID = 0;
|
||||
let likeCount, likeImg;
|
||||
let likedComments;
|
||||
let commentID = 0
|
||||
let likeCount, likeImg
|
||||
let likedComments
|
||||
let like = true;
|
||||
|
||||
$('#likebtn').click(function() {
|
||||
|
@ -346,7 +346,7 @@ $(document).on('click', '.likeComment', function(cmnt) {
|
|||
commentID = $(this).attr('commentID')
|
||||
|
||||
likedComments = localStorage.likedComments ? JSON.parse(localStorage.likedComments) : []
|
||||
if (likedComments.includes(commentID)) return;
|
||||
if (likedComments.includes(commentID)) return
|
||||
|
||||
lvID = $(this).attr('levelID') || 0
|
||||
likeImg = $(this).find('img')
|
||||
|
@ -356,7 +356,7 @@ $(document).on('click', '.likeComment', function(cmnt) {
|
|||
|
||||
$('#submitVote').click(function() {
|
||||
|
||||
if (likedComments.includes(commentID)) return $('#likeMessage').text("You've already liked/disliked this comment!");
|
||||
if (likedComments.includes(commentID)) return $('#likeMessage').text("You've already liked/disliked this comment!")
|
||||
|
||||
let ID = commentID
|
||||
let username = $('#like-username').val()
|
||||
|
@ -364,14 +364,14 @@ $('#submitVote').click(function() {
|
|||
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 => {
|
||||
Fetch(`/api/profile/${username}`).then(res => {
|
||||
if (!res || res == "-1") {allowEsc = true; $('.postbutton').show(); return $('#likeMessage').text("The username you provided doesn't exist!")}
|
||||
else accountID = res.accountID
|
||||
|
||||
|
@ -379,8 +379,8 @@ $('#submitVote').click(function() {
|
|||
.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')
|
||||
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()
|
||||
|
@ -388,7 +388,7 @@ $('#submitVote').click(function() {
|
|||
allowEsc = true
|
||||
likedComments.push(commentID)
|
||||
localStorage.setItem('likedComments', JSON.stringify(likedComments))
|
||||
})
|
||||
})
|
||||
.fail(e => {allowEsc = true; $('.postbutton').show();$('#likeMessage').text(e.responseText.includes("DOCTYPE") ? "Something went wrong..." : e.responseText)})
|
||||
})
|
||||
})
|
||||
|
@ -400,14 +400,14 @@ $('#compactMode').click(function() {
|
|||
$('.profilePostHide').hide()
|
||||
$('.statusIcon').show()
|
||||
$('#statusDiv').css('height', $('#statusDiv').attr('compactHeight'))
|
||||
$(this).attr('src', "../assets/expanded-on.png")
|
||||
$(this).attr('src', "/assets/expanded-on.png")
|
||||
}
|
||||
|
||||
else {
|
||||
$('.profilePostHide').show()
|
||||
$('.statusIcon').hide()
|
||||
$('.statusIcon').hide()
|
||||
$('#statusDiv').css('height', $('#statusDiv').attr('normalHeight'))
|
||||
$(this).attr('src', "../assets/expanded-off.png")
|
||||
$(this).attr('src', "/assets/expanded-off.png")
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -416,12 +416,12 @@ $('#leavePost').on("change keyup keydown paste click", "textarea", function () {
|
|||
})
|
||||
|
||||
$(document).keydown(function(k) {
|
||||
|
||||
|
||||
if ($('#content').is(':visible')) {
|
||||
if (k.which == 13) k.preventDefault() //enter
|
||||
}
|
||||
|
||||
if (loadingComments || $('.popup').is(":visible")) return;
|
||||
if (loadingComments || $('.popup').is(":visible")) return
|
||||
|
||||
if (k.which == 37 && $('#pageDown').is(":visible")) { //left
|
||||
$('#pageDown').trigger('click')
|
||||
|
@ -431,7 +431,7 @@ $(document).keydown(function(k) {
|
|||
$('#pageUp').trigger('click')
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
|
132
html/search.html
|
@ -1,9 +1,9 @@
|
|||
<head>
|
||||
<title id="tabTitle">Level Search</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="../assets/css/browser.css?v=1" type="text/css" rel="stylesheet">
|
||||
<link href="/assets/css/browser.css?v=1" 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/coin.png">
|
||||
<link rel="icon" href="/assets/coin.png">
|
||||
<meta id="meta-title" property="og:title" content="Level Search">
|
||||
<meta id="meta-desc" property="og:description" content="Search for Geometry Dash levels, and filter by length, difficulty, song + more!">
|
||||
<meta id="meta-image" name="og:image" itemprop="image" content="../coin.png">
|
||||
|
@ -18,15 +18,15 @@
|
|||
<div class="brownbox bounce center supercenter" style="width: 60vh; height: 34%">
|
||||
<h2 class="smaller center" style="font-size: 5.5vh; margin-top: 1%">Jump to Page</h2>
|
||||
<input type="number" id="pageSelect" placeholder="1"><br>
|
||||
<img src="../assets/ok.png" height=20%; id="pageJump" class="gdButton center closeWindow">
|
||||
<img class="closeWindow gdButton" src="../assets/close.png" height="25%" style="position: absolute; top: -13.5%; left: -6vh">
|
||||
<img src="/assets/ok.png" height=20%; id="pageJump" class="gdButton center closeWindow">
|
||||
<img class="closeWindow gdButton" src="/assets/close.png" height="25%" style="position: absolute; top: -13.5%; left: -6vh">
|
||||
|
||||
<div class="supercenter" style="left: 25%; top: 43%; height: 10%;">
|
||||
<img class="gdButton" src="../assets/whitearrow-left.png" height="160%" onclick="$('#pageSelect').val(parseInt($('#pageSelect').val() || 0) - 1); $('#pageSelect').trigger('input');">
|
||||
<img class="gdButton" src="/assets/whitearrow-left.png" height="160%" onclick="$('#pageSelect').val(parseInt($('#pageSelect').val() || 0) - 1); $('#pageSelect').trigger('input');">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="supercenter" style="left: 75%; top: 43%; height: 10%;">
|
||||
<img class="gdButton" src="../assets/whitearrow-right.png" height="160%" onclick="$('#pageSelect').val(parseInt($('#pageSelect').val() || 0) + 1); $('#pageSelect').trigger('input');">
|
||||
<img class="gdButton" src="/assets/whitearrow-right.png" height="160%" onclick="$('#pageSelect').val(parseInt($('#pageSelect').val() || 0) + 1); $('#pageSelect').trigger('input');">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -37,8 +37,8 @@
|
|||
<p class="bigger center" style="line-height: 5vh; margin-top: 1.5vh;">
|
||||
Delete all saved online levels?<br><cy>Levels will be cleared from your browser.</cy>
|
||||
</p>
|
||||
<img src="../assets/btn-cancel-green.png" height=25%; class="gdButton center closeWindow">
|
||||
<img src="../assets/btn-delete.png" height=25%; id="purgeSaved" class="gdButton center sideSpaceB">
|
||||
<img src="/assets/btn-cancel-green.png" height=25%; class="gdButton center closeWindow">
|
||||
<img src="/assets/btn-delete.png" height=25%; id="purgeSaved" class="gdButton center sideSpaceB">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -49,22 +49,22 @@
|
|||
A random level cannot be picked with your current <cy>search filters!</cy>
|
||||
This is because there is no way to tell how many results were found, due to the GD servers inaccurately saying there's <cg>9999</cg>.
|
||||
</p>
|
||||
<img src="../assets/ok.png" width=20%; class="gdButton center closeWindow">
|
||||
<img src="/assets/ok.png" width=20%; class="gdButton center closeWindow">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%;>
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%;>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 0%; right: 0%; width: 100%; text-align: right;">
|
||||
<img class="cornerPiece" src="../assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
<img class="cornerPiece" src="/assets/corner.png" width=7%; style="transform: scaleX(-1)">
|
||||
</div>
|
||||
|
||||
<div id="searchBox" class="supercenter dragscroll">
|
||||
<div style="height: 4.5%"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="epicbox supercenter gs" style="width: 120vh; height: 80%; pointer-events: none;"></div>
|
||||
|
||||
<div class="center" style="position:absolute; top: 8%; left: 0%; right: 0%">
|
||||
|
@ -76,61 +76,62 @@
|
|||
</div>
|
||||
|
||||
<div title="Jump to page" style="text-align: right; position:absolute; top: 7.5%; right: 2%; height: 12%;">
|
||||
<img src="../assets/magnify.png" height="60%" class="gdButton" style="margin-top: 5%" onclick="$('#pageDiv').show(); $('#pageSelect').focus().select()">
|
||||
<img src="/assets/magnify.png" height="60%" class="gdButton" style="margin-top: 5%" onclick="$('#pageDiv').show(); $('#pageSelect').focus().select()">
|
||||
</div>
|
||||
|
||||
<div id="shuffle" title="Random level" style="display: none; text-align: right; position:absolute; top: 7.5%; right: 6.5%; height: 12%;">
|
||||
<img src="../assets/random.png" height="60%" class="gdButton" style="margin-top: 5%">
|
||||
<img src="/assets/random.png" height="60%" class="gdButton" style="margin-top: 5%">
|
||||
</div>
|
||||
|
||||
<div id="lastPage" title="Last page" style="display: none; text-align: right; position:absolute; top: 7.5%; right: 11%; height: 11%;">
|
||||
<img src="../assets/double-arrow.png" height="60%" class="gdButton" style="margin-top: 5%">
|
||||
<img src="/assets/double-arrow.png" height="60%" class="gdButton" style="margin-top: 5%">
|
||||
</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()">
|
||||
<img class="gdButton yesClick" id="backButton" src="/assets/back.png" height="30%" onclick="backButton()">
|
||||
</div>
|
||||
|
||||
<div id="purge" style="position:absolute; bottom: 1%; right: -3%; width: 10%; display:none;">
|
||||
<img class="gdButton" src="../assets/delete.png" width="60%" onclick="$('#purgeDiv').show()">
|
||||
<img class="gdButton" src="/assets/delete.png" width="60%" onclick="$('#purgeDiv').show()">
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 2%; right: 1%; text-align: right; width: 15%;">
|
||||
<img class="gdButton" src="../assets/refresh.png" width="40%" id="refreshPage"></a>
|
||||
<img class="gdButton" src="/assets/refresh.png" width="40%" id="refreshPage"></a>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 2%; right: 8.5%; text-align: right; width: 15%; display: none" id="gdWorld">
|
||||
<a title="Geometry Dash World" href="/search/*?type=gdw"><img class="gdButton" src="../assets/gdw_circle.png" width="40%"></a>
|
||||
<a title="Geometry Dash World" href="/search/*?type=gdw"><img class="gdButton" src="/assets/gdw_circle.png" width="40%"></a>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; bottom: 2%; right: 8.5%; text-align: right; width: 15%; display: none" id="normalGD">
|
||||
<a title="Back to Geometry Dash" href="/search/*?type=featured"><img class="gdButton" src="../assets/gd_circle.png" width="40%"></a>
|
||||
<a title="Back to Geometry Dash" href="/search/*?type=featured"><img class="gdButton" src="/assets/gd_circle.png" width="40%"></a>
|
||||
</div>
|
||||
|
||||
<div style="position: absolute; left: 7%; top: 45%; height: 10%;">
|
||||
<img class="gdButton" id="pageDown" style="display: none"; src="../assets/arrow-left.png" height="90%">
|
||||
<img class="gdButton" id="pageDown" style="display: none"; src="/assets/arrow-left.png" height="90%">
|
||||
</div>
|
||||
|
||||
<div style="position: absolute; right: 7%; top: 45%; height: 10%;">
|
||||
<img class="gdButton" id="pageUp" style="display: none"; src="../assets/arrow-right.png" height="90%">
|
||||
<img class="gdButton" id="pageUp" style="display: none"; src="/assets/arrow-right.png" height="90%">
|
||||
</div>
|
||||
|
||||
<div class="supercenter" id="loading" style="height: 10%; top: 47%; display: none;">
|
||||
<img class="spin noSelect" src="../assets/loading.png" height="105%">
|
||||
<img class="spin noSelect" src="/assets/loading.png" height="105%">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../global.js?v=1"></script>
|
||||
<script type="text/javascript" src="./global.js?v=1"></script>
|
||||
<script type="text/javascript" src="../dragscroll.js"></script>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
$('#pageDown').hide()
|
||||
$('#pageUp').hide()
|
||||
|
||||
let accID;
|
||||
let accID
|
||||
let path = location.pathname.replace('/search/', "")
|
||||
let url = new URL(window.location.href)
|
||||
let gauntlet = url.searchParams.get('gauntlet')
|
||||
|
@ -140,7 +141,7 @@ let list = url.searchParams.get('list')
|
|||
let count = url.searchParams.get('count')
|
||||
let header = url.searchParams.get('header')
|
||||
let demonList = ["demonList", "demonlist"].some(x => typeof url.searchParams.get(x) == "string" || type == x)
|
||||
let loading = false;
|
||||
let loading = false
|
||||
let gauntlets = ["Fire", "Ice", "Poison", "Shadow", "Lava", "Bonus", "Chaos", "Demon", "Time", "Crystal", "Magic", "Spike", "Monster", "Doom", "Death"]
|
||||
|
||||
let page = Math.max(1, url.searchParams.get('page')) - 1
|
||||
|
@ -152,24 +153,26 @@ let superSearch = ['*', '*?type=mostliked', '*?type=mostdownloaded', '*?type=rec
|
|||
let pageCache = {}
|
||||
|
||||
let demonListLink = "https://pointercrate.com/"
|
||||
let searchFilters = `../api/search/${type == 'saved' ? JSON.parse(localStorage.getItem('saved') || '[]').reverse().toString() : accID || path}?page=[PAGE]${count ? "" : "&count=10"}${window.location.search.replace(/\?/g, "&").replace("page", "nope")}`
|
||||
let searchFilters = `/api/search/${type == 'saved' ? JSON.parse(localStorage.getItem('saved') || '[]').reverse().toString() : accID || path}?page=[PAGE]${count ? "" : "&count=10"}${window.location.search.replace(/\?/g, "&").replace("page", "nope")}`
|
||||
|
||||
function clean(text) {return (text || "").toString().replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/=/g, "=").replace(/"/g, """).replace(/'/g, "'")}
|
||||
let clean = text => (text || '').toString().replace(/./gs, c => (
|
||||
{'&': '&', '<': '<', '>': '>', '=': '=', '"': '"', "'": '''}[c] || c
|
||||
))
|
||||
|
||||
if (type == "followed") {
|
||||
let followed = localStorage.followed ? JSON.parse(localStorage.followed) : []
|
||||
searchFilters += ("&creators=" + followed.join())
|
||||
searchFilters += ("&creators=" + followed.join())
|
||||
}
|
||||
|
||||
let hostMatch = window.location.host.match(/\./g)
|
||||
if (hostMatch && hostMatch.length > 1) { // gdps check
|
||||
if (hostMatch?.length > 1) { // gdps check
|
||||
$('#gdWorld').remove()
|
||||
$('#normalGD').remove()
|
||||
}
|
||||
|
||||
function Append(firstLoad, noCache) {
|
||||
|
||||
loading = true;
|
||||
loading = true
|
||||
if (!firstLoad) $('#pagenum').text(`Page ${(page + 1)}${pages ? ` of ${pages}` : ""}`)
|
||||
$('#searchBox').html('<div style="height: 4.5%"></div>')
|
||||
$('#pageSelect').val(page + 1)
|
||||
|
@ -207,7 +210,7 @@ function Append(firstLoad, noCache) {
|
|||
|
||||
if (demonList) {
|
||||
demonListLink = res[0].demonList
|
||||
res = res.sort(function(a, b){return a.demonPosition - b.demonPosition});
|
||||
res = res.sort((a, b) => a.demonPosition - b.demonPosition);
|
||||
}
|
||||
|
||||
res.forEach((x, y) => {
|
||||
|
@ -229,35 +232,35 @@ function Append(firstLoad, noCache) {
|
|||
<h2 class="pre smaller inline gdButton help ${hasAuthor ? "" : "green unregistered"}" title="Account ID: ${x.accountID}\nPlayer ID: ${x.playerID}"><!--
|
||||
-->${hasAuthor && !onePointNine ? `<a style="margin-right: 0.66vh" 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 sideSpaceD" 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%">` : ''}<!--
|
||||
-->${x.twoPlayer ? `<img class="help valign sideSpaceD" title="Two player level" src="../assets/twoPlayer.png" height="12%">` : ''}
|
||||
--><img class="gdButton valign sideSpaceD" 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%">` : ''}<!--
|
||||
-->${x.twoPlayer ? `<img class="help valign sideSpaceD" title="Two player level" src="/assets/twoPlayer.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; padding: 1% 1% 0% 0%">${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 rightSpace" title="Length" src="../assets/time.png" height="14%">${x.length}
|
||||
<img class="help valign rightSpace" title="Downloads" src="../assets/download.png" height="14%">${x.downloads}
|
||||
<img class="help valign rightSpace" title="Likes" src="../assets/${x.disliked ? 'dis' : ''}like.png" height="14%">${x.likes}
|
||||
${x.orbs != 0 ? `<img class="help valign rightSpace" title="Mana Orbs" src="../assets/orbs.png" height="14%">${x.orbs}` : ""}
|
||||
<img class="help valign rightSpace" title="Length" src="/assets/time.png" height="14%">${x.length}
|
||||
<img class="help valign rightSpace" title="Downloads" src="/assets/download.png" height="14%">${x.downloads}
|
||||
<img class="help valign rightSpace" title="Likes" src="/assets/${x.disliked ? 'dis' : ''}like.png" height="14%">${x.likes}
|
||||
${x.orbs != 0 ? `<img class="help valign rightSpace" title="Mana Orbs" src="/assets/orbs.png" height="14%">${x.orbs}` : ""}
|
||||
</h3>
|
||||
|
||||
|
||||
<div class="center" style="position:absolute; top: ${6.5 + (y * 33.5) + (x.coins == 0 ? 2.5 : 0)}%; left: 4.4%; transform:scale(0.82); height: 10%; width: 12.5%;">
|
||||
<img class="help spaced" id="dFace" title="${x.difficulty}${x.epic ? " (Epic)" : x.featured ? " (Featured)" : ""}" src="../assets/difficulties/${x.difficultyFace}.png" height="150%" style="margin-bottom: 0%; ${x.epic ? 'transform:scale(1.2)' : x.featured ? 'transform:scale(1.1)' : ''}">
|
||||
<img class="help spaced" id="dFace" title="${x.difficulty}${x.epic ? " (Epic)" : x.featured ? " (Featured)" : ""}" src="/assets/difficulties/${x.difficultyFace}.png" height="150%" style="margin-bottom: 0%; ${x.epic ? 'transform:scale(1.2)' : x.featured ? 'transform:scale(1.1)' : ''}">
|
||||
<h3 title="">${x.difficulty.includes('Demon') ? "Demon" : x.difficulty}</h3>
|
||||
${x.stars != 0 && !demonList ? `<h3 class="help" title="${x.stars} star${x.stars == 1 ? "" : "s"}${x.starsRequested ? ` (${x.starsRequested} requested)` : ""}">${x.stars}<img class="valign sideSpaceB" src="../assets/star.png" height="35%" style="transform:translateY(-8%)"></h3>` : ""}
|
||||
${x.stars != 0 && !demonList ? `<h3 class="help" title="${x.stars} star${x.stars == 1 ? "" : "s"}${x.starsRequested ? ` (${x.starsRequested} requested)` : ""}">${x.stars}<img class="valign sideSpaceB" src="/assets/star.png" height="35%" style="transform:translateY(-8%)"></h3>` : ""}
|
||||
|
||||
${demonList ? `<h3 class="help yellow" title="Ranked #${x.demonPosition} on the Demon List">#${x.demonPosition}</h3>` : ""}
|
||||
|
||||
<div id="coins" style="margin-top: 3%" title="${x.coins} user coin${x.coins == 1 ? "" : "s"} (${x.verifiedCoins ? "" : "un"}verified)">
|
||||
${x.coins > 0 ? `<img src="../assets/${x.verifiedCoins ? 'silver' : 'brown'}coin.png" height="50%" class="help">` : ""}
|
||||
${x.coins > 1 ? `<img src="../assets/${x.verifiedCoins ? 'silver' : 'brown'}coin.png" height="50%" class="help squeezeB">` : ""}
|
||||
${x.coins > 2 ? `<img src="../assets/${x.verifiedCoins ? 'silver' : 'brown'}coin.png" height="50%" class="help squeezeB">` : ""}
|
||||
${x.coins > 0 ? `<img src="/assets/${x.verifiedCoins ? 'silver' : 'brown'}coin.png" height="50%" class="help">` : ""}
|
||||
${x.coins > 1 ? `<img src="/assets/${x.verifiedCoins ? 'silver' : 'brown'}coin.png" height="50%" class="help squeezeB">` : ""}
|
||||
${x.coins > 2 ? `<img src="/assets/${x.verifiedCoins ? 'silver' : 'brown'}coin.png" height="50%" class="help squeezeB">` : ""}
|
||||
</div>
|
||||
</div>
|
||||
<div class="center" style="position:absolute; right: 7%; transform:translateY(-${demonList ? 19.5 : 16.25}vh); height: 10%">
|
||||
<a title="View level" href="../${x.id}""><img style="margin-bottom: 4.5%" class="valign gdButton" src="../assets/view.png" height="105%"></a>
|
||||
${demonList ? `<br><a title="View leaderboard" href="../demon/${x.demonPosition}""><img class="valign gdButton" src="../assets/trophyButton.png" height="110%"></a>
|
||||
<a title="View on Pointercrate" href="${demonListLink}demonlist/${x.demonPosition}" target=_blank><img class="valign gdButton" src="../assets/demonButton.png" height="110%"></a>` : "" }
|
||||
<a title="View level" href="../${x.id}""><img style="margin-bottom: 4.5%" class="valign gdButton" src="/assets/view.png" height="105%"></a>
|
||||
${demonList ? `<br><a title="View leaderboard" href="../demon/${x.demonPosition}""><img class="valign gdButton" src="/assets/trophyButton.png" height="110%"></a>
|
||||
<a title="View on Pointercrate" href="${demonListLink}demonlist/${x.demonPosition}" target=_blank><img class="valign gdButton" src="/assets/demonButton.png" height="110%"></a>` : "" }
|
||||
<p title="Level ID" style="text-align: right; color: rgba(0, 0, 0, 0.4); font-size: 2.2vh; transform: translate(2.8vh, ${demonList ? -1.8 : 2.5}vh)">#${x.id}</p>
|
||||
</div>
|
||||
</div>`)
|
||||
|
@ -336,31 +339,26 @@ if (!$('#header').text() && typeof userMode != "string") {
|
|||
$('.closeWindow').click(function() {$(".popup").attr('style', 'display: none;')})
|
||||
|
||||
$('#purgeSaved').click(function() {
|
||||
localStorage.removeItem('saved');
|
||||
localStorage.removeItem('saved')
|
||||
location.reload()
|
||||
})
|
||||
|
||||
var max = 9999
|
||||
var min = 1
|
||||
function onPageSel(that) {
|
||||
let x = $(that).val()
|
||||
if (x != "") $(that).val(clamp(Math.floor(x), 1, 9999))
|
||||
}
|
||||
|
||||
$('#pageSelect').on('input', function () {
|
||||
var x = $(this).val();
|
||||
if ($(this).val() != "") $(this).val(Math.max(Math.min(Math.floor(x), max), min));
|
||||
});
|
||||
|
||||
$('#pageSelect').on('blur', function () {
|
||||
var x = $(this).val();
|
||||
if ($(this).val() != "") $(this).val(Math.max(Math.min(Math.floor(x), max), min));
|
||||
});
|
||||
$('#pageSelect').on('input', function() {onPageSel(this)})
|
||||
$('#pageSelect').on('blur', function() {onPageSel(this)})
|
||||
|
||||
$('#shuffle').click(function() {
|
||||
if (superSearch) {
|
||||
$('#searchBox').html('<div style="height: 4.5%"></div>')
|
||||
$('#loading').show()
|
||||
fetch("../api/search/*?page=0&type=recent").then(res => res.json()).then(recent => {
|
||||
fetch("/api/search/*?page=0&type=recent").then(res => res.json()).then(recent => {
|
||||
let mostRecent = recent[0].id
|
||||
function fetchRandom() {
|
||||
fetch(`../api/level/${Math.floor(Math.random() * (mostRecent)) + 1}`).then(res => res.json()).then(res => {
|
||||
fetch(`/api/level/${randInt(0, mostRecent) + 1}`).then(res => res.json()).then(res => {
|
||||
if (res == "-1" || !res.id) return fetchRandom()
|
||||
else window.location.href = "../" + res.id
|
||||
})
|
||||
|
@ -371,7 +369,7 @@ $('#shuffle').click(function() {
|
|||
else if (pages) {
|
||||
let random = {}
|
||||
let pageCount = +count || 10
|
||||
randomResult = Math.floor(Math.random() * (results)) + 1
|
||||
randomResult = randInt(0, results) + 1
|
||||
randomPage = Math.ceil(randomResult / pageCount)
|
||||
randomIndex = randomResult % pageCount
|
||||
if (randomIndex == 0) randomIndex = pageCount
|
||||
|
@ -385,11 +383,11 @@ $('#shuffle').click(function() {
|
|||
})
|
||||
|
||||
$(document).keydown(function(k) {
|
||||
if (loading) return;
|
||||
if (loading) return
|
||||
|
||||
if ($('#pageDiv').is(':visible')) {
|
||||
if (k.which == 13) $('#pageJump').trigger('click') //enter
|
||||
else return;
|
||||
if (k.which == 13) $('#pageJump').trigger('click') //enter
|
||||
else return
|
||||
}
|
||||
|
||||
if (k.which == 37 && $('#pageDown').is(":visible")) $('#pageDown').trigger('click') // left
|
||||
|
|
|
@ -51,4 +51,4 @@
|
|||
{ "form": "spider", "id": 7, "type": "treasureRoom", "keys": 1 },
|
||||
{ "form": "spider", "id": 10, "type": "gauntlet", "gauntlet": "Demon" },
|
||||
{ "form": "spider", "id": 17, "type": "treasureRoom", "keys": 5 }
|
||||
]
|
||||
]
|
||||
|
|
221
iconkit/icon.js
|
@ -1,3 +1,4 @@
|
|||
"use strict";
|
||||
const WHITE = 0xffffff
|
||||
const colorNames = { "1": "Color 1", "2": "Color 2", "g": "Glow", "w": "White", "u": "UFO Dome" }
|
||||
const formNames = { "player": "icon", "player_ball": "ball", "bird": "ufo", "dart": "wave" }
|
||||
|
@ -5,10 +6,19 @@ const loader = PIXI.Loader.shared
|
|||
|
||||
const loadedNewIcons = {}
|
||||
|
||||
let positionMultiplier = 4
|
||||
const TAU = Math.PI * 2
|
||||
// by default, converts degrees to rads
|
||||
const toRadians = (angle, scale = 360) => TAU / scale * angle
|
||||
// default rad to deg
|
||||
const fromRadians = (rad, scale = 360) => rad / (TAU / scale)
|
||||
// `scale` is the num of subdivisions in a turn. More info: https://en.wikipedia.org/wiki/Turn_(angle)
|
||||
// `scale = 400` corresponds to gradians, `256` to byte radians, and `100` to percentage of a turn
|
||||
|
||||
const positionMultiplier = 4
|
||||
function positionPart(part, partIndex, layer, formName, isNew, isGlow) {
|
||||
layer.position.x += (part.pos[0] * positionMultiplier * (isNew ? 0.5 : 1))
|
||||
layer.position.y -= (part.pos[1] * positionMultiplier * (isNew ? 0.5 : 1))
|
||||
let truePosMultiplier = positionMultiplier / (isNew ? 2 : 1)
|
||||
layer.position.x += (part.pos[0] * truePosMultiplier)
|
||||
layer.position.y -= (part.pos[1] * truePosMultiplier)
|
||||
layer.scale.x = part.scale[0]
|
||||
layer.scale.y = part.scale[1]
|
||||
if (part.flipped[0]) layer.scale.x *= -1
|
||||
|
@ -20,17 +30,18 @@ function positionPart(part, partIndex, layer, formName, isNew, isGlow) {
|
|||
let tintInfo = iconData.robotAnimations.info[formName].tints
|
||||
let foundTint = tintInfo[partIndex]
|
||||
if (foundTint > 0) {
|
||||
let darkenFilter = new PIXI.filters.ColorMatrixFilter();
|
||||
let darkenFilter = new PIXI.filters.ColorMatrixFilter()
|
||||
darkenFilter.brightness(0)
|
||||
darkenFilter.alpha = (255 - foundTint) / 255
|
||||
darkenFilter.alpha = 1 - foundTint / 255
|
||||
layer.filters = [darkenFilter]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validNum(val, defaultVal) {
|
||||
function sanitizeNum(val, defaultVal) {
|
||||
let colVal = +val
|
||||
return isNaN(colVal) ? defaultVal : colVal
|
||||
// yes, it also checks for NaN
|
||||
return isFinite(colVal) ? colVal : defaultVal
|
||||
}
|
||||
|
||||
function getGlowColor(colors) {
|
||||
|
@ -39,17 +50,17 @@ function getGlowColor(colors) {
|
|||
return glowCol
|
||||
}
|
||||
|
||||
function validateIconID(id, form) {
|
||||
let realID = Math.min(iconData.newIconCounts[form], Math.abs(validNum(id, 1)))
|
||||
function sanitizeIconID(id, form) {
|
||||
let realID = Math.min(iconData.newIconCounts[form], Math.abs(sanitizeNum(id, 1)))
|
||||
if (realID == 0 && !["player", "player_ball"].includes(form)) realID = 1
|
||||
return realID
|
||||
}
|
||||
|
||||
function parseIconColor(col) {
|
||||
if (!col) return WHITE
|
||||
else if (typeof col == "string" && col.length >= 6) return parseInt(col, 16)
|
||||
if (typeof col == "string" && col.length >= 6) return parseInt(col, 16)
|
||||
let rgb = iconData.colors[col]
|
||||
return rgb ? rgbToDecimal(rgb) : WHITE;
|
||||
return rgb ? rgb2Pac(rgb) : WHITE
|
||||
}
|
||||
|
||||
function parseIconForm(form) {
|
||||
|
@ -58,7 +69,7 @@ function parseIconForm(form) {
|
|||
}
|
||||
|
||||
function loadIconLayers(form, id, cb) {
|
||||
let iconStr = `${form}_${padZero(validateIconID(id, form))}`
|
||||
let iconStr = `${form}_${padZero(sanitizeIconID(id, form))}`
|
||||
let texturesToLoad = Object.keys(iconData.gameSheet).filter(x => x.startsWith(iconStr + "_"))
|
||||
|
||||
if (loadedNewIcons[texturesToLoad[0]]) return cb(loader, loader.resources, true)
|
||||
|
@ -67,7 +78,10 @@ function loadIconLayers(form, id, cb) {
|
|||
if (iconData.newIcons.includes(iconStr)) return loadNewIcon(iconStr, cb)
|
||||
}
|
||||
|
||||
loader.add(texturesToLoad.filter(x => !loader.resources[x]).map(x => ({ name: x, url: `/iconkit/icons/${x}` })))
|
||||
loader.add(texturesToLoad
|
||||
.filter(x => !loader.resources[x])
|
||||
.map(x => ({ name: x, url: `/iconkit/icons/${x}` }))
|
||||
)
|
||||
loader.load(cb) // no params
|
||||
}
|
||||
|
||||
|
@ -80,11 +94,11 @@ function loadNewIcon(iconStr, cb) {
|
|||
loader.add({ name: sheetName, url: `/iconkit/newicons/${iconStr}-hd.png` })
|
||||
loader.load((l, resources) => {
|
||||
let texture = resources[sheetName].texture
|
||||
Object.keys(data).forEach(x => {
|
||||
let bounds = data[x]
|
||||
Object.keys(data).forEach(k => {
|
||||
let bounds = data[k]
|
||||
let textureRect = new PIXI.Rectangle(bounds.pos[0], bounds.pos[1], bounds.size[0], bounds.size[1])
|
||||
let partTexture = new PIXI.Texture(texture, textureRect)
|
||||
loadedNewIcons[x] = partTexture
|
||||
loadedNewIcons[k] = partTexture
|
||||
})
|
||||
cb(l, resources, true)
|
||||
})
|
||||
|
@ -104,23 +118,23 @@ function parseNewPlist(data) {
|
|||
iconData.gameSheet[frameName] = {}
|
||||
positionData[frameName] = {}
|
||||
|
||||
for (let n=0; n < frameData.length; n += 2) {
|
||||
for (let n = 0; n < frameData.length; n += 2) {
|
||||
let keyName = frameData[n].innerHTML
|
||||
let keyData = frameData[n + 1].innerHTML
|
||||
if (["spriteOffset", "spriteSize", "spriteSourceSize"].includes(keyName)) {
|
||||
iconData.gameSheet[frameName][keyName] = parseWeirdArray(keyData)
|
||||
switch (keyName) {
|
||||
case "spriteOffset": case "spriteSize": case "spriteSourceSize":
|
||||
iconData.gameSheet[frameName][keyName] = parseWeirdArray(keyData)
|
||||
break
|
||||
case "textureRotated":
|
||||
isRotated = frameData[n + 1].outerHTML.includes("true")
|
||||
iconData.gameSheet[frameName][keyName] = isRotated
|
||||
break
|
||||
case "textureRect":
|
||||
let textureArr = keyData.slice(1, -1).split("},{").map(parseWeirdArray)
|
||||
positionData[frameName].pos = textureArr[0]
|
||||
positionData[frameName].size = textureArr[1]
|
||||
break
|
||||
}
|
||||
|
||||
else if (keyName == "textureRotated") {
|
||||
isRotated = frameData[n + 1].outerHTML.includes("true")
|
||||
iconData.gameSheet[frameName][keyName] = isRotated
|
||||
}
|
||||
|
||||
else if (keyName == "textureRect") {
|
||||
let textureArr = keyData.slice(1, -1).split("},{").map(x => parseWeirdArray(x))
|
||||
positionData[frameName].pos = textureArr[0]
|
||||
positionData[frameName].size = textureArr[1]
|
||||
}
|
||||
}
|
||||
|
||||
if (isRotated) positionData[frameName].size.reverse()
|
||||
|
@ -129,35 +143,37 @@ function parseNewPlist(data) {
|
|||
return positionData
|
||||
}
|
||||
|
||||
function parseWeirdArray(data) {
|
||||
return data.replace(/[^0-9,-]/g, "").split(",").map(x => +x)
|
||||
}
|
||||
let parseWeirdArray = data => data.replace(/[^\d,-]/g, "").split(",").map(x => +x)
|
||||
|
||||
function padZero(num) {
|
||||
let numStr = num.toString()
|
||||
if (num < 10) numStr = "0" + numStr
|
||||
return numStr
|
||||
}
|
||||
let padZero = num => num.toString().padStart(2, "0")
|
||||
|
||||
function rgbToDecimal(rgb) {
|
||||
return (rgb.r << 16) + (rgb.g << 8) + rgb.b;
|
||||
}
|
||||
/*
|
||||
name explanation:
|
||||
`Number`s are not decimals, because they are not `String`s, and the internal representation is binary.
|
||||
This means "rgbToDecimal" is a misleading name.
|
||||
Converting independent color components into one number is called "color packing".
|
||||
So I thougth it would be funny to rename `rgbToPacked` into `rgb2Pac`.
|
||||
Alternative names could be `rgbPacker` or `packRGB`, IDK
|
||||
- said by @Rudxain
|
||||
*/
|
||||
let rgb2Pac = rgb => (rgb.r << 16) | (rgb.g << 8) | rgb.b
|
||||
|
||||
class Icon {
|
||||
constructor(data={}, cb) {
|
||||
this.app = data.app
|
||||
this.sprite = new PIXI.Container();
|
||||
this.sprite = new PIXI.Container()
|
||||
this.form = data.form || "player"
|
||||
this.id = validateIconID(data.id, this.form)
|
||||
this.id = sanitizeIconID(data.id, this.form)
|
||||
this.new = !!data.new
|
||||
|
||||
this.colors = {
|
||||
"1": validNum(data.col1, 0xafafaf), // primary
|
||||
"2": validNum(data.col2, WHITE), // secondary
|
||||
"g": validNum(data.colG, validNum(+data.colg, null)), // glow
|
||||
"w": validNum(data.colW, validNum(+data.colw, WHITE)), // white
|
||||
"u": validNum(data.colU, validNum(+data.colu, WHITE)), // ufo
|
||||
"1": sanitizeNum(data.col1, 0xafafaf), // primary
|
||||
"2": sanitizeNum(data.col2, WHITE), // secondary
|
||||
"g": sanitizeNum(data.colG, sanitizeNum(data.colg, null)), // glow
|
||||
"w": sanitizeNum(data.colW, sanitizeNum(data.colw, WHITE)), // white
|
||||
"u": sanitizeNum(data.colU, sanitizeNum(data.colu, WHITE)), // ufo
|
||||
}
|
||||
|
||||
|
||||
this.glow = !!data.glow
|
||||
this.layers = []
|
||||
this.glowLayers = []
|
||||
|
@ -178,22 +194,24 @@ class Icon {
|
|||
let idlePosition = this.getAnimation(data.animation, data.animationForm).frames[0]
|
||||
idlePosition.forEach((x, y) => {
|
||||
x.name = iconData.robotAnimations.info[this.form].names[y]
|
||||
|
||||
let part = new IconPart(this.form, this.id, this.colors, false, { part: x, skipGlow: true, new: this.new })
|
||||
positionPart(x, y, part.sprite, this.form, this.new)
|
||||
|
||||
|
||||
let glowPart = new IconPart(this.form, this.id, this.colors, true, { part: x, onlyGlow: true, new: this.new })
|
||||
positionPart(x, y, glowPart.sprite, this.form, this.new, true)
|
||||
|
||||
glowPart.sprite.visible = this.glow
|
||||
this.glowLayers.push(glowPart)
|
||||
|
||||
|
||||
this.layers.push(part)
|
||||
this.sprite.addChild(part.sprite)
|
||||
})
|
||||
|
||||
let fullGlow = new PIXI.Container();
|
||||
|
||||
let fullGlow = new PIXI.Container()
|
||||
this.glowLayers.forEach(x => fullGlow.addChild(x.sprite))
|
||||
this.sprite.addChildAt(fullGlow, 0)
|
||||
if (typeof Ease !== "undefined") this.ease = new Ease.Ease()
|
||||
if (typeof Ease != "undefined") this.ease = new Ease.Ease()
|
||||
this.animationSpeed = Math.abs(Number(data.animationSpeed) || 1)
|
||||
if (data.animation) this.setAnimation(data.animation, data.animationForm)
|
||||
}
|
||||
|
@ -209,14 +227,16 @@ class Icon {
|
|||
|
||||
getAllLayers() {
|
||||
let allLayers = [];
|
||||
(this.complex ? this.glowLayers : []).concat(this.layers).forEach(x => x.sections.forEach(s => allLayers.push(s)))
|
||||
(this.complex ? this.glowLayers : [])
|
||||
.concat(this.layers)
|
||||
.forEach(x => x.sections.forEach(s => allLayers.push(s)))
|
||||
return allLayers
|
||||
}
|
||||
|
||||
setColor(colorType, newColor, extra={}) {
|
||||
let colorStr = String(colorType).toLowerCase()
|
||||
if (!colorType || !Object.keys(this.colors).includes(colorStr)) return
|
||||
else this.colors[colorStr] = newColor
|
||||
if (!colorType || !this.colors.hasOwnProperty(colorStr)) return
|
||||
this.colors[colorStr] = newColor
|
||||
let newGlow = getGlowColor(this.colors)
|
||||
this.getAllLayers().forEach(x => {
|
||||
if (colorType != "g" && x.colorType == colorStr) x.setColor(newColor)
|
||||
|
@ -228,13 +248,9 @@ class Icon {
|
|||
}
|
||||
}
|
||||
|
||||
formName() {
|
||||
return formNames[this.form] || this.form
|
||||
}
|
||||
formName() { return formNames[this.form] || this.form }
|
||||
|
||||
isGlowing() {
|
||||
return this.glowLayers[0].sprite.visible
|
||||
}
|
||||
isGlowing() { return this.glowLayers[0].sprite.visible }
|
||||
|
||||
setGlow(toggle) {
|
||||
this.glow = !!toggle
|
||||
|
@ -258,7 +274,7 @@ class Icon {
|
|||
animData.frames[this.animationFrame].forEach((newPart, index) => {
|
||||
let section = this.layers[index]
|
||||
let glowSection = this.glowLayers[index]
|
||||
let truePosMultiplier = this.new ? positionMultiplier * 0.5 : positionMultiplier
|
||||
let truePosMultiplier = positionMultiplier / (this.new ? 2 : 1)
|
||||
if (!section) return
|
||||
|
||||
// gd is weird with negative rotations
|
||||
|
@ -270,16 +286,16 @@ class Icon {
|
|||
y: newPart.pos[1] * truePosMultiplier * -1,
|
||||
scaleX: newPart.scale[0],
|
||||
scaleY: newPart.scale[1],
|
||||
rotation: realRot * (Math.PI / 180) // radians
|
||||
rotation: toRadians(realRot)
|
||||
}
|
||||
if (newPart.flipped[0]) movementData.scaleX *= -1
|
||||
if (newPart.flipped[1]) movementData.scaleY *= -1
|
||||
|
||||
let bothSections = [section, glowSection]
|
||||
bothSections.forEach((x, y) => {
|
||||
let easing = this.ease.add(x.sprite, movementData, { duration: duration || 1, ease: 'linear' })
|
||||
let easing = this.ease.add(x.sprite, movementData, { duration: duration || 1, ease: "linear" })
|
||||
let continueAfterEase = animData.frames.length > 1 && y == 0 && index == 0 && animName == this.animationName
|
||||
if (continueAfterEase) easing.on('complete', () => {
|
||||
if (continueAfterEase) easing.on("complete", () => {
|
||||
this.animationFrame++
|
||||
if (this.animationFrame >= animData.frames.length) {
|
||||
if (animData.info.loop) this.animationFrame = 0
|
||||
|
@ -294,7 +310,7 @@ class Icon {
|
|||
// find actual icon size by reading pixel data (otherwise there's whitespace and shit)
|
||||
if (this.new) this.sprite.scale.set(1)
|
||||
let spriteSize = [Math.round(this.sprite.width), Math.round(this.sprite.height)]
|
||||
let pixels = this.app.renderer.plugins.extract.pixels(this.sprite);
|
||||
let pixels = this.app.renderer.plugins.extract.pixels(this.sprite)
|
||||
let xRange = [spriteSize[0], 0]
|
||||
let yRange = [spriteSize[1], 0]
|
||||
|
||||
|
@ -316,7 +332,7 @@ class Icon {
|
|||
// this took hours to figure out. i fucking hate my life
|
||||
xRange[1]++
|
||||
yRange[1]++
|
||||
|
||||
|
||||
let realWidth = xRange[1] - xRange[0]
|
||||
let realHeight = yRange[1] - yRange[0]
|
||||
|
||||
|
@ -336,35 +352,35 @@ class Icon {
|
|||
|
||||
toDataURL(dataType="image/png") {
|
||||
this.autocrop()
|
||||
this.app.renderer.render(this.app.stage);
|
||||
let b64data = this.app.view.toDataURL(dataType);
|
||||
this.app.renderer.render(this.app.stage)
|
||||
let b64data = this.app.view.toDataURL(dataType)
|
||||
this.revertCrop()
|
||||
return b64data
|
||||
}
|
||||
|
||||
pngExport() {
|
||||
let b64data = this.toDataURL()
|
||||
let downloader = document.createElement('a');
|
||||
let downloader = document.createElement("a")
|
||||
downloader.href = b64data
|
||||
downloader.setAttribute("download", `${this.formName()}_${this.id}.png`);
|
||||
document.body.appendChild(downloader);
|
||||
downloader.click();
|
||||
document.body.removeChild(downloader);
|
||||
downloader.setAttribute("download", `${this.formName()}_${this.id}.png`)
|
||||
document.body.appendChild(downloader)
|
||||
downloader.click()
|
||||
document.body.removeChild(downloader)
|
||||
}
|
||||
|
||||
copyToClipboard() {
|
||||
this.autocrop()
|
||||
this.app.renderer.render(app.stage);
|
||||
this.app.renderer.render(app.stage)
|
||||
this.app.view.toBlob(blob => {
|
||||
let item = new ClipboardItem({ "image/png": blob });
|
||||
navigator.clipboard.write([item]);
|
||||
});
|
||||
let item = new ClipboardItem({ "image/png": blob })
|
||||
navigator.clipboard.write([item])
|
||||
})
|
||||
this.revertCrop()
|
||||
|
||||
}
|
||||
|
||||
psdExport() {
|
||||
if (typeof agPsd === "undefined") throw new Error("ag-psd not imported!")
|
||||
if (typeof agPsd == "undefined") throw new Error("ag-psd not imported!")
|
||||
let glowing = this.isGlowing()
|
||||
this.setGlow(true)
|
||||
|
||||
|
@ -376,10 +392,10 @@ class Icon {
|
|||
function addPSDLayer(layer, parent, sprite) {
|
||||
allLayers.forEach(x => x.sprite.alpha = 0)
|
||||
layer.sprite.alpha = 255
|
||||
|
||||
|
||||
let layerChild = { name: layer.colorName, canvas: renderer.plugins.extract.canvas(sprite) }
|
||||
if (layer.colorType == "g") {
|
||||
if (parent.part) layerChild.name = parent.part.name + " glow"
|
||||
if (parent.part) layerChild.name = `${parent.part.name} glow`
|
||||
else layerChild.blendMode = "linear dodge"
|
||||
if (!complex && !glowing) layerChild.hidden = true
|
||||
}
|
||||
|
@ -404,13 +420,13 @@ class Icon {
|
|||
|
||||
allLayers.forEach(x => x.sprite.alpha = 255)
|
||||
let output = agPsd.writePsd(psd)
|
||||
let blob = new Blob([output]);
|
||||
let downloader = document.createElement('a');
|
||||
downloader.href = URL.createObjectURL(blob);
|
||||
downloader.setAttribute("download", `${this.formName()}_${this.id}.psd`);
|
||||
document.body.appendChild(downloader);
|
||||
downloader.click();
|
||||
document.body.removeChild(downloader);
|
||||
let blob = new Blob([output])
|
||||
let downloader = document.createElement("a")
|
||||
downloader.href = URL.createObjectURL(blob)
|
||||
downloader.setAttribute("download", `${this.formName()}_${this.id}.psd`)
|
||||
document.body.appendChild(downloader)
|
||||
downloader.click()
|
||||
document.body.removeChild(downloader)
|
||||
this.setGlow(glowing)
|
||||
}
|
||||
}
|
||||
|
@ -421,11 +437,11 @@ class IconPart {
|
|||
if (colors[1] == 0 && !misc.skipGlow) glow = true // add glow if p1 is black
|
||||
|
||||
let iconPath = `${form}_${padZero(id)}`
|
||||
let partString = misc.part ? "_" + padZero(misc.part.part) : ""
|
||||
let partString = misc.part ? `_${padZero(misc.part.part)}` : ""
|
||||
let sections = {}
|
||||
if (misc.part) this.part = misc.part
|
||||
|
||||
this.sprite = new PIXI.Container();
|
||||
this.sprite = new PIXI.Container()
|
||||
this.sections = []
|
||||
|
||||
if (!misc.skipGlow) {
|
||||
|
@ -448,11 +464,22 @@ class IconPart {
|
|||
}
|
||||
}
|
||||
|
||||
let layerOrder = ["glow", "ufo", "col2", "col1", "white"].map(x => sections[x]).filter(x => x)
|
||||
layerOrder.forEach(x => {
|
||||
let layerOrder = ["glow", "ufo", "col2", "col1", "white"]
|
||||
for (let x of layerOrder) {
|
||||
x = sections[x]
|
||||
if (!x) continue
|
||||
this.sections.push(x)
|
||||
this.sprite.addChild(x.sprite)
|
||||
})
|
||||
}
|
||||
/* alternative:
|
||||
|
||||
layerOrder.map(x => sections[x])
|
||||
.filter(x => x)
|
||||
.forEach(x => {
|
||||
this.sections.push(x)
|
||||
this.sprite.addChild(x.sprite)
|
||||
})
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,7 +506,7 @@ class IconLayer {
|
|||
}
|
||||
|
||||
setColor(color) {
|
||||
this.color = validNum(color, WHITE)
|
||||
this.color = sanitizeNum(color, WHITE)
|
||||
this.sprite.tint = this.color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.agPsd = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
||||
(function(f){if(typeof exports=="object"&&typeof module!="undefined"){module.exports=f()}else if(typeof define=="function"&&define.amd){define([],f)}else{var g;if(typeof window!="undefined"){g=window}else if(typeof global!="undefined"){g=global}else if(typeof self!="undefined"){g=self}else{g=this}g.agPsd = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.readAbr = void 0;
|
||||
|
@ -1189,7 +1189,7 @@ addHandler('Anno', function (target) { return target.annotations !== undefined;
|
|||
var sound = annotation.type === 'sound';
|
||||
if (sound && !(annotation.data instanceof Uint8Array))
|
||||
throw new Error('Sound annotation data should be Uint8Array');
|
||||
if (!sound && typeof annotation.data !== 'string')
|
||||
if (!sound && typeof annotation.data != 'string')
|
||||
throw new Error('Text annotation data should be string');
|
||||
var lengthOffset = writer.offset;
|
||||
psdWriter_1.writeUint32(writer, 0); // length
|
||||
|
@ -3049,16 +3049,16 @@ function getTypeByKey(key, value, root) {
|
|||
return ('Wdth' in value) ? 'Objc' : (('units' in value) ? 'UntF' : 'doub');
|
||||
}
|
||||
else if (key === 'Type') {
|
||||
return typeof value === 'string' ? 'enum' : 'long';
|
||||
return typeof value == 'string' ? 'enum' : 'long';
|
||||
}
|
||||
else if (key === 'AntA') {
|
||||
return typeof value === 'string' ? 'enum' : 'bool';
|
||||
return typeof value == 'string' ? 'enum' : 'bool';
|
||||
}
|
||||
else if (key === 'Hrzn' || key === 'Vrtc' || key === 'Top ' || key === 'Left' || key === 'Btom' || key === 'Rght') {
|
||||
return typeof value === 'number' ? 'doub' : 'UntF';
|
||||
return typeof value == 'number' ? 'doub' : 'UntF';
|
||||
}
|
||||
else if (key === 'Vrsn') {
|
||||
return typeof value === 'number' ? 'long' : 'Objc';
|
||||
return typeof value == 'number' ? 'long' : 'Objc';
|
||||
}
|
||||
else if (key === 'Rd ' || key === 'Grn ' || key === 'Bl ') {
|
||||
return root === 'artd' ? 'long' : 'doub';
|
||||
|
@ -3390,7 +3390,7 @@ function writeReferenceStructure(writer, _key, items) {
|
|||
for (var i = 0; i < items.length; i++) {
|
||||
var value = items[i];
|
||||
var type = 'unknown';
|
||||
if (typeof value === 'string') {
|
||||
if (typeof value == 'string') {
|
||||
if (/^[a-z]+\.[a-z]+$/i.test(value)) {
|
||||
type = 'Enmr';
|
||||
}
|
||||
|
@ -3485,7 +3485,7 @@ function parseUnits(_a) {
|
|||
exports.parseUnits = parseUnits;
|
||||
function parseUnitsOrNumber(value, units) {
|
||||
if (units === void 0) { units = 'Pixels'; }
|
||||
if (typeof value === 'number')
|
||||
if (typeof value == 'number')
|
||||
return { value: value, units: units };
|
||||
return parseUnits(value);
|
||||
}
|
||||
|
@ -3508,10 +3508,10 @@ exports.unitsPercent = unitsPercent;
|
|||
function unitsValue(x, key) {
|
||||
if (x == null)
|
||||
return { units: 'Pixels', value: 0 };
|
||||
if (typeof x !== 'object')
|
||||
if (typeof x != 'object')
|
||||
throw new Error("Invalid value: " + JSON.stringify(x) + " (key: " + key + ") (should have value and units)");
|
||||
var units = x.units, value = x.value;
|
||||
if (typeof value !== 'number')
|
||||
if (typeof value != 'number')
|
||||
throw new Error("Invalid value in " + JSON.stringify(x) + " (key: " + key + ")");
|
||||
if (units !== 'Pixels' && units !== 'Millimeters' && units !== 'Points' && units !== 'None' &&
|
||||
units !== 'Picas' && units !== 'Inches' && units !== 'Centimeters' && units !== 'Density') {
|
||||
|
@ -4009,7 +4009,7 @@ function parseEngineData(data) {
|
|||
if (!stack.length)
|
||||
throw new Error('Invalid data');
|
||||
var top = stack[stack.length - 1];
|
||||
if (typeof top === 'string') {
|
||||
if (typeof top == 'string') {
|
||||
stack[stack.length - 2][top] = value;
|
||||
pop();
|
||||
}
|
||||
|
@ -4024,7 +4024,7 @@ function parseEngineData(data) {
|
|||
if (!stack.length)
|
||||
pushContainer({});
|
||||
var top = stack[stack.length - 1];
|
||||
if (top && typeof top === 'string') {
|
||||
if (top && typeof top == 'string') {
|
||||
if (name === 'nil') {
|
||||
pushValue(null);
|
||||
}
|
||||
|
@ -4032,7 +4032,7 @@ function parseEngineData(data) {
|
|||
pushValue("/" + name);
|
||||
}
|
||||
}
|
||||
else if (top && typeof top === 'object') {
|
||||
else if (top && typeof top == 'object') {
|
||||
stack.push(name);
|
||||
}
|
||||
else {
|
||||
|
@ -4196,15 +4196,15 @@ function serializeEngineData(data, condensed) {
|
|||
writePrefix();
|
||||
writeString(condensed ? '/nil' : 'null');
|
||||
}
|
||||
else if (typeof value === 'number') {
|
||||
else if (typeof value == 'number') {
|
||||
writePrefix();
|
||||
writeString(serializeNumber(value, key));
|
||||
}
|
||||
else if (typeof value === 'boolean') {
|
||||
else if (typeof value == 'boolean') {
|
||||
writePrefix();
|
||||
writeString(value ? 'true' : 'false');
|
||||
}
|
||||
else if (typeof value === 'string') {
|
||||
else if (typeof value == 'string') {
|
||||
writePrefix();
|
||||
if ((key === '99' || key === '98') && value.charAt(0) === '/') {
|
||||
writeString(value);
|
||||
|
@ -4223,7 +4223,7 @@ function serializeEngineData(data, condensed) {
|
|||
}
|
||||
else if (Array.isArray(value)) {
|
||||
writePrefix();
|
||||
if (value.every(function (x) { return typeof x === 'number'; })) {
|
||||
if (value.every(function (x) { return typeof x == 'number'; })) {
|
||||
writeString('[');
|
||||
var intArray = intArrays.indexOf(key) !== -1;
|
||||
for (var _i = 0, value_1 = value; _i < value_1.length; _i++) {
|
||||
|
@ -4247,7 +4247,7 @@ function serializeEngineData(data, condensed) {
|
|||
writeString(']');
|
||||
}
|
||||
}
|
||||
else if (typeof value === 'object') {
|
||||
else if (typeof value == 'object') {
|
||||
if (inProperty && !condensed)
|
||||
writeString('\n');
|
||||
writeIndent();
|
||||
|
@ -4266,7 +4266,7 @@ function serializeEngineData(data, condensed) {
|
|||
return undefined;
|
||||
}
|
||||
if (condensed) {
|
||||
if (typeof data === 'object') {
|
||||
if (typeof data == 'object') {
|
||||
for (var _i = 0, _a = getKeys(data); _i < _a.length; _i++) {
|
||||
var key = _a[_i];
|
||||
writeProperty(key, data[key]);
|
||||
|
@ -4560,7 +4560,7 @@ var createImageData = function (width, height) {
|
|||
return tempCanvas.getContext('2d').createImageData(width, height);
|
||||
};
|
||||
exports.createImageData = createImageData;
|
||||
if (typeof document !== 'undefined') {
|
||||
if (typeof document != 'undefined') {
|
||||
exports.createCanvas = function (width, height) {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
|
@ -5225,7 +5225,7 @@ function writePsdUint8Array(psd, options) {
|
|||
}
|
||||
exports.writePsdUint8Array = writePsdUint8Array;
|
||||
function writePsdBuffer(psd, options) {
|
||||
if (typeof Buffer === 'undefined') {
|
||||
if (typeof Buffer == 'undefined') {
|
||||
throw new Error('Buffer not supported on this platform');
|
||||
}
|
||||
return Buffer.from(writePsdUint8Array(psd, options));
|
||||
|
@ -7050,7 +7050,7 @@ function deduplicateValues(base, runs, keys) {
|
|||
if (Array.isArray(value)) {
|
||||
identical = runs.every(function (r) { return arraysEqual(r.style[key], value); });
|
||||
}
|
||||
else if (typeof value === 'object') {
|
||||
else if (typeof value == 'object') {
|
||||
identical = runs.every(function (r) { return objectsEqual(r.style[key], value); });
|
||||
}
|
||||
else {
|
||||
|
@ -7068,7 +7068,7 @@ function deduplicateValues(base, runs, keys) {
|
|||
if (Array.isArray(value)) {
|
||||
same = arraysEqual(r.style[key], value);
|
||||
}
|
||||
else if (typeof value === 'object') {
|
||||
else if (typeof value == 'object') {
|
||||
same = objectsEqual(r.style[key], value);
|
||||
}
|
||||
else {
|
||||
|
@ -7514,7 +7514,7 @@ function decodeString(value) {
|
|||
throw Error("Lone surrogate U+" + code.toString(16).toUpperCase() + " is not a scalar value");
|
||||
}
|
||||
}
|
||||
else if ((byte1 & 0xf8) === 0xf0) {
|
||||
else if ((byte1 & 0xf8) == 0xf0) {
|
||||
var byte2 = continuationByte(value, i++);
|
||||
var byte3 = continuationByte(value, i++);
|
||||
var byte4 = continuationByte(value, i++);
|
||||
|
@ -7539,7 +7539,7 @@ exports.decodeString = decodeString;
|
|||
|
||||
|
||||
},{}],15:[function(require,module,exports){
|
||||
'use strict'
|
||||
"use strict";
|
||||
|
||||
exports.byteLength = byteLength
|
||||
exports.toByteArray = toByteArray
|
||||
|
@ -7547,7 +7547,7 @@ exports.fromByteArray = fromByteArray
|
|||
|
||||
var lookup = []
|
||||
var revLookup = []
|
||||
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
|
||||
var Arr = typeof Uint8Array != 'undefined' ? Uint8Array : Array
|
||||
|
||||
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
for (var i = 0, len = code.length; i < len; ++i) {
|
||||
|
@ -7700,7 +7700,7 @@ function fromByteArray (uint8) {
|
|||
*/
|
||||
/* eslint-disable no-proto */
|
||||
|
||||
'use strict'
|
||||
"use strict";
|
||||
|
||||
var base64 = require('base64-js')
|
||||
var ieee754 = require('ieee754')
|
||||
|
@ -7728,8 +7728,8 @@ exports.kMaxLength = K_MAX_LENGTH
|
|||
*/
|
||||
Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport()
|
||||
|
||||
if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' &&
|
||||
typeof console.error === 'function') {
|
||||
if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console != 'undefined' &&
|
||||
typeof console.error == 'function') {
|
||||
console.error(
|
||||
'This browser lacks typed array (Uint8Array) support which is required by ' +
|
||||
'`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'
|
||||
|
@ -7785,8 +7785,8 @@ function createBuffer (length) {
|
|||
|
||||
function Buffer (arg, encodingOrOffset, length) {
|
||||
// Common case.
|
||||
if (typeof arg === 'number') {
|
||||
if (typeof encodingOrOffset === 'string') {
|
||||
if (typeof arg == 'number') {
|
||||
if (typeof encodingOrOffset == 'string') {
|
||||
throw new TypeError(
|
||||
'The "string" argument must be of type string. Received type number'
|
||||
)
|
||||
|
@ -7797,7 +7797,7 @@ function Buffer (arg, encodingOrOffset, length) {
|
|||
}
|
||||
|
||||
// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
|
||||
if (typeof Symbol !== 'undefined' && Symbol.species != null &&
|
||||
if (typeof Symbol != 'undefined' && Symbol.species != null &&
|
||||
Buffer[Symbol.species] === Buffer) {
|
||||
Object.defineProperty(Buffer, Symbol.species, {
|
||||
value: null,
|
||||
|
@ -7810,7 +7810,7 @@ if (typeof Symbol !== 'undefined' && Symbol.species != null &&
|
|||
Buffer.poolSize = 8192 // not used by this implementation
|
||||
|
||||
function from (value, encodingOrOffset, length) {
|
||||
if (typeof value === 'string') {
|
||||
if (typeof value == 'string') {
|
||||
return fromString(value, encodingOrOffset)
|
||||
}
|
||||
|
||||
|
@ -7830,7 +7830,7 @@ function from (value, encodingOrOffset, length) {
|
|||
return fromArrayBuffer(value, encodingOrOffset, length)
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
if (typeof value == 'number') {
|
||||
throw new TypeError(
|
||||
'The "value" argument must not be of type number. Received type number'
|
||||
)
|
||||
|
@ -7844,8 +7844,8 @@ function from (value, encodingOrOffset, length) {
|
|||
var b = fromObject(value)
|
||||
if (b) return b
|
||||
|
||||
if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null &&
|
||||
typeof value[Symbol.toPrimitive] === 'function') {
|
||||
if (typeof Symbol != 'undefined' && Symbol.toPrimitive != null &&
|
||||
typeof value[Symbol.toPrimitive] == 'function') {
|
||||
return Buffer.from(
|
||||
value[Symbol.toPrimitive]('string'), encodingOrOffset, length
|
||||
)
|
||||
|
@ -7875,7 +7875,7 @@ Buffer.prototype.__proto__ = Uint8Array.prototype
|
|||
Buffer.__proto__ = Uint8Array
|
||||
|
||||
function assertSize (size) {
|
||||
if (typeof size !== 'number') {
|
||||
if (typeof size != 'number') {
|
||||
throw new TypeError('"size" argument must be of type number')
|
||||
} else if (size < 0) {
|
||||
throw new RangeError('The value "' + size + '" is invalid for option "size"')
|
||||
|
@ -7884,18 +7884,14 @@ function assertSize (size) {
|
|||
|
||||
function alloc (size, fill, encoding) {
|
||||
assertSize(size)
|
||||
if (size <= 0) {
|
||||
return createBuffer(size)
|
||||
}
|
||||
if (fill !== undefined) {
|
||||
return (size <= 0 || fill === undefined
|
||||
? createBuffer(size)
|
||||
:
|
||||
// Only pay attention to encoding if it's a string. This
|
||||
// prevents accidentally sending in a number that would
|
||||
// be interpretted as a start offset.
|
||||
return typeof encoding === 'string'
|
||||
? createBuffer(size).fill(fill, encoding)
|
||||
: createBuffer(size).fill(fill)
|
||||
}
|
||||
return createBuffer(size)
|
||||
createBuffer(size).fill(fill, typeof encoding == 'string' ? encoding : undefined)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7925,7 +7921,7 @@ Buffer.allocUnsafeSlow = function (size) {
|
|||
}
|
||||
|
||||
function fromString (string, encoding) {
|
||||
if (typeof encoding !== 'string' || encoding === '') {
|
||||
if (typeof encoding != 'string' || encoding === '') {
|
||||
encoding = 'utf8'
|
||||
}
|
||||
|
||||
|
@ -7994,7 +7990,7 @@ function fromObject (obj) {
|
|||
}
|
||||
|
||||
if (obj.length !== undefined) {
|
||||
if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) {
|
||||
if (typeof obj.length != 'number' || numberIsNaN(obj.length)) {
|
||||
return createBuffer(0)
|
||||
}
|
||||
return fromArrayLike(obj)
|
||||
|
@ -8113,7 +8109,7 @@ function byteLength (string, encoding) {
|
|||
if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) {
|
||||
return string.byteLength
|
||||
}
|
||||
if (typeof string !== 'string') {
|
||||
if (typeof string != 'string') {
|
||||
throw new TypeError(
|
||||
'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' +
|
||||
'Received type ' + typeof string
|
||||
|
@ -8378,7 +8374,7 @@ function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
|
|||
if (buffer.length === 0) return -1
|
||||
|
||||
// Normalize byteOffset
|
||||
if (typeof byteOffset === 'string') {
|
||||
if (typeof byteOffset == 'string') {
|
||||
encoding = byteOffset
|
||||
byteOffset = 0
|
||||
} else if (byteOffset > 0x7fffffff) {
|
||||
|
@ -8403,7 +8399,7 @@ function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
|
|||
}
|
||||
|
||||
// Normalize val
|
||||
if (typeof val === 'string') {
|
||||
if (typeof val == 'string') {
|
||||
val = Buffer.from(val, encoding)
|
||||
}
|
||||
|
||||
|
@ -8414,9 +8410,9 @@ function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
|
|||
return -1
|
||||
}
|
||||
return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
|
||||
} else if (typeof val === 'number') {
|
||||
} else if (typeof val == 'number') {
|
||||
val = val & 0xFF // Search for a byte value [0-255]
|
||||
if (typeof Uint8Array.prototype.indexOf === 'function') {
|
||||
if (typeof Uint8Array.prototype.indexOf == 'function') {
|
||||
if (dir) {
|
||||
return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
|
||||
} else {
|
||||
|
@ -8549,7 +8545,7 @@ Buffer.prototype.write = function write (string, offset, length, encoding) {
|
|||
length = this.length
|
||||
offset = 0
|
||||
// Buffer#write(string, encoding)
|
||||
} else if (length === undefined && typeof offset === 'string') {
|
||||
} else if (length === undefined && typeof offset == 'string') {
|
||||
encoding = offset
|
||||
length = this.length
|
||||
offset = 0
|
||||
|
@ -9228,7 +9224,7 @@ Buffer.prototype.copy = function copy (target, targetStart, start, end) {
|
|||
|
||||
var len = end - start
|
||||
|
||||
if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') {
|
||||
if (this === target && typeof Uint8Array.prototype.copyWithin == 'function') {
|
||||
// Use built-in when available, missing from IE11
|
||||
this.copyWithin(targetStart, start, end)
|
||||
} else if (this === target && start < targetStart && targetStart < end) {
|
||||
|
@ -9253,19 +9249,19 @@ Buffer.prototype.copy = function copy (target, targetStart, start, end) {
|
|||
// buffer.fill(string[, offset[, end]][, encoding])
|
||||
Buffer.prototype.fill = function fill (val, start, end, encoding) {
|
||||
// Handle string cases:
|
||||
if (typeof val === 'string') {
|
||||
if (typeof start === 'string') {
|
||||
if (typeof val == 'string') {
|
||||
if (typeof start == 'string') {
|
||||
encoding = start
|
||||
start = 0
|
||||
end = this.length
|
||||
} else if (typeof end === 'string') {
|
||||
} else if (typeof end == 'string') {
|
||||
encoding = end
|
||||
end = this.length
|
||||
}
|
||||
if (encoding !== undefined && typeof encoding !== 'string') {
|
||||
if (encoding !== undefined && typeof encoding != 'string') {
|
||||
throw new TypeError('encoding must be a string')
|
||||
}
|
||||
if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
|
||||
if (typeof encoding == 'string' && !Buffer.isEncoding(encoding)) {
|
||||
throw new TypeError('Unknown encoding: ' + encoding)
|
||||
}
|
||||
if (val.length === 1) {
|
||||
|
@ -9276,7 +9272,7 @@ Buffer.prototype.fill = function fill (val, start, end, encoding) {
|
|||
val = code
|
||||
}
|
||||
}
|
||||
} else if (typeof val === 'number') {
|
||||
} else if (typeof val == 'number') {
|
||||
val = val & 255
|
||||
}
|
||||
|
||||
|
@ -9295,7 +9291,7 @@ Buffer.prototype.fill = function fill (val, start, end, encoding) {
|
|||
if (!val) val = 0
|
||||
|
||||
var i
|
||||
if (typeof val === 'number') {
|
||||
if (typeof val == 'number') {
|
||||
for (i = start; i < end; ++i) {
|
||||
this[i] = val
|
||||
}
|
||||
|
@ -9319,25 +9315,22 @@ Buffer.prototype.fill = function fill (val, start, end, encoding) {
|
|||
// HELPER FUNCTIONS
|
||||
// ================
|
||||
|
||||
var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g
|
||||
var INVALID_BASE64_RE = /[^+/\dA-Z-_]/gi
|
||||
|
||||
function base64clean (str) {
|
||||
// Node takes equal signs as end of the Base64 encoding
|
||||
str = str.split('=')[0]
|
||||
str = str.split('=', 1)[0]
|
||||
// Node strips out invalid characters like \n and \t from the string, base64-js does not
|
||||
str = str.trim().replace(INVALID_BASE64_RE, '')
|
||||
// Node converts strings with length < 2 to ''
|
||||
if (str.length < 2) return ''
|
||||
// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
|
||||
while (str.length % 4 !== 0) {
|
||||
str = str + '='
|
||||
}
|
||||
while (str.length % 4 !== 0) str += '='
|
||||
return str
|
||||
}
|
||||
|
||||
function toHex (n) {
|
||||
if (n < 16) return '0' + n.toString(16)
|
||||
return n.toString(16)
|
||||
return (n < 16 ? '0' : '') + n.toString(16)
|
||||
}
|
||||
|
||||
function utf8ToBytes (string, units) {
|
||||
|
|
340
index.js
|
@ -1,30 +1,33 @@
|
|||
const express = require('express');
|
||||
const request = require('request');
|
||||
const compression = require('compression');
|
||||
const timeout = require('connect-timeout');
|
||||
const rateLimit = require("express-rate-limit");
|
||||
const fs = require("fs");
|
||||
const app = express();
|
||||
"use strict";
|
||||
const express = require('express')
|
||||
const request = require('request')
|
||||
const compression = require('compression')
|
||||
const timeout = require('connect-timeout')
|
||||
const rateLimit = require("express-rate-limit")
|
||||
const fs = require("fs")
|
||||
const app = express()
|
||||
|
||||
let serverList = require('./servers.json')
|
||||
let pinnedServers = serverList.filter(x => x.pinned)
|
||||
let notPinnedServers = serverList.filter(x => !x.pinned).sort((a, b) => a.name.localeCompare(b.name))
|
||||
const serverList = require('./servers.json')
|
||||
const pinnedServers = []
|
||||
const notPinnedServers = []
|
||||
serverList.forEach(x => (x.pinned ? pinnedServers : notPinnedServers).push(x))
|
||||
notPinnedServers.sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
app.servers = pinnedServers.concat(notPinnedServers)
|
||||
app.safeServers = JSON.parse(JSON.stringify(app.servers)) // clone
|
||||
app.safeServers.forEach(x => { delete x.endpoint; delete x.substitutions; delete x.overrides; delete x.disabled })
|
||||
app.safeServers = JSON.parse(JSON.stringify(app.servers)) // deep clone
|
||||
app.safeServers.forEach(x => ['endpoint', 'substitutions', 'overrides', 'disabled'].forEach(k => delete x[k]))
|
||||
app.config = require('./settings.js')
|
||||
|
||||
let rlMessage = "Rate limited ¯\\_(ツ)_/¯<br><br>Please do not spam my servers with a crazy amount of requests. It slows things down on my end and stresses RobTop's servers just as much." +
|
||||
" If you really want to send a zillion requests for whatever reason, please download the GDBrowser repository locally - or even just send the request directly to the GD servers.<br><br>" +
|
||||
const rlMessage = "Rate limited ¯\\_(ツ)_/¯<br><br>Please do not spam my servers with a crazy amount of requests. It slows things down on my end and stresses RobTop's servers just as much. "+
|
||||
"If you really want to send a zillion requests for whatever reason, please download the GDBrowser repository locally - or even just send the request directly to the GD servers.<br><br>"+
|
||||
"This kind of spam usually leads to GDBrowser getting IP banned by RobTop, and every time that happens I have to start making the rate limit even stricter. Please don't be the reason for that.<br><br>"
|
||||
|
||||
const RL = rateLimit({
|
||||
windowMs: app.config.rateLimiting ? 5 * 60 * 1000 : 0,
|
||||
max: app.config.rateLimiting ? 100 : 0, // max requests per 5 minutes
|
||||
message: rlMessage,
|
||||
keyGenerator: function(req) { return req.headers['x-real-ip'] || req.headers['x-forwarded-for'] },
|
||||
skip: function(req) { return ((req.url.includes("api/level") && !req.query.hasOwnProperty("download")) ? true : false) }
|
||||
keyGenerator: req => req.headers['x-real-ip'] || req.headers['x-forwarded-for'],
|
||||
skip: req => req.url.includes("api/level") && !req.query.hasOwnProperty("download")
|
||||
})
|
||||
|
||||
const RL2 = rateLimit({
|
||||
|
@ -34,8 +37,8 @@ const RL2 = rateLimit({
|
|||
keyGenerator: function(req) { return req.headers['x-real-ip'] || req.headers['x-forwarded-for'] }
|
||||
})
|
||||
|
||||
let XOR = require('./classes/XOR.js');
|
||||
let achievements = require('./misc/achievements.json')
|
||||
const XOR = require('./classes/XOR.js')
|
||||
const achievements = require('./misc/achievements.json')
|
||||
let achievementTypes = require('./misc/achievementTypes.json')
|
||||
let music = require('./misc/music.json')
|
||||
let assetPage = fs.readFileSync('./html/assets.html', 'utf8')
|
||||
|
@ -45,25 +48,27 @@ app.lastSuccess = {}
|
|||
app.actuallyWorked = {}
|
||||
|
||||
app.servers.forEach(x => {
|
||||
app.accountCache[x.id || "gd"] = {}
|
||||
app.lastSuccess[x.id || "gd"] = Date.now()
|
||||
x = x.id || "gd"
|
||||
app.accountCache[x] = {}
|
||||
app.lastSuccess[x] = Date.now()
|
||||
})
|
||||
app.mainEndpoint = app.servers.find(x => !x.id).endpoint // boomlings.com unless changed in fork
|
||||
|
||||
app.set('json spaces', 2)
|
||||
app.use(compression());
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({extended: true}));
|
||||
app.use(timeout('20s'));
|
||||
app.use(compression())
|
||||
app.use(express.json())
|
||||
app.use(express.urlencoded({extended: true}))
|
||||
app.use(timeout('20s'))
|
||||
|
||||
app.use(async function(req, res, next) {
|
||||
|
||||
let subdomains = req.subdomains.map(x => x.toLowerCase())
|
||||
if (!subdomains.length) subdomains = [""]
|
||||
req.server = app.servers.find(x => subdomains.includes(x.id.toLowerCase()))
|
||||
if (subdomains.length > 1 || !req.server) return res.redirect("http://" + req.get('host').split(".").slice(subdomains.length).join(".") + req.originalUrl)
|
||||
if (subdomains.length > 1 || !req.server)
|
||||
return res.redirect("http://" + req.get('host').split(".").slice(subdomains.length).join(".") + req.originalUrl)
|
||||
|
||||
// will expand this in the future :wink:
|
||||
// will expand this in the future :wink: 😉
|
||||
res.sendError = function(errorCode=500) {
|
||||
res.status(errorCode).send("-1")
|
||||
}
|
||||
|
@ -80,14 +85,17 @@ app.use(async function(req, res, next) {
|
|||
if (req.query.online > 0) req.offline = false
|
||||
|
||||
req.gdParams = function(obj={}, substitute=true) {
|
||||
Object.keys(app.config.params).forEach(x => { if (!obj[x]) obj[x] = app.config.params[x] })
|
||||
Object.keys(req.server.extraParams || {}).forEach(x => { if (!obj[x]) obj[x] = req.server.extraParams[x] })
|
||||
Object.keys(app.config.params).forEach(k => obj[k] ||= app.config.params[k])
|
||||
Object.keys(req.server.extraParams || {}).forEach(k => obj[k] ||= req.server.extraParams[k])
|
||||
let ip = req.headers['x-real-ip'] || req.headers['x-forwarded-for']
|
||||
let params = {form: obj, headers: app.config.ipForwarding && ip ? {'x-forwarded-for': ip, 'x-real-ip': ip} : {}}
|
||||
|
||||
if (substitute) { // GDPS substitutions in settings.js
|
||||
for (let ss in req.server.substitutions) {
|
||||
if (params.form[ss]) { params.form[req.server.substitutions[ss]] = params.form[ss]; delete params.form[ss] }
|
||||
if (params.form[ss]) {
|
||||
params.form[req.server.substitutions[ss]] = params.form[ss]
|
||||
delete params.form[ss]
|
||||
}
|
||||
}
|
||||
}
|
||||
return params
|
||||
|
@ -95,16 +103,16 @@ app.use(async function(req, res, next) {
|
|||
|
||||
req.gdRequest = function(target, params={}, cb=function(){}) {
|
||||
if (!target) return cb(true)
|
||||
target = req.server.overrides ? (req.server.overrides[target] || target) : target
|
||||
target = (req.server.overrides && req.server.overrides[target]) || target
|
||||
let parameters = params.headers ? params : req.gdParams(params)
|
||||
let endpoint = req.endpoint
|
||||
if (params.forceGD || (params.form && params.form.forceGD)) endpoint = "http://www.boomlings.com/database/"
|
||||
let {endpoint} = req
|
||||
if (params.forceGD || (params.form?.forceGD))
|
||||
endpoint = "http://www.boomlings.com/database/"
|
||||
request.post(endpoint + target + '.php', parameters, function(err, res, body) {
|
||||
let error = err
|
||||
if (!error && (err || !body || body.match(/^-\d$/) || body.startsWith("error") || body.startsWith("<"))) {
|
||||
error = {serverError: true, response: body}
|
||||
}
|
||||
return cb(error, res, body)
|
||||
if (!err && (!body || /(^-\d$)|^error|^</.test(body)))
|
||||
err = {serverError: true, response: body}
|
||||
|
||||
return cb(err, res, body)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -116,20 +124,25 @@ fs.readdirSync('./api').filter(x => !x.includes(".")).forEach(x => directories.p
|
|||
|
||||
app.trackSuccess = function(id) {
|
||||
app.lastSuccess[id] = Date.now()
|
||||
if (!app.actuallyWorked[id]) app.actuallyWorked[id] = true
|
||||
app.actuallyWorked[id] ||= true
|
||||
}
|
||||
|
||||
app.timeSince = function(id, time) {
|
||||
if (!time) time = app.lastSuccess[id]
|
||||
let secsPassed = Math.floor((Date.now() - time) / 1000)
|
||||
let minsPassed = Math.floor(secsPassed / 60)
|
||||
secsPassed -= 60 * minsPassed;
|
||||
secsPassed -= 60 * minsPassed
|
||||
return `${app.actuallyWorked[id] ? "" : "~"}${minsPassed}m ${secsPassed}s`
|
||||
}
|
||||
|
||||
app.userCache = function(id, accountID, playerID, name) {
|
||||
|
||||
if (!accountID || accountID == "0" || (name && name.toLowerCase() == "robtop" && accountID != "71") || !app.config.cacheAccountIDs) return
|
||||
|
||||
if ( // "IDK how to format this nicely" @Rudxain
|
||||
!accountID || accountID == "0" ||
|
||||
(name?.toLowerCase() == "robtop" && accountID != "71") ||
|
||||
!app.config.cacheAccountIDs
|
||||
)
|
||||
return
|
||||
if (!playerID) return app.accountCache[id][accountID.toLowerCase()]
|
||||
let cacheStuff = [accountID, playerID, name]
|
||||
app.accountCache[id][name.toLowerCase()] = cacheStuff
|
||||
|
@ -138,7 +151,10 @@ app.userCache = function(id, accountID, playerID, name) {
|
|||
|
||||
app.run = {}
|
||||
directories.forEach(d => {
|
||||
fs.readdirSync('./api/' + d).forEach(x => {if (x.includes('.')) app.run[x.split('.')[0]] = require('./api/' + d + "/" + x) })
|
||||
fs.readdirSync('./api/' + d)
|
||||
.forEach(x => {
|
||||
if (x.includes('.')) app.run[x.split('.', 1)[0]] = require(`./api/${d}/${x}`)
|
||||
})
|
||||
})
|
||||
|
||||
app.xor = new XOR()
|
||||
|
@ -162,26 +178,29 @@ catch(e) {
|
|||
}
|
||||
|
||||
app.parseResponse = function (responseBody, splitter=":") {
|
||||
if (!responseBody || responseBody == "-1") return {};
|
||||
if (!responseBody || responseBody == "-1") return {}
|
||||
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
|
||||
let response = responseBody.split('#', 1)[0].split(splitter)
|
||||
let res = {}
|
||||
for (let i = 0; i < response.length; i += 2)
|
||||
res[response[i]] = response[i + 1]
|
||||
return res
|
||||
}
|
||||
|
||||
//xss bad
|
||||
app.clean = function(text) {if (!text || typeof text != "string") return text; else return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/=/g, "=").replace(/"/g, """).replace(/'/g, "'")}
|
||||
app.clean = text => {
|
||||
const escChar = c => ({"&": "&", "<": "<", ">": ">", "=": "=", '"': """, "'": "'"}[c] || c)
|
||||
return !text || typeof text != "string" ? text : text.replace(/./gs, escChar)
|
||||
}
|
||||
|
||||
// ASSETS
|
||||
|
||||
app.use('/assets', express.static(__dirname + '/assets', {maxAge: "7d"}));
|
||||
app.use('/assets/css', express.static(__dirname + '/assets/css'));
|
||||
app.use('/assets', express.static(__dirname + '/assets', {maxAge: "7d"}))
|
||||
app.use('/assets/css', express.static(__dirname + '/assets/css'))
|
||||
|
||||
app.use('/iconkit', express.static(__dirname + '/iconkit'));
|
||||
app.get("/global.js", function(req, res) { res.status(200).sendFile(__dirname + "/misc/global.js") })
|
||||
app.use('/iconkit', express.static(__dirname + '/iconkit'))
|
||||
app.get("/misc/global.js", function(req, res) { res.status(200).sendFile(__dirname + "/misc/global.js") })
|
||||
app.get("/dragscroll.js", function(req, res) { res.status(200).sendFile(__dirname + "/misc/dragscroll.js") })
|
||||
|
||||
app.get("/assets/:dir*?", function(req, res) {
|
||||
|
@ -208,116 +227,151 @@ app.get("/assets/:dir*?", function(req, res) {
|
|||
|
||||
// POST REQUESTS
|
||||
|
||||
app.post("/like", RL, function(req, res) { app.run.like(app, req, res) })
|
||||
app.post("/postComment", RL, function(req, res) { app.run.postComment(app, req, res) })
|
||||
app.post("/postProfileComment", RL, function(req, res) { app.run.postProfileComment(app, req, res) })
|
||||
function doPOST(name, key, noRL, wtf) {
|
||||
const args = ["/" + name]
|
||||
if (!noRL) args.push(RL)
|
||||
app.post(...args, function(req, res) { app.run[ key || name ](app, req, res, wtf ? true : undefined) })
|
||||
}
|
||||
doPOST("like")
|
||||
doPOST("postComment")
|
||||
doPOST("postProfileComment")
|
||||
doPOST("messages", "getMessages")
|
||||
doPOST("messages/:id", "fetchMessage")
|
||||
doPOST("deleteMessage")
|
||||
doPOST("sendMessage")
|
||||
doPOST("accurateLeaderboard", "accurate", true, true)
|
||||
doPOST("analyzeLevel", "analyze", true)
|
||||
|
||||
app.post("/messages", RL, function(req, res) { app.run.getMessages(app, req, res) })
|
||||
app.post("/messages/:id", RL, function(req, res) { app.run.fetchMessage(app, req, res) })
|
||||
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.accurate(app, req, res, true) })
|
||||
app.post("/analyzeLevel", function(req, res) { app.run.analyze(app, req, res) })
|
||||
|
||||
// HTML
|
||||
|
||||
let onePointNineDisabled = ['daily', 'weekly', 'gauntlets', 'messages']
|
||||
let downloadDisabled = ['daily', 'weekly']
|
||||
let onePointNineDisabled = ['daily', 'weekly', 'gauntlets', 'messages'] // using `concat` won't shorten this
|
||||
let gdpsHide = ['achievements', 'messages']
|
||||
|
||||
app.get("/", function(req, res) {
|
||||
if (req.query.hasOwnProperty("offline") || (req.offline && !req.query.hasOwnProperty("home"))) res.status(200).sendFile(__dirname + "/html/offline.html")
|
||||
app.get("/", function(req, res) {
|
||||
if (req.query.hasOwnProperty("offline") || (req.offline && !req.query.hasOwnProperty("home")))
|
||||
res.status(200).sendFile(__dirname + "/html/offline.html")
|
||||
else {
|
||||
fs.readFile('./html/home.html', 'utf8', function (err, data) {
|
||||
let html = data;
|
||||
let html = data
|
||||
if (req.isGDPS) {
|
||||
html = html.replace('"levelBG"', '"levelBG purpleBG"')
|
||||
.replace(/Geometry Dash Browser!/g, req.server.name + " Browser!")
|
||||
.replace("/assets/gdlogo", `/assets/gdps/${req.id}_logo`)
|
||||
.replace("coin.png\" itemprop", `gdps/${req.id}_icon.png" itemprop`)
|
||||
.replace(/coin\.png/g, `${req.server.onePointNine ? "blue" : "silver"}coin.png`)
|
||||
html = html
|
||||
.replace('"levelBG"', '"levelBG purpleBG"')
|
||||
.replace(/Geometry Dash Browser!/g, req.server.name + " Browser!")
|
||||
.replace("/assets/gdlogo", `/assets/gdps/${req.id}_logo`)
|
||||
.replace("coin.png\" itemprop", `gdps/${req.id}_icon.png" itemprop`)
|
||||
.replace(/coin\.png/g, `${req.server.onePointNine ? "blue" : "silver"}coin.png`)
|
||||
|
||||
gdpsHide.forEach(x => { html = html.replace(`menu-${x}`, 'changeDaWorld') })
|
||||
}
|
||||
if (req.onePointNine) onePointNineDisabled.forEach(x => { html = html.replace(`menu-${x}`, 'menuDisabled') })
|
||||
if (req.server.disabled) req.server.disabled.forEach(x => { html = html.replace(`menu-${x}`, 'menuDisabled') })
|
||||
const htmlReplacer = x => { html = html.replace(`menu-${x}`, 'menuDisabled') }
|
||||
if (req.onePointNine) onePointNineDisabled.forEach(htmlReplacer)
|
||||
if (req.server.disabled) req.server.disabled.forEach(htmlReplacer)
|
||||
if (req.server.downloadsDisabled && process.platform == "linux") {
|
||||
downloadDisabled.forEach(x => { html = html.replace(`menu-${x}`, 'menuDisabled') })
|
||||
html = html.replace('id="dl" style="display: none', 'style="display: block')
|
||||
.replace('No active <span id="noLevel">daily</span> level!', '[Blocked by RobTop]')
|
||||
downloadDisabled.forEach(htmlReplacer)
|
||||
html = html
|
||||
.replace('id="dl" style="display: none', 'style="display: block')
|
||||
.replace('No active <span id="noLevel">daily</span> level!', '[Blocked by RobTop]')
|
||||
}
|
||||
if (html.includes('menuDisabled" src="../assets/category-weekly')) { // if weekly disabled, replace with featured
|
||||
html = html.replace('block" id="menu_weekly', 'none" id="menu_weekly')
|
||||
.replace('none" id="menu_featured', 'block" id="menu_featured')
|
||||
if (html.includes('menuDisabled" src="/assets/category-weekly')) { // if weekly disabled, replace with featured
|
||||
html = html
|
||||
.replace('block" id="menu_weekly', 'none" id="menu_weekly')
|
||||
.replace('none" id="menu_featured', 'block" id="menu_featured')
|
||||
}
|
||||
return res.status(200).send(html)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
function sendHTML(dir, name) {
|
||||
app.get("/" + dir, function(req, res) { res.status(200).sendFile(`${__dirname}/html/${name || dir}.html`) })
|
||||
}
|
||||
sendHTML("achievements")
|
||||
sendHTML("analyze/:id", "analyze")
|
||||
sendHTML("api")
|
||||
sendHTML("boomlings")
|
||||
sendHTML("comments/:id", "comments")
|
||||
sendHTML("demon/:id", "demon")
|
||||
sendHTML("gauntlets")
|
||||
sendHTML("gdps")
|
||||
sendHTML("iconkit")
|
||||
sendHTML("leaderboard")
|
||||
sendHTML("leaderboard/:text", "levelboard")
|
||||
sendHTML("mappacks")
|
||||
sendHTML("messages")
|
||||
sendHTML("search", "filters")
|
||||
sendHTML("search/:text", "search")
|
||||
|
||||
app.get("/achievements", function(req, res) { res.status(200).sendFile(__dirname + "/html/achievements.html") })
|
||||
app.get("/analyze/:id", function(req, res) { res.status(200).sendFile(__dirname + "/html/analyze.html") })
|
||||
app.get("/api", function(req, res) { res.status(200).sendFile(__dirname + "/html/api.html") })
|
||||
app.get("/boomlings", function(req, res) { res.status(200).sendFile(__dirname + "/html/boomlings.html") })
|
||||
app.get("/comments/:id", function(req, res) { res.status(200).sendFile(__dirname + "/html/comments.html") })
|
||||
app.get("/demon/:id", function(req, res) { res.status(200).sendFile(__dirname + "/html/demon.html") })
|
||||
app.get("/gauntlets", function(req, res) { res.status(200).sendFile(__dirname + "/html/gauntlets.html") })
|
||||
app.get("/gdps", function(req, res) { res.status(200).sendFile(__dirname + "/html/gdps.html") })
|
||||
app.get("/iconkit", function(req, res) { res.status(200).sendFile(__dirname + "/html/iconkit.html") })
|
||||
app.get("/leaderboard", function(req, res) { res.status(200).sendFile(__dirname + "/html/leaderboard.html") })
|
||||
app.get("/leaderboard/:text", function(req, res) { res.status(200).sendFile(__dirname + "/html/levelboard.html") })
|
||||
app.get("/mappacks", function(req, res) { res.status(200).sendFile(__dirname + "/html/mappacks.html") })
|
||||
app.get("/messages", function(req, res) { res.status(200).sendFile(__dirname + "/html/messages.html") })
|
||||
app.get("/search", function(req, res) { res.status(200).sendFile(__dirname + "/html/filters.html") })
|
||||
app.get("/search/:text", function(req, res) { res.status(200).sendFile(__dirname + "/html/search.html") })
|
||||
|
||||
// API
|
||||
|
||||
app.get("/api/analyze/:id", RL, function(req, res) { app.run.level(app, req, res, true, true) })
|
||||
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) })
|
||||
|
||||
function doGET(name, key, RL, wtf1, wtf2) {
|
||||
const args = ["/api/" + name]
|
||||
if (RL !== null && RL !== undefined) args.push(RL)
|
||||
app.post(...args, function(req, res) { app.run[ key || name ](app, req, res, wtf1 ? true : undefined, wtf2 ? true : undefined) })
|
||||
}
|
||||
|
||||
doGET("analyze/:id", "level", RL, true, true)
|
||||
doGET("boomlings", "", null)
|
||||
doGET("comments/:id", "comments", RL2)
|
||||
|
||||
app.get("/api/credits", function(req, res) { res.status(200).send(require('./misc/credits.json')) })
|
||||
app.get("/api/gauntlets", function(req, res) { app.run.gauntlets(app, req, res) })
|
||||
|
||||
doGET("gauntlets")
|
||||
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, function(req, res) { app.run.level(app, req, res, true) })
|
||||
app.get("/api/mappacks", function(req, res) { app.run.mappacks(app, req, res) })
|
||||
app.get("/api/profile/:id", RL2, function(req, res) { app.run.profile(app, req, res, true) })
|
||||
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) })
|
||||
|
||||
doGET("leaderboardLevel/:id", "leaderboardLevel", RL2)
|
||||
doGET("level/:id", "level", RL, true)
|
||||
doGET("mappacks")
|
||||
doGET("profile/:id", "profile", RL2, true)
|
||||
doGET("search/:text", "search", RL2)
|
||||
doGET("song/:song", "song")
|
||||
|
||||
|
||||
// REDIRECTS
|
||||
|
||||
app.get("/icon", function(req, res) { res.redirect('/iconkit') })
|
||||
app.get("/obj/:text", function(req, res) { res.redirect('/obj/' + req.params.text) })
|
||||
app.get("/leaderboards/:id", function(req, res) { res.redirect('/leaderboard/' + req.params.id) })
|
||||
app.get("/profile/:id", function(req, res) { res.redirect('/u/' + req.params.id) })
|
||||
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) })
|
||||
function doRedir(name, dir, key = 'id') {
|
||||
app.get('/' + name, function(req, res) { res.redirect('/' + dir + (key && '/' + req.params[key]) ) })
|
||||
}
|
||||
doRedir('icon', 'iconkit', '')
|
||||
doRedir('obj/:text', 'obj', 'text')
|
||||
doRedir('leaderboards/:id', 'leaderboard')
|
||||
doRedir('profile/:id', 'u')
|
||||
doRedir('p/:id', 'u')
|
||||
doRedir('l/:id', 'leaderboard')
|
||||
doRedir('a/:id', 'analyze')
|
||||
doRedir('c/:id', 'comments')
|
||||
doRedir('d/:id', 'demon')
|
||||
|
||||
|
||||
// API AND HTML
|
||||
|
||||
app.get("/u/:id", function(req, res) { app.run.profile(app, req, res) })
|
||||
app.get("/:id", function(req, res) { app.run.level(app, req, res) })
|
||||
|
||||
doPOST("u/:id", "profile", true)
|
||||
doPOST(":id", "level", true)
|
||||
|
||||
// MISC
|
||||
|
||||
app.get("/api/userCache", function(req, res) { res.status(200).send(app.accountCache) })
|
||||
app.get("/api/achievements", function(req, res) { res.status(200).send({achievements, types: achievementTypes, shopIcons: sacredTexts.shops, colors: sacredTexts.colors }) })
|
||||
app.get("/api/achievements", function(req, res) {
|
||||
res.status(200).send(
|
||||
{achievements, types: achievementTypes, shopIcons: sacredTexts.shops, colors: sacredTexts.colors}
|
||||
)
|
||||
})
|
||||
app.get("/api/music", function(req, res) { res.status(200).send(music) })
|
||||
app.get("/api/gdps", function(req, res) {res.status(200).send(req.query.hasOwnProperty("current") ? app.safeServers.find(x => req.server.id == x.id) : app.safeServers) })
|
||||
app.get("/api/gdps", function(req, res) {
|
||||
res.status(200).send(
|
||||
req.query.hasOwnProperty("current")
|
||||
? app.safeServers.find(x => req.server.id == x.id)
|
||||
: app.safeServers
|
||||
)
|
||||
})
|
||||
|
||||
// important icon stuff
|
||||
let sacredTexts = {}
|
||||
|
||||
fs.readdirSync('./iconkit/sacredtexts').forEach(x => {
|
||||
sacredTexts[x.split(".")[0]] = require("./iconkit/sacredtexts/" + x)
|
||||
sacredTexts[x.split(".", 1)[0]] = require("./iconkit/sacredtexts/" + x)
|
||||
})
|
||||
|
||||
let previewIcons = fs.readdirSync('./iconkit/premade')
|
||||
|
@ -326,7 +380,7 @@ let newPreviewIcons = fs.readdirSync('./iconkit/newpremade')
|
|||
let previewCounts = {}
|
||||
previewIcons.forEach(x => {
|
||||
if (x.endsWith("_0.png")) return
|
||||
let iconType = sacredTexts.forms[x.split("_")[0]].form
|
||||
let iconType = sacredTexts.forms[x.split("_", 1)[0]].form
|
||||
if (!previewCounts[iconType]) previewCounts[iconType] = 1
|
||||
else previewCounts[iconType]++
|
||||
})
|
||||
|
@ -337,15 +391,15 @@ sacredTexts.newIcons = []
|
|||
let newIconCounts = {}
|
||||
newIcons.forEach(x => {
|
||||
if (x.endsWith(".plist")) {
|
||||
sacredTexts.newIcons.push(x.split("-")[0])
|
||||
let formName = x.split(/_\d/g)[0]
|
||||
sacredTexts.newIcons.push(x.split("-", 1)[0])
|
||||
let formName = x.split(/_\d/g, 1)[0]
|
||||
if (!newIconCounts[formName]) newIconCounts[formName] = 1
|
||||
else newIconCounts[formName]++
|
||||
}
|
||||
})
|
||||
sacredTexts.newIconCounts = newIconCounts
|
||||
Missing rate limitingThis route handler performs a file system access, but is not rate-limited. ## Missing rate limiting
This route handler performs [a file system access](1), but is not rate-limited.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/71)
|
||||
|
||||
app.get('/api/icons', function(req, res) {
|
||||
app.get('/api/icons', function(req, res) {
|
||||
res.status(200).send(sacredTexts);
|
||||
});
|
||||
|
||||
|
@ -353,37 +407,37 @@ app.get('/api/icons', function(req, res) {
|
|||
let iconKitFiles = {}
|
||||
let sampleIcons = require('./misc/sampleIcons.json')
|
||||
fs.readdirSync('./iconkit/extradata').forEach(x => {
|
||||
iconKitFiles[x.split(".")[0]] = require("./iconkit/extradata/" + x)
|
||||
iconKitFiles[x.split(".", 1)[0]] = require("./iconkit/extradata/" + x)
|
||||
})
|
||||
|
||||
iconKitFiles.previewIcons = previewIcons
|
||||
iconKitFiles.newPreviewIcons = newPreviewIcons
|
||||
Object.assign(iconKitFiles, {previewIcons, newPreviewIcons})
|
||||
|
||||
app.get('/api/iconkit', function(req, res) {
|
||||
let sample = [JSON.stringify(sampleIcons[Math.floor(Math.random() * sampleIcons.length)].slice(1))]
|
||||
app.get('/api/iconkit', function(req, res) {
|
||||
let sample = [JSON.stringify(sampleIcons[Math.random() * sampleIcons.length >>>0].slice(1))]
|
||||
let iconserver = req.isGDPS ? req.server.name : undefined
|
||||
res.status(200).send(Object.assign(iconKitFiles, {sample, server: iconserver, noCopy: req.onePointNine || req.offline}));
|
||||
});
|
||||
})
|
||||
|
||||
app.get('/icon/:text', function(req, res) {
|
||||
let iconID = Number(req.query.icon || 1)
|
||||
let iconForm = sacredTexts.forms[req.query.form] ? req.query.form : "icon"
|
||||
let iconPath = `${iconForm}_${iconID}.png`
|
||||
let fileExists = iconKitFiles.previewIcons.includes(iconPath)
|
||||
if (fileExists) return res.status(200).sendFile(`./iconkit/premade/${iconPath}`, {root: __dirname })
|
||||
else return res.status(200).sendFile(`./iconkit/premade/${iconForm}_01.png`, {root: __dirname})
|
||||
return res.status(200).sendFile(`./iconkit/premade/${fileExists ? iconPath : iconForm + '_01.png'}`, {root: __dirname})
|
||||
})
|
||||
|
||||
app.get('*', function(req, res) {
|
||||
if (req.path.startsWith('/api') || req.path.startsWith("/iconkit")) res.status(404).send('-1')
|
||||
else res.redirect('/search/404%20')
|
||||
});
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
if (err && err.message == "Response timeout") res.status(504).send('Internal server error! (Timed out)')
|
||||
if (/^\/(api|iconkit)/.test(req.path))
|
||||
res.status(404).send('-1')
|
||||
else
|
||||
res.redirect('/search/404%20')
|
||||
})
|
||||
|
||||
process.on('uncaughtException', (e) => { console.log(e) });
|
||||
process.on('unhandledRejection', (e, p) => { console.log(e) });
|
||||
app.use(function (err, req, res) {
|
||||
if (err?.message == "Response timeout") res.status(504).send('Internal server error! (Timed out)')
|
||||
})
|
||||
|
||||
app.listen(app.config.port, () => console.log(`Site online! (port ${app.config.port})`))
|
||||
process.on('uncaughtException', e => console.log(e))
|
||||
process.on('unhandledRejection', e => console.log(e))
|
||||
|
||||
app.listen(app.config.port, () => console.log(`Site online! (port ${app.config.port})`))
|
||||
|
|
|
@ -1,30 +1,33 @@
|
|||
"use strict";
|
||||
function somethingSelected() {
|
||||
return typeof window.getSelection == 'function' && window.getSelection().toString() != "";
|
||||
}
|
||||
const remover = / |\n|\t/g;
|
||||
const remover = /[ \n\t]/g; //should it be /\s/g ?
|
||||
$('.dragscroll').each(function(_, el) {
|
||||
let previouslyMouseDown = false;
|
||||
let previouslyMouseDown = false
|
||||
el.addEventListener('mousemove', function(e) {
|
||||
if (e.buttons != 1) {
|
||||
if (previouslyMouseDown) {
|
||||
el.style.removeProperty('user-select');
|
||||
el.style.removeProperty('-webkit-user-select');
|
||||
el.style.removeProperty('user-select')
|
||||
el.style.removeProperty('-webkit-user-select')
|
||||
previouslyMouseDown = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (somethingSelected())
|
||||
return;
|
||||
if (somethingSelected()) return
|
||||
if (!previouslyMouseDown) {
|
||||
for (let el of e.target.childNodes) {
|
||||
if (el.nodeType === Node.TEXT_NODE && el.textContent.replace(remover, '').length)
|
||||
return;
|
||||
}
|
||||
el.style['user-select'] = 'none';
|
||||
el.style['-webkit-user-select'] = 'none';
|
||||
if ([...e.target.childNodes].some(
|
||||
el => el.nodeType === Node.TEXT_NODE
|
||||
&&
|
||||
el.textContent.replace(remover, '').length
|
||||
)
|
||||
) return
|
||||
|
||||
el.style['user-select'] = 'none'
|
||||
el.style['-webkit-user-select'] = 'none'
|
||||
previouslyMouseDown = true;
|
||||
}
|
||||
//el.scrollLeft -= e.movementX;
|
||||
//el.scrollLeft -= e.movementX
|
||||
el.scrollTop -= e.movementY;
|
||||
}, {passive: true});
|
||||
});
|
111
misc/global.js
|
@ -1,3 +1,4 @@
|
|||
"use strict";
|
||||
$('body').append(`
|
||||
<div data-nosnippet id="tooSmall" class="brownbox center supercenter" style="display: none; width: 80%">
|
||||
<h1>Yikes!</h1>
|
||||
|
@ -9,28 +10,36 @@ $('body').append(`
|
|||
`)
|
||||
|
||||
|
||||
$(window).resize(function () {
|
||||
if (window.innerHeight > window.innerWidth - 75) {
|
||||
$('#everything').hide();
|
||||
$('#tooSmall').show();
|
||||
}
|
||||
$(window).resize(function() {
|
||||
// these alternatives may be helpful: https://stackoverflow.com/a/4917796
|
||||
let isPortrait = window.innerHeight > window.innerWidth - 75
|
||||
$('#everything')[isPortrait ? 'hide' : 'show']()
|
||||
$('#tooSmall')[isPortrait ? 'show' : 'hide']()
|
||||
})
|
||||
|
||||
else {
|
||||
$('#everything').show();
|
||||
$('#tooSmall').hide()
|
||||
}
|
||||
});
|
||||
// supports Numbers, BigInts, and Strings!
|
||||
const clamp = (x, min, max) => x < min ? min : (x > max ? max : x) // interval [min, max]
|
||||
|
||||
const randRange = (min, max) => Math.random() * (max - min) + +min // prevent string concat
|
||||
// interval [min, max)
|
||||
const randInt = (min, max) => Math.floor(randRange(min, max))
|
||||
|
||||
//fn, to always get an updated answer
|
||||
let isDownloadURL = () => window.location.href.endsWith('?download')
|
||||
|
||||
function saveUrl() {
|
||||
if (window.location.href.endsWith('?download')) return;
|
||||
sessionStorage.setItem('prevUrl', window.location.href);
|
||||
if ( !isDownloadURL() ) sessionStorage.setItem('prevUrl', window.location.href)
|
||||
}
|
||||
|
||||
function backButton() {
|
||||
if (window.history.length > 1 && document.referrer.startsWith(window.location.origin)){
|
||||
if (window.location.href.endsWith('?download') && sessionStorage.getItem('prevUrl') === window.location.href.replace('?download', '')) window.history.go(-2);
|
||||
else window.history.back()
|
||||
}
|
||||
if (window.history.length > 1 && document.referrer.startsWith(window.location.origin)) {
|
||||
let steps = (
|
||||
isDownloadURL() &&
|
||||
sessionStorage.getItem('prevUrl') === window.location.href.replace('?download', '')
|
||||
? -2 : -1
|
||||
)
|
||||
window.history.go(steps)
|
||||
}
|
||||
else window.location.href = "../../../../../"
|
||||
}
|
||||
|
||||
|
@ -42,23 +51,23 @@ function Fetch(link) {
|
|||
fetch(link).then(resp => {
|
||||
if (!resp.ok) return rej(resp)
|
||||
gdps = resp.headers.get('gdps')
|
||||
if (gdps && gdps.startsWith('1.9/')) { onePointNine = true; gdps = gdps.slice(4) }
|
||||
if (gdps?.startsWith('1.9/')) { onePointNine = true; gdps = gdps.slice(4) }
|
||||
resp.json().then(res)
|
||||
}).catch(rej)
|
||||
})
|
||||
}
|
||||
|
||||
let allowEsc = true;
|
||||
let popupEsc = true;
|
||||
let allowEsc = true
|
||||
let popupEsc = true
|
||||
|
||||
$(document).keydown(function(k) {
|
||||
if (k.keyCode == 27) { //esc
|
||||
if (!allowEsc) return
|
||||
k.preventDefault()
|
||||
if (popupEsc && $('.popup').is(":visible")) $('.popup').hide();
|
||||
else $('#backButton').trigger('click')
|
||||
}
|
||||
});
|
||||
if (k.code != 'Escape' || !allowEsc) return
|
||||
k.preventDefault()
|
||||
if (popupEsc && $('.popup').is(":visible"))
|
||||
$('.popup').hide()
|
||||
else
|
||||
$('#backButton').trigger('click')
|
||||
})
|
||||
|
||||
let iconData = null
|
||||
let iconCanvas = null
|
||||
|
@ -72,9 +81,9 @@ async function renderIcons() {
|
|||
if (overrideLoader) return
|
||||
let iconsToRender = $('gdicon:not([rendered], [dontload])')
|
||||
if (iconsToRender.length < 1) return
|
||||
if (!iconData) iconData = await Fetch("../api/icons")
|
||||
if (!iconCanvas) iconCanvas = document.createElement('canvas')
|
||||
if (!iconRenderer) iconRenderer = new PIXI.Application({ view: iconCanvas, width: 300, height: 300, backgroundAlpha: 0});
|
||||
iconData ||= await Fetch("/api/icons")
|
||||
iconCanvas ||= document.createElement('canvas')
|
||||
iconRenderer ||= new PIXI.Application({ view: iconCanvas, width: 300, height: 300, backgroundAlpha: 0})
|
||||
if (loader.loading) return overrideLoader = true
|
||||
buildIcon(iconsToRender, 0)
|
||||
}
|
||||
|
@ -121,37 +130,37 @@ function finishIcon(currentIcon, name, data) {
|
|||
}
|
||||
|
||||
// reset scroll
|
||||
while ($(this).scrollTop() != 0) {
|
||||
while ($(this).scrollTop() != 0)
|
||||
$(this).scrollTop(0);
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
$(window).trigger('resize');
|
||||
});
|
||||
|
||||
// Adds all necessary elements into the tab index (all buttons and links that aren't natively focusable)
|
||||
const inaccessibleLinkSelector = "*:not(a) > img.gdButton, .leaderboardTab, .gdcheckbox, .diffDiv, .lengthDiv";
|
||||
|
||||
document.querySelectorAll(inaccessibleLinkSelector).forEach(elem => {
|
||||
elem.setAttribute('tabindex', 0);
|
||||
$(window).trigger('resize')
|
||||
})
|
||||
|
||||
document.getElementById('backButton')?.setAttribute('tabindex', 1); // Prioritize back button, first element to be focused
|
||||
// Adds all necessary elements into the tab index (all buttons and links that aren't natively focusable)
|
||||
const inaccessibleLinkSelector = "*:not(a) > img.gdButton, .leaderboardTab, .gdcheckbox, .diffDiv, .lengthDiv"
|
||||
|
||||
document.querySelectorAll(inaccessibleLinkSelector)
|
||||
.forEach(elem => { elem.setAttribute('tabindex', 0) })
|
||||
|
||||
document.getElementById('backButton')?.setAttribute('tabindex', 1) // Prioritize back button, first element to be focused
|
||||
|
||||
// Event listener to run a .click() function if
|
||||
window.addEventListener("keydown", e => {
|
||||
if(e.key !== 'Enter') return;
|
||||
window.addEventListener("keydown", k => {
|
||||
// standard and Numpad support
|
||||
if ( !k.code.endsWith('Enter') ) return
|
||||
|
||||
const active = document.activeElement;
|
||||
const isUnsupportedLink = active.hasAttribute('tabindex'); // Only click on links that aren't already natively supported to prevent double clicking
|
||||
if(isUnsupportedLink) active.click();
|
||||
const active = document.activeElement
|
||||
const isUnsupportedLink = active.hasAttribute('tabindex') // Only click on links that aren't already natively supported to prevent double clicking
|
||||
if(isUnsupportedLink) active.click()
|
||||
})
|
||||
|
||||
// stolen from stackoverflow
|
||||
$.fn.isInViewport = function () {
|
||||
let elementTop = $(this).offset().top;
|
||||
let elementBottom = elementTop + $(this).outerHeight();
|
||||
let viewportTop = $(window).scrollTop();
|
||||
let viewportBottom = viewportTop + $(window).height();
|
||||
return elementBottom > viewportTop && elementTop < viewportBottom;
|
||||
};
|
||||
let elementTop = $(this).offset().top
|
||||
let elementBottom = elementTop + $(this).outerHeight()
|
||||
let viewportTop = $(window).scrollTop()
|
||||
let viewportBottom = viewportTop + $(window).height()
|
||||
return elementBottom > viewportTop && elementTop < viewportBottom
|
||||
}
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
"use strict";
|
||||
let path = "../extra/"
|
||||
|
||||
let files = ["AchievementsDesc", "AchievementsDescMD", null, "AchievementsDescSZ"]
|
||||
let gameNames = ["gd", "meltdown", "world", "subzero"]
|
||||
let achString = "geometry.ach."
|
||||
const files = ["", "MD", null, "SZ"]
|
||||
const gameNames = ["gd", "meltdown", "world", "subzero"]
|
||||
const achString = "geometry.ach."
|
||||
let rewardTypes = { color: "color1", icon: "cube", bird: "ufo", dart: "wave", special: "trail", death: "deathEffect" }
|
||||
let games = { "md": "meltdown", "world.": "world", "subzero.": "subzero" }
|
||||
|
||||
const plist = require('plist');
|
||||
const fs = require('fs');
|
||||
const plist = require('plist')
|
||||
const fs = require('fs')
|
||||
|
||||
let achArray = []
|
||||
|
||||
files.forEach((file, fileNum) => {
|
||||
if (!file) return
|
||||
let data = plist.parse(fs.readFileSync(path + file + '.plist', 'utf8'));
|
||||
|
||||
if (file === null) return
|
||||
file = "AchievementsDesc" + file
|
||||
f
|
||||
console.log(`Converting ${file}.plist...`)
|
||||
|
||||
for (let key in data) {
|
||||
if (!achArray.find(x => x.trueID == key)) {
|
||||
let fileData = data[key];
|
||||
let fileData = data[key]
|
||||
let reward = fileData.icon ? fileData.icon.split("_") : []
|
||||
let achObj = {
|
||||
id: key.slice(achString.length),
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
let gdPath = 'C:\\Program Files (x86)\\Steam\\steamapps\\common\\Geometry Dash\\Resources\\'
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
"use strict";
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
const gdPath = 'C:\\Program Files (x86)\\Steam\\steamapps\\common\\Geometry Dash\\Resources\\'
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
|
||||
const plist = require('plist');
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
const fs = require('fs');
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
const plist = require('plist')
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
const fs = require('fs')
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
const forms = require('./forms.json')
|
||||
const data = plist.parse(fs.readFileSync(gdPath + 'GJ_GameSheet02-uhd.plist', 'utf8'));
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
const glowSheet = plist.parse(fs.readFileSync(gdPath + 'GJ_GameSheetGlow-uhd.plist', 'utf8'));
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
const data = plist.parse(fs.readFileSync(gdPath + 'GJ_GameSheet02-uhd.plist', 'utf8'))
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
const glowSheet = plist.parse(fs.readFileSync(gdPath + 'GJ_GameSheetGlow-uhd.plist', 'utf8'))
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
let formList = Object.values(forms).map(x => x.form)
|
||||
|
||||
let frames = {}
|
||||
|
||||
function addIcons(data) {
|
||||
Object.keys(data).filter(x => formList.includes(x.split("_")[0])).forEach(x => frames[x] = data[x])
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
Object.keys(data)
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
.filter(k => formList.includes(k.split("_", 1)[0]))
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
.forEach(k => frames[k] = data[k])
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
}
|
||||
|
||||
addIcons(data.frames)
|
||||
|
@ -18,13 +21,13 @@ addIcons(glowSheet.frames)
|
|||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
|
||||
for (let key in frames) {
|
||||
if (key.startsWith(".")) delete frames[key]
|
||||
else { let fileData = frames[key];
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
for (let innerKey in fileData) {
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
if (typeof fileData[innerKey]) {
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
else {
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
let fileData = frames[key]
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
for (let innerKey in fileData) {
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
if (!["spriteSize", "spriteOffset"].includes(innerKey)) delete fileData[innerKey] // remove useless stuff
|
||||
else fileData[innerKey] = JSON.parse(fileData[innerKey].replace(/{/g, '[').replace(/}/g, ']'));
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
else fileData[innerKey] = JSON.parse(fileData[innerKey].replaceAll('{', '[').replaceAll('}', ']'))
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
}
|
||||
}
|
||||
}}
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
fs.writeFileSync('./parsed/gameSheet.json', JSON.stringify(frames, null, 2).replace(/\[\n.+?(-?\d+),\n.+?(-?\d+)\n.+]/g, "[$1, $2]")); // regex to make it easier to read
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
console.log("Successfully parsed!")
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
}
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
fs.writeFileSync('./parsed/gameSheet.json', JSON.stringify(frames, null, 2).replace(/\[\n.+?(-?\d+),\n.+?(-?\d+)\n.+]/g, "[$1, $2]")); // regex to make it easier to read
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
console.log("Successfully parsed!")
|
||||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
||||
|
|
|||
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
Incomplete string escaping or encodingThis replaces only the first occurrence of '}}'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '}}'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/69)
Incomplete string escaping or encodingThis replaces only the first occurrence of '{{'. ## Incomplete string escaping or encoding
This replaces only the first occurrence of '{{'.
[Show more details](https://github.com/GDColon/GDBrowser/security/code-scanning/70)
I realized I realized `replaceAll` is better there
|
|
@ -1,5 +1,6 @@
|
|||
const plist = require('plist');
|
||||
const fs = require('fs');
|
||||
"use strict";
|
||||
const plist = require('plist')
|
||||
const fs = require('fs')
|
||||
const gdPath = 'C:\\Program Files (x86)\\Steam\\steamapps\\common\\Geometry Dash\\Resources\\'
|
||||
const animationPlists = ["Robot_AnimDesc.plist", "Spider_AnimDesc.plist"]
|
||||
const objectDefinitions = "objectDefinitions.plist"
|
||||
|
@ -29,16 +30,16 @@ plistData.forEach(x => {
|
|||
Object.keys(x.animationContainer).forEach(a => fullAnimationData[a] = x.animationContainer[a])
|
||||
})
|
||||
|
||||
let animations = { "robot": {}, "spider": {} }
|
||||
let animations = { robot: {}, spider: {} }
|
||||
|
||||
for (let animation in fullAnimationData) {
|
||||
let animationName = animation.split(".")[0].split("_")
|
||||
let animationName = animation.split(".", 1)[0].split("_")
|
||||
let animationForm = animationName.shift()
|
||||
let animationIndex = Number(animationName.pop()) - 1
|
||||
animationName = animationName.join("_")
|
||||
|
||||
let animationList = Object.values(fullAnimationData[animation])
|
||||
let formName = animation.split("_")[0].toLowerCase()
|
||||
let formName = animation.split("_", 1)[0].toLowerCase()
|
||||
let animationData = animationList.map(anim => {
|
||||
let textureInfo = anim.texture.split("_")
|
||||
let flips = parseSet(anim.flipped)
|
||||
|
@ -55,17 +56,19 @@ for (let animation in fullAnimationData) {
|
|||
if (!animations[formName][animationName]) {
|
||||
let timingDefs = timings[animationForm].animations[animationName] || {}
|
||||
let animationInfo = { duration: cleanFloat(Number(timingDefs.delay || 0.05) * 1000) }
|
||||
if (timingDefs.looped == '1' || (!timingDefs.looped && animationName.includes("loop"))) animationInfo.loop = true
|
||||
if (timingDefs.singleFrame) animationInfo.single = true
|
||||
if (timingDefs.looped == '1' || (!timingDefs.looped && animationName.includes("loop")))
|
||||
animationInfo.loop = true
|
||||
if (timingDefs.singleFrame)
|
||||
animationInfo.single = true
|
||||
animations[formName][animationName] = { info: animationInfo, frames: [] }
|
||||
}
|
||||
animations[formName][animationName].frames[animationIndex] = animationData
|
||||
}
|
||||
|
||||
let cleanJSON = JSON.stringify({info, animations}, null, 2)
|
||||
.replace(/: \[\n\s+([0-9a-z.-]+),\n\s+([0-9a-z.-]+)\n\s+],/g, ": [$1, $2],") // keep sets on one line
|
||||
.replace(/],\n(\s+)"(.+?)": \[\n/g, '],\n\n$1"$2": [\n') // blank line between animations
|
||||
.replace(' "animations"', '\n "animations"') // blank line before animation list
|
||||
.replace(/: \[\n\s+([\da-z.-]+),\n\s+([\da-z.-]+)\n\s+],/g, ": [$1, $2],") // keep sets on one line
|
||||
.replace(/],\n(\s+)"(.+?)": \[\n/g, '],\n\n$1"$2": [\n') // blank line between animations
|
||||
.replace(' "animations"', '\n "animations"') // blank line before animation list
|
||||
|
||||
fs.writeFileSync('./parsed/robotAnimations.json', cleanJSON); // regex to make it easier to read
|
||||
fs.writeFileSync('./parsed/robotAnimations.json', cleanJSON); // regex to make it easier to read
|
||||
console.log("Successfully parsed!")
|
|
@ -17,7 +17,6 @@
|
|||
[ "Cool", 37, 20, 17, 1 ],
|
||||
[ "Cyclic", 30, 3, 12, 0 ],
|
||||
[ "DanZmeN", 104, 34, 12, 1 ],
|
||||
[ "DanZmeN", 104, 34, 12, 1 ],
|
||||
[ "envylol", 73, 20, 1, 1],
|
||||
DanZmeN was duped lol DanZmeN was duped lol
|
||||
[ "EVW", 28, 12, 9, 0 ],
|
||||
[ "Flub", 25, 3, 12, 1 ],
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
// Feel free to enable/disable stuff here for smoother local use, free of rate limits
|
||||
|
||||
module.exports = {
|
||||
|
||||
|
||||
port: 2000, // Port to host website on
|
||||
|
||||
params: { // Always send this stuff to the servers
|
||||
params: { // Always send this stuff to the servers
|
||||
secret: 'Wmfd2893gb7',
|
||||
gameVersion: '21',
|
||||
binaryVersion: '35',
|
||||
|
|
Use of a broken or weak cryptographic algorithm
Sensitive data from an access to username is used in a broken or weak cryptographic algorithm.
Sensitive data from an access to userName is used in a broken or weak cryptographic algorithm.
Show more details