// ==UserScript== // @name Bonk Playlists // @version 5.1 // @author Salama // @description Adds map playlists to bonk.io // @match https://bonk.io/gameframe-release.html // @run-at document-start // @grant none // @supportURL https://discord.gg/Dj6usq7ww3 // @namespace https://greasyfork.org/users/824888 // @downloadURL none // ==/UserScript== // for use as a userscript ensure you have Excigma's code injector userscript // https://greasyfork.org/en/scripts/433861-code-injector-bonk-io let injector = (str) => { let newStr = str; window.playlists = {}; window.playlists.edit = false; window.playlists.autofav = false; window.playlists.editing = false; window.playlists.categoryFunc = ()=>{}; window.playlists.mapLoader = ()=>{}; window.playlists.menuFunctions = {}; window.playlists.toolFunctions = {}; window.playlists.setMapsLoaded = ()=>{}; window.playlists.setMapsLoadFinished = ()=>{}; window.playlists.bigClass = {}; let token = null; window.playlists.merge = { enabled: false, from: { element: null, index: null }, to: { element: null, index: null } }; let dropdownOption = document.createElement('div'); let playlistsButton = document.createElement('div'); let toolbox = document.createElement('div'); //Insert before favs document.getElementById("maploadtypedropdown").insertBefore(dropdownOption, document.getElementById("maploadtypedropdownoption1")); // Monitor style changes const dropdownObserver = new MutationObserver(() => { document.getElementById("maploadtypedropdownoptionplaylists").style.display = document.getElementById("maploadtypedropdownoption1").style.display; document.getElementById("maploadtypedropdownoptionplaylists").onclick = () => { document.getElementById("maploadtypedropdowntitle").innerHTML = "MY PLAYLISTS"; window.playlists.categoryFunc("blank", true); window.playlists.categoryFunc("playlists", true); document.getElementById("maploadwindowsearchoptions").style.visibility = "hidden"; document.getElementById("maploadwindowhotnessslider").style.visibility = "hidden"; document.getElementById("maploadwindowsearchinput").style.visibility = "hidden"; document.getElementById("maploadwindowsearchbutton").style.visibility = "hidden"; document.getElementById("maploadwindowtoolbox").style.display = "flex"; getPlaylists(); }; if(document.getElementById("maploadtypedropdowntitle").innerHTML === "MY PLAYLISTS") { document.getElementById("maploadwindowplaylistbackbutton").style.display = "block"; document.getElementById("maploadwindowtoolbox").style.display = "flex"; document.getElementById("maploadwindowmapscontainer").style.bottom = "28px"; document.getElementById("maploadwindowmapscontainer").style.height = "calc(100% - 108px - 23px)"; document.getElementById("maploadwindowsearchinput").style.visibility = "hidden"; document.getElementById("maploadwindowsearchbutton").style.visibility = "hidden"; } else { // Might conflict with future mods document.getElementById("maploadwindowplaylistbackbutton").style.display = "none"; document.getElementById("maploadwindowtoolbox").style.display = "none"; document.getElementById("maploadwindowmapscontainer").style.removeProperty("bottom"); document.getElementById("maploadwindowmapscontainer").style.removeProperty("height"); document.getElementById("maploadwindowsearchinput").style.removeProperty("visibility"); document.getElementById("maploadwindowsearchbutton").style.removeProperty("visibility"); if(window.playlists.edit) { document.getElementById("maploadwindowplaylistedit").click(); } if(window.playlists.merge.enabled) { document.getElementById("maploadwindowplaylistmerge").click(); } } document.getElementById("maploadwindowplaylistbackbutton").onclick = document.getElementById("maploadtypedropdownoptionplaylists").onclick; document.getElementById("maploadtypedropdownoptionplaylists").onmouseenter = document.getElementById("maploadtypedropdownoption1").onmouseenter; document.getElementById("maploadtypedropdownoptionplaylists").onmouseleave = document.getElementById("maploadtypedropdownoption1").onmouseleave; document.getElementById("maploadtypedropdownoptionplaylists").onmousedown = document.getElementById("maploadtypedropdownoption1").onmousedown; document.getElementById("maploadwindowplaylistbackbutton").onmouseenter = document.getElementById("maploadtypedropdownoption1").onmouseenter; document.getElementById("maploadwindowplaylistbackbutton").onmouseleave = document.getElementById("maploadtypedropdownoption1").onmouseleave; document.getElementById("maploadwindowplaylistbackbutton").onmousedown = document.getElementById("maploadtypedropdownoption1").onmousedown; }); chatObserver = new MutationObserver(e => { for(let mutation of e) { if(mutation.type == "childList") { for(let node of mutation.addedNodes) { if(node.textContent === "* Accepted commands are listed above ") { let helpmsg = document.createElement("div"); mutation.target.insertBefore(helpmsg, node.previousSibling); helpmsg.outerHTML = '
/p - commands from playlists mod
'; } } } } }); chatObserver.observe(document.getElementById("newbonklobby_chat_content"), {attributes: false, childList: true, subtree: false}); dropdownObserver.observe(document.getElementById("maploadtypedropdownoption1"), {attributes: true, childList: false, subtree: true}); document.getElementById("maploadwindow").appendChild(playlistsButton); document.getElementById("maploadwindow").appendChild(toolbox); toolbox.outerHTML = ``; dropdownOption.outerHTML = ``; playlistsButton.outerHTML = `
BACK
`; let dbRequest = indexedDB.open("salamaStorage", 1); let db; window.playlists.playlists = []; window.playlists.savePlaylists = playlists => { try { let transaction = db.transaction("playlists", "readwrite"); transaction.objectStore("playlists").put(playlists, 1); } catch(e) { console.log("Couln't save playlists to db: ", e) } } dbRequest.onsuccess = e => { db = e.target.result; let transaction = db.transaction("playlists"); let getRequest = transaction.objectStore("playlists").get(1); getRequest.onsuccess = e => { window.playlists.playlists = e.target.result; } } dbRequest.onupgradeneeded = e => { db = e.target.result; let objectStore = db.createObjectStore("playlists"); objectStore.put(JSON.parse(localStorage.playlists || "[]"), 1); delete localStorage.playlists; } window.playlists.setToken = t => { token = t; } //This is mainly meant to prevent you from accidentally importing the wrong file const validatePlaylists = playlists => { try { let newPlaylists = JSON.parse(playlists); for(let playlist of newPlaylists) { if(!( Object.keys(playlist).find(i => !["name","description","image","maps","b1maps"].includes(i)) === undefined && typeof(playlist.name) == "string" && typeof(playlist.description) == "string" && ((typeof(playlist.image) == "string" && playlist.image.substr(0, 5) == "data:") || playlist.image == undefined) && playlist.maps.filter(e => {return typeof(e)=="number"}).length == playlist.maps.length )) return false; } return true; } catch { return false; } } document.getElementById("maploadwindowplaylistexport").addEventListener("click", () => { let a = document.createElement("a"); document.body.appendChild(a); a.href = URL.createObjectURL(new Blob([JSON.stringify(window.playlists.playlists)], {type: "oclet/stream"})); a.download = "playlists.txt"; a.click(); document.body.removeChild(a); }) document.getElementById("maploadwindowplaylistimport").addEventListener("click", () => { let a = document.createElement("input"); a.type = 'file'; document.body.appendChild(a); a.onchange = e => { let file = e.target.files[0]; let reader = new FileReader(); reader.readAsText(file); reader.onload = readerEvent => { let newPlaylists = readerEvent.target.result; if(validatePlaylists(newPlaylists)) { window.playlists.playlists = window.playlists.playlists.concat(JSON.parse(newPlaylists)); window.playlists.savePlaylists(window.playlists.playlists); document.getElementById("maploadwindowplaylistautofav").click(); } } }; a.click(); document.body.removeChild(a); }) document.getElementById("maploadwindowplaylistautofav").addEventListener("click", async () => { let popup = document.createElement('div'); document.getElementById("maploadwindow").appendChild(popup); popup.outerHTML = `
Autofav
Counting maps...
CANCEL
START
`; let error = false; document.getElementById("maploadwindowplaylistautofavcancel").addEventListener("click", () => { error = "cancelled"; document.getElementById("maploadwindowplaylistautofavpopup").remove(); document.getElementById("maploadtypedropdownoptionplaylists").click(); }); let maps = []; const get = async count => { return new Promise(resolve => { window.$.post("https://bonk2.io/scripts/map_getfave.php", { token: token, startingfrom: 32 * count }).done(async e => { maps = maps.concat(e.maps.map(e => {return e.id})); error = (e.r == "success" ? false : e.r); if(e.more && !error) await get(count + 1); resolve(); }).fail(e => { error = e.statusText; resolve(); }); }); } await get(0); if(error && error != "cancelled") { document.getElementById("maploadwindowplaylistautofavstatus").innerText += `\nError: ${error}`; } else if(error != "cancelled") { if(window.playlists.playlists.length > 0) { maps = [...new Set(window.playlists.playlists.map(e => {return e.maps;}).reduce((a, b) => {return a.concat(b);}).filter(e => {return !maps.includes(e);}))]; } else { maps = []; } document.getElementById("maploadwindowplaylistautofavstatus").innerText += `\n${maps.length} maps to favorite`; document.getElementById("maploadwindowplaylistautofavprogress").innerText = `[${'0'.repeat((maps.length+'').length)} / ${maps.length}]`; if(maps.length == 0) return; let date = new Date(); if(maps.length > 600) { document.getElementById("maploadwindowplaylistautofavstatus").innerText += `\nYou will get ratelimited due to the high amount of maps, which means that you will have to continue this after ${((date.getHours() + 1) % 24)}:00. This also means that you can't favorite maps normally before that time.`; } else if(maps.length > 580) { document.getElementById("maploadwindowplaylistautofavstatus").innerText += `\nYou might get ratelimited due to the high amount of maps, which means that you will have to continue this after ${((date.getHours() + 1) % 24)}:00. This would also mean that you can't favorite maps normally before that time.`; } document.getElementById("maploadwindowplaylistautofavstart").classList.remove("brownButtonDisabled"); document.getElementById("maploadwindowplaylistautofavstart").addEventListener("click", async () => { document.getElementById("maploadwindowplaylistautofavstart").classList.add("brownButtonDisabled"); window.playlists.autofav = true; let count = 0; let notFound = []; for(let map of maps) { if(error) { window.playlists.autofav = false; return; } await window.$.post("https://bonk2.io/scripts/map_fave.php", { token: token, mapid: map, action: "f" }).done(e => { if(e.r === "fail") { switch(e.e) { case "map_unpublished": case "map_not_found": case "already_faved": notFound.push(map); break; case "token": document.getElementById("maploadwindowplaylistautofavstatus").innerText += "\nError: invalid token"; break; case "ratelimited": document.getElementById("maploadwindowplaylistautofavstatus").innerText += `\nRatelimited! Please continue after ${((date.getHours() + 1) % 24)}:00.`; error = "ratelimited"; break; } } count++; if(!error) document.getElementById("maploadwindowplaylistautofavprogress").innerText = `[${'0'.repeat((maps.length+'').length-(count+'').length)}${count} / ${maps.length}]`; }) } window.playlists.autofav = false; document.getElementById("maploadwindowplaylistautofavcancel").classList.add("brownButtonDisabled"); if(notFound.length > 0) { document.getElementById("maploadwindowplaylistautofavstatus").innerText += `\nSome of the playlists contain ${notFound.length} maps in total that have been hidden or deleted. Do you want to remove them?`; document.getElementById("maploadwindowplaylistautofavno").style.display = "block"; document.getElementById("maploadwindowplaylistautofavyes").style.display = "block"; document.getElementById("maploadwindowplaylistautofavstart").style.display = "none"; document.getElementById("maploadwindowplaylistautofavcancel").style.display = "none"; document.getElementById("maploadwindowplaylistautofavno").addEventListener("click", () => { document.getElementById("maploadwindowplaylistautofavpopup").remove(); document.getElementById("maploadtypedropdownoptionplaylists").click(); }); document.getElementById("maploadwindowplaylistautofavyes").addEventListener("click", () => { for(let list of window.playlists.playlists) { list.maps = list.maps.filter(e => {return notFound.indexOf(e) === -1;}); } window.playlists.savePlaylists(window.playlists.playlists); document.getElementById("maploadwindowplaylistautofavpopup").remove(); document.getElementById("maploadtypedropdownoptionplaylists").click(); }); } else { document.getElementById("maploadwindowplaylistautofavyes").innerText = "DONE"; document.getElementById("maploadwindowplaylistautofavyes").style.display = "block"; document.getElementById("maploadwindowplaylistautofavyes").addEventListener("click", () => { document.getElementById("maploadwindowplaylistautofavpopup").remove(); document.getElementById("maploadtypedropdownoptionplaylists").click(); }) } }); } }); document.getElementById("maploadwindowplaylistedit").addEventListener("click", e => { window.playlists.editing = false; window.playlists.edit = !window.playlists.edit; if(window.playlists.edit) { document.getElementById("maploadwindowplaylistmerge").classList.add("brownButtonDisabled"); document.getElementById("maploadwindowplaylistimport").classList.add("brownButtonDisabled"); document.getElementById("maploadwindowplaylistexport").classList.add("brownButtonDisabled"); document.getElementById("maploadwindowplaylistautofav").classList.add("brownButtonDisabled"); document.getElementById("maploadwindowplaylistdeleteall").style.display = "block"; document.getElementById("maploadwindowplaylistdeleteall").innerText = "DELETE ALL"; e.target.style.filter = "brightness(1.75)"; document.getElementById("maploadtypedropdownoptionplaylists").click(); } else { document.getElementById("maploadwindowplaylistedit").style.removeProperty("filter"); document.getElementById("maploadwindowplaylistmerge").classList.remove("brownButtonDisabled"); document.getElementById("maploadwindowplaylistimport").classList.remove("brownButtonDisabled"); document.getElementById("maploadwindowplaylistexport").classList.remove("brownButtonDisabled"); document.getElementById("maploadwindowplaylistautofav").classList.remove("brownButtonDisabled"); document.getElementById("maploadwindowplaylistdeleteall").style.display = "none"; window.playlists.savePlaylists(window.playlists.playlists); if(document.getElementById("maploadtypedropdowntitle").innerHTML === "MY PLAYLISTS") { document.getElementById("maploadtypedropdownoptionplaylists").click(); } } }); document.getElementById("maploadwindowplaylistmerge").addEventListener("click", e => { window.playlists.merge.enabled = !window.playlists.merge.enabled; if(window.playlists.merge.enabled) { window.playlists.edit = false; document.getElementById("maploadwindowplaylistedit").style.removeProperty("filter"); e.target.style.filter = "brightness(1.75)"; document.getElementById("maploadwindowplaylistedit").classList.add("brownButtonDisabled"); document.getElementById("maploadwindowplaylistimport").classList.add("brownButtonDisabled"); document.getElementById("maploadwindowplaylistexport").classList.add("brownButtonDisabled"); document.getElementById("maploadwindowplaylistautofav").classList.add("brownButtonDisabled"); } else { e.target.style.removeProperty("filter"); if(window.playlists.merge.from.element !== null) { window.playlists.merge.from.element.style.removeProperty("filter"); window.playlists.merge.from.element.style.visibility = "hidden"; } if(window.playlists.merge.to.element !== null) { window.playlists.merge.to.element.style.removeProperty("filter"); window.playlists.merge.to.element.style.visibility = "hidden"; } window.playlists.merge = { enabled: false, from: { element: null, index: null }, to: { element: null, index: null } }; document.getElementById("maploadwindowplaylistedit").classList.remove("brownButtonDisabled"); document.getElementById("maploadwindowplaylistimport").classList.remove("brownButtonDisabled"); document.getElementById("maploadwindowplaylistexport").classList.remove("brownButtonDisabled"); document.getElementById("maploadwindowplaylistautofav").classList.remove("brownButtonDisabled"); document.getElementById("maploadtypedropdownoptionplaylists").click(); } }); document.getElementById("maploadwindowplaylistdeleteall").addEventListener("click", e => { switch(e.target.innerText) { case "DELETE ALL": e.target.innerText = "SURE?"; break; case "SURE?": e.target.innerText = "100% SURE?"; break; case "100% SURE?": e.target.innerText = "FINAL WARNING"; break; case "FINAL WARNING": e.target.innerText = "DELETE ALL"; window.playlists.playlists = []; for(let playlist of [...document.getElementsByClassName("maploadwindowplaylistdiv")]) { playlist.style.opacity = 0.3; playlist.style.pointerEvents = "none"; } break; } }) document.getElementById("newbonklobby_mapbutton").addEventListener("click", () => { if(document.getElementById("maploadtypedropdowntitle").innerText === "MY PLAYLISTS") { document.getElementById("maploadwindowplaylistbackbutton").style.display = "block"; document.getElementById("maploadwindowtoolbox").style.display = "flex"; document.getElementById("maploadwindowmapscontainer").style.bottom = "28px"; document.getElementById("maploadwindowmapscontainer").style.height = "calc(100% - 108px - 23px)"; } else { document.getElementById("maploadwindowplaylistbackbutton").style.display = "none"; document.getElementById("maploadwindowtoolbox").style.display = "none"; document.getElementById("maploadwindowmapscontainer").style.removeProperty("bottom"); document.getElementById("maploadwindowmapscontainer").style.removeProperty("height"); } }); const chatHandler = e => { if(e.keyCode === 13) { if(e.target.value.length > 0) { if(e.target.value[0] === "/") { let command = e.target.value.split(" ")[0].substring(1); let args = e.target.value.split(" ").slice(1); if(command === "fav") { console.log("Autofav = " + window.playlists.autofav); if(window.playlists.autofav) { e.target.value = ""; window.playlists.menuFunctions.showStatusMessage("* Favoriting maps is disabled while autofav is on", "#b53030"); } } else if(command.startsWith("p") && !Number.isNaN(Number(command.substr(1)))) { e.target.value = ""; if(args[0] === "list" && command === "p") { window.playlists.menuFunctions.showStatusMessage("Saved playlists", "#b53030"); for(let i = 0; i < window.playlists.playlists.length; i++) { window.playlists.menuFunctions.showStatusMessage("* [" + (i+1) + "] " + window.playlists.playlists[i].name, "#b53030"); } return; } if(args.length === 0) { args[0] = parseInt(command.substr(1)); } if(Number.isNaN(parseInt(args[0]))) { // Show help window.playlists.menuFunctions.showStatusMessage("* List of playlist commands:", "#b53030", true); window.playlists.menuFunctions.showStatusMessage("/p list", "#b53030", true); window.playlists.menuFunctions.showStatusMessage("/p [index]", "#b53030", true); return; } if(args[0] < 1 || args[0] > window.playlists.playlists.length) { if(window.playlists.playlists.length === 0) { window.playlists.menuFunctions.showStatusMessage("You don't have any playlists!", "#b53030"); return; } window.playlists.menuFunctions.showStatusMessage("Playlist index must be between 1 and " + (window.playlists.playlists.length), "#b53030"); return; } let gameSettings = window.playlists.toolFunctions.getGameSettings(); if(!gameSettings.map.m.pub && gameSettings.map.dbv == 2) { window.playlists.menuFunctions.showStatusMessage("You can't add a private map to a playlist! If it is a Bonk 1 map, *you* need to select the map from Bonk 1 map list without starting the game. A Bonk 1 map, which is selected from a playlist, cannot be added or removed.", "#b53030"); return; } if(gameSettings.map.m.dbv === 2 && gameSettings.map.m.date !== undefined && gameSettings.map.m.date !== null && gameSettings.map.m.date !== "") { if(window.playlists.playlists[args[0] - 1].maps.includes(gameSettings.map.m.dbid)) { window.playlists.playlists[args[0] - 1].maps.splice(window.playlists.playlists[args[0] - 1].maps.indexOf(gameSettings.map.m.dbid), 1); window.playlists.menuFunctions.showStatusMessage("* Map removed from playlist", "#b53030", true); } else { // Hacky way to favorite the map e.target.value = "/fav"; window.playlists.playlists[args[0] - 1].maps.push(gameSettings.map.m.dbid); window.playlists.menuFunctions.showStatusMessage("* Map added to playlist", "#b53030", true); } } else { if(window.playlists.playlists[args[0] - 1].b1maps.map(e => {return e.id}).includes(gameSettings.map.m.dbid)) { window.playlists.playlists[args[0] - 1].b1maps.splice(window.playlists.playlists[args[0] - 1].b1maps.map(e => {return e.id}).indexOf(gameSettings.map.m.dbid), 1); window.playlists.menuFunctions.showStatusMessage("* Map removed from playlist", "#b53030", true); } else { let b1map = { id: gameSettings.map.m.dbid, name: gameSettings.map.m.n, authorname: gameSettings.map.m.a, leveldata: window.playlists.bigClass.encodeToDatabase(gameSettings.map), vu: gameSettings.map.m.vu, vd: gameSettings.map.m.vd, remixname: gameSettings.map.m.rxn, remixauthor: gameSettings.map.m.rxa, remixdb: gameSettings.map.m.rxdb, remixid: gameSettings.map.m.rxid, publisheddate: gameSettings.map.m.date } if(gameSettings.map.m.date === undefined || gameSettings.map.m.date === null || gameSettings.map.m.date === "" || gameSettings.map.m.vu * 1 != gameSettings.map.m.vu || gameSettings.map.m.vd * 1 != gameSettings.map.m.vd) { window.playlists.menuFunctions.showStatusMessage("* Map could not be added to the playlist! To add Bonk 1 maps, *you* need to select the map from Bonk 1 map list without starting the game. A Bonk 1 map, which is selected from a playlist, cannot be added or removed.", "#b53030", true); } else { window.playlists.playlists[args[0] - 1].b1maps.push(b1map); window.playlists.menuFunctions.showStatusMessage("* Map added to playlist", "#b53030", true); } } } window.playlists.savePlaylists(window.playlists.playlists); } } } } } document.getElementById("newbonklobby_chat_input").addEventListener("keydown", chatHandler, true); document.getElementById("ingamechatinputtext").addEventListener("keydown", chatHandler, true); const getPlaylists = () => { window.playlists.setMapsLoaded(false); window.playlists.setMapsLoadFinished(false); let newPlaylistButton = { name: "NEW PLAYLIST", description: "Click here to create a new playlist", image: `data:image/svg+xml,`, maps: "new", b1maps: "new" }; let playlistCreator = (list = {name: "", description: "", image: ""}, edit = null) => { let newPlaylist = document.createElement("div"); newPlaylist.classList.add("maploadwindowmapdiv"); newPlaylist.style.height = "200px"; let encodedImage; let image = document.createElement("input"); image.type = 'file'; image.style.width = "100%"; image.style.height = "110.417px"; image.style.borderWidth = "1px"; image.style.borderStyle = "solid"; image.onchange = e => { let file = e.target.files[0]; let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = readerEvent => { encodedImage = readerEvent.target.result; } }; let title = document.createElement("input"); title.classList.add("maploadwindowtext_picks"); title.classList.add("maploadwindowtextname_picks"); title.placeholder = "Playlist Name"; title.value = list.name; let description = document.createElement("input"); description.classList.add("maploadwindowtext_picks"); description.classList.add("maploadwindowtextcomment_picks"); description.placeholder = "Playlist Description"; description.style.top = "150px"; description.style.height = "60px"; description.style.height = "19px"; description.value = list.description; let cancelButton = document.createElement("div"); cancelButton.classList.add("brownButton"); cancelButton.classList.add("brownButton_classic"); cancelButton.classList.add("buttonShadow"); cancelButton.style.width = "calc(50% - 12px)"; cancelButton.style.height = "25px"; cancelButton.style.bottom = "5px"; cancelButton.style.position = "absolute"; cancelButton.innerText = "CANCEL"; cancelButton.onclick = () => { if(edit !== null) { edit.style.display = ""; } newPlaylist.remove(); window.playlists.editing = false; }; let saveButton = document.createElement("div"); saveButton.classList.add("brownButton"); saveButton.classList.add("brownButton_classic"); saveButton.classList.add("buttonShadow"); saveButton.style.width = "calc(50% - 12px)"; saveButton.style.height = "25px"; saveButton.style.bottom = "5px"; saveButton.style.right = "6px"; saveButton.style.position = "absolute"; saveButton.innerText = "SAVE"; saveButton.onclick = () => { if(edit === null) { window.playlists.playlists.push({ name: title.value, description: description.value, image: encodedImage, maps: [], b1maps: [] }); } else { window.playlists.playlists[window.playlists.playlists.indexOf(list)] = Object.assign(window.playlists.playlists[window.playlists.playlists.indexOf(list)], {name: title.value, description: description.value, image: encodedImage === undefined ? list.image : encodedImage}); } document.getElementById("maploadtypedropdownoptionplaylists").click(); window.playlists.editing = false; }; newPlaylist.appendChild(image); newPlaylist.appendChild(title); newPlaylist.appendChild(description); newPlaylist.appendChild(cancelButton); newPlaylist.appendChild(saveButton); return newPlaylist; } window.playlists.setMapsLoaded(true); for(let list of window.playlists.playlists.concat([newPlaylistButton])) { let playlist = document.createElement("div"); playlist.classList.add("maploadwindowmapdiv"); if(list != newPlaylistButton) playlist.classList.add("maploadwindowplaylistdiv"); playlist.style.height = "200px"; document.getElementById("maploadwindowmapscontainer").appendChild(playlist); let image = document.createElement("img"); if(list.image != undefined) { image.src = list.image; } else { let color = [...list.name.substr(0,32)].reduce((a, b) => a + b.charCodeAt(0), 0) % 360; image.src = `data:image/svg+xml,`; } image.style.width = "160.6px"; image.style.height = "110.417px"; let title = document.createElement("span"); title.classList.add("maploadwindowtext_picks"); title.classList.add("maploadwindowtextname_picks"); title.innerText = list.name; let description = document.createElement("span"); description.classList.add("maploadwindowtext_picks"); description.classList.add("maploadwindowtextcomment_picks"); description.style.top = "150px"; description.style.height = "60px"; description.innerText = list.description; if(list.maps !== "new") { let deleteButton = document.createElement("div"); deleteButton.style.visibility = "hidden"; deleteButton.style.width = "50px"; deleteButton.style.padding = "3px"; deleteButton.style.fontSize = "16px"; deleteButton.classList.add("maploadwindowdeletebutton"); deleteButton.classList.add("brownButton"); deleteButton.classList.add("brownButton_classic"); deleteButton.classList.add("buttonShadow"); deleteButton.innerText = "DELETE"; deleteButton.onclick = () => { if(deleteButton.innerText === "DELETE") { deleteButton.innerText = "SURE?"; return; } playlist.style.opacity = 0.3; playlist.style.pointerEvents = "none"; window.playlists.playlists.splice(window.playlists.playlists.indexOf(list), 1); } let editButton = document.createElement("div"); editButton.style.visibility = "hidden"; editButton.style.left = "10px"; editButton.style.width = "50px"; editButton.style.padding = "3px"; editButton.style.fontSize = "16px"; editButton.classList.add("maploadwindowdeletebutton"); editButton.classList.add("brownButton"); editButton.classList.add("brownButton_classic"); editButton.classList.add("buttonShadow"); editButton.innerText = "EDIT"; editButton.onclick = () => { playlist.style.display = "none"; document.getElementById("maploadwindowmapscontainer").insertBefore(playlistCreator(list, playlist), playlist); window.playlists.editing = true; } let leftButton = document.createElement("div"); leftButton.style.visibility = "hidden"; leftButton.classList.add("brownButton"); leftButton.classList.add("brownButton_classic"); leftButton.classList.add("buttonShadow"); leftButton.style.width = "26px"; leftButton.style.height = "26px" leftButton.style.bottom = "10px"; leftButton.style.left = "10px"; leftButton.style.position = "absolute"; leftButton.style.zIndex = 1; leftButton.innerText = "<"; let rightButton = document.createElement("div"); rightButton.style.visibility = "hidden"; rightButton.classList.add("brownButton"); rightButton.classList.add("brownButton_classic"); rightButton.classList.add("buttonShadow"); rightButton.style.width = "26px"; rightButton.style.height = "26px" rightButton.style.bottom = "10px"; rightButton.style.right = "10px"; rightButton.style.position = "absolute"; rightButton.style.zIndex = 1; rightButton.innerText = ">"; leftButton.onclick = () => { let index = window.playlists.playlists.indexOf(list); if(index > 0) { window.playlists.playlists[index] = window.playlists.playlists.splice(index - 1, 1, window.playlists.playlists[index])[0]; playlist.remove(); document.getElementById("maploadwindowmapscontainer").insertBefore(playlist, document.getElementById("maploadwindowmapscontainer").children[index-1]); playlist.onmouseleave(); } } rightButton.onclick = () => { let index = window.playlists.playlists.indexOf(list); if(index < window.playlists.playlists.length - 1) { window.playlists.playlists[index] = window.playlists.playlists.splice(index + 1, 1, window.playlists.playlists[index])[0]; playlist.remove(); document.getElementById("maploadwindowmapscontainer").insertBefore(playlist, document.getElementById("maploadwindowmapscontainer").children[index+1]); playlist.onmouseleave(); } } let mergeButton = document.createElement("div"); mergeButton.style.visibility = "hidden"; mergeButton.classList.add("brownButton"); mergeButton.classList.add("brownButton_classic"); mergeButton.classList.add("buttonShadow"); mergeButton.style.width = "124px"; mergeButton.style.height = "52px" mergeButton.style.top = "23px"; mergeButton.style.left = "23px"; mergeButton.style.position = "absolute"; mergeButton.style.zIndex = 1; mergeButton.style.justifyContent = "center"; mergeButton.style.display = "flex"; mergeButton.style.alignItems = "center"; mergeButton.onclick = () => { mergeButton.style.filter = "brightness(1.75)"; if(window.playlists.merge.from.index === null) { window.playlists.merge.from = { element: mergeButton, index: window.playlists.playlists.indexOf(list) } } else if(window.playlists.merge.from.element === mergeButton) { mergeButton.style.removeProperty("filter"); window.playlists.merge.from = { element: null, index: null } } else { if(mergeButton.innerText !== "SURE?") { mergeButton.innerText = "SURE?"; return; } window.playlists.merge.to = { element: mergeButton, index: window.playlists.playlists.indexOf(list) } window.playlists.playlists[window.playlists.merge.to.index].b1maps = [...new Set( (window.playlists.playlists[window.playlists.merge.from.index].b1maps.concat(window.playlists.playlists[window.playlists.merge.to.index].b1maps)).map(m => JSON.stringify(m)) )].map(m => JSON.parse(m)); window.playlists.playlists[window.playlists.merge.to.index].maps = [...new Set(window.playlists.playlists[window.playlists.merge.from.index].maps.concat(window.playlists.playlists[window.playlists.merge.to.index].maps))]; window.playlists.playlists.splice(window.playlists.merge.from.index, 1); window.playlists.merge.from.element.parentElement.style.opacity = 0.3; window.playlists.merge.from.element.parentElement.style.pointerEvents = "none"; window.playlists.savePlaylists(window.playlists.playlists); window.playlists.merge.from.element.style.removeProperty("filter"); window.playlists.merge.from.element.style.visibility = "hidden"; window.playlists.merge.to.element.style.removeProperty("filter"); window.playlists.merge.to.element.style.visibility = "hidden"; document.getElementById("maploadwindowplaylistmerge").click(); } } playlist.onmouseenter = () => { if(window.playlists.editing) return; if(window.playlists.edit) { deleteButton.style.visibility = "inherit"; editButton.style.visibility = "inherit"; leftButton.style.visibility = "inherit"; rightButton.style.visibility = "inherit"; } else if(window.playlists.merge.enabled && window.playlists.merge.from.element !== mergeButton) { if(window.playlists.merge.from.index === null) { mergeButton.innerText = "MERGE FROM"; } else { mergeButton.innerText = "MERGE TO"; mergeButton.style.removeProperty("filter"); } mergeButton.style.visibility = "inherit"; } } playlist.onmouseleave = () => { deleteButton.style.visibility = "hidden"; editButton.style.visibility = "hidden"; leftButton.style.visibility = "hidden"; rightButton.style.visibility = "hidden"; if(window.playlists.merge.from.element !== mergeButton && window.playlists.merge.to.element !== mergeButton) mergeButton.style.visibility = "hidden"; } playlist.appendChild(deleteButton); playlist.appendChild(editButton); playlist.appendChild(leftButton); playlist.appendChild(rightButton); playlist.appendChild(mergeButton); } else { playlist.id = "maploadwindowplaylistnew"; playlist.style.display = window.playlists.edit ? "inline-block" : "none"; } playlist.appendChild(image); playlist.appendChild(title); playlist.appendChild(description); playlist.onclick = (e) => { if(list.maps !== "new") { if(window.playlists.edit || window.playlists.merge.enabled) return; while(document.getElementById("maploadwindowmapscontainer").firstChild) { document.getElementById("maploadwindowmapscontainer").firstChild.remove(); } document.getElementById("maploadwindowtoolbox").style.display = "none"; document.getElementById("maploadwindowmapscontainer").style.removeProperty("bottom"); document.getElementById("maploadwindowmapscontainer").style.removeProperty("height"); document.getElementById("maploadwindowstatustext").style.visibility = "inherit"; if((list.maps.length + list.b1maps.length) == 0) { document.getElementById("maploadwindowstatustext").textContent = "No Maps"; return; } if(e.target.classList.contains("brownButton")) return; let foundBonk2Maps = 0; let addMaps = (offset = 0) => { $.post("https://bonk2.io/scripts/map_getfave.php", { token: token, startingfrom: offset * 32 }).done(function (h0i, Y0i) { if (arguments[0].r != "success") { document.getElementById("maploadwindowstatustext").style.visibility = "inherit"; document.getElementById("maploadwindowstatustext").textContent = "Fetch error"; } else { let filteredMapList = arguments[0]; filteredMapList.maps = filteredMapList.maps.filter(e => {if(list.maps.includes(e.id)) {return e;}}).sort().slice(0, list.maps.length); document.getElementById("maploadwindowstatustext").style.visibility = "hidden"; if(filteredMapList.maps.length > 0) { window.playlists.mapLoader(filteredMapList); foundBonk2Maps += filteredMapList.maps.length; } if(arguments[0].more && foundBonk2Maps < list.maps.length) { addMaps(offset + 1); } else if(list.b1maps.length > 0) { window.playlists.mapLoader({r: "success", maps: list.b1maps, more: false}, 0); window.playlists.setMapsLoadFinished(true); } else { window.playlists.setMapsLoadFinished(true); } } }); } addMaps(); } else if(list.maps === "new" && !window.playlists.editing) { playlist.style.display = "none"; document.getElementById("maploadwindowmapscontainer").insertBefore(playlistCreator(), playlist); } } } document.getElementById("maploadwindowstatustext").style.visibility = "hidden"; } patchCounter = 0; const patch = (a, b) => { c = newStr; newStr = newStr.replace(a, b); //console.log(`Patch ${patchCounter++}: ${c === newStr ? 'fail' : 'success'}`); return c !== newStr; } const categoryFunc = newStr.match(/[A-Za-z0-9\$_]{3}\([A-Za-z0-9\$_]{3}\.[A-Za-z0-9\$_]{3}\([0-9]*\),true\)/)[0].substr(0,3); patch(`function ${categoryFunc}`, `window.playlists.categoryFunc=${categoryFunc};function ${categoryFunc}`); //Get map loader let mapLoader = newStr.match(/function [A-Za-z0-9\$_]{3}.{0,500}try{\(function\(\){.{1000}/g); for(let loader of mapLoader) { if(loader.match("=2")) { mapLoader = loader; break; }; } mapLoader = mapLoader.split("(")[0].split(" ")[1]; patch(`function ${mapLoader}`, `window.playlists.mapLoader=${mapLoader};function ${mapLoader}`); //Get token patch('[1,10000,25000,100000,500000,8000000,5000000000];', '[1,10000,25000,100000,500000,8000000,5000000000];' + "window.playlists.setToken(arguments[0]);"); //Mapload ready variable let readyVar = newStr.match(/\+ 1000 && [A-Za-z0-9\$_]{3}\[[0-9+]+\]/)[0].split(" ")[3]; patch('[1,10000,25000,100000,500000,8000000,5000000000];', '[1,10000,25000,100000,500000,8000000,5000000000];' + `window.playlists.setMapsLoaded=a=>{${readyVar}=a;};`); //Mapload finish variable let finishVar = newStr.match(/false\);\}else \{if\([A-Za-z0-9\$_]{3}\[[0-9]+\]\)\{/)[0].split(/[\(\)]/)[2]; //Inverting the value is important patch('[1,10000,25000,100000,500000,8000000,5000000000];', '[1,10000,25000,100000,500000,8000000,5000000000];' + `window.playlists.setMapsFinished=a=>{${finishVar}=!a;};`); //Get some useful functions let menuRegex = newStr.match(/== 13\){...\(\);}}/)[0]; patch(menuRegex, menuRegex + "window.playlists.menuFunctions = this;"); let toolRegex = newStr.match(/=new [A-Za-z0-9\$_]{1,3}\(this,[A-Za-z0-9\$_]{1,3}\[0\]\[0\],[A-Za-z0-9\$_]{1,3}\[0\]\[1\]\);/); patch(toolRegex, toolRegex + "window.playlists.toolFunctions = this;"); //Big class let bigClass = newStr.match(/[A-Z]\[[A-Za-z0-9\$_]{1,3}\[[0-9]+\]\[[0-9]+\]\]\([A-Za-z0-9\$_]{1,3}\[0\]\[0\]\);[A-Za-z0-9\$_]{1,3}\[[0-9]+\]\[[A-Za-z0-9\$_]{1,3}\[[0-9]+\]\[[0-9]+\]\]\([A-Za-z0-9\$_]{1,3}\[[0-9]+\],{m:/)[0][0]; patch(`function ${bigClass}(){}`, `function ${bigClass}(){};window.playlists.bigClass=${bigClass};`); console.log("Bonk Playlists injector run"); return newStr; } if(!window.bonkCodeInjectors) window.bonkCodeInjectors = []; window.bonkCodeInjectors.push(bonkCode => { try { return injector(bonkCode); } catch (error) { alert( `Whoops! Bonk Playlists was unable to load. This may be due to an update to Bonk.io. If so, please report this error! This could also be because you have an extension that is incompatible with \ Bonk Playlists, such as the Bonk Leagues Client. You would have to disable it to use \ Bonk Playlists.`); throw error; } }); console.log("Bonk Playlists injector loaded");