GDBrowser/html/search.html
2022-05-29 13:18:14 -04:00

400 lines
No EOL
20 KiB
HTML

<head>
<title id="tabTitle">Level Search</title>
<meta charset="utf-8">
<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">
<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">
<meta name="twitter:card" content="summary">
</head>
<body class="levelBG" onbeforeunload="saveUrl()">
<div id="everything" style="overflow: auto;">
<div class="popup" id="pageDiv">
<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">
<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');">
</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');">
</div>
</div>
</div>
<div class="popup" id="purgeDiv">
<div class="fancybox bounce center supercenter" style="width: 35%; height: 28%">
<h2 class="smaller center" style="font-size: 5.5vh">Delete All</h2>
<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">
</div>
</div>
<div class="popup" id="shuffleDiv">
<div class="fancybox bounce center supercenter">
<h2 class="smaller center" style="font-size: 5.5vh">Random Level</h2>
<p class="bigger center" id="levelInfo" style="line-height: 5vh; margin-top: 1.5vh;">
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">
</div>
</div>
<div style="position:absolute; bottom: 0%; left: 0%; width: 100%">
<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)">
</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%">
<h1 id="header"></h1>
</div>
<div style="text-align: right; position:absolute; top: 1%; right: 2%">
<h2 class="smaller" style="font-size: 4.5vh" id="pagenum"></h2>
</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()">
</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%">
</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%">
</div>
<div style="position:absolute; top: 2%; left: 1.5%; width: 10%; height: 25%; pointer-events: none">
<img class="gdButton yesClick" id="backButton" src="../assets/back.png" height="30%" onclick="backButton()">
</div>
<div 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()">
</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>
</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>
</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>
</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%">
</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%">
</div>
<div class="supercenter" id="loading" style="height: 10%; top: 47%; display: none;">
<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="../dragscroll.js"></script>
<script>
$('#pageDown').hide()
$('#pageUp').hide()
let accID;
let path = location.pathname.replace('/search/', "")
let url = new URL(window.location.href)
let gauntlet = url.searchParams.get('gauntlet')
let userMode = url.searchParams.get('user')
let type = url.searchParams.get('type')
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 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
let pages = 0
let results = 0
let legalPages = true
let gdwMode = false
let superSearch = ['*', '*?type=mostliked', '*?type=mostdownloaded', '*?type=recent'].includes(window.location.href.split('/')[4].toLowerCase())
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")}`
function clean(text) {return (text || "").toString().replace(/&/g, "&#38;").replace(/</g, "&#60;").replace(/>/g, "&#62;").replace(/=/g, "&#61;").replace(/"/g, "&#34;").replace(/'/g, "&#39;")}
if (type == "followed") {
let followed = localStorage.followed ? JSON.parse(localStorage.followed) : []
searchFilters += ("&creators=" + followed.join())
}
let hostMatch = window.location.host.match(/\./g)
if (hostMatch && hostMatch.length > 1) { // gdps check
$('#gdWorld').remove()
$('#normalGD').remove()
}
function Append(firstLoad, noCache) {
loading = true;
if (!firstLoad) $('#pagenum').text(`Page ${(page + 1)}${pages ? ` of ${pages}` : ""}`)
$('#searchBox').html('<div style="height: 4.5%"></div>')
$('#pageSelect').val(page + 1)
$('#loading').show()
if (page == 0) $('#pageDown').hide()
else $('#pageDown').show()
if (page == (pages - 1)) $('#lastPage').addClass('grayscale').find('img').removeClass('gdButton')
else $('#lastPage').removeClass('grayscale').find('img').addClass('gdButton')
if (!noCache && pageCache[page]) appendLevels(pageCache[page])
else Fetch(searchFilters.replace("[PAGE]", page)).then(appendLevels).catch(e => $('#loading').hide())
function appendLevels(res) {
if (res == '-1' || res.length == 0) { $('#loading').hide(); $('#pageUp').hide(); return loading = false }
pageCache[page] = res
if (firstLoad) {
pages = res[0].pages
results = res[0].results
if (!pages || pages == 1000 || pages < 1) {
pages = null
if (!superSearch) $('#shuffle').addClass('grayscale')
else $('#shuffle').css('filter', 'hue-rotate(100deg)')
}
$('#shuffle').show()
if (pages > 1) $('#lastPage').show()
$('#pagenum').text(`Page ${page + 1}${pages ? ` of ${pages}` : ""}`)
}
if ((pages && page+1 >= pages) || (!pages && res.length < 9 && type != "recent")) $('#pageUp').hide()
else $('#pageUp').show()
if (demonList) {
demonListLink = res[0].demonList
res = res.sort(function(a, b){return a.demonPosition - b.demonPosition});
}
res.forEach((x, y) => {
let hasAuthor = (x.accountID != "0")
let userSearch = (type == 5 || typeof userMode == 'string')
if (y == 0 && userSearch) {
$('#header').text(((!x.author || x.author == "-" ? "Someone" : x.author)) + (x.author.toLowerCase().endsWith('s') ? "'" : "'s") + " levels")
document.title = $('#header').text()
accID = x.playerID
}
let filteredSong = clean(x.songName.replace(/[^ -~]/g, ""))
if (!filteredSong) filteredSong = clean(x.songName)
let songColor = x.customSong == 0 ? "blue" : (x.songLink && !x.songLink.match(/^https?:\/\/\audio\.ngfiles\.com\//)) ? "nong" : "whatIfItWasPurple"
let noLink = songColor != "whatIfItWasPurple"
$('#searchBox').append(`<div class="searchresult" title="${clean(x.description)}">
<h1 class="lessspaced pre" title="${x.name} by ${!x.author || x.author == "-" ? "some nerd" : x.author}" style="width: fit-content; padding-right: 1%">${clean(x.name || " ")}</h1>
<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%">` : ''}
</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}` : ""}
</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)' : ''}">
<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>` : ""}
${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">` : ""}
</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>` : "" }
<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>`)
})
$('#searchBox').append('<div style="height: 4.5%"></div>').scrollTop(0)
$('#loading').hide()
loading = false;
}
}
Append(true)
$('#pageUp').click(function() {page += 1; if (!loading) Append()})
$('#pageDown').click(function() {page -= 1; if (!loading) Append()})
$('#lastPage').click(function() {page = (pages - 1); if (!loading) Append()})
$('#pageJump').click(function() {if (loading) return; page = parseInt(($('#pageSelect').val() || 1) - 1); Append()})
$('#refreshPage').click(function() { Append(false, true) } )
if (header) {
header = header.slice(0, 32) || "Level Search"
$('#header').text(header)
document.title = header
}
else {
if (type == 1 || type == 'mostdownloaded') $('#header').text("Most Downloaded")
if (type == 2 || type == 'mostliked') $('#header').text("Most Liked")
if (type == 3 || type == 'trending') $('#header').text("Trending Levels")
if (type == 4 || type == 'recent') $('#header').text("Recent Levels")
if (type == 6 || type == 'featured') { $('#header').text("Featured"); $('#gdWorld').show() }
if (type == 7 || type == 'magic') $('#header').text("Magic Levels")
if (type == 11 || type == 'awarded' || type == 'starred') $('#header').text("Awarded Levels")
if (type == 16 || type == 'halloffame' || type == 'hof') $('#header').text("Hall of Fame")
if (type == 17 || type == 'gdw' || type == 'gdworld') { $('#header').text("Featured (GD World)"); $('#normalGD').show() }
if (path != "*" && (type == 10 || list != null)) $('#header').text("Custom List")
if (type == 'followed') $('#header').text("Followed Creators")
document.title = $('#header').text() || "Level Search"
$('#meta-title').attr('content', $('#header').text() || "Level Search")
if ($('#header').text()) $('#meta-desc').attr('content', `View Geometry Dash's ${$('#header').text()}${$('#header').text() == "Hall of Fame" ? "" : "list"}!`)
}
if (type == 'saved') {
$('#header').text("Saved Levels")
$('#purge').show()
document.title = "Saved Levels"
$('#meta-title').attr('content', `Saved Levels`)
$('#meta-desc').attr('content', `View your collection of saved Geometry Dash levels!`)
}
if (gauntlet) {
$('body').addClass('darkBG')
$('.cornerPiece').addClass('grayscale')
$('#header').text((gauntlets[parseInt(gauntlet) - 1] || "Unknown") + " Gauntlet")
$('#meta-title').attr('content', (gauntlets[parseInt(gauntlet) - 1] || "Unknown") + " Gauntlet")
$('#meta-desc').attr('content', `View the 5 levels in the ${(gauntlets[parseInt(gauntlet) - 1] || "Unknown") + " Gauntlet"}!`)
}
if (demonList) {
$('body').addClass('darkBG')
$('.cornerPiece').addClass('grayscale')
$('#header').text("Demon List")
$('#meta-title').attr('content', "Demon List")
$('#meta-desc').attr('content', "View the hardest demons in Geometry Dash!")
}
if (!$('#header').text() && typeof userMode != "string") {
if (path != "*") {
$('#header').text(decodeURIComponent(path))
$('#tabTitle').text(decodeURIComponent(path) + " - Level Search")
} else
$('#header').text("Online Levels")
}
$('.closeWindow').click(function() {$(".popup").attr('style', 'display: none;')})
$('#purgeSaved').click(function() {
localStorage.removeItem('saved');
location.reload()
})
var max = 9999
var min = 1
$('#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));
});
$('#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 => {
let mostRecent = recent[0].id
function fetchRandom() {
fetch(`../api/level/${Math.floor(Math.random() * (mostRecent)) + 1}`).then(res => res.json()).then(res => {
if (res == "-1" || !res.id) return fetchRandom()
else window.location.href = "../" + res.id
})
}
fetchRandom()
})
}
else if (pages) {
let random = {}
let pageCount = +count || 10
randomResult = Math.floor(Math.random() * (results)) + 1
randomPage = Math.ceil(randomResult / pageCount)
randomIndex = randomResult % pageCount
if (randomIndex == 0) randomIndex = pageCount
$('#searchBox').html('<div style="height: 4.5%"></div>')
$('#loading').show()
fetch(searchFilters.replace('[PAGE]', randomPage-1)).then(res => res.json()).then(res => {
window.location.href = "../" + res[randomIndex-1].id
})
}
else return $('#shuffleDiv').show()
})
$(document).keydown(function(k) {
if (loading) return;
if ($('#pageDiv').is(':visible')) {
if (k.which == 13) $('#pageJump').trigger('click') //enter
else return;
}
if (k.which == 37 && $('#pageDown').is(":visible")) $('#pageDown').trigger('click') // left
if (k.which == 39 && $('#pageUp').is(":visible")) $('#pageUp').trigger('click') // right
});
</script>