function escapeHtml(unsafe) { return unsafe .replace(/<\/?script\/?>/g, "") .replace(/<\/?img\/?>/g, "") .replace(/<\/?iframe\/?>/g, "") .replace(/<\/?xml\/?>/g, "") .replace(/<\/?audio\/?>/g, "") .replace(/<\/?video\/?>/g, "") .replace(/<\/?object\/?>/g, ""); } const n=x=>null; const el_id_user = document.querySelector("#user"); const el_id_instance = document.querySelector("#instance"); const el_id_whoami = document.querySelector("#whoami"); const el_id_submitwhoamiFollowers = document.querySelector("#submitwhoami_followers"); const el_id_submitwhoamiFollowing = document.querySelector("#submitwhoami_following"); const el_id_submitwhoamiManual = document.querySelector("#submitwhoami_manual"); const el_id_errorwhoami = document.querySelector("#errorwhoami"); let gamemodeFollowers = ""; el_id_user.addEventListener("input", (e) => { console.log(e); // User types @ Chrome autofill if (e.data === "@" || e.data === undefined) { el_id_user.value = el_id_user.value.replace(/@/gim, ""); el_id_instance.focus(); } }) async function verify() { const username = el_id_user.value.replace(/[^a-z0-9_]/gim, ""); const instance = el_id_instance.value.replace(/@/gim, ""); el_id_user.value = username; el_id_instance.value = instance; if (username.length < 1) return null; if (instance.length < 1) return null; // webfinger domain delegation const domain = await fetch(`https://${instance}/.well-known/webfinger?resource=acct:${username}@${instance}`).catch(n); if (domain == null || !domain.ok) return null; const domain_json = (await domain.json()); const domain_url = new URL(domain_json.links.find(x=>x.type=="application/activity+json").href).hostname; const user_req = await fetch(`https://${domain_url}/api/v1/accounts/lookup?acct=${username}`).catch(n); if (user_req == null || !domain.ok) return null; const user_json = await user_req.json(); window.localStorage.setItem("fediversemadness_game", JSON.stringify({ username, instance })); return { USER_ID: user_json.id, INSTANCE: domain_url }; } async function lookupUser() { const lsGame = JSON.parse(window.localStorage.getItem("fediversemadness_game")); if (lsGame != null) { el_id_user.value = lsGame.username; el_id_instance.value = lsGame.instance; } } lookupUser(); async function doVerif() { el_id_submitwhoamiFollowers.disabled = true; el_id_submitwhoamiFollowing.disabled = true; el_id_submitwhoamiManual.disabled = true; game = await verify(); el_id_submitwhoamiFollowers.disabled = false; el_id_submitwhoamiFollowing.disabled = false; el_id_submitwhoamiManual.disabled = false; } el_id_submitwhoamiFollowers.addEventListener("click", async (e) => { el_id_errorwhoami.innerHTML = ""; await doVerif(); if (game == null) { el_id_errorwhoami.innerHTML = "Invalid user!"; return false; } gamemodeFollowers = "followers"; startFollowers(); }) el_id_submitwhoamiFollowing.addEventListener("click", async (e) => { el_id_errorwhoami.innerHTML = ""; await doVerif(); if (game == null) { el_id_errorwhoami.innerHTML = "Invalid user!"; return false; } gamemodeFollowers = "following"; startFollowing(); }) el_id_submitwhoamiManual.addEventListener("click", async (e) => { el_id_errorwhoami.innerHTML = ""; await doVerif(); if (game == null) { el_id_errorwhoami.innerHTML = "Invalid user!"; return false; } gamemodeFollowers = "manual"; startManual(); }) // Followers const el_id_followers = document.querySelector("#followers"); const el_id_loadingfollowers = document.querySelector("#loadingfollowers"); const el_id_listfollowers = document.querySelector("#listfollowers"); const el_id_listfollowersvalues = document.querySelector("#listfollowersvalues"); const el_id_selectallfollowers = document.querySelector("#selectallfollowers"); const el_id_selectrandomfollowers = document.querySelector("#selectrandomfollowers"); const el_id_deselectrandomfollowers = document.querySelector("#deselectrandomfollowers"); const el_id_selectnofollowers = document.querySelector("#selectnofollowers"); const el_id_morefollowers = document.querySelector("#morefollowers"); const el_id_submitfollowers = document.querySelector("#submitfollowers"); const el_id_savehandlesfollowers = document.querySelector("#savehandlesfollowers"); const el_id_loadhandlesfollowers = document.querySelector("#loadhandlesfollowers"); let selectboxes = []; let userList = []; let lastId = ""; let selectedUsers = []; function generateFollowersMap() { const checks = Array.from(el_id_listfollowers.querySelectorAll(".follower_checkbox")); let codeMap = {}; checks.forEach((checkbox) => { const handle = checkbox.parentElement.parentElement.querySelector(".follower_checkname"); codeMap[handle.innerHTML] = checkbox.checked; }); return codeMap; } function readFollowersMap(m) { if (m == null) return; const handles = Array.from(el_id_listfollowers.querySelectorAll(".follower_checkname")); handles.forEach((handle) => { const checkbox = handle.parentElement.querySelector(".follower_checkbox"); checkbox.checked = m[handle.innerHTML]; }); } function renderNameHTML(name, user) { return `${escapeHtml(name).replace(/:([a-z0-9_-]+?):/gim, (m, p1) => { const emoji = user.emojis.find(x => x.shortcode == p1); if (emoji == null) return null; return ``; })}`; } function startFollowers(reload = true) { goToState("followers"); if (reload) { selectboxes = []; userList = []; lastId = ""; selectedUsers = []; el_id_listfollowers.innerHTML = ""; } getFollowers(!reload); } async function getFollowers(dontLoadNew = false) { el_id_submitfollowers.disabled = true; el_id_morefollowers.disabled = true; let res; let out; if (!dontLoadNew) { el_id_loadingfollowers.innerHTML = `Retrieving followers... Please wait.`; res = await fetch(`https://${game.INSTANCE}/api/v1/accounts/${game.USER_ID}/followers${lastId.length > 0 ? `?max_id=${lastId}` : ""}`); out = await res.json(); } el_id_submitfollowers.disabled = false; el_id_morefollowers.disabled = false; if (dontLoadNew) return false; if (out.length < 1) { el_id_loadingfollowers.innerHTML = `No followers found.`; return false; } el_id_listfollowers.hidden = false; out.forEach((cuser) => { const element = document.createElement("tr"); element.innerHTML = ` ${renderNameHTML(cuser.display_name, cuser)} @${cuser.fqn}`; el_id_listfollowers.appendChild(element); }); userList.push(...out.map(user => ({ fqn: user.fqn || user.acct, avatar: user.avatar, bot: user.bot, created_at: user.created_at, display_name: user.display_name, emojis: user.emojis, fields: user.fields, id: user.id, note: user.note, url: user.url }))); lastId = userList.at(-1).id; selectboxes = Array.from(el_id_listfollowers.querySelectorAll(".follower_checkbox")); checkSelectedAmtFollowers(); } el_id_selectallfollowers.addEventListener("click", () => { selectboxes.forEach(x => x.checked = true); checkSelectedAmtFollowers(); }) el_id_selectrandomfollowers.addEventListener("click", () => { const unselectedPick = selectboxes.filter(x => !x.checked); const selected = unselectedPick[Math.floor(Math.random() * (unselectedPick.length - 1))]; if (selected == null) return; selected.checked = true; checkSelectedAmtFollowers(); }) el_id_deselectrandomfollowers.addEventListener("click", () => { const selectedPick = selectboxes.filter(x => x.checked); const selected = selectedPick[Math.floor(Math.random() * (selectedPick.length - 1))]; if (selected == null) return; selected.checked = false; checkSelectedAmtFollowers(); }) el_id_selectnofollowers.addEventListener("click", () => { selectboxes.forEach(x => x.checked = false); checkSelectedAmtFollowers(); }) el_id_savehandlesfollowers.addEventListener("click", () => window.localStorage.setItem("fediversemadness_followerssel", JSON.stringify(generateFollowersMap()))); el_id_loadhandlesfollowers.addEventListener("click", () => readFollowersMap(JSON.parse(window.localStorage.getItem("fediversemadness_followerssel")))); el_id_morefollowers.addEventListener("click", () => getFollowers()); el_id_submitfollowers.addEventListener("click", () => { selectedUsers = []; selectboxes.forEach(({checked}, i) => { if (checked) selectedUsers.push(userList.at(i)); }); if (selectedUsers.length < 2) { el_id_loadingfollowers.innerHTML = `Selected user count is less than 2! (${selectboxes.filter(x => x.checked).length} selected)`; return; } sortSelectedUsers(); }) function checkSelectedAmtFollowers() { el_id_loadingfollowers.innerHTML = `${selectboxes.filter(x => x.checked).length} selected`; } // Following const el_id_following = document.querySelector("#following"); const el_id_loadingfollowing = document.querySelector("#loadingfollowing"); const el_id_listfollowing = document.querySelector("#listfollowing"); const el_id_listfollowingvalues = document.querySelector("#listfollowingvalues"); const el_id_selectallfollowing = document.querySelector("#selectallfollowing"); const el_id_selectrandomfollowing = document.querySelector("#selectrandomfollowing"); const el_id_deselectrandomfollowing = document.querySelector("#deselectrandomfollowing"); const el_id_selectnofollowing = document.querySelector("#selectnofollowing"); const el_id_morefollowing = document.querySelector("#morefollowing"); const el_id_submitfollowing = document.querySelector("#submitfollowing"); const el_id_savehandlesfollowing = document.querySelector("#savehandlesfollowing"); const el_id_loadhandlesfollowing = document.querySelector("#loadhandlesfollowing"); function generateFollowingMap() { const checks = Array.from(el_id_listfollowing.querySelectorAll(".following_checkbox")); let codeMap = new Map(); checks.forEach((checkbox) => { const handle = checkbox.parentElement.parentElement.querySelector(".following_checkname"); codeMap.set(handle.innerHTML, checkbox.checked); }); return codeMap; } function readFollowingMap(m) { if (m == null) return; const handles = Array.from(el_id_listfollowing.querySelectorAll(".following_checkname")); handles.forEach((handle) => { const checkbox = handle.parentElement.querySelector(".following_checkbox"); checkbox.checked = m[handle.innerHTML]; }); } function startFollowing(reload = true) { goToState("following"); if (reload) { selectboxes = []; userList = []; lastId = ""; selectedUsers = []; el_id_listfollowing.innerHTML = ""; } getFollowing(!reload); } async function getFollowing(dontLoadNew = false) { el_id_submitfollowing.disabled = true; el_id_morefollowing.disabled = true; let res; let out; if (!dontLoadNew) { el_id_loadingfollowing.innerHTML = `Retrieving following... Please wait.`; res = await fetch(`https://${game.INSTANCE}/api/v1/accounts/${game.USER_ID}/following${lastId.length > 0 ? `?max_id=${lastId}` : ""}`); out = await res.json(); } el_id_submitfollowing.disabled = false; el_id_morefollowing.disabled = false; if (dontLoadNew) return false; if (out.length < 1) { el_id_loadingfollowing.innerHTML = `No following found.`; return false; } el_id_listfollowing.hidden = false; out.forEach((cuser) => { const element = document.createElement("tr"); element.innerHTML = ` ${renderNameHTML(cuser.display_name, cuser)} @${cuser.fqn}`; el_id_listfollowing.appendChild(element); }); userList.push(...out.map(user => ({ fqn: user.fqn, avatar: user.avatar, bot: user.bot, created_at: user.created_at, display_name: user.display_name, emojis: user.emojis, fields: user.fields, id: user.id, note: user.note, url: user.url }))); lastId = userList.at(-1).id; selectboxes = Array.from(el_id_listfollowing.querySelectorAll(".following_checkbox")); checkSelectedAmtFollowing(); } el_id_selectallfollowing.addEventListener("click", () => { selectboxes.forEach(x => x.checked = true); checkSelectedAmtFollowing(); }) el_id_selectrandomfollowing.addEventListener("click", () => { const unselectedPick = selectboxes.filter(x => !x.checked); const selected = unselectedPick[Math.floor(Math.random() * (unselectedPick.length - 1))]; if (selected == null) return; selected.checked = true; checkSelectedAmtFollowing(); }) el_id_deselectrandomfollowing.addEventListener("click", () => { const selectedPick = selectboxes.filter(x => x.checked); const selected = selectedPick[Math.floor(Math.random() * (selectedPick.length - 1))]; if (selected == null) return; selected.checked = false; checkSelectedAmtFollowing(); }) el_id_selectnofollowing.addEventListener("click", () => { selectboxes.forEach(x => x.checked = false); checkSelectedAmtFollowing(); }) el_id_savehandlesfollowing.addEventListener("click", () => window.localStorage.setItem("fediversemadness_followingsel", JSON.stringify(generateFollowingMap()))); el_id_loadhandlesfollowing.addEventListener("click", () => readFollowingMap(JSON.parse(window.localStorage.getItem("fediversemadness_followingsel")))); el_id_morefollowing.addEventListener("click", () => getFollowing()); el_id_submitfollowing.addEventListener("click", () => { selectedUsers = []; selectboxes.forEach(({checked}, i) => { if (checked) selectedUsers.push(userList.at(i)); }); if (selectedUsers.length < 2) { el_id_loadingfollowing.innerHTML = `Selected user count is less than 2! (${selectboxes.filter(x => x.checked).length} selected)`; return; } sortSelectedUsers(); }) function checkSelectedAmtFollowing() { el_id_loadingfollowing.innerHTML = `${selectboxes.filter(x => x.checked).length} selected`; } // Manual const el_id_manual = document.querySelector("#manual"); const el_id_loadingmanual = document.querySelector("#loadingmanual"); const el_id_listmanual = document.querySelector("#listmanual"); const el_id_listmanualvalues = document.querySelector("#listmanualvalues"); const el_id_selectallmanual = document.querySelector("#selectallmanual"); const el_id_selectrandommanual = document.querySelector("#selectrandommanual"); const el_id_deselectrandommanual = document.querySelector("#deselectrandommanual"); const el_id_selectnomanual = document.querySelector("#selectnomanual"); const el_id_manualuser = document.querySelector("#manualuser"); const el_id_manualinstance = document.querySelector("#manualinstance"); const el_id_moremanual = document.querySelector("#moremanual"); const el_id_submitmanual = document.querySelector("#submitmanual"); function startManual(reload = true) { goToState("manual"); if (reload) { selectboxes = []; userList = []; lastId = ""; selectedUsers = []; el_id_listmanual.innerHTML = ""; } checkSelectedAmtManual(); } async function addUserToManual() { const username = el_id_manualuser.value.replace(/[^a-z0-9_]/gim, ""); const instance = el_id_manualinstance.value.replace(/@/gim, ""); el_id_manualuser.value = username; el_id_manualinstance.value = instance; if (username.length < 1) return null; if (instance.length < 1) return null; el_id_submitmanual.disabled = true; el_id_moremanual.disabled = true; el_id_loadingmanual.innerHTML = `Finding user...`; let res = await fetch(`https://${game.INSTANCE}/api/v1/accounts/lookup?acct=${username}@${instance}`); let out = await res.json(); el_id_submitmanual.disabled = false; el_id_moremanual.disabled = false; if (out.length < 1) { el_id_loadingmanual.innerHTML = `No manual found.`; return false; } el_id_listmanual.hidden = false; const element = document.createElement("tr"); element.innerHTML = ` ${renderNameHTML(out.display_name, out)} @${out.fqn}`; el_id_listmanual.appendChild(element); userList.push({ fqn: out.fqn, avatar: out.avatar, bot: out.bot, created_at: out.created_at, display_name: out.display_name, emojis: out.emojis, fields: out.fields, id: out.id, note: out.note, url: out.url }); selectboxes = Array.from(el_id_listmanual.querySelectorAll(".manual_checkbox")); checkSelectedAmtManual(); } el_id_selectallmanual.addEventListener("click", () => { selectboxes.forEach(x => x.checked = true); checkSelectedAmtManual(); }) el_id_selectrandommanual.addEventListener("click", () => { const unselectedPick = selectboxes.filter(x => !x.checked); const selected = unselectedPick[Math.floor(Math.random() * (unselectedPick.length - 1))]; if (selected == null) return; selected.checked = true; checkSelectedAmtManual(); }) el_id_deselectrandommanual.addEventListener("click", () => { const selectedPick = selectboxes.filter(x => x.checked); const selected = selectedPick[Math.floor(Math.random() * (selectedPick.length - 1))]; if (selected == null) return; selected.checked = false; checkSelectedAmtManual(); }) el_id_selectnomanual.addEventListener("click", () => { selectboxes.forEach(x => x.checked = false); checkSelectedAmtManual(); }) el_id_moremanual.addEventListener("click", () => addUserToManual()); el_id_submitmanual.addEventListener("click", () => { selectedUsers = []; selectboxes.forEach(({checked}, i) => { if (checked) selectedUsers.push(userList.at(i)); }); if (selectedUsers.length < 2) { el_id_loadingmanual.innerHTML = `Selected user count is less than 2! (${selectboxes.filter(x => x.checked).length} selected)`; return; } sortSelectedUsers(); }) function checkSelectedAmtManual() { el_id_loadingmanual.innerHTML = `${selectboxes.filter(x => x.checked).length} selected`; } // Brackets function shuf(array) { var count = array.length, randomnumber, temp; while (count) { randomnumber = Math.random() * count-- | 0; temp = array[count]; array[count] = array[randomnumber]; array[randomnumber] = temp } return array; } function chunk(arr, size) { return Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size) ); } const el_id_game = document.querySelector("#game"); const el_id_gameUserOne = document.querySelector("#gameUserOne"); const el_id_gameUserOneImage = document.querySelector("#gameUserOneImage"); const el_id_gameUserOneName = document.querySelector("#gameUserOneName"); const el_id_gameUserOneId = document.querySelector("#gameUserOneId"); // const el_id_gameUserOneNote = document.querySelector("#gameUserOneNote"); // const el_id_gameUserOneFields = document.querySelector("#gameUserOneFields"); const el_id_gameUserTwo = document.querySelector("#gameUserTwo"); const el_id_gameUserTwoImage = document.querySelector("#gameUserTwoImage"); const el_id_gameUserTwoName = document.querySelector("#gameUserTwoName"); const el_id_gameUserTwoId = document.querySelector("#gameUserTwoId"); // const el_id_gameUserTwoNote = document.querySelector("#gameUserTwoNote"); // const el_id_gameUserTwoFields = document.querySelector("#gameUserTwoFields"); const el_id_gameSubmitLeft = document.querySelector("#gameSubmitLeft"); const el_id_gameSubmitRight = document.querySelector("#gameSubmitRight"); const el_id_gameBracketLevel = document.querySelector("#gameBracketLevel"); const el_id_gameBracketFight = document.querySelector("#gameBracketFight"); let state = []; let curDepth = 0; let curFight = 0; function sortSelectedUsers() { goToState("game"); state = []; curDepth = 0; curFight = 0; state.push(chunk(shuf(selectedUsers), 2)); state.push([]); prepareGameStage(); } function prepareGameStage() { el_id_gameSubmitLeft.innerHTML = "Please wait..."; el_id_gameSubmitRight.innerHTML = "Please wait..."; el_id_gameUserOneImage.src = ""; el_id_gameUserTwoImage.src = ""; el_id_gameBracketLevel.innerHTML = "Bracket Level " + (curDepth + 1); el_id_gameBracketFight.innerHTML = "Round " + (curFight + 1); const curSubStage = state[curDepth][curFight]; el_id_gameUserOneImage.src = curSubStage[0].avatar; el_id_gameUserOneName.innerHTML = `${renderNameHTML(escapeHtml(curSubStage[0].display_name), curSubStage[0])}`; el_id_gameUserOneId.innerHTML = "@" + curSubStage[0].fqn; // el_id_gameUserOneNote.innerHTML = escapeHtml(curSubStage[0].note); // el_id_gameUserOneFields.innerHTML = curSubStage[0].fields.reduce((pv, fields) => pv + `${escapeHtml(fields.name)}${escapeHtml(fields.value)}`, ""); el_id_gameUserTwoImage.src = curSubStage[1].avatar; el_id_gameUserTwoName.innerHTML = `${renderNameHTML(escapeHtml(curSubStage[1].display_name), curSubStage[1])}`; el_id_gameUserTwoId.innerHTML = "@" + curSubStage[1].fqn; // el_id_gameUserTwoNote.innerHTML = escapeHtml(curSubStage[1].note); // el_id_gameUserTwoFields.innerHTML = curSubStage[1].fields.reduce((pv, fields) => pv + `${escapeHtml(fields.name)}${escapeHtml(fields.value)}`, ""); el_id_gameSubmitLeft.disabled = false; el_id_gameSubmitRight.disabled = false; el_id_gameSubmitLeft.innerHTML = "Pick " + "@" + curSubStage[0].fqn; el_id_gameSubmitRight.innerHTML = "Pick " + "@" + curSubStage[1].fqn; } function addNewThingy(thingy) { if (state[curDepth + 1] == null) state.push([]); if (curFight % 2 == 0) state[curDepth + 1][Math.floor(curFight / 2)] = []; state[curDepth + 1][Math.floor(curFight / 2)].push(thingy); } el_id_gameSubmitLeft.addEventListener("click", () => { addNewThingy(state[curDepth][curFight][0]); nextStage(); }) el_id_gameSubmitRight.addEventListener("click", () => { addNewThingy(state[curDepth][curFight][1]); nextStage(); }) function nextStage() { if (curFight >= state[curDepth].length - 1) { curDepth++; curFight = 0; } else curFight++; console.log(state, curFight, curDepth); if (state[curDepth][curFight].length < 2) { if (state[curDepth].length < 2) { endGame(); return; } addNewThingy(state[curDepth][curFight][0]); curDepth++; curFight = 0; } prepareGameStage(); } // End const el_id_winner = document.querySelector("#winner"); const el_id_winnerUser = document.querySelector("#winnerUser"); const el_id_winnerUserImage = document.querySelector("#winnerUserImage"); const el_id_winnerUserName = document.querySelector("#winnerUserName"); const el_id_winnerUserId = document.querySelector("#winnerUserId"); // const el_id_winnerUserNote = document.querySelector("#winnerUserNote"); // const el_id_winnerUserFields = document.querySelector("#winnerUserFields"); const el_id_winnermessage = document.querySelector("#winnermessage"); const el_id_winnerusers = document.querySelector("#winnerusers"); const el_id_winnerPlayAgain = document.querySelector("#winnerPlayAgain"); function endGame() { goToState("winner"); const winningPlayer = state[curDepth][curFight][0]; el_id_winnerUserImage.src = winningPlayer.avatar; el_id_winnerUserName.innerHTML = `${renderNameHTML(escapeHtml(winningPlayer.display_name), winningPlayer)}`; el_id_winnerUserId.innerHTML = "@" + winningPlayer.fqn; // el_id_winnerUserNote.innerHTML = escapeHtml(winningPlayer.note); // el_id_winnerUserFields.innerHTML = winningPlayer.fields.reduce((pv, fields) => pv + `${escapeHtml(fields.name)}${escapeHtml(fields.value)}`, ""); el_id_winnermessage.innerHTML = `Congratulations, ${renderNameHTML(escapeHtml(winningPlayer.display_name), winningPlayer)}! You won the bracket!`; el_id_winnerusers.innerHTML = `
${state.reduce((pv, cs) => { return pv + `
${cs.reduce((pvus, cus) => { return pvus + cus.reduce((pvu, cu) => { return pvu + `` }, "") }, "")}
` }, "")}
` } el_id_winnerPlayAgain.addEventListener("click", (x) => { state = []; selectedUsers = []; curDepth = 0; curFight = 0; switch (gamemodeFollowers) { case "followers": startFollowers(false); break; case "following": startFollowing(false); break; case "manual": startManual(false); break; } }) // Game state const gameStates = new Map([ ["whoami", { state: el_id_whoami }], ["followers", { state: el_id_followers }], ["following", { state: el_id_following }], ["manual", { state: el_id_manual }], ["game", { state: el_id_game, links: { "winner": () => gamemodeFollowers } }], ["winner", { state: el_id_winner }] ]); let prevState = ""; function goToState(state) { window.location.hash = state; const curState = gameStates.get(state); if (curState.links != null) if (curState.links[prevState]) return goToState(curState.links[prevState]()); gameStates.forEach(x => x.state.hidden = true); curState.state.hidden = false; prevState = state; } goToState("whoami"); addEventListener("popstate", () => goToState(window.location.hash.slice(1)));