From 584f512a58690a0e569bbd24e156696995a367c5 Mon Sep 17 00:00:00 2001 From: Rian8337 <52914632+Rian8337@users.noreply.github.com> Date: Sun, 14 Mar 2021 12:52:36 +0700 Subject: [PATCH 01/10] Update whitelist.pug --- views/whitelist.pug | 60 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/views/whitelist.pug b/views/whitelist.pug index 02b2d4a..67b270f 100644 --- a/views/whitelist.pug +++ b/views/whitelist.pug @@ -17,6 +17,8 @@ h3 a(href='/whitelist?page=1',class='nav', class='active')= "Whitelist" li(class='nav') a(href='/toppp',class='nav')= "Top PP" + li(class="nav") + a(href='/calculate', class="nav")= "Calculate Beatmap PP" li(class='nav') a(href='/about',class='nav')= "About / Donation" @@ -41,13 +43,23 @@ hr table(border="0", width="100%") tbody - th(width="10%")= "Map ID" - th(width="80%")= "Map Name" + th(width="7.5%")= "Map ID" + th(width="70%")= "Map Name" + th(width="2.5%")= "CS" + th(width="2.5%")= "AR" + th(width="2.5%")= "OD" + th(width="2.5%")= "HP" + th(width="2.5%")= "SR" th(width="10%")= "osu! redirect" each val in list tr td= val.mapid td= val.mapname + td= val.diffstat.cs + td= val.diffstat.ar + td= val.diffstat.od + td= val.diffstat.hp + td= val.diffstat.sr td a(href='https://osu.ppy.sh/b/'+val.mapid)= "Link" @@ -62,4 +74,48 @@ div li(class="nav") a(href='/whitelist?page=' + (page+1) + (query ? '?query='+query : ''), class="pagenav")= "Next Page >>>" +hr +div + h3 Search Query Guide + h7 + strong Available filter option: + | CS, AR, OD, HP, SR + br + strong Available sorting option: + | CS, AR, OD, HP, SR, mapid, mapname (you can put "-" in front to use descend sort instead of ascend) + br + br + strong Equality symbols for filter option: + | + ul + li <= (less than or equal to) + li < (less than) + li = (equal to) + li > (more than) + li >= (more than or equal to) + | All filter and sort options are case insensitive, with each of them separated by space. + br + br + | By default, there is no filter, and the sort option is set to beatmap name. + br + br + | Anything that doesn't fall into any of the filter or sort option will be treated as searching beatmap name. + br + br + strong Examples: + ul + li + strong: i cs>=4.2 cs<=5 sort=cs + | will search for beatmaps with CS between 4.2 (inclusive) and 5 (inclusive) and sort them based on CS ascendingly + li + strong: i od>=5 od<9 ar>7 ar<=9.7 sort=-ar + | will search for beatmaps with AR between 7 (exclusive) and 9.7 (inclusive) and OD between 5 (inclusive) and 9 (exclusive), and then + | sorting the search result by AR descendingly + li + strong: i cs>=4.2 ar>9.3 od>=8 hp>=5 sort=-sr logic boi is the best + | will search for beatmaps with CS above 4.2 (inclusive), AR above 9.3 (exclusive), OD above 8 (inclusive), + | HP above 5 (inclusive), and matches the keyword "logic boi is the best" (much like osu! search function), + | and then sorting the search result by star rating descendingly + +hr From 14f14213bbbd8fd58e1ccf086a9e584b094c1dff Mon Sep 17 00:00:00 2001 From: Rian8337 <52914632+Rian8337@users.noreply.github.com> Date: Sun, 14 Mar 2021 13:05:30 +0700 Subject: [PATCH 02/10] Add whitelist search query --- app.js | 111 +++++++++++++++++++++++++++++++++++++++----- views/default.css | 5 ++ views/whitelist.pug | 2 +- 3 files changed, 106 insertions(+), 12 deletions(-) diff --git a/app.js b/app.js index 312454b..d1d35cb 100644 --- a/app.js +++ b/app.js @@ -43,6 +43,27 @@ function convertURIregex(input) { return input; } +function getComparisonText(comparison) { + switch (comparison) { + case "<": + return "$lt"; + case "<=": + return "$lte"; + case ">": + return "$gt"; + case ">=": + return "$gte"; + default: + return "$eq"; + } +} + +function getComparisonObject(comparison, value) { + const comparisonString = getComparisonText(comparison); + + return Object.defineProperty({}, comparisonString, {value, writable: true, configurable: true, enumerable: true}); +} + top_pp_list = []; clientdb.connect( function(err, db) { @@ -107,18 +128,86 @@ function makeBoard() { }); app.get('/whitelist', (req, res) => { - var page = parseInt(req.url.split('?page=')[1]); - var query = req.url.split('?query=')[1] - var mapquery; - if (!page) {page = 1;} - if (!query) {mapquery = {}; query = '';} - else { - var regexquery = new RegExp(convertURIregex(query), 'i'); - mapquery = {mapname: regexquery}; + const page = parseInt(req.url.split('?page=')[1]) || 1; + const query = convertURI(req.url.split('?query=')[1] || "").toLowerCase(); + const mapquery = {}; + const sort = { mapname: 1 }; + if (query) { + let mapNameQuery = ""; + const comparisonRegex = /[<=>]{1,2}/; + const finalQueries = query.split(/\s+/g); + for (const finalQuery of finalQueries) { + let [key, value] = finalQuery.split(comparisonRegex, 2); + const comparison = (comparisonRegex.exec(finalQuery) ?? ["="])[0]; + switch (key) { + case "cs": + case "ar": + case "od": + case "hp": + case "sr": + const propertyName = `diffstat.${key}`; + if (mapquery.hasOwnProperty(propertyName)) { + Object.defineProperty(mapquery[propertyName], getComparisonText(comparison), {value: parseFloat(value), writable: true, configurable: true, enumerable: true}); + } else { + Object.defineProperty(mapquery, `diffstat.${key}`, {value: getComparisonObject(comparison, parseFloat(value)), writable: true, configurable: true, enumerable: true}); + } + break; + case "star": + case "stars": + if (mapquery.hasOwnProperty("diffstat.sr")) { + Object.defineProperty(mapquery["diffstat.sr"], getComparisonText(comparison), {value: parseFloat(value), writable: true, configurable: true, enumerable: true}); + } else { + Object.defineProperty(mapquery, "diffstat.sr", {value: getComparisonObject(comparison, parseFloat(value)), writable: true, configurable: true, enumerable: true}); + } + break; + case "sort": + const isDescendSort = value.startsWith("-"); + if (isDescendSort) { + value = value.substring(1); + } + switch (value) { + case "beatmapid": + case "mapid": + case "id": + Object.defineProperty(sort, "mapid", {value: isDescendSort ? -1 : 1, writable: true, configurable: true, enumerable: true}); + break; + case "beatmapname": + case "mapname": + case "name": + Object.defineProperty(sort, "mapname", {value: isDescendSort ? -1 : 1, writable: true, configurable: true, enumerable: true}); + break; + case "cs": + case "ar": + case "od": + case "hp": + Object.defineProperty(sort, `diffstat.${value}`, {value: isDescendSort ? -1 : 1, writable: true, configurable: true, enumerable: true}); + break; + case "sr": + case "star": + case "stars": + Object.defineProperty(sort, "diffstat.sr", {value: isDescendSort ? -1 : 1, writable: true, configurable: true, enumerable: true}); + break; + default: + mapNameQuery += finalQuery + " "; + } + break; + default: + mapNameQuery += finalQuery + " "; + } + } + if (mapNameQuery) { + const regexQuery = mapNameQuery.trim().split(/\s+/g).map(v => { + return {mapname: new RegExp(convertURIregex(v, "i"))}; + }); + Object.defineProperty(mapquery, "$and", {value: regexQuery, writable: false, configurable: true, enumerable: true}); + } + } + // Allow star rating sort to override beatmap title sort + if (sort.hasOwnProperty("diffstat.sr")) { + delete sort["mapname"]; } - var mapsort = { mapname: 1 }; - whitelistdb.find(mapquery, {projection: {_id: 0}}).sort(mapsort).skip((page-1)*30).limit(30).toArray(function(err, resarr) { - //console.log(resarr); + whitelistdb.find(mapquery, {projection: {_id: 0, mapid: 1, mapname: 1, diffstat: 1}}).sort(sort).skip((page-1)*30).limit(30).toArray(function(err, resarr) { + resarr.map(v => v.diffstat.sr = parseFloat((v.diffstat.sr).toFixed(2))); var title = 'Map Whitelisting Board' res.render('whitelist', { title: title, diff --git a/views/default.css b/views/default.css index 64ac604..e2a5b60 100644 --- a/views/default.css +++ b/views/default.css @@ -27,3 +27,8 @@ h5 { font: 16px Exo; font-weight: 350; } + +h7 { + font: 14px Exo; + font-weight: 150; +} \ No newline at end of file diff --git a/views/whitelist.pug b/views/whitelist.pug index 67b270f..5e9de78 100644 --- a/views/whitelist.pug +++ b/views/whitelist.pug @@ -118,4 +118,4 @@ div | HP above 5 (inclusive), and matches the keyword "logic boi is the best" (much like osu! search function), | and then sorting the search result by star rating descendingly -hr +hr \ No newline at end of file From 89d18d82a028c7609468444d7db6a045f47242d9 Mon Sep 17 00:00:00 2001 From: Rian8337 <52914632+Rian8337@users.noreply.github.com> Date: Sun, 14 Mar 2021 14:24:59 +0700 Subject: [PATCH 03/10] Add BPM filter and sort option --- app.js | 13 +++++++++---- views/whitelist.pug | 10 ++++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app.js b/app.js index d1d35cb..f36c797 100644 --- a/app.js +++ b/app.js @@ -131,7 +131,7 @@ function makeBoard() { const page = parseInt(req.url.split('?page=')[1]) || 1; const query = convertURI(req.url.split('?query=')[1] || "").toLowerCase(); const mapquery = {}; - const sort = { mapname: 1 }; + const sort = {}; if (query) { let mapNameQuery = ""; const comparisonRegex = /[<=>]{1,2}/; @@ -145,6 +145,7 @@ function makeBoard() { case "od": case "hp": case "sr": + case "bpm": const propertyName = `diffstat.${key}`; if (mapquery.hasOwnProperty(propertyName)) { Object.defineProperty(mapquery[propertyName], getComparisonText(comparison), {value: parseFloat(value), writable: true, configurable: true, enumerable: true}); @@ -180,6 +181,7 @@ function makeBoard() { case "ar": case "od": case "hp": + case "bpm": Object.defineProperty(sort, `diffstat.${value}`, {value: isDescendSort ? -1 : 1, writable: true, configurable: true, enumerable: true}); break; case "sr": @@ -202,9 +204,12 @@ function makeBoard() { Object.defineProperty(mapquery, "$and", {value: regexQuery, writable: false, configurable: true, enumerable: true}); } } - // Allow star rating sort to override beatmap title sort - if (sort.hasOwnProperty("diffstat.sr")) { - delete sort["mapname"]; + if (!sort.hasOwnProperty("mapname")) { + Object.defineProperty(sort, "mapname", {value: 1, writable: false, configurable: true, enumerable: true}); + } + // Allow SR and BPM sort to override beatmap title sort + if (sort.hasOwnProperty("diffstat.sr") || sort.hasOwnProperty("diffstat.bpm")) { + delete sort.mapname; } whitelistdb.find(mapquery, {projection: {_id: 0, mapid: 1, mapname: 1, diffstat: 1}}).sort(sort).skip((page-1)*30).limit(30).toArray(function(err, resarr) { resarr.map(v => v.diffstat.sr = parseFloat((v.diffstat.sr).toFixed(2))); diff --git a/views/whitelist.pug b/views/whitelist.pug index 5e9de78..2966ae7 100644 --- a/views/whitelist.pug +++ b/views/whitelist.pug @@ -80,10 +80,10 @@ div h3 Search Query Guide h7 strong Available filter option: - | CS, AR, OD, HP, SR + | CS, AR, OD, HP, SR, BPM br strong Available sorting option: - | CS, AR, OD, HP, SR, mapid, mapname (you can put "-" in front to use descend sort instead of ascend) + | CS, AR, OD, HP, SR, BPM, mapid, mapname (you can put "-" in front to use descend sort instead of ascend) br br strong Equality symbols for filter option: @@ -100,6 +100,9 @@ div | By default, there is no filter, and the sort option is set to beatmap name. br br + | Using SR and/or BPM sort option will override beatmap name sort option. + br + br | Anything that doesn't fall into any of the filter or sort option will be treated as searching beatmap name. br br @@ -112,6 +115,9 @@ div strong: i od>=5 od<9 ar>7 ar<=9.7 sort=-ar | will search for beatmaps with AR between 7 (exclusive) and 9.7 (inclusive) and OD between 5 (inclusive) and 9 (exclusive), and then | sorting the search result by AR descendingly + li + strong: i od>=7 bpm>=180 + | will search for beatmaps with OD above 7 (inclusive) and BPM above 180 (inclusive) and sort them based on BPM ascendingly li strong: i cs>=4.2 ar>9.3 od>=8 hp>=5 sort=-sr logic boi is the best | will search for beatmaps with CS above 4.2 (inclusive), AR above 9.3 (exclusive), OD above 8 (inclusive), From 3f833a044296a5c08ce1ed397fb3ac0d8eee7c29 Mon Sep 17 00:00:00 2001 From: Rian8337 <52914632+Rian8337@users.noreply.github.com> Date: Sun, 14 Mar 2021 14:25:22 +0700 Subject: [PATCH 04/10] Remove SR mapping (fixed by bot) --- app.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app.js b/app.js index f36c797..6bde2d5 100644 --- a/app.js +++ b/app.js @@ -212,7 +212,6 @@ function makeBoard() { delete sort.mapname; } whitelistdb.find(mapquery, {projection: {_id: 0, mapid: 1, mapname: 1, diffstat: 1}}).sort(sort).skip((page-1)*30).limit(30).toArray(function(err, resarr) { - resarr.map(v => v.diffstat.sr = parseFloat((v.diffstat.sr).toFixed(2))); var title = 'Map Whitelisting Board' res.render('whitelist', { title: title, From 77497eac875abd6b9e40d3b695ee8b4d7707e74d Mon Sep 17 00:00:00 2001 From: Rian8337 <52914632+Rian8337@users.noreply.github.com> Date: Sun, 14 Mar 2021 14:31:57 +0700 Subject: [PATCH 05/10] Use propertyName variable instead of straight string --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 6bde2d5..31e71eb 100644 --- a/app.js +++ b/app.js @@ -150,7 +150,7 @@ function makeBoard() { if (mapquery.hasOwnProperty(propertyName)) { Object.defineProperty(mapquery[propertyName], getComparisonText(comparison), {value: parseFloat(value), writable: true, configurable: true, enumerable: true}); } else { - Object.defineProperty(mapquery, `diffstat.${key}`, {value: getComparisonObject(comparison, parseFloat(value)), writable: true, configurable: true, enumerable: true}); + Object.defineProperty(mapquery, propertyName, {value: getComparisonObject(comparison, parseFloat(value)), writable: true, configurable: true, enumerable: true}); } break; case "star": From 5f9a8d98ead7c216816ee300c4dceb6ea289dae8 Mon Sep 17 00:00:00 2001 From: Rian8337 <52914632+Rian8337@users.noreply.github.com> Date: Sun, 14 Mar 2021 14:44:11 +0700 Subject: [PATCH 06/10] Add BPM column --- views/whitelist.pug | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/views/whitelist.pug b/views/whitelist.pug index 2966ae7..bac4596 100644 --- a/views/whitelist.pug +++ b/views/whitelist.pug @@ -44,12 +44,13 @@ hr table(border="0", width="100%") tbody th(width="7.5%")= "Map ID" - th(width="70%")= "Map Name" + th(width="67.5%")= "Map Name" th(width="2.5%")= "CS" th(width="2.5%")= "AR" th(width="2.5%")= "OD" th(width="2.5%")= "HP" th(width="2.5%")= "SR" + th(width="2.5%")= "BPM" th(width="10%")= "osu! redirect" each val in list tr @@ -60,6 +61,7 @@ table(border="0", width="100%") td= val.diffstat.od td= val.diffstat.hp td= val.diffstat.sr + td= val.diffstat.bpm td a(href='https://osu.ppy.sh/b/'+val.mapid)= "Link" From 79c3750b9a4d50d97e4efdc7abdd931e98b99ad0 Mon Sep 17 00:00:00 2001 From: Rian8337 <52914632+Rian8337@users.noreply.github.com> Date: Sun, 14 Mar 2021 14:47:14 +0700 Subject: [PATCH 07/10] Use nonstrict mode JavaScript --- app.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app.js b/app.js index 31e71eb..9b35997 100644 --- a/app.js +++ b/app.js @@ -148,17 +148,17 @@ function makeBoard() { case "bpm": const propertyName = `diffstat.${key}`; if (mapquery.hasOwnProperty(propertyName)) { - Object.defineProperty(mapquery[propertyName], getComparisonText(comparison), {value: parseFloat(value), writable: true, configurable: true, enumerable: true}); + mapquery[propertyName][getComparisonText(comparison)] = parseFloat(value); } else { - Object.defineProperty(mapquery, propertyName, {value: getComparisonObject(comparison, parseFloat(value)), writable: true, configurable: true, enumerable: true}); + mapquery[propertyName] = getComparisonObject(comparison, parseFloat(value)); } break; case "star": case "stars": if (mapquery.hasOwnProperty("diffstat.sr")) { - Object.defineProperty(mapquery["diffstat.sr"], getComparisonText(comparison), {value: parseFloat(value), writable: true, configurable: true, enumerable: true}); + mapquery["diffstat.sr"][getComparisonText(comparison)] = parseFloat(value); } else { - Object.defineProperty(mapquery, "diffstat.sr", {value: getComparisonObject(comparison, parseFloat(value)), writable: true, configurable: true, enumerable: true}); + mapquery["diffstat.sr"] = getComparisonObject(comparison, parseFloat(value)); } break; case "sort": @@ -170,24 +170,24 @@ function makeBoard() { case "beatmapid": case "mapid": case "id": - Object.defineProperty(sort, "mapid", {value: isDescendSort ? -1 : 1, writable: true, configurable: true, enumerable: true}); + sort.mapid = isDescendSort ? -1 : 1; break; case "beatmapname": case "mapname": case "name": - Object.defineProperty(sort, "mapname", {value: isDescendSort ? -1 : 1, writable: true, configurable: true, enumerable: true}); + sort.mapname = isDescendSort ? -1 : 1; break; case "cs": case "ar": case "od": case "hp": case "bpm": - Object.defineProperty(sort, `diffstat.${value}`, {value: isDescendSort ? -1 : 1, writable: true, configurable: true, enumerable: true}); + sort[`diffstat.${value}`] = isDescendSort ? -1 : 1; break; case "sr": case "star": case "stars": - Object.defineProperty(sort, "diffstat.sr", {value: isDescendSort ? -1 : 1, writable: true, configurable: true, enumerable: true}); + sort["diffstat.sr"] = isDescendSort ? -1 : 1; break; default: mapNameQuery += finalQuery + " "; @@ -201,11 +201,11 @@ function makeBoard() { const regexQuery = mapNameQuery.trim().split(/\s+/g).map(v => { return {mapname: new RegExp(convertURIregex(v, "i"))}; }); - Object.defineProperty(mapquery, "$and", {value: regexQuery, writable: false, configurable: true, enumerable: true}); + mapquery.$and = regexQuery; } } if (!sort.hasOwnProperty("mapname")) { - Object.defineProperty(sort, "mapname", {value: 1, writable: false, configurable: true, enumerable: true}); + sort.mapname = 1; } // Allow SR and BPM sort to override beatmap title sort if (sort.hasOwnProperty("diffstat.sr") || sort.hasOwnProperty("diffstat.bpm")) { From a9ca444c1e2cf44292debf61521e014ea3509af0 Mon Sep 17 00:00:00 2001 From: Rian8337 <52914632+Rian8337@users.noreply.github.com> Date: Sun, 14 Mar 2021 14:49:00 +0700 Subject: [PATCH 08/10] Use case insensitive flag for regex --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 9b35997..c70eb12 100644 --- a/app.js +++ b/app.js @@ -199,7 +199,7 @@ function makeBoard() { } if (mapNameQuery) { const regexQuery = mapNameQuery.trim().split(/\s+/g).map(v => { - return {mapname: new RegExp(convertURIregex(v, "i"))}; + return {mapname: new RegExp(convertURIregex(v), "i")}; }); mapquery.$and = regexQuery; } From e5810715509c3c520fcf533cd11cea7e12c41976 Mon Sep 17 00:00:00 2001 From: Rian8337 <52914632+Rian8337@users.noreply.github.com> Date: Sun, 14 Mar 2021 14:50:34 +0700 Subject: [PATCH 09/10] Remove calculate pp menu button --- views/whitelist.pug | 2 -- 1 file changed, 2 deletions(-) diff --git a/views/whitelist.pug b/views/whitelist.pug index bac4596..5609a64 100644 --- a/views/whitelist.pug +++ b/views/whitelist.pug @@ -17,8 +17,6 @@ h3 a(href='/whitelist?page=1',class='nav', class='active')= "Whitelist" li(class='nav') a(href='/toppp',class='nav')= "Top PP" - li(class="nav") - a(href='/calculate', class="nav")= "Calculate Beatmap PP" li(class='nav') a(href='/about',class='nav')= "About / Donation" From 0e15b665da61c38071084ece60b5e4420f5b1628 Mon Sep 17 00:00:00 2001 From: Rian8337 <52914632+Rian8337@users.noreply.github.com> Date: Sun, 14 Mar 2021 16:19:51 +0700 Subject: [PATCH 10/10] Keep current query in text box --- views/whitelist.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/whitelist.pug b/views/whitelist.pug index 5609a64..6c2cb78 100644 --- a/views/whitelist.pug +++ b/views/whitelist.pug @@ -23,7 +23,7 @@ h3 div(class="queryall") h5(class="queryshow")= "Current query: " + query form - input(type="text", name="query", id='rcorners', hint="Search") + input(type="text", name="query", value=query, id='rcorners', hint="Search") input(type="submit", id='rcorners2', value="Search") hr