mirror of
https://gitlab.com/skysthelimit.dev/selenite.git
synced 2025-06-17 19:12:07 -05:00
355 lines
14 KiB
JavaScript
355 lines
14 KiB
JavaScript
function starname(star) {
|
|
if (typeof(star) == "null") return "unknown";
|
|
if (typeof(star) == "undefined") return "unknown";
|
|
if (star<2) return "easy";
|
|
if (star<2.7) return "normal";
|
|
if (star<4) return "hard";
|
|
if (star<5.3) return "insane";
|
|
if (star<6.5) return "expert";
|
|
return "expert-plus";
|
|
}
|
|
|
|
// star: number; numerical representation of star rating
|
|
// returns an html element used in difficulty selection menu
|
|
function createStarRow(star) {
|
|
let row = document.createElement("div");
|
|
row.className = "star-row";
|
|
for (let i=0; i<10; ++i) {
|
|
let container = document.createElement("div");
|
|
container.className = "imgcontainer";
|
|
let img = document.createElement("img");
|
|
container.appendChild(img);
|
|
row.appendChild(container);
|
|
img.src = "img/star.png";
|
|
let value = Math.min(Math.max(star-i,0),1);
|
|
let size = 8 + value*10;
|
|
let pad = (1-value) * 5;
|
|
let style = "width:" + size + "px;";
|
|
style += "bottom:" + pad + "px;";
|
|
style += "left:" + pad + "px;";
|
|
if (value == 0) {
|
|
style += "opacity:0.4;";
|
|
}
|
|
img.setAttribute("style", style);
|
|
}
|
|
return row;
|
|
}
|
|
// creates a difficulty selection menu
|
|
function createDifficultyList(boxclicked, event) {
|
|
// check if a list of this kind is already there
|
|
if (window.currentDifficultyList) {
|
|
window.removeEventListener("click", window.currentDifficultyList.clicklistener);
|
|
window.currentDifficultyList.parentElement.removeChild(window.currentDifficultyList);
|
|
window.currentDifficultyList = null;
|
|
}
|
|
// window.showingDifficultyList = true;
|
|
event.stopPropagation();
|
|
// calculate list position on page
|
|
let rect = boxclicked.getBoundingClientRect();
|
|
let x = event.clientX - rect.left;
|
|
let y = event.clientY - rect.top;
|
|
// create list
|
|
let difficultyBox = document.createElement("div");
|
|
window.currentDifficultyList = difficultyBox;
|
|
difficultyBox.className = "difficulty-box";
|
|
difficultyBox.style.left = x + "px";
|
|
difficultyBox.style.top = y + "px";
|
|
boxclicked.appendChild(difficultyBox);
|
|
// close list if clicked outside
|
|
var closeDifficultyList = function() {
|
|
boxclicked.removeChild(difficultyBox);
|
|
window.currentDifficultyList = null;
|
|
window.removeEventListener('click', closeDifficultyList, false);
|
|
};
|
|
window.addEventListener("click", closeDifficultyList, false);
|
|
difficultyBox.clicklistener = closeDifficultyList;
|
|
// fill list
|
|
for (let i=0; i<boxclicked.data.ChildrenBeatmaps.length; ++i) {
|
|
// add a row
|
|
let difficultyItem = document.createElement("div");
|
|
difficultyItem.className = "difficulty-item";
|
|
difficultyBox.appendChild(difficultyItem);
|
|
difficultyItem.data = boxclicked.data.ChildrenBeatmaps[i];
|
|
// add ring icon representing star
|
|
let ringbase = document.createElement("div");
|
|
let ring = document.createElement("div");
|
|
ringbase.className = "bigringbase";
|
|
ring.className = "bigring";
|
|
ring.classList.add(starname(boxclicked.data.ChildrenBeatmaps[i].DifficultyRating));
|
|
difficultyItem.appendChild(ringbase);
|
|
difficultyItem.appendChild(ring);
|
|
// add version name & mapper
|
|
let line = document.createElement("div");
|
|
let version = document.createElement("div");
|
|
let mapper = document.createElement("div");
|
|
line.className = "versionline";
|
|
version.className = "version";
|
|
mapper.className = "mapper";
|
|
line.appendChild(version);
|
|
line.appendChild(mapper);
|
|
difficultyItem.appendChild(line);
|
|
version.innerText = boxclicked.data.ChildrenBeatmaps[i].DiffName;
|
|
mapper.innerText = "mapped by " + boxclicked.data.Creator;
|
|
// add row of stars
|
|
difficultyItem.appendChild(createStarRow(boxclicked.data.ChildrenBeatmaps[i].DifficultyRating));
|
|
// add callbacks
|
|
difficultyItem.onhover = function() {
|
|
|
|
}
|
|
difficultyItem.onclick = function(e) {
|
|
// check if ready
|
|
if (!window.scriptReady || !window.soundReady || !window.skinReady || !this.parentElement.parentElement.oszblob) {
|
|
return;
|
|
}
|
|
launchGame(this.parentElement.parentElement.oszblob, this.data.BeatmapID, this.data.DiffName);
|
|
}
|
|
}
|
|
difficultyBox.onclick = function(e) {
|
|
e.stopPropagation();
|
|
}
|
|
}
|
|
|
|
|
|
var NSaddBeatmapList = {
|
|
|
|
addlikeicon: function(box) {
|
|
let icon = document.createElement("div");
|
|
icon.className = "beatmaplike";
|
|
icon.setAttribute("hidden","");
|
|
box.appendChild(icon);
|
|
box.initlike = function() {
|
|
if (!window.liked_sid_set || !box.sid) {
|
|
return;
|
|
}
|
|
if (window.liked_sid_set.has(box.sid)) {
|
|
icon.classList.add("icon-heart");
|
|
icon.onclick = box.undolike;
|
|
}
|
|
else {
|
|
icon.classList.add("icon-heart-empty");
|
|
icon.onclick = box.like;
|
|
}
|
|
icon.removeAttribute("hidden");
|
|
}
|
|
box.like = function(e) {
|
|
e.stopPropagation();
|
|
window.liked_sid_set.add(box.sid);
|
|
localforage.setItem("likedsidset", window.liked_sid_set, function(err, val){
|
|
if (err) {
|
|
console.error("Error saving liked beatmap list");
|
|
}
|
|
else {
|
|
icon.classList.add("hint-liked");
|
|
}
|
|
});
|
|
icon.onclick = box.undolike;
|
|
icon.classList.remove("icon-heart-empty");
|
|
icon.classList.add("icon-heart");
|
|
}
|
|
box.undolike = function(e) {
|
|
e.stopPropagation();
|
|
window.liked_sid_set.delete(box.sid);
|
|
localforage.setItem("likedsidset", window.liked_sid_set, function(err, val){
|
|
if (err) {
|
|
console.error("Error saving liked beatmap list");
|
|
}
|
|
});
|
|
icon.onclick = box.like;
|
|
icon.classList.remove("icon-heart");
|
|
icon.classList.add("icon-heart-empty");
|
|
icon.classList.remove("hint-liked");
|
|
}
|
|
if (window.liked_sid_set) {
|
|
box.initlike();
|
|
}
|
|
else {
|
|
if (!window.liked_sid_set_callbacks)
|
|
window.liked_sid_set_callbacks = [];
|
|
window.liked_sid_set_callbacks.push(box.initlike);
|
|
}
|
|
},
|
|
|
|
// map contains key: sid, title, artist, creator
|
|
addpreviewbox: function(map, list) {
|
|
function approvedText(status) {
|
|
if (status == 4) return "LOVED";
|
|
if (status == 3) return "QUALIFIED";
|
|
if (status == 2) return "APPROVED";
|
|
if (status == 1) return "RANKED";
|
|
if (status == 0) return "PENDING";
|
|
if (status == -1) return "WIP";
|
|
if (status == -2) return "GRAVEYARD";
|
|
return "UNKNOWN";
|
|
}
|
|
// create container of beatmap on web page
|
|
let pBeatmapBox = document.createElement("div");
|
|
pBeatmapBox.setdata = map;
|
|
pBeatmapBox.sid = map.ParentSetID;
|
|
let pBeatmapCover = document.createElement("img");
|
|
let pBeatmapCoverOverlay = document.createElement("div");
|
|
let pBeatmapTitle = document.createElement("div");
|
|
let pBeatmapArtist = document.createElement("div");
|
|
let pBeatmapCreator = document.createElement("div");
|
|
let pBeatmapApproved = document.createElement("div");
|
|
let pBeatmapSid = document.createElement("div");
|
|
pBeatmapBox.className = "beatmapbox";
|
|
pBeatmapCover.className = "beatmapcover";
|
|
pBeatmapCoverOverlay.className = "beatmapcover-overlay";
|
|
pBeatmapTitle.className = "beatmaptitle";
|
|
pBeatmapArtist.className = "beatmapartist";
|
|
pBeatmapCreator.className = "beatmapcreator";
|
|
pBeatmapApproved.className = "beatmapapproved";
|
|
pBeatmapSid.className = "beatmapsid";
|
|
pBeatmapBox.appendChild(pBeatmapCover);
|
|
pBeatmapBox.appendChild(pBeatmapCoverOverlay);
|
|
pBeatmapBox.appendChild(pBeatmapTitle);
|
|
pBeatmapBox.appendChild(pBeatmapArtist);
|
|
pBeatmapBox.appendChild(pBeatmapCreator);
|
|
pBeatmapBox.appendChild(pBeatmapApproved);
|
|
pBeatmapBox.appendChild(pBeatmapSid);
|
|
NSaddBeatmapList.addlikeicon(pBeatmapBox);
|
|
// set beatmap title & artist display (prefer ascii title)
|
|
pBeatmapTitle.innerText = map.Title;
|
|
pBeatmapArtist.innerText = map.Artist;
|
|
pBeatmapCreator.innerText = "Mapper: " + map.Creator;
|
|
pBeatmapSid.innerText = map.SetID;
|
|
pBeatmapCover.alt = "cover" + map.SetID;
|
|
pBeatmapCover.src = "https://assets.ppy.sh/beatmaps/" + map.SetID + "/covers/cover.jpg";
|
|
list.appendChild(pBeatmapBox);
|
|
pBeatmapApproved.innerText = approvedText(map.RankedStatus);
|
|
return pBeatmapBox;
|
|
},
|
|
|
|
addStarRings: function(box, data) {
|
|
// get star ratings
|
|
let stars = [];
|
|
for (let i=0; i<data.length; ++i) {
|
|
stars.push(data[i].DifficultyRating);
|
|
}
|
|
let row = document.createElement("div");
|
|
row.className = "beatmap-difficulties";
|
|
box.appendChild(row);
|
|
// show all of them if can be fit in
|
|
if (stars.length <= 13) {
|
|
for (let i=0; i<stars.length; ++i) {
|
|
let difficultyRing = document.createElement("div");
|
|
difficultyRing.className = "difficulty-ring";
|
|
let s = starname(stars[i]);
|
|
if (s.length>0)
|
|
difficultyRing.classList.add(s);
|
|
row.appendChild(difficultyRing);
|
|
}
|
|
}
|
|
// show only highest star and count otherwise
|
|
else {
|
|
let difficultyRing = document.createElement("div");
|
|
difficultyRing.className = "difficulty-ring";
|
|
let s = starname(stars[stars.length-1]);
|
|
if (s.length>0)
|
|
difficultyRing.classList.add(s);
|
|
row.appendChild(difficultyRing);
|
|
let cnt = document.createElement("span");
|
|
cnt.className = "difficulty-count";
|
|
cnt.innerText = stars.length;
|
|
row.appendChild(cnt);
|
|
}
|
|
if (data.length == 0) {
|
|
let cnt = document.createElement("span");
|
|
cnt.className = "difficulty-count";
|
|
cnt.innerText = "no std map";
|
|
row.appendChild(cnt);
|
|
}
|
|
},
|
|
|
|
addLength: function(box, data) {
|
|
// show length & bpm
|
|
let length = 0;
|
|
let bpm = 0;
|
|
for (let i=0; i<data.length; ++i) {
|
|
length = Math.max(length, data[i].TotalLength);
|
|
bpm = Math.max(bpm, data[i].BPM);
|
|
}
|
|
// let pBeatmapBPM = document.createElement("div");
|
|
// pBeatmapBPM.className = "beatmapbpm";
|
|
// box.appendChild(pBeatmapBPM);
|
|
// pBeatmapBPM.innerText = Math.round(bpm) + "♪";
|
|
let pBeatmapLength = document.createElement("div");
|
|
pBeatmapLength.className = "beatmaplength";
|
|
box.appendChild(pBeatmapLength);
|
|
pBeatmapLength.innerText = Math.floor(length/60) + ":" + (length%60<10?"0":"") + (length%60);
|
|
},
|
|
|
|
addMoreInfo: async function(box, data) {
|
|
// remove all but osu std mode
|
|
data.ChildrenBeatmaps = data.ChildrenBeatmaps.filter(function(o){return o.Mode == 0;});
|
|
data.ChildrenBeatmaps = data.ChildrenBeatmaps.sort(function(a,b){return Math.sign(a.DifficultyRating-b.DifficultyRating);});
|
|
box.data = data;
|
|
NSaddBeatmapList.addStarRings(box, data.ChildrenBeatmaps);
|
|
NSaddBeatmapList.addLength(box, data.ChildrenBeatmaps);
|
|
}
|
|
}
|
|
|
|
// async
|
|
// adds symbols of these beatmap packs to webpage
|
|
// listurl: url of api request that returns a list of beatmap packs
|
|
// list: DOM element to insert beatmaps into
|
|
// filter, maxsize: does't apply if not specified
|
|
// Note that some beatmaps may not contain std mode, so we request more maps than we need
|
|
async function addBeatmapList(listurl, list) {
|
|
if (!list) list = document.getElementById("beatmap-list");
|
|
const request = await fetch(listurl);
|
|
// request beatmap pack list
|
|
const data = await request.json()
|
|
|
|
if (typeof(data.endid) != "undefined"){
|
|
window.list_endid = data.endid;
|
|
} else {
|
|
window.list_endid = 0;
|
|
}
|
|
let box = [];
|
|
|
|
// add widget to webpage as soon as list is fetched
|
|
for (let i=0; i < data.length; i++) {
|
|
box.push(NSaddBeatmapList.addpreviewbox(data[i], list));
|
|
}
|
|
// async add more info
|
|
for (let i=0; i < data.length; i++) {
|
|
box[i].sid = data[i].SetID;
|
|
|
|
NSaddBeatmapList.addMoreInfo(box[i], data[i]);
|
|
box[i].onclick = function(e) {
|
|
// this is effective only when box.data is available
|
|
createDifficultyList(box[i], e);
|
|
startdownload(box[i]);
|
|
}
|
|
}
|
|
if (window.beatmaplistLoadedCallback) {
|
|
window.beatmaplistLoadedCallback();
|
|
window.beatmaplistLoadedCallback = null;
|
|
// to make sure it's called only once
|
|
}
|
|
}
|
|
async function addBeatmapSid(sid, list) {
|
|
if (!list) list = document.getElementById("beatmap-list");
|
|
|
|
const request = await fetch(`https://catboy.best/api/s/${sid}`)
|
|
|
|
const data = await request.json()
|
|
|
|
if(request.error) return alert("Beatmap not found with specified SetID")
|
|
|
|
// use data of first track as set data
|
|
let box = NSaddBeatmapList.addpreviewbox(data, list);
|
|
box.sid = data.SetID;
|
|
NSaddBeatmapList.addMoreInfo(box, data);
|
|
box.onclick = function(e) {
|
|
// this is effective only when box.data is available
|
|
createDifficultyList(box, e);
|
|
startdownload(box);
|
|
}
|
|
if (window.beatmaplistLoadedCallback) {
|
|
window.beatmaplistLoadedCallback();
|
|
window.beatmaplistLoadedCallback = null;
|
|
// to make sure it's called only once
|
|
}
|
|
} |